"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/@lexical+table@0.41.0";
exports.ids = ["vendor-chunks/@lexical+table@0.41.0"];
exports.modules = {
/***/ "(rsc)/./node_modules/.pnpm/@lexical+table@0.41.0/node_modules/@lexical/table/LexicalTable.dev.mjs":
/*!***************************************************************************************************!*\
!*** ./node_modules/.pnpm/@lexical+table@0.41.0/node_modules/@lexical/table/LexicalTable.dev.mjs ***!
\***************************************************************************************************/
/***/ ((__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 */ $computeTableMap: () => (/* binding */ $computeTableMap),\n/* harmony export */ $computeTableMapSkipCellCheck: () => (/* binding */ $computeTableMapSkipCellCheck),\n/* harmony export */ $createTableCellNode: () => (/* binding */ $createTableCellNode),\n/* harmony export */ $createTableNode: () => (/* binding */ $createTableNode),\n/* harmony export */ $createTableNodeWithDimensions: () => (/* binding */ $createTableNodeWithDimensions),\n/* harmony export */ $createTableRowNode: () => (/* binding */ $createTableRowNode),\n/* harmony export */ $createTableSelection: () => (/* binding */ $createTableSelection),\n/* harmony export */ $createTableSelectionFrom: () => (/* binding */ $createTableSelectionFrom),\n/* harmony export */ $deleteTableColumn: () => (/* binding */ $deleteTableColumn),\n/* harmony export */ $deleteTableColumnAtSelection: () => (/* binding */ $deleteTableColumnAtSelection),\n/* harmony export */ $deleteTableColumn__EXPERIMENTAL: () => (/* binding */ $deleteTableColumn__EXPERIMENTAL),\n/* harmony export */ $deleteTableRowAtSelection: () => (/* binding */ $deleteTableRowAtSelection),\n/* harmony export */ $deleteTableRow__EXPERIMENTAL: () => (/* binding */ $deleteTableRow__EXPERIMENTAL),\n/* harmony export */ $findCellNode: () => (/* binding */ $findCellNode),\n/* harmony export */ $findTableNode: () => (/* binding */ $findTableNode),\n/* harmony export */ $getElementForTableNode: () => (/* binding */ $getElementForTableNode),\n/* harmony export */ $getNodeTriplet: () => (/* binding */ $getNodeTriplet),\n/* harmony export */ $getTableAndElementByKey: () => (/* binding */ $getTableAndElementByKey),\n/* harmony export */ $getTableCellNodeFromLexicalNode: () => (/* binding */ $getTableCellNodeFromLexicalNode),\n/* harmony export */ $getTableCellNodeRect: () => (/* binding */ $getTableCellNodeRect),\n/* harmony export */ $getTableColumnIndexFromTableCellNode: () => (/* binding */ $getTableColumnIndexFromTableCellNode),\n/* harmony export */ $getTableNodeFromLexicalNodeOrThrow: () => (/* binding */ $getTableNodeFromLexicalNodeOrThrow),\n/* harmony export */ $getTableRowIndexFromTableCellNode: () => (/* binding */ $getTableRowIndexFromTableCellNode),\n/* harmony export */ $getTableRowNodeFromTableCellNodeOrThrow: () => (/* binding */ $getTableRowNodeFromTableCellNodeOrThrow),\n/* harmony export */ $insertTableColumn: () => (/* binding */ $insertTableColumn),\n/* harmony export */ $insertTableColumnAtSelection: () => (/* binding */ $insertTableColumnAtSelection),\n/* harmony export */ $insertTableColumn__EXPERIMENTAL: () => (/* binding */ $insertTableColumn__EXPERIMENTAL),\n/* harmony export */ $insertTableRow: () => (/* binding */ $insertTableRow),\n/* harmony export */ $insertTableRowAtSelection: () => (/* binding */ $insertTableRowAtSelection),\n/* harmony export */ $insertTableRow__EXPERIMENTAL: () => (/* binding */ $insertTableRow__EXPERIMENTAL),\n/* harmony export */ $isScrollableTablesActive: () => (/* binding */ $isScrollableTablesActive),\n/* harmony export */ $isSimpleTable: () => (/* binding */ $isSimpleTable),\n/* harmony export */ $isTableCellNode: () => (/* binding */ $isTableCellNode),\n/* harmony export */ $isTableNode: () => (/* binding */ $isTableNode),\n/* harmony export */ $isTableRowNode: () => (/* binding */ $isTableRowNode),\n/* harmony export */ $isTableSelection: () => (/* binding */ $isTableSelection),\n/* harmony export */ $mergeCells: () => (/* binding */ $mergeCells),\n/* harmony export */ $moveTableColumn: () => (/* binding */ $moveTableColumn),\n/* harmony export */ $removeTableRowAtIndex: () => (/* binding */ $removeTableRowAtIndex),\n/* harmony export */ $unmergeCell: () => (/* binding */ $unmergeCell),\n/* harmony export */ INSERT_TABLE_COMMAND: () => (/* binding */ INSERT_TABLE_COMMAND),\n/* harmony export */ TableCellHeaderStates: () => (/* binding */ TableCellHeaderStates),\n/* harmony export */ TableCellNode: () => (/* binding */ TableCellNode),\n/* harmony export */ TableExtension: () => (/* binding */ TableExtension),\n/* harmony export */ TableNode: () => (/* binding */ TableNode),\n/* harmony export */ TableObserver: () => (/* binding */ TableObserver),\n/* harmony export */ TableRowNode: () => (/* binding */ TableRowNode),\n/* harmony export */ applyTableHandlers: () => (/* binding */ applyTableHandlers),\n/* harmony export */ getDOMCellFromTarget: () => (/* binding */ getDOMCellFromTarget),\n/* harmony export */ getTableElement: () => (/* binding */ getTableElement),\n/* harmony export */ getTableObserverFromTableElement: () => (/* binding */ getTableObserverFromTableElement),\n/* harmony export */ registerTableCellUnmergeTransform: () => (/* binding */ registerTableCellUnmergeTransform),\n/* harmony export */ registerTablePlugin: () => (/* binding */ registerTablePlugin),\n/* harmony export */ registerTableSelectionObserver: () => (/* binding */ registerTableSelectionObserver),\n/* harmony export */ setScrollableTablesActive: () => (/* binding */ setScrollableTablesActive)\n/* harmony export */ });\n/* harmony import */ var lexical__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lexical */ \"(rsc)/./node_modules/.pnpm/lexical@0.41.0/node_modules/lexical/Lexical.dev.mjs\");\n/* harmony import */ var _lexical_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lexical/utils */ \"(rsc)/./node_modules/.pnpm/@lexical+utils@0.41.0/node_modules/@lexical/utils/LexicalUtils.dev.mjs\");\n/* harmony import */ var _lexical_extension__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @lexical/extension */ \"(rsc)/./node_modules/.pnpm/@lexical+extension@0.41.0/node_modules/@lexical/extension/LexicalExtension.dev.mjs\");\n/* harmony import */ var _lexical_clipboard__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lexical/clipboard */ \"(rsc)/./node_modules/.pnpm/@lexical+clipboard@0.41.0/node_modules/@lexical/clipboard/LexicalClipboard.dev.mjs\");\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n\n\n\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst PIXEL_VALUE_REG_EXP = /^(\\d+(?:\\.\\d+)?)px$/;\n\n// .PlaygroundEditorTheme__tableCell width value from\n// packages/lexical-playground/src/themes/PlaygroundEditorTheme.css\nconst COLUMN_WIDTH = 75;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst TableCellHeaderStates = {\n BOTH: 3,\n COLUMN: 2,\n NO_STATUS: 0,\n ROW: 1\n};\n/** @noInheritDoc */\nclass TableCellNode extends lexical__WEBPACK_IMPORTED_MODULE_0__.ElementNode {\n /** @internal */\n __colSpan;\n /** @internal */\n __rowSpan;\n /** @internal */\n __headerState;\n /** @internal */\n __width;\n /** @internal */\n __backgroundColor;\n /** @internal */\n __verticalAlign;\n static getType() {\n return 'tablecell';\n }\n static clone(node) {\n return new TableCellNode(node.__headerState, node.__colSpan, node.__width, node.__key);\n }\n afterCloneFrom(node) {\n super.afterCloneFrom(node);\n this.__rowSpan = node.__rowSpan;\n this.__backgroundColor = node.__backgroundColor;\n this.__verticalAlign = node.__verticalAlign;\n }\n static importDOM() {\n return {\n td: node => ({\n conversion: $convertTableCellNodeElement,\n priority: 0\n }),\n th: node => ({\n conversion: $convertTableCellNodeElement,\n priority: 0\n })\n };\n }\n static importJSON(serializedNode) {\n return $createTableCellNode().updateFromJSON(serializedNode);\n }\n updateFromJSON(serializedNode) {\n return super.updateFromJSON(serializedNode).setHeaderStyles(serializedNode.headerState).setColSpan(serializedNode.colSpan || 1).setRowSpan(serializedNode.rowSpan || 1).setWidth(serializedNode.width || undefined).setBackgroundColor(serializedNode.backgroundColor || null).setVerticalAlign(serializedNode.verticalAlign || undefined);\n }\n constructor(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width, key) {\n super(key);\n this.__colSpan = colSpan;\n this.__rowSpan = 1;\n this.__headerState = headerState;\n this.__width = width;\n this.__backgroundColor = null;\n this.__verticalAlign = undefined;\n }\n createDOM(config) {\n const element = document.createElement(this.getTag());\n if (this.__width) {\n element.style.width = `${this.__width}px`;\n }\n if (this.__colSpan > 1) {\n element.colSpan = this.__colSpan;\n }\n if (this.__rowSpan > 1) {\n element.rowSpan = this.__rowSpan;\n }\n if (this.__backgroundColor !== null) {\n element.style.backgroundColor = this.__backgroundColor;\n }\n if (isValidVerticalAlign(this.__verticalAlign)) {\n element.style.verticalAlign = this.__verticalAlign;\n }\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(element, config.theme.tableCell, this.hasHeader() && config.theme.tableCellHeader);\n return element;\n }\n exportDOM(editor) {\n const output = super.exportDOM(editor);\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.isHTMLElement)(output.element)) {\n const element = output.element;\n element.setAttribute('data-temporary-table-cell-lexical-key', this.getKey());\n element.style.border = '1px solid black';\n if (this.__colSpan > 1) {\n element.colSpan = this.__colSpan;\n }\n if (this.__rowSpan > 1) {\n element.rowSpan = this.__rowSpan;\n }\n element.style.width = `${this.getWidth() || COLUMN_WIDTH}px`;\n element.style.verticalAlign = this.getVerticalAlign() || 'top';\n element.style.textAlign = 'start';\n if (this.__backgroundColor === null && this.hasHeader()) {\n element.style.backgroundColor = '#f2f3f5';\n }\n }\n return output;\n }\n exportJSON() {\n return {\n ...super.exportJSON(),\n ...(isValidVerticalAlign(this.__verticalAlign) && {\n verticalAlign: this.__verticalAlign\n }),\n backgroundColor: this.getBackgroundColor(),\n colSpan: this.__colSpan,\n headerState: this.__headerState,\n rowSpan: this.__rowSpan,\n width: this.getWidth()\n };\n }\n getColSpan() {\n return this.getLatest().__colSpan;\n }\n setColSpan(colSpan) {\n const self = this.getWritable();\n self.__colSpan = colSpan;\n return self;\n }\n getRowSpan() {\n return this.getLatest().__rowSpan;\n }\n setRowSpan(rowSpan) {\n const self = this.getWritable();\n self.__rowSpan = rowSpan;\n return self;\n }\n getTag() {\n return this.hasHeader() ? 'th' : 'td';\n }\n setHeaderStyles(headerState, mask = TableCellHeaderStates.BOTH) {\n const self = this.getWritable();\n self.__headerState = headerState & mask | self.__headerState & ~mask;\n return self;\n }\n getHeaderStyles() {\n return this.getLatest().__headerState;\n }\n setWidth(width) {\n const self = this.getWritable();\n self.__width = width;\n return self;\n }\n getWidth() {\n return this.getLatest().__width;\n }\n getBackgroundColor() {\n return this.getLatest().__backgroundColor;\n }\n setBackgroundColor(newBackgroundColor) {\n const self = this.getWritable();\n self.__backgroundColor = newBackgroundColor;\n return self;\n }\n getVerticalAlign() {\n return this.getLatest().__verticalAlign;\n }\n setVerticalAlign(newVerticalAlign) {\n const self = this.getWritable();\n self.__verticalAlign = newVerticalAlign || undefined;\n return self;\n }\n toggleHeaderStyle(headerStateToToggle) {\n const self = this.getWritable();\n if ((self.__headerState & headerStateToToggle) === headerStateToToggle) {\n self.__headerState -= headerStateToToggle;\n } else {\n self.__headerState += headerStateToToggle;\n }\n return self;\n }\n hasHeaderState(headerState) {\n return (this.getHeaderStyles() & headerState) === headerState;\n }\n hasHeader() {\n return this.getLatest().__headerState !== TableCellHeaderStates.NO_STATUS;\n }\n updateDOM(prevNode) {\n return prevNode.__headerState !== this.__headerState || prevNode.__width !== this.__width || prevNode.__colSpan !== this.__colSpan || prevNode.__rowSpan !== this.__rowSpan || prevNode.__backgroundColor !== this.__backgroundColor || prevNode.__verticalAlign !== this.__verticalAlign;\n }\n isShadowRoot() {\n return true;\n }\n collapseAtStart() {\n return true;\n }\n canBeEmpty() {\n return false;\n }\n canIndent() {\n return false;\n }\n}\nfunction isValidVerticalAlign(verticalAlign) {\n return verticalAlign === 'middle' || verticalAlign === 'bottom';\n}\nfunction $convertTableCellNodeElement(domNode) {\n const domNode_ = domNode;\n const nodeName = domNode.nodeName.toLowerCase();\n let width = undefined;\n if (PIXEL_VALUE_REG_EXP.test(domNode_.style.width)) {\n width = parseFloat(domNode_.style.width);\n }\n\n // Determine header state based on the 'scope' attribute\n let headerState = TableCellHeaderStates.NO_STATUS;\n if (nodeName === 'th') {\n const scope = domNode_.getAttribute('scope');\n if (scope === 'col') {\n headerState = TableCellHeaderStates.COLUMN;\n } else if (scope === 'row') {\n headerState = TableCellHeaderStates.ROW;\n } else {\n headerState = TableCellHeaderStates.ROW;\n }\n }\n const tableCellNode = $createTableCellNode(headerState, domNode_.colSpan, width);\n tableCellNode.__rowSpan = domNode_.rowSpan;\n const backgroundColor = domNode_.style.backgroundColor;\n if (backgroundColor !== '') {\n tableCellNode.__backgroundColor = backgroundColor;\n }\n const verticalAlign = domNode_.style.verticalAlign;\n if (isValidVerticalAlign(verticalAlign)) {\n tableCellNode.__verticalAlign = verticalAlign;\n }\n const style = domNode_.style;\n const textDecoration = (style && style.textDecoration || '').split(' ');\n const hasBoldFontWeight = style.fontWeight === '700' || style.fontWeight === 'bold';\n const hasLinethroughTextDecoration = textDecoration.includes('line-through');\n const hasItalicFontStyle = style.fontStyle === 'italic';\n const hasUnderlineTextDecoration = textDecoration.includes('underline');\n return {\n after: childLexicalNodes => {\n const result = [];\n let paragraphNode = null;\n const removeSingleLineBreakNode = () => {\n if (paragraphNode) {\n const firstChild = paragraphNode.getFirstChild();\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isLineBreakNode)(firstChild) && paragraphNode.getChildrenSize() === 1) {\n firstChild.remove();\n }\n }\n };\n for (const child of childLexicalNodes) {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isInlineElementOrDecoratorNode)(child) || (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isTextNode)(child) || (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isLineBreakNode)(child)) {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isTextNode)(child)) {\n if (hasBoldFontWeight) {\n child.toggleFormat('bold');\n }\n if (hasLinethroughTextDecoration) {\n child.toggleFormat('strikethrough');\n }\n if (hasItalicFontStyle) {\n child.toggleFormat('italic');\n }\n if (hasUnderlineTextDecoration) {\n child.toggleFormat('underline');\n }\n }\n if (paragraphNode) {\n paragraphNode.append(child);\n } else {\n paragraphNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)().append(child);\n result.push(paragraphNode);\n }\n } else {\n result.push(child);\n removeSingleLineBreakNode();\n paragraphNode = null;\n }\n }\n removeSingleLineBreakNode();\n if (result.length === 0) {\n result.push((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)());\n }\n return result;\n },\n node: tableCellNode\n };\n}\nfunction $createTableCellNode(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width) {\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$applyNodeReplacement)(new TableCellNode(headerState, colSpan, width));\n}\nfunction $isTableCellNode(node) {\n return node instanceof TableCellNode;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst INSERT_TABLE_COMMAND = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.createCommand)('INSERT_TABLE_COMMAND');\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n// Do not require this module directly! Use normal `invariant` calls.\n\nfunction formatDevErrorMessage(message) {\n throw new Error(message);\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/** @noInheritDoc */\nclass TableRowNode extends lexical__WEBPACK_IMPORTED_MODULE_0__.ElementNode {\n /** @internal */\n __height;\n static getType() {\n return 'tablerow';\n }\n static clone(node) {\n return new TableRowNode(node.__height, node.__key);\n }\n static importDOM() {\n return {\n tr: node => ({\n conversion: $convertTableRowElement,\n priority: 0\n })\n };\n }\n static importJSON(serializedNode) {\n return $createTableRowNode().updateFromJSON(serializedNode);\n }\n updateFromJSON(serializedNode) {\n return super.updateFromJSON(serializedNode).setHeight(serializedNode.height);\n }\n constructor(height, key) {\n super(key);\n this.__height = height;\n }\n exportJSON() {\n const height = this.getHeight();\n return {\n ...super.exportJSON(),\n ...(height === undefined ? undefined : {\n height\n })\n };\n }\n createDOM(config) {\n const element = document.createElement('tr');\n if (this.__height) {\n element.style.height = `${this.__height}px`;\n }\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(element, config.theme.tableRow);\n return element;\n }\n extractWithChild(child, selection, destination) {\n return destination === 'html';\n }\n isShadowRoot() {\n return true;\n }\n setHeight(height) {\n const self = this.getWritable();\n self.__height = height;\n return self;\n }\n getHeight() {\n return this.getLatest().__height;\n }\n updateDOM(prevNode) {\n return prevNode.__height !== this.__height;\n }\n canBeEmpty() {\n return false;\n }\n canIndent() {\n return false;\n }\n}\nfunction $convertTableRowElement(domNode) {\n const domNode_ = domNode;\n let height = undefined;\n if (PIXEL_VALUE_REG_EXP.test(domNode_.style.height)) {\n height = parseFloat(domNode_.style.height);\n }\n return {\n after: children => (0,_lexical_utils__WEBPACK_IMPORTED_MODULE_1__.$descendantsMatching)(children, $isTableCellNode),\n node: $createTableRowNode(height)\n };\n}\nfunction $createTableRowNode(height) {\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$applyNodeReplacement)(new TableRowNode(height));\n}\nfunction $isTableRowNode(node) {\n return node instanceof TableRowNode;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst documentMode = CAN_USE_DOM && 'documentMode' in document ? document.documentMode : null;\nconst IS_FIREFOX = CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);\nCAN_USE_DOM && 'InputEvent' in window && !documentMode ? 'getTargetRanges' in new window.InputEvent('input') : false;\n\nfunction $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) {\n const tableNode = $createTableNode();\n for (let iRow = 0; iRow < rowCount; iRow++) {\n const tableRowNode = $createTableRowNode();\n for (let iColumn = 0; iColumn < columnCount; iColumn++) {\n let headerState = TableCellHeaderStates.NO_STATUS;\n if (typeof includeHeaders === 'object') {\n if (iRow === 0 && includeHeaders.rows) {\n headerState |= TableCellHeaderStates.ROW;\n }\n if (iColumn === 0 && includeHeaders.columns) {\n headerState |= TableCellHeaderStates.COLUMN;\n }\n } else if (includeHeaders) {\n if (iRow === 0) {\n headerState |= TableCellHeaderStates.ROW;\n }\n if (iColumn === 0) {\n headerState |= TableCellHeaderStates.COLUMN;\n }\n }\n const tableCellNode = $createTableCellNode(headerState);\n const paragraphNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)();\n paragraphNode.append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createTextNode)());\n tableCellNode.append(paragraphNode);\n tableRowNode.append(tableCellNode);\n }\n tableNode.append(tableRowNode);\n }\n return tableNode;\n}\nfunction $getTableCellNodeFromLexicalNode(startingNode) {\n const node = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(startingNode, n => $isTableCellNode(n));\n if ($isTableCellNode(node)) {\n return node;\n }\n return null;\n}\nfunction $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {\n const node = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(startingNode, n => $isTableRowNode(n));\n if ($isTableRowNode(node)) {\n return node;\n }\n throw new Error('Expected table cell to be inside of table row.');\n}\nfunction $getTableNodeFromLexicalNodeOrThrow(startingNode) {\n const node = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(startingNode, n => $isTableNode(n));\n if ($isTableNode(node)) {\n return node;\n }\n throw new Error('Expected table cell to be inside of table.');\n}\nfunction $getTableRowIndexFromTableCellNode(tableCellNode) {\n const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);\n const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableRowNode);\n return tableNode.getChildren().findIndex(n => n.is(tableRowNode));\n}\nfunction $getTableColumnIndexFromTableCellNode(tableCellNode) {\n const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);\n return tableRowNode.getChildren().findIndex(n => n.is(tableCellNode));\n}\nfunction $getTableCellSiblingsFromTableCellNode(tableCellNode, table) {\n const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);\n const {\n x,\n y\n } = tableNode.getCordsFromCellNode(tableCellNode, table);\n return {\n above: tableNode.getCellNodeFromCords(x, y - 1, table),\n below: tableNode.getCellNodeFromCords(x, y + 1, table),\n left: tableNode.getCellNodeFromCords(x - 1, y, table),\n right: tableNode.getCellNodeFromCords(x + 1, y, table)\n };\n}\nfunction $removeTableRowAtIndex(tableNode, indexToDelete) {\n const tableRows = tableNode.getChildren();\n if (indexToDelete >= tableRows.length || indexToDelete < 0) {\n throw new Error('Expected table cell to be inside of table row.');\n }\n const targetRowNode = tableRows[indexToDelete];\n targetRowNode.remove();\n return tableNode;\n}\n\n/**\n * @deprecated This function does not support merged cells. Use {@link $insertTableRowAtSelection} or {@link $insertTableRowAtNode} instead.\n */\nfunction $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount, table) {\n const tableRows = tableNode.getChildren();\n if (targetIndex >= tableRows.length || targetIndex < 0) {\n throw new Error('Table row target index out of range');\n }\n const targetRowNode = tableRows[targetIndex];\n if ($isTableRowNode(targetRowNode)) {\n for (let r = 0; r < rowCount; r++) {\n const tableRowCells = targetRowNode.getChildren();\n const tableColumnCount = tableRowCells.length;\n const newTableRowNode = $createTableRowNode();\n for (let c = 0; c < tableColumnCount; c++) {\n const tableCellFromTargetRow = tableRowCells[c];\n if (!$isTableCellNode(tableCellFromTargetRow)) {\n formatDevErrorMessage(`Expected table cell`);\n }\n const {\n above,\n below\n } = $getTableCellSiblingsFromTableCellNode(tableCellFromTargetRow, table);\n let headerState = TableCellHeaderStates.NO_STATUS;\n const width = above && above.getWidth() || below && below.getWidth() || undefined;\n if (above && above.hasHeaderState(TableCellHeaderStates.COLUMN) || below && below.hasHeaderState(TableCellHeaderStates.COLUMN)) {\n headerState |= TableCellHeaderStates.COLUMN;\n }\n const tableCellNode = $createTableCellNode(headerState, 1, width);\n tableCellNode.append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)());\n newTableRowNode.append(tableCellNode);\n }\n if (shouldInsertAfter) {\n targetRowNode.insertAfter(newTableRowNode);\n } else {\n targetRowNode.insertBefore(newTableRowNode);\n }\n }\n } else {\n throw new Error('Row before insertion index does not exist.');\n }\n return tableNode;\n}\nconst getHeaderState = (currentState, possibleState) => {\n if (currentState === TableCellHeaderStates.BOTH || currentState === possibleState) {\n return possibleState;\n }\n return TableCellHeaderStates.NO_STATUS;\n};\n\n/**\n * Inserts a table row before or after the current focus cell node,\n * taking into account any spans. If successful, returns the\n * inserted table row node.\n */\nfunction $insertTableRowAtSelection(insertAfter = true) {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) || $isTableSelection(selection))) {\n formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);\n }\n const anchor = selection.anchor.getNode();\n const focus = selection.focus.getNode();\n const [anchorCell] = $getNodeTriplet(anchor);\n const [focusCell,, grid] = $getNodeTriplet(focus);\n const [, focusCellMap, anchorCellMap] = $computeTableMap(grid, focusCell, anchorCell);\n const {\n startRow: anchorStartRow\n } = anchorCellMap;\n const {\n startRow: focusStartRow\n } = focusCellMap;\n if (insertAfter) {\n return $insertTableRowAtNode(anchorStartRow + anchorCell.__rowSpan > focusStartRow + focusCell.__rowSpan ? anchorCell : focusCell, true);\n } else {\n return $insertTableRowAtNode(focusStartRow < anchorStartRow ? focusCell : anchorCell, false);\n }\n}\n\n/**\n * @deprecated renamed to {@link $insertTableRowAtSelection}\n */\nconst $insertTableRow__EXPERIMENTAL = $insertTableRowAtSelection;\n\n/**\n * Inserts a table row before or after the given cell node,\n * taking into account any spans. If successful, returns the\n * inserted table row node.\n */\nfunction $insertTableRowAtNode(cellNode, insertAfter = true) {\n const [,, grid] = $getNodeTriplet(cellNode);\n const [gridMap, cellMap] = $computeTableMap(grid, cellNode, cellNode);\n const columnCount = gridMap[0].length;\n const {\n startRow: cellStartRow\n } = cellMap;\n let insertedRow = null;\n if (insertAfter) {\n const insertAfterEndRow = cellStartRow + cellNode.__rowSpan - 1;\n const insertAfterEndRowMap = gridMap[insertAfterEndRow];\n const newRow = $createTableRowNode();\n for (let i = 0; i < columnCount; i++) {\n const {\n cell,\n startRow\n } = insertAfterEndRowMap[i];\n if (startRow + cell.__rowSpan - 1 <= insertAfterEndRow) {\n const currentCell = insertAfterEndRowMap[i].cell;\n const currentCellHeaderState = currentCell.__headerState;\n const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.COLUMN);\n newRow.append($createTableCellNode(headerState).append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)()));\n } else {\n cell.setRowSpan(cell.__rowSpan + 1);\n }\n }\n const insertAfterEndRowNode = grid.getChildAtIndex(insertAfterEndRow);\n if (!$isTableRowNode(insertAfterEndRowNode)) {\n formatDevErrorMessage(`insertAfterEndRow is not a TableRowNode`);\n }\n insertAfterEndRowNode.insertAfter(newRow);\n insertedRow = newRow;\n } else {\n const insertBeforeStartRow = cellStartRow;\n const insertBeforeStartRowMap = gridMap[insertBeforeStartRow];\n const newRow = $createTableRowNode();\n for (let i = 0; i < columnCount; i++) {\n const {\n cell,\n startRow\n } = insertBeforeStartRowMap[i];\n if (startRow === insertBeforeStartRow) {\n const currentCell = insertBeforeStartRowMap[i].cell;\n const currentCellHeaderState = currentCell.__headerState;\n const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.COLUMN);\n newRow.append($createTableCellNode(headerState).append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)()));\n } else {\n cell.setRowSpan(cell.__rowSpan + 1);\n }\n }\n const insertBeforeStartRowNode = grid.getChildAtIndex(insertBeforeStartRow);\n if (!$isTableRowNode(insertBeforeStartRowNode)) {\n formatDevErrorMessage(`insertBeforeStartRow is not a TableRowNode`);\n }\n insertBeforeStartRowNode.insertBefore(newRow);\n insertedRow = newRow;\n }\n return insertedRow;\n}\n\n/**\n * @deprecated This function does not support merged cells. Use {@link $insertTableColumnAtSelection} or {@link $insertTableColumnAtNode} instead.\n */\nfunction $insertTableColumn(tableNode, targetIndex, shouldInsertAfter = true, columnCount, table) {\n const tableRows = tableNode.getChildren();\n const tableCellsToBeInserted = [];\n for (let r = 0; r < tableRows.length; r++) {\n const currentTableRowNode = tableRows[r];\n if ($isTableRowNode(currentTableRowNode)) {\n for (let c = 0; c < columnCount; c++) {\n const tableRowChildren = currentTableRowNode.getChildren();\n if (targetIndex >= tableRowChildren.length || targetIndex < 0) {\n throw new Error('Table column target index out of range');\n }\n const targetCell = tableRowChildren[targetIndex];\n if (!$isTableCellNode(targetCell)) {\n formatDevErrorMessage(`Expected table cell`);\n }\n const {\n left,\n right\n } = $getTableCellSiblingsFromTableCellNode(targetCell, table);\n let headerState = TableCellHeaderStates.NO_STATUS;\n if (left && left.hasHeaderState(TableCellHeaderStates.ROW) || right && right.hasHeaderState(TableCellHeaderStates.ROW)) {\n headerState |= TableCellHeaderStates.ROW;\n }\n const newTableCell = $createTableCellNode(headerState);\n newTableCell.append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)());\n tableCellsToBeInserted.push({\n newTableCell,\n targetCell\n });\n }\n }\n }\n tableCellsToBeInserted.forEach(({\n newTableCell,\n targetCell\n }) => {\n if (shouldInsertAfter) {\n targetCell.insertAfter(newTableCell);\n } else {\n targetCell.insertBefore(newTableCell);\n }\n });\n return tableNode;\n}\n\n/**\n * Inserts a column before or after the current focus cell node,\n * taking into account any spans. If successful, returns the\n * first inserted cell node.\n */\nfunction $insertTableColumnAtSelection(insertAfter = true) {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) || $isTableSelection(selection))) {\n formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);\n }\n const anchor = selection.anchor.getNode();\n const focus = selection.focus.getNode();\n const [anchorCell] = $getNodeTriplet(anchor);\n const [focusCell,, grid] = $getNodeTriplet(focus);\n const [, focusCellMap, anchorCellMap] = $computeTableMap(grid, focusCell, anchorCell);\n const {\n startColumn: anchorStartColumn\n } = anchorCellMap;\n const {\n startColumn: focusStartColumn\n } = focusCellMap;\n if (insertAfter) {\n return $insertTableColumnAtNode(anchorStartColumn + anchorCell.__colSpan > focusStartColumn + focusCell.__colSpan ? anchorCell : focusCell, true);\n } else {\n return $insertTableColumnAtNode(focusStartColumn < anchorStartColumn ? focusCell : anchorCell, false);\n }\n}\n\n/**\n * @deprecated renamed to {@link $insertTableColumnAtSelection}\n */\nconst $insertTableColumn__EXPERIMENTAL = $insertTableColumnAtSelection;\n\n/**\n * Inserts a column before or after the given cell node,\n * taking into account any spans. If successful, returns the\n * first inserted cell node.\n */\nfunction $insertTableColumnAtNode(cellNode, insertAfter = true, shouldSetSelection = true) {\n const [,, grid] = $getNodeTriplet(cellNode);\n const [gridMap, cellMap] = $computeTableMap(grid, cellNode, cellNode);\n const rowCount = gridMap.length;\n const {\n startColumn\n } = cellMap;\n const insertAfterColumn = insertAfter ? startColumn + cellNode.__colSpan - 1 : startColumn - 1;\n const gridFirstChild = grid.getFirstChild();\n if (!$isTableRowNode(gridFirstChild)) {\n formatDevErrorMessage(`Expected firstTable child to be a row`);\n }\n let firstInsertedCell = null;\n function $createTableCellNodeForInsertTableColumn(headerState = TableCellHeaderStates.NO_STATUS) {\n const cell = $createTableCellNode(headerState).append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)());\n if (firstInsertedCell === null) {\n firstInsertedCell = cell;\n }\n return cell;\n }\n let loopRow = gridFirstChild;\n rowLoop: for (let i = 0; i < rowCount; i++) {\n if (i !== 0) {\n const currentRow = loopRow.getNextSibling();\n if (!$isTableRowNode(currentRow)) {\n formatDevErrorMessage(`Expected row nextSibling to be a row`);\n }\n loopRow = currentRow;\n }\n const rowMap = gridMap[i];\n const currentCellHeaderState = rowMap[insertAfterColumn < 0 ? 0 : insertAfterColumn].cell.__headerState;\n const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.ROW);\n if (insertAfterColumn < 0) {\n $insertFirst(loopRow, $createTableCellNodeForInsertTableColumn(headerState));\n continue;\n }\n const {\n cell: currentCell,\n startColumn: currentStartColumn,\n startRow: currentStartRow\n } = rowMap[insertAfterColumn];\n if (currentStartColumn + currentCell.__colSpan - 1 <= insertAfterColumn) {\n let insertAfterCell = currentCell;\n let insertAfterCellRowStart = currentStartRow;\n let prevCellIndex = insertAfterColumn;\n while (insertAfterCellRowStart !== i && insertAfterCell.__rowSpan > 1) {\n prevCellIndex -= currentCell.__colSpan;\n if (prevCellIndex >= 0) {\n const {\n cell: cell_,\n startRow: startRow_\n } = rowMap[prevCellIndex];\n insertAfterCell = cell_;\n insertAfterCellRowStart = startRow_;\n } else {\n loopRow.append($createTableCellNodeForInsertTableColumn(headerState));\n continue rowLoop;\n }\n }\n insertAfterCell.insertAfter($createTableCellNodeForInsertTableColumn(headerState));\n } else {\n currentCell.setColSpan(currentCell.__colSpan + 1);\n }\n }\n if (firstInsertedCell !== null && shouldSetSelection) {\n $moveSelectionToCell(firstInsertedCell);\n }\n const colWidths = grid.getColWidths();\n if (colWidths) {\n const newColWidths = [...colWidths];\n const columnIndex = insertAfterColumn < 0 ? 0 : insertAfterColumn;\n const newWidth = newColWidths[columnIndex];\n newColWidths.splice(columnIndex, 0, newWidth);\n grid.setColWidths(newColWidths);\n }\n return firstInsertedCell;\n}\n\n/**\n * @deprecated This function does not support merged cells. Use {@link $deleteTableColumnAtSelection} instead.\n */\nfunction $deleteTableColumn(tableNode, targetIndex) {\n const tableRows = tableNode.getChildren();\n for (let i = 0; i < tableRows.length; i++) {\n const currentTableRowNode = tableRows[i];\n if ($isTableRowNode(currentTableRowNode)) {\n const tableRowChildren = currentTableRowNode.getChildren();\n if (targetIndex >= tableRowChildren.length || targetIndex < 0) {\n throw new Error('Table column target index out of range');\n }\n tableRowChildren[targetIndex].remove();\n }\n }\n return tableNode;\n}\nfunction $deleteTableRowAtSelection() {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) || $isTableSelection(selection))) {\n formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);\n }\n const [anchor, focus] = selection.isBackward() ? [selection.focus.getNode(), selection.anchor.getNode()] : [selection.anchor.getNode(), selection.focus.getNode()];\n const [anchorCell,, grid] = $getNodeTriplet(anchor);\n const [focusCell] = $getNodeTriplet(focus);\n const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(grid, anchorCell, focusCell);\n const {\n startRow: anchorStartRow\n } = anchorCellMap;\n const {\n startRow: focusStartRow\n } = focusCellMap;\n const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;\n if (gridMap.length === focusEndRow - anchorStartRow + 1) {\n // Empty grid\n grid.remove();\n return;\n }\n const columnCount = gridMap[0].length;\n const nextRow = gridMap[focusEndRow + 1];\n const nextRowNode = grid.getChildAtIndex(focusEndRow + 1);\n for (let row = focusEndRow; row >= anchorStartRow; row--) {\n for (let column = columnCount - 1; column >= 0; column--) {\n const {\n cell,\n startRow: cellStartRow,\n startColumn: cellStartColumn\n } = gridMap[row][column];\n if (cellStartColumn !== column) {\n // Don't repeat work for the same Cell\n continue;\n }\n // Rows overflowing top or bottom have to be trimmed\n if (cellStartRow < anchorStartRow || cellStartRow + cell.__rowSpan - 1 > focusEndRow) {\n const intersectionStart = Math.max(cellStartRow, anchorStartRow);\n const intersectionEnd = Math.min(cell.__rowSpan + cellStartRow - 1, focusEndRow);\n const overflowRowsCount = intersectionStart <= intersectionEnd ? intersectionEnd - intersectionStart + 1 : 0;\n cell.setRowSpan(cell.__rowSpan - overflowRowsCount);\n }\n // Rows overflowing bottom have to be moved to the next row\n if (cellStartRow >= anchorStartRow && cellStartRow + cell.__rowSpan - 1 > focusEndRow &&\n // Handle overflow only once\n row === focusEndRow) {\n if (!(nextRowNode !== null)) {\n formatDevErrorMessage(`Expected nextRowNode not to be null`);\n }\n let insertAfterCell = null;\n for (let columnIndex = 0; columnIndex < column; columnIndex++) {\n const currentCellMap = nextRow[columnIndex];\n const currentCell = currentCellMap.cell;\n // Checking the cell having startRow as same as nextRow\n if (currentCellMap.startRow === row + 1) {\n insertAfterCell = currentCell;\n }\n if (currentCell.__colSpan > 1) {\n columnIndex += currentCell.__colSpan - 1;\n }\n }\n if (insertAfterCell === null) {\n $insertFirst(nextRowNode, cell);\n } else {\n insertAfterCell.insertAfter(cell);\n }\n }\n }\n const rowNode = grid.getChildAtIndex(row);\n if (!$isTableRowNode(rowNode)) {\n formatDevErrorMessage(`Expected TableNode childAtIndex(${String(row)}) to be RowNode`);\n }\n rowNode.remove();\n }\n if (nextRow !== undefined) {\n const {\n cell\n } = nextRow[0];\n $moveSelectionToCell(cell);\n } else {\n const previousRow = gridMap[anchorStartRow - 1];\n const {\n cell\n } = previousRow[0];\n $moveSelectionToCell(cell);\n }\n}\n\n/**\n * @deprecated renamed to {@link $deleteTableRowAtSelection}\n */\nconst $deleteTableRow__EXPERIMENTAL = $deleteTableRowAtSelection;\nfunction $deleteTableColumnAtSelection() {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) || $isTableSelection(selection))) {\n formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);\n }\n const anchor = selection.anchor.getNode();\n const focus = selection.focus.getNode();\n const [anchorCell,, grid] = $getNodeTriplet(anchor);\n const [focusCell] = $getNodeTriplet(focus);\n const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(grid, anchorCell, focusCell);\n const {\n startColumn: anchorStartColumn\n } = anchorCellMap;\n const {\n startRow: focusStartRow,\n startColumn: focusStartColumn\n } = focusCellMap;\n const startColumn = Math.min(anchorStartColumn, focusStartColumn);\n const endColumn = Math.max(anchorStartColumn + anchorCell.__colSpan - 1, focusStartColumn + focusCell.__colSpan - 1);\n const selectedColumnCount = endColumn - startColumn + 1;\n const columnCount = gridMap[0].length;\n if (columnCount === endColumn - startColumn + 1) {\n // Empty grid\n grid.selectPrevious();\n grid.remove();\n return;\n }\n const rowCount = gridMap.length;\n for (let row = 0; row < rowCount; row++) {\n for (let column = startColumn; column <= endColumn; column++) {\n const {\n cell,\n startColumn: cellStartColumn\n } = gridMap[row][column];\n if (cellStartColumn < startColumn) {\n if (column === startColumn) {\n const overflowLeft = startColumn - cellStartColumn;\n // Overflowing left\n cell.setColSpan(cell.__colSpan -\n // Possible overflow right too\n Math.min(selectedColumnCount, cell.__colSpan - overflowLeft));\n }\n } else if (cellStartColumn + cell.__colSpan - 1 > endColumn) {\n if (column === endColumn) {\n // Overflowing right\n const inSelectedArea = endColumn - cellStartColumn + 1;\n cell.setColSpan(cell.__colSpan - inSelectedArea);\n }\n } else {\n cell.remove();\n }\n }\n }\n const focusRowMap = gridMap[focusStartRow];\n const nextColumn = anchorStartColumn > focusStartColumn ? focusRowMap[anchorStartColumn + anchorCell.__colSpan] : focusRowMap[focusStartColumn + focusCell.__colSpan];\n if (nextColumn !== undefined) {\n const {\n cell\n } = nextColumn;\n $moveSelectionToCell(cell);\n } else {\n const previousRow = focusStartColumn < anchorStartColumn ? focusRowMap[focusStartColumn - 1] : focusRowMap[anchorStartColumn - 1];\n const {\n cell\n } = previousRow;\n $moveSelectionToCell(cell);\n }\n const colWidths = grid.getColWidths();\n if (colWidths) {\n const newColWidths = [...colWidths];\n newColWidths.splice(startColumn, selectedColumnCount);\n grid.setColWidths(newColWidths);\n }\n}\n\n/**\n * @deprecated renamed to {@link $deleteTableColumnAtSelection}\n */\nconst $deleteTableColumn__EXPERIMENTAL = $deleteTableColumnAtSelection;\nfunction $moveSelectionToCell(cell) {\n const firstDescendant = cell.getFirstDescendant();\n if (firstDescendant == null) {\n cell.selectStart();\n } else {\n firstDescendant.getParentOrThrow().selectStart();\n }\n}\nfunction $insertFirst(parent, node) {\n const firstChild = parent.getFirstChild();\n if (firstChild !== null) {\n firstChild.insertBefore(node);\n } else {\n parent.append(node);\n }\n}\nfunction $mergeCells(cellNodes) {\n if (cellNodes.length === 0) {\n return null;\n }\n\n // Find the table node\n const tableNode = $getTableNodeFromLexicalNodeOrThrow(cellNodes[0]);\n const [gridMap] = $computeTableMapSkipCellCheck(tableNode, null, null);\n\n // Find the boundaries of the selection including merged cells\n let minRow = Infinity;\n let maxRow = -Infinity;\n let minCol = Infinity;\n let maxCol = -Infinity;\n\n // First pass: find the actual boundaries considering merged cells\n const processedCells = new Set();\n for (const row of gridMap) {\n for (const mapCell of row) {\n if (!mapCell || !mapCell.cell) {\n continue;\n }\n const cellKey = mapCell.cell.getKey();\n if (processedCells.has(cellKey)) {\n continue;\n }\n if (cellNodes.some(cell => cell.is(mapCell.cell))) {\n processedCells.add(cellKey);\n // Get the actual position of this cell in the grid\n const cellStartRow = mapCell.startRow;\n const cellStartCol = mapCell.startColumn;\n const cellRowSpan = mapCell.cell.__rowSpan || 1;\n const cellColSpan = mapCell.cell.__colSpan || 1;\n\n // Update boundaries considering the cell's actual position and span\n minRow = Math.min(minRow, cellStartRow);\n maxRow = Math.max(maxRow, cellStartRow + cellRowSpan - 1);\n minCol = Math.min(minCol, cellStartCol);\n maxCol = Math.max(maxCol, cellStartCol + cellColSpan - 1);\n }\n }\n }\n\n // Validate boundaries\n if (minRow === Infinity || minCol === Infinity) {\n return null;\n }\n\n // The total span of the merged cell\n const totalRowSpan = maxRow - minRow + 1;\n const totalColSpan = maxCol - minCol + 1;\n\n // Use the top-left cell as the target cell\n const targetCellMap = gridMap[minRow][minCol];\n if (!targetCellMap.cell) {\n return null;\n }\n const targetCell = targetCellMap.cell;\n\n // Set the spans for the target cell\n targetCell.setColSpan(totalColSpan);\n targetCell.setRowSpan(totalRowSpan);\n\n // Move content from other cells to the target cell\n const seenCells = new Set([targetCell.getKey()]);\n\n // Second pass: merge content and remove other cells\n for (let row = minRow; row <= maxRow; row++) {\n for (let col = minCol; col <= maxCol; col++) {\n const mapCell = gridMap[row][col];\n if (!mapCell.cell) {\n continue;\n }\n const currentCell = mapCell.cell;\n const key = currentCell.getKey();\n if (!seenCells.has(key)) {\n seenCells.add(key);\n const isEmpty = $cellContainsEmptyParagraph(currentCell);\n if (!isEmpty) {\n targetCell.append(...currentCell.getChildren());\n }\n currentCell.remove();\n }\n }\n }\n\n // Ensure target cell has content\n if (targetCell.getChildrenSize() === 0) {\n targetCell.append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)());\n }\n return targetCell;\n}\nfunction $cellContainsEmptyParagraph(cell) {\n if (cell.getChildrenSize() !== 1) {\n return false;\n }\n const firstChild = cell.getFirstChildOrThrow();\n if (!(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isParagraphNode)(firstChild) || !firstChild.isEmpty()) {\n return false;\n }\n return true;\n}\nfunction $unmergeCell() {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) || $isTableSelection(selection))) {\n formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);\n }\n const anchor = selection.anchor.getNode();\n const cellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(anchor, $isTableCellNode);\n if (!$isTableCellNode(cellNode)) {\n formatDevErrorMessage(`Expected to find a parent TableCellNode`);\n }\n return $unmergeCellNode(cellNode);\n}\nfunction $unmergeCellNode(cellNode) {\n const [cell, row, grid] = $getNodeTriplet(cellNode);\n const colSpan = cell.__colSpan;\n const rowSpan = cell.__rowSpan;\n if (colSpan === 1 && rowSpan === 1) {\n return;\n }\n const [map, cellMap] = $computeTableMap(grid, cell, cell);\n const {\n startColumn,\n startRow\n } = cellMap;\n // Create a heuristic for what the style of the unmerged cells should be\n // based on whether every row or column already had that state before the\n // unmerge.\n const baseColStyle = cell.__headerState & TableCellHeaderStates.COLUMN;\n const colStyles = Array.from({\n length: colSpan\n }, (_v, i) => {\n let colStyle = baseColStyle;\n for (let rowIdx = 0; colStyle !== 0 && rowIdx < map.length; rowIdx++) {\n colStyle &= map[rowIdx][i + startColumn].cell.__headerState;\n }\n return colStyle;\n });\n const baseRowStyle = cell.__headerState & TableCellHeaderStates.ROW;\n const rowStyles = Array.from({\n length: rowSpan\n }, (_v, i) => {\n let rowStyle = baseRowStyle;\n for (let colIdx = 0; rowStyle !== 0 && colIdx < map[0].length; colIdx++) {\n rowStyle &= map[i + startRow][colIdx].cell.__headerState;\n }\n return rowStyle;\n });\n if (colSpan > 1) {\n for (let i = 1; i < colSpan; i++) {\n cell.insertAfter($createTableCellNode(colStyles[i] | rowStyles[0]).append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)()));\n }\n cell.setColSpan(1);\n }\n if (rowSpan > 1) {\n let currentRowNode;\n for (let i = 1; i < rowSpan; i++) {\n const currentRow = startRow + i;\n const currentRowMap = map[currentRow];\n currentRowNode = (currentRowNode || row).getNextSibling();\n if (!$isTableRowNode(currentRowNode)) {\n formatDevErrorMessage(`Expected row next sibling to be a row`);\n }\n let insertAfterCell = null;\n for (let column = 0; column < startColumn; column++) {\n const currentCellMap = currentRowMap[column];\n const currentCell = currentCellMap.cell;\n if (currentCellMap.startRow === currentRow) {\n insertAfterCell = currentCell;\n }\n if (currentCell.__colSpan > 1) {\n column += currentCell.__colSpan - 1;\n }\n }\n if (insertAfterCell === null) {\n for (let j = colSpan - 1; j >= 0; j--) {\n $insertFirst(currentRowNode, $createTableCellNode(colStyles[j] | rowStyles[i]).append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)()));\n }\n } else {\n for (let j = colSpan - 1; j >= 0; j--) {\n insertAfterCell.insertAfter($createTableCellNode(colStyles[j] | rowStyles[i]).append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)()));\n }\n }\n }\n cell.setRowSpan(1);\n }\n}\nfunction $computeTableMap(tableNode, cellA, cellB) {\n const [tableMap, cellAValue, cellBValue] = $computeTableMapSkipCellCheck(tableNode, cellA, cellB);\n if (!(cellAValue !== null)) {\n formatDevErrorMessage(`Anchor not found in Table`);\n }\n if (!(cellBValue !== null)) {\n formatDevErrorMessage(`Focus not found in Table`);\n }\n return [tableMap, cellAValue, cellBValue];\n}\nfunction $computeTableMapSkipCellCheck(tableNode, cellA, cellB) {\n const tableMap = [];\n let cellAValue = null;\n let cellBValue = null;\n function getMapRow(i) {\n let row = tableMap[i];\n if (row === undefined) {\n tableMap[i] = row = [];\n }\n return row;\n }\n const gridChildren = tableNode.getChildren();\n for (let rowIdx = 0; rowIdx < gridChildren.length; rowIdx++) {\n const row = gridChildren[rowIdx];\n if (!$isTableRowNode(row)) {\n formatDevErrorMessage(`Expected TableNode children to be TableRowNode`);\n }\n const startMapRow = getMapRow(rowIdx);\n for (let cell = row.getFirstChild(), colIdx = 0; cell != null; cell = cell.getNextSibling()) {\n if (!$isTableCellNode(cell)) {\n formatDevErrorMessage(`Expected TableRowNode children to be TableCellNode`);\n } // Skip past any columns that were merged from a higher row\n while (startMapRow[colIdx] !== undefined) {\n colIdx++;\n }\n const value = {\n cell,\n startColumn: colIdx,\n startRow: rowIdx\n };\n const {\n __rowSpan: rowSpan,\n __colSpan: colSpan\n } = cell;\n for (let j = 0; j < rowSpan; j++) {\n if (rowIdx + j >= gridChildren.length) {\n // The table is non-rectangular with a rowSpan\n // below the last
in the table.\n // We should probably handle this with a node transform\n // to ensure that tables are always rectangular but this\n // will avoid crashes such as #6584\n // Note that there are probably still latent bugs\n // regarding colSpan or general cell count mismatches.\n break;\n }\n const mapRow = getMapRow(rowIdx + j);\n for (let i = 0; i < colSpan; i++) {\n mapRow[colIdx + i] = value;\n }\n }\n if (cellA !== null && cellAValue === null && cellA.is(cell)) {\n cellAValue = value;\n }\n if (cellB !== null && cellBValue === null && cellB.is(cell)) {\n cellBValue = value;\n }\n }\n }\n return [tableMap, cellAValue, cellBValue];\n}\nfunction $getNodeTriplet(source) {\n let cell;\n if (source instanceof TableCellNode) {\n cell = source;\n } else if ('__type' in source) {\n const cell_ = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(source, $isTableCellNode);\n if (!$isTableCellNode(cell_)) {\n formatDevErrorMessage(`Expected to find a parent TableCellNode`);\n }\n cell = cell_;\n } else {\n const cell_ = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(source.getNode(), $isTableCellNode);\n if (!$isTableCellNode(cell_)) {\n formatDevErrorMessage(`Expected to find a parent TableCellNode`);\n }\n cell = cell_;\n }\n const row = cell.getParent();\n if (!$isTableRowNode(row)) {\n formatDevErrorMessage(`Expected TableCellNode to have a parent TableRowNode`);\n }\n const grid = row.getParent();\n if (!$isTableNode(grid)) {\n formatDevErrorMessage(`Expected TableRowNode to have a parent TableNode`);\n }\n return [cell, row, grid];\n}\nfunction $computeTableCellRectSpans(map, boundary) {\n const {\n minColumn,\n maxColumn,\n minRow,\n maxRow\n } = boundary;\n let topSpan = 1;\n let leftSpan = 1;\n let rightSpan = 1;\n let bottomSpan = 1;\n const topRow = map[minRow];\n const bottomRow = map[maxRow];\n for (let col = minColumn; col <= maxColumn; col++) {\n topSpan = Math.max(topSpan, topRow[col].cell.__rowSpan);\n bottomSpan = Math.max(bottomSpan, bottomRow[col].cell.__rowSpan);\n }\n for (let row = minRow; row <= maxRow; row++) {\n leftSpan = Math.max(leftSpan, map[row][minColumn].cell.__colSpan);\n rightSpan = Math.max(rightSpan, map[row][maxColumn].cell.__colSpan);\n }\n return {\n bottomSpan,\n leftSpan,\n rightSpan,\n topSpan\n };\n}\nfunction $computeTableCellRectBoundary(map, cellAMap, cellBMap) {\n // Initial boundaries based on the anchor and focus cells\n let minColumn = Math.min(cellAMap.startColumn, cellBMap.startColumn);\n let minRow = Math.min(cellAMap.startRow, cellBMap.startRow);\n let maxColumn = Math.max(cellAMap.startColumn + cellAMap.cell.__colSpan - 1, cellBMap.startColumn + cellBMap.cell.__colSpan - 1);\n let maxRow = Math.max(cellAMap.startRow + cellAMap.cell.__rowSpan - 1, cellBMap.startRow + cellBMap.cell.__rowSpan - 1);\n\n // Keep expanding until we have a complete rectangle\n let hasChanges;\n do {\n hasChanges = false;\n\n // Check all cells in the table\n for (let row = 0; row < map.length; row++) {\n for (let col = 0; col < map[0].length; col++) {\n const cell = map[row][col];\n if (!cell) {\n continue;\n }\n const cellEndCol = cell.startColumn + cell.cell.__colSpan - 1;\n const cellEndRow = cell.startRow + cell.cell.__rowSpan - 1;\n\n // Check if this cell intersects with our current selection rectangle\n const intersectsHorizontally = cell.startColumn <= maxColumn && cellEndCol >= minColumn;\n const intersectsVertically = cell.startRow <= maxRow && cellEndRow >= minRow;\n\n // If the cell intersects either horizontally or vertically\n if (intersectsHorizontally && intersectsVertically) {\n // Expand boundaries to include this cell completely\n const newMinColumn = Math.min(minColumn, cell.startColumn);\n const newMaxColumn = Math.max(maxColumn, cellEndCol);\n const newMinRow = Math.min(minRow, cell.startRow);\n const newMaxRow = Math.max(maxRow, cellEndRow);\n\n // Check if boundaries changed\n if (newMinColumn !== minColumn || newMaxColumn !== maxColumn || newMinRow !== minRow || newMaxRow !== maxRow) {\n minColumn = newMinColumn;\n maxColumn = newMaxColumn;\n minRow = newMinRow;\n maxRow = newMaxRow;\n hasChanges = true;\n }\n }\n }\n }\n } while (hasChanges);\n return {\n maxColumn,\n maxRow,\n minColumn,\n minRow\n };\n}\n\n/**\n * Checks if the table does not have any merged cells.\n *\n * @param table Table to check for if it has any merged cells.\n * @returns True if the table does not have any merged cells, false otherwise.\n */\nfunction $isSimpleTable(table) {\n const rows = table.getChildren();\n let columns = null;\n for (const row of rows) {\n if (!$isTableRowNode(row)) {\n return false;\n }\n if (columns === null) {\n columns = row.getChildrenSize();\n }\n if (row.getChildrenSize() !== columns) {\n return false;\n }\n const cells = row.getChildren();\n for (const cell of cells) {\n if (!$isTableCellNode(cell) || cell.getRowSpan() !== 1 || cell.getColSpan() !== 1) {\n return false;\n }\n }\n }\n return (columns || 0) > 0;\n}\n\n/**\n * Moves a column from one position to another within a simple (non-merged) table.\n *\n * @param tableNode The table node to modify.\n * @param originColumn The index of the column to move.\n * @param targetColumn The index to move the column to.\n */\nfunction $moveTableColumn(tableNode, originColumn, targetColumn) {\n if (originColumn === targetColumn) {\n return;\n }\n const columnCount = tableNode.getColumnCount();\n if (originColumn < 0 || originColumn >= columnCount || targetColumn < 0 || targetColumn >= columnCount) {\n return;\n }\n if (!$isSimpleTable(tableNode)) {\n return;\n }\n const rows = tableNode.getChildren().filter($isTableRowNode);\n rows.forEach(row => {\n const cells = row.getChildren();\n const [moved] = cells.splice(originColumn, 1);\n cells.splice(targetColumn, 0, moved);\n row.splice(0, cells.length, cells);\n });\n const colWidths = tableNode.getColWidths();\n if (colWidths && colWidths.length === columnCount) {\n const newWidths = [...colWidths];\n const [movedWidth] = newWidths.splice(originColumn, 1);\n newWidths.splice(targetColumn, 0, movedWidth);\n tableNode.setColWidths(newWidths);\n }\n}\nfunction $getTableCellNodeRect(tableCellNode) {\n const [cellNode,, gridNode] = $getNodeTriplet(tableCellNode);\n const rows = gridNode.getChildren();\n const rowCount = rows.length;\n const columnCount = rows[0].getChildren().length;\n\n // Create a matrix of the same size as the table to track the position of each cell\n const cellMatrix = new Array(rowCount);\n for (let i = 0; i < rowCount; i++) {\n cellMatrix[i] = new Array(columnCount);\n }\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n const row = rows[rowIndex];\n const cells = row.getChildren();\n let columnIndex = 0;\n for (let cellIndex = 0; cellIndex < cells.length; cellIndex++) {\n // Find the next available position in the matrix, skip the position of merged cells\n while (cellMatrix[rowIndex][columnIndex]) {\n columnIndex++;\n }\n const cell = cells[cellIndex];\n const rowSpan = cell.__rowSpan || 1;\n const colSpan = cell.__colSpan || 1;\n\n // Put the cell into the corresponding position in the matrix\n for (let i = 0; i < rowSpan; i++) {\n for (let j = 0; j < colSpan; j++) {\n cellMatrix[rowIndex + i][columnIndex + j] = cell;\n }\n }\n\n // Return to the original index, row span and column span of the cell.\n if (cellNode === cell) {\n return {\n colSpan,\n columnIndex,\n rowIndex,\n rowSpan\n };\n }\n columnIndex += colSpan;\n }\n }\n return null;\n}\n\nfunction $getCellNodes(tableSelection) {\n const [[anchorNode, anchorCell, anchorRow, anchorTable], [focusNode, focusCell, focusRow, focusTable]] = ['anchor', 'focus'].map(k => {\n const node = tableSelection[k].getNode();\n const cellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(node, $isTableCellNode);\n if (!$isTableCellNode(cellNode)) {\n formatDevErrorMessage(`Expected TableSelection ${k} to be (or a child of) TableCellNode, got key ${node.getKey()} of type ${node.getType()}`);\n }\n const rowNode = cellNode.getParent();\n if (!$isTableRowNode(rowNode)) {\n formatDevErrorMessage(`Expected TableSelection ${k} cell parent to be a TableRowNode`);\n }\n const tableNode = rowNode.getParent();\n if (!$isTableNode(tableNode)) {\n formatDevErrorMessage(`Expected TableSelection ${k} row parent to be a TableNode`);\n }\n return [node, cellNode, rowNode, tableNode];\n });\n // TODO: nested tables may violate this\n if (!anchorTable.is(focusTable)) {\n formatDevErrorMessage(`Expected TableSelection anchor and focus to be in the same table`);\n }\n return {\n anchorCell,\n anchorNode,\n anchorRow,\n anchorTable,\n focusCell,\n focusNode,\n focusRow,\n focusTable\n };\n}\nclass TableSelection {\n tableKey;\n anchor;\n focus;\n _cachedNodes;\n dirty;\n constructor(tableKey, anchor, focus) {\n this.anchor = anchor;\n this.focus = focus;\n anchor._selection = this;\n focus._selection = this;\n this._cachedNodes = null;\n this.dirty = false;\n this.tableKey = tableKey;\n }\n getStartEndPoints() {\n return [this.anchor, this.focus];\n }\n\n /**\n * {@link $createTableSelection} unfortunately makes it very easy to create\n * nonsense selections, so we have a method to see if the selection probably\n * makes sense.\n *\n * @returns true if the TableSelection is (probably) valid\n */\n isValid() {\n if (this.tableKey === 'root' || this.anchor.key === 'root' || this.anchor.type !== 'element' || this.focus.key === 'root' || this.focus.type !== 'element') {\n return false;\n }\n\n // Check if the referenced nodes still exist in the editor\n const tableNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNodeByKey)(this.tableKey);\n const anchorNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNodeByKey)(this.anchor.key);\n const focusNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNodeByKey)(this.focus.key);\n return tableNode !== null && anchorNode !== null && focusNode !== null;\n }\n\n /**\n * Returns whether the Selection is \"backwards\", meaning the focus\n * logically precedes the anchor in the EditorState.\n * @returns true if the Selection is backwards, false otherwise.\n */\n isBackward() {\n return this.focus.isBefore(this.anchor);\n }\n getCachedNodes() {\n return this._cachedNodes;\n }\n setCachedNodes(nodes) {\n this._cachedNodes = nodes;\n }\n is(selection) {\n return $isTableSelection(selection) && this.tableKey === selection.tableKey && this.anchor.is(selection.anchor) && this.focus.is(selection.focus);\n }\n set(tableKey, anchorCellKey, focusCellKey) {\n // note: closure compiler's acorn does not support ||=\n this.dirty = this.dirty || tableKey !== this.tableKey || anchorCellKey !== this.anchor.key || focusCellKey !== this.focus.key;\n this.tableKey = tableKey;\n this.anchor.key = anchorCellKey;\n this.focus.key = focusCellKey;\n this._cachedNodes = null;\n }\n clone() {\n return new TableSelection(this.tableKey, (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createPoint)(this.anchor.key, this.anchor.offset, this.anchor.type), (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createPoint)(this.focus.key, this.focus.offset, this.focus.type));\n }\n isCollapsed() {\n return false;\n }\n extract() {\n return this.getNodes();\n }\n insertRawText(text) {\n // Do nothing?\n }\n insertText() {\n // Do nothing?\n }\n\n /**\n * Returns whether the provided TextFormatType is present on the Selection.\n * This will be true if any paragraph in table cells has the specified format.\n *\n * @param type the TextFormatType to check for.\n * @returns true if the provided format is currently toggled on on the Selection, false otherwise.\n */\n hasFormat(type) {\n let format = 0;\n const cellNodes = this.getNodes().filter($isTableCellNode);\n cellNodes.forEach(cellNode => {\n const paragraph = cellNode.getFirstChild();\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isParagraphNode)(paragraph)) {\n format |= paragraph.getTextFormat();\n }\n });\n const formatFlag = lexical__WEBPACK_IMPORTED_MODULE_0__.TEXT_TYPE_TO_FORMAT[type];\n return (format & formatFlag) !== 0;\n }\n insertNodes(nodes) {\n const focusNode = this.focus.getNode();\n if (!(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(focusNode)) {\n formatDevErrorMessage(`Expected TableSelection focus to be an ElementNode`);\n }\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$normalizeSelection__EXPERIMENTAL)(focusNode.select(0, focusNode.getChildrenSize()));\n selection.insertNodes(nodes);\n }\n\n // TODO Deprecate this method. It's confusing when used with colspan|rowspan\n getShape() {\n const {\n anchorCell,\n focusCell\n } = $getCellNodes(this);\n const anchorCellNodeRect = $getTableCellNodeRect(anchorCell);\n if (!(anchorCellNodeRect !== null)) {\n formatDevErrorMessage(`getCellRect: expected to find AnchorNode`);\n }\n const focusCellNodeRect = $getTableCellNodeRect(focusCell);\n if (!(focusCellNodeRect !== null)) {\n formatDevErrorMessage(`getCellRect: expected to find focusCellNode`);\n }\n const startX = Math.min(anchorCellNodeRect.columnIndex, focusCellNodeRect.columnIndex);\n const stopX = Math.max(anchorCellNodeRect.columnIndex + anchorCellNodeRect.colSpan - 1, focusCellNodeRect.columnIndex + focusCellNodeRect.colSpan - 1);\n const startY = Math.min(anchorCellNodeRect.rowIndex, focusCellNodeRect.rowIndex);\n const stopY = Math.max(anchorCellNodeRect.rowIndex + anchorCellNodeRect.rowSpan - 1, focusCellNodeRect.rowIndex + focusCellNodeRect.rowSpan - 1);\n return {\n fromX: Math.min(startX, stopX),\n fromY: Math.min(startY, stopY),\n toX: Math.max(startX, stopX),\n toY: Math.max(startY, stopY)\n };\n }\n getNodes() {\n if (!this.isValid()) {\n return [];\n }\n const cachedNodes = this._cachedNodes;\n if (cachedNodes !== null) {\n return cachedNodes;\n }\n const {\n anchorTable: tableNode,\n anchorCell,\n focusCell\n } = $getCellNodes(this);\n const focusCellGrid = focusCell.getParents()[1];\n if (focusCellGrid !== tableNode) {\n if (!tableNode.isParentOf(focusCell)) {\n // focus is on higher Grid level than anchor\n const gridParent = tableNode.getParent();\n if (!(gridParent != null)) {\n formatDevErrorMessage(`Expected gridParent to have a parent`);\n }\n this.set(this.tableKey, gridParent.getKey(), focusCell.getKey());\n } else {\n // anchor is on higher Grid level than focus\n const focusCellParent = focusCellGrid.getParent();\n if (!(focusCellParent != null)) {\n formatDevErrorMessage(`Expected focusCellParent to have a parent`);\n }\n this.set(this.tableKey, focusCell.getKey(), focusCellParent.getKey());\n }\n return this.getNodes();\n }\n\n // TODO Mapping the whole Grid every time not efficient. We need to compute the entire state only\n // once (on load) and iterate on it as updates occur. However, to do this we need to have the\n // ability to store a state. Killing TableSelection and moving the logic to the plugin would make\n // this possible.\n const [map, cellAMap, cellBMap] = $computeTableMap(tableNode, anchorCell, focusCell);\n const {\n minColumn,\n maxColumn,\n minRow,\n maxRow\n } = $computeTableCellRectBoundary(map, cellAMap, cellBMap);\n\n // We use a Map here because merged cells in the grid would otherwise\n // show up multiple times in the nodes array\n const nodeMap = new Map([[tableNode.getKey(), tableNode]]);\n let lastRow = null;\n for (let i = minRow; i <= maxRow; i++) {\n for (let j = minColumn; j <= maxColumn; j++) {\n const {\n cell\n } = map[i][j];\n const currentRow = cell.getParent();\n if (!$isTableRowNode(currentRow)) {\n formatDevErrorMessage(`Expected TableCellNode parent to be a TableRowNode`);\n }\n if (currentRow !== lastRow) {\n nodeMap.set(currentRow.getKey(), currentRow);\n lastRow = currentRow;\n }\n if (!nodeMap.has(cell.getKey())) {\n $visitRecursively(cell, childNode => {\n nodeMap.set(childNode.getKey(), childNode);\n });\n }\n }\n }\n const nodes = Array.from(nodeMap.values());\n if (!(0,lexical__WEBPACK_IMPORTED_MODULE_0__.isCurrentlyReadOnlyMode)()) {\n this._cachedNodes = nodes;\n }\n return nodes;\n }\n getTextContent() {\n const nodes = this.getNodes().filter(node => $isTableCellNode(node));\n let textContent = '';\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n const row = node.__parent;\n const nextRow = (nodes[i + 1] || {}).__parent;\n textContent += node.getTextContent() + (nextRow !== row ? '\\n' : '\\t');\n }\n return textContent;\n }\n}\nfunction $isTableSelection(x) {\n return x instanceof TableSelection;\n}\nfunction $createTableSelection() {\n // TODO this is a suboptimal design, it doesn't make sense to have\n // a table selection that isn't associated with a table. This\n // constructor should have required arguments and in true we\n // should check that they point to a table and are element points to\n // cell nodes of that table.\n const anchor = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createPoint)('root', 0, 'element');\n const focus = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createPoint)('root', 0, 'element');\n return new TableSelection('root', anchor, focus);\n}\nfunction $createTableSelectionFrom(tableNode, anchorCell, focusCell) {\n const tableNodeKey = tableNode.getKey();\n const anchorCellKey = anchorCell.getKey();\n const focusCellKey = focusCell.getKey();\n {\n if (!tableNode.isAttached()) {\n formatDevErrorMessage(`$createTableSelectionFrom: tableNode ${tableNodeKey} is not attached`);\n }\n if (!tableNode.is($findTableNode(anchorCell))) {\n formatDevErrorMessage(`$createTableSelectionFrom: anchorCell ${anchorCellKey} is not in table ${tableNodeKey}`);\n }\n if (!tableNode.is($findTableNode(focusCell))) {\n formatDevErrorMessage(`$createTableSelectionFrom: focusCell ${focusCellKey} is not in table ${tableNodeKey}`);\n } // TODO: Check for rectangular grid\n }\n const prevSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n const nextSelection = $isTableSelection(prevSelection) ? prevSelection.clone() : $createTableSelection();\n nextSelection.set(tableNode.getKey(), anchorCell.getKey(), focusCell.getKey());\n return nextSelection;\n}\n\n/**\n * Depth first visitor\n * @param node The starting node\n * @param $visit The function to call for each node. If the function returns false, then children of this node will not be explored\n */\nfunction $visitRecursively(node, $visit) {\n const stack = [[node]];\n for (let currentArray = stack.at(-1); currentArray !== undefined && stack.length > 0; currentArray = stack.at(-1)) {\n const currentNode = currentArray.pop();\n if (currentNode === undefined) {\n stack.pop();\n } else if ($visit(currentNode) !== false && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(currentNode)) {\n stack.push(currentNode.getChildren());\n }\n }\n}\n\nfunction $getTableAndElementByKey(tableNodeKey, editor = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getEditor)()) {\n const tableNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNodeByKey)(tableNodeKey);\n if (!$isTableNode(tableNode)) {\n formatDevErrorMessage(`TableObserver: Expected tableNodeKey ${tableNodeKey} to be a TableNode`);\n }\n const tableElement = getTableElement(tableNode, editor.getElementByKey(tableNodeKey));\n if (!(tableElement !== null)) {\n formatDevErrorMessage(`TableObserver: Expected to find TableElement in DOM for key ${tableNodeKey}`);\n }\n return {\n tableElement,\n tableNode\n };\n}\nclass TableObserver {\n focusX;\n focusY;\n listenersToRemove;\n table;\n isHighlightingCells;\n anchorX;\n anchorY;\n tableNodeKey;\n anchorCell;\n focusCell;\n anchorCellNodeKey;\n focusCellNodeKey;\n editor;\n tableSelection;\n hasHijackedSelectionStyles;\n isSelecting;\n pointerType;\n shouldCheckSelection;\n abortController;\n listenerOptions;\n nextFocus;\n constructor(editor, tableNodeKey) {\n this.isHighlightingCells = false;\n this.anchorX = -1;\n this.anchorY = -1;\n this.focusX = -1;\n this.focusY = -1;\n this.listenersToRemove = new Set();\n this.tableNodeKey = tableNodeKey;\n this.editor = editor;\n this.table = {\n columns: 0,\n domRows: [],\n rows: 0\n };\n this.tableSelection = null;\n this.anchorCellNodeKey = null;\n this.focusCellNodeKey = null;\n this.anchorCell = null;\n this.focusCell = null;\n this.hasHijackedSelectionStyles = false;\n this.isSelecting = false;\n this.pointerType = null;\n this.shouldCheckSelection = false;\n this.abortController = new AbortController();\n this.listenerOptions = {\n signal: this.abortController.signal\n };\n this.nextFocus = null;\n this.trackTable();\n }\n getTable() {\n return this.table;\n }\n removeListeners() {\n this.abortController.abort('removeListeners');\n Array.from(this.listenersToRemove).forEach(removeListener => removeListener());\n this.listenersToRemove.clear();\n }\n $lookup() {\n return $getTableAndElementByKey(this.tableNodeKey, this.editor);\n }\n trackTable() {\n const observer = new MutationObserver(records => {\n this.editor.getEditorState().read(() => {\n let gridNeedsRedraw = false;\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const target = record.target;\n const nodeName = target.nodeName;\n if (nodeName === 'TABLE' || nodeName === 'TBODY' || nodeName === 'THEAD' || nodeName === 'TR') {\n gridNeedsRedraw = true;\n break;\n }\n }\n if (!gridNeedsRedraw) {\n return;\n }\n const {\n tableNode,\n tableElement\n } = this.$lookup();\n this.table = getTable(tableNode, tableElement);\n }, {\n editor: this.editor\n });\n });\n this.editor.getEditorState().read(() => {\n const {\n tableNode,\n tableElement\n } = this.$lookup();\n this.table = getTable(tableNode, tableElement);\n observer.observe(tableElement, {\n attributes: true,\n childList: true,\n subtree: true\n });\n }, {\n editor: this.editor\n });\n }\n $clearHighlight() {\n const editor = this.editor;\n this.isHighlightingCells = false;\n this.anchorX = -1;\n this.anchorY = -1;\n this.focusX = -1;\n this.focusY = -1;\n this.tableSelection = null;\n this.anchorCellNodeKey = null;\n this.focusCellNodeKey = null;\n this.anchorCell = null;\n this.focusCell = null;\n this.hasHijackedSelectionStyles = false;\n this.$enableHighlightStyle();\n const {\n tableNode,\n tableElement\n } = this.$lookup();\n const grid = getTable(tableNode, tableElement);\n $updateDOMForSelection(editor, grid, null);\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)() !== null) {\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(null);\n editor.dispatchCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.SELECTION_CHANGE_COMMAND, undefined);\n }\n }\n $enableHighlightStyle() {\n const editor = this.editor;\n const {\n tableElement\n } = this.$lookup();\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.removeClassNamesFromElement)(tableElement, editor._config.theme.tableSelection);\n tableElement.classList.remove('disable-selection');\n this.hasHijackedSelectionStyles = false;\n }\n $disableHighlightStyle() {\n const {\n tableElement\n } = this.$lookup();\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(tableElement, this.editor._config.theme.tableSelection);\n this.hasHijackedSelectionStyles = true;\n }\n $updateTableTableSelection(selection) {\n if (selection !== null) {\n if (!(selection.tableKey === this.tableNodeKey)) {\n formatDevErrorMessage(`TableObserver.$updateTableTableSelection: selection.tableKey !== this.tableNodeKey ('${selection.tableKey}' !== '${this.tableNodeKey}')`);\n }\n const editor = this.editor;\n this.tableSelection = selection;\n this.isHighlightingCells = true;\n this.$disableHighlightStyle();\n this.updateDOMSelection();\n $updateDOMForSelection(editor, this.table, this.tableSelection);\n } else {\n this.$clearHighlight();\n }\n }\n\n /**\n * @internal\n * Firefox has a strange behavior where pressing the down arrow key from\n * above the table will move the caret after the table and then lexical\n * will select the last cell instead of the first.\n * We do still want to let the browser handle caret movement but we will\n * use this property to \"tag\" the update so that we can recheck the\n * selection after the event is processed.\n */\n setShouldCheckSelection() {\n this.shouldCheckSelection = true;\n }\n /**\n * @internal\n */\n getAndClearShouldCheckSelection() {\n if (this.shouldCheckSelection) {\n this.shouldCheckSelection = false;\n return true;\n }\n return false;\n }\n\n /**\n * @internal\n * When handling mousemove events we track what the focus cell should be, but\n * the DOM selection may end up somewhere else entirely. We don't have an elegant\n * way to handle this after the DOM selection has been resolved in a\n * SELECTION_CHANGE_COMMAND callback.\n */\n setNextFocus(nextFocus) {\n this.nextFocus = nextFocus;\n }\n\n /** @internal */\n getAndClearNextFocus() {\n const {\n nextFocus\n } = this;\n if (nextFocus !== null) {\n this.nextFocus = null;\n }\n return nextFocus;\n }\n\n /** @internal */\n updateDOMSelection() {\n if (this.anchorCell !== null && this.focusCell !== null) {\n const domSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.getDOMSelection)(this.editor._window);\n // We are not using a native selection for tables, and if we\n // set one then the reconciler will undo it.\n // TODO - it would make sense to have one so that native\n // copy/paste worked. Right now we have to emulate with\n // keyboard events but it won't fire if triggered from the menu\n if (domSelection && domSelection.rangeCount > 0) {\n domSelection.removeAllRanges();\n }\n }\n }\n $setFocusCellForSelection(cell, ignoreStart = false) {\n const editor = this.editor;\n const {\n tableNode\n } = this.$lookup();\n const cellX = cell.x;\n const cellY = cell.y;\n this.focusCell = cell;\n\n // Enable highlighting if: ignoreStart is true, or anchor differs from focus,\n // or we have valid tableSelection with anchor (for first drag after column switch)\n if (!this.isHighlightingCells) {\n const shouldEnable = ignoreStart || this.anchorX !== cellX || this.anchorY !== cellY || this.tableSelection != null && this.anchorCellNodeKey != null;\n if (shouldEnable) {\n this.isHighlightingCells = true;\n this.$disableHighlightStyle();\n }\n }\n\n // Skip if we're trying to select the same cell we already have selected\n // But only if focusX/focusY are valid (not -1, which means not reset)\n if (this.focusX !== -1 && this.focusY !== -1 && cellX === this.focusX && cellY === this.focusY) {\n return false;\n }\n this.focusX = cellX;\n this.focusY = cellY;\n if (this.isHighlightingCells) {\n const focusTableCellNode = $getNearestTableCellInTableFromDOMNode(tableNode, cell.elem);\n if (this.tableSelection != null && this.anchorCellNodeKey != null) {\n let targetCellNode = focusTableCellNode;\n\n // Fallback: use coordinates if DOM lookup failed (handles timing issues on first drag)\n if (targetCellNode === null && ignoreStart) {\n targetCellNode = tableNode.getCellNodeFromCords(cellX, cellY, this.table);\n }\n if (targetCellNode !== null) {\n const anchorTableCell = this.$getAnchorTableCellOrThrow();\n this.focusCellNodeKey = targetCellNode.getKey();\n this.tableSelection = $createTableSelectionFrom(tableNode, anchorTableCell, targetCellNode);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(this.tableSelection);\n editor.dispatchCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.SELECTION_CHANGE_COMMAND, undefined);\n $updateDOMForSelection(editor, this.table, this.tableSelection);\n return true;\n }\n }\n }\n return false;\n }\n $getAnchorTableCell() {\n return this.anchorCellNodeKey ? (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNodeByKey)(this.anchorCellNodeKey) : null;\n }\n $getAnchorTableCellOrThrow() {\n const anchorTableCell = this.$getAnchorTableCell();\n if (!(anchorTableCell !== null)) {\n formatDevErrorMessage(`TableObserver anchorTableCell is null`);\n }\n return anchorTableCell;\n }\n $getFocusTableCell() {\n return this.focusCellNodeKey ? (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNodeByKey)(this.focusCellNodeKey) : null;\n }\n $getFocusTableCellOrThrow() {\n const focusTableCell = this.$getFocusTableCell();\n if (!(focusTableCell !== null)) {\n formatDevErrorMessage(`TableObserver focusTableCell is null`);\n }\n return focusTableCell;\n }\n $setAnchorCellForSelection(cell) {\n this.isHighlightingCells = false;\n this.anchorCell = cell;\n this.anchorX = cell.x;\n this.anchorY = cell.y;\n // Reset focus state to prevent stale values from previous selections\n this.focusX = -1;\n this.focusY = -1;\n this.focusCell = null;\n this.focusCellNodeKey = null;\n const {\n tableNode\n } = this.$lookup();\n const anchorTableCellNode = $getNearestTableCellInTableFromDOMNode(tableNode, cell.elem);\n if (anchorTableCellNode !== null) {\n const anchorNodeKey = anchorTableCellNode.getKey();\n if (this.tableSelection != null) {\n this.tableSelection = this.tableSelection.clone();\n this.tableSelection.set(tableNode.getKey(), anchorNodeKey, anchorNodeKey);\n } else {\n this.tableSelection = $createTableSelectionFrom(tableNode, anchorTableCellNode, anchorTableCellNode);\n }\n this.anchorCellNodeKey = anchorNodeKey;\n }\n }\n $formatCells(type) {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!$isTableSelection(selection)) {\n formatDevErrorMessage(`Expected Table selection`);\n }\n const formatSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createRangeSelection)();\n const anchor = formatSelection.anchor;\n const focus = formatSelection.focus;\n const cellNodes = selection.getNodes().filter($isTableCellNode);\n if (!(cellNodes.length > 0)) {\n formatDevErrorMessage(`No table cells present`);\n }\n const paragraph = cellNodes[0].getFirstChild();\n const alignFormatWith = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isParagraphNode)(paragraph) ? paragraph.getFormatFlags(type, null) : null;\n cellNodes.forEach(cellNode => {\n anchor.set(cellNode.getKey(), 0, 'element');\n focus.set(cellNode.getKey(), cellNode.getChildrenSize(), 'element');\n formatSelection.formatText(type, alignFormatWith);\n });\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(selection);\n this.editor.dispatchCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.SELECTION_CHANGE_COMMAND, undefined);\n }\n $clearText() {\n const {\n editor\n } = this;\n const tableNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNodeByKey)(this.tableNodeKey);\n if (!$isTableNode(tableNode)) {\n throw new Error('Expected TableNode.');\n }\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!$isTableSelection(selection)) {\n formatDevErrorMessage(`Expected TableSelection`);\n }\n const selectedNodes = selection.getNodes().filter($isTableCellNode);\n\n // Check if the entire table is selected by verifying first and last cells\n const firstRow = tableNode.getFirstChild();\n const lastRow = tableNode.getLastChild();\n const isEntireTableSelected = selectedNodes.length > 0 && firstRow !== null && lastRow !== null && $isTableRowNode(firstRow) && $isTableRowNode(lastRow) && selectedNodes[0] === firstRow.getFirstChild() && selectedNodes[selectedNodes.length - 1] === lastRow.getLastChild();\n if (isEntireTableSelected) {\n tableNode.selectPrevious();\n const parent = tableNode.getParent();\n // Delete entire table\n tableNode.remove();\n // Handle case when table was the only node\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRootNode)(parent) && parent.isEmpty()) {\n editor.dispatchCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.INSERT_PARAGRAPH_COMMAND, undefined);\n }\n return;\n }\n selectedNodes.forEach(cellNode => {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(cellNode)) {\n const paragraphNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)();\n const textNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createTextNode)();\n paragraphNode.append(textNode);\n cellNode.append(paragraphNode);\n cellNode.getChildren().forEach(child => {\n if (child !== paragraphNode) {\n child.remove();\n }\n });\n }\n });\n $updateDOMForSelection(editor, this.table, null);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(null);\n editor.dispatchCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.SELECTION_CHANGE_COMMAND, undefined);\n }\n}\n\nconst LEXICAL_ELEMENT_KEY = '__lexicalTableSelection';\nconst isPointerDownOnEvent = event => {\n return (event.buttons & 1) === 1;\n};\nfunction isHTMLTableElement(el) {\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.isHTMLElement)(el) && el.nodeName === 'TABLE';\n}\nfunction getTableElement(tableNode, dom) {\n if (!dom) {\n return dom;\n }\n const element = isHTMLTableElement(dom) ? dom : tableNode.getDOMSlot(dom).element;\n if (!(element.nodeName === 'TABLE')) {\n formatDevErrorMessage(`getTableElement: Expecting table in as DOM node for TableNode, not ${dom.nodeName}`);\n }\n return element;\n}\nfunction getEditorWindow(editor) {\n return editor._window;\n}\nfunction $findParentTableCellNodeInTable(tableNode, node) {\n for (let currentNode = node, lastTableCellNode = null; currentNode !== null; currentNode = currentNode.getParent()) {\n if (tableNode.is(currentNode)) {\n return lastTableCellNode;\n } else if ($isTableCellNode(currentNode)) {\n lastTableCellNode = currentNode;\n }\n }\n return null;\n}\nconst ARROW_KEY_COMMANDS_WITH_DIRECTION = [[lexical__WEBPACK_IMPORTED_MODULE_0__.KEY_ARROW_DOWN_COMMAND, 'down'], [lexical__WEBPACK_IMPORTED_MODULE_0__.KEY_ARROW_UP_COMMAND, 'up'], [lexical__WEBPACK_IMPORTED_MODULE_0__.KEY_ARROW_LEFT_COMMAND, 'backward'], [lexical__WEBPACK_IMPORTED_MODULE_0__.KEY_ARROW_RIGHT_COMMAND, 'forward']];\nconst DELETE_TEXT_COMMANDS = [lexical__WEBPACK_IMPORTED_MODULE_0__.DELETE_WORD_COMMAND, lexical__WEBPACK_IMPORTED_MODULE_0__.DELETE_LINE_COMMAND, lexical__WEBPACK_IMPORTED_MODULE_0__.DELETE_CHARACTER_COMMAND];\nconst DELETE_KEY_COMMANDS = [lexical__WEBPACK_IMPORTED_MODULE_0__.KEY_BACKSPACE_COMMAND, lexical__WEBPACK_IMPORTED_MODULE_0__.KEY_DELETE_COMMAND];\nfunction applyTableHandlers(tableNode, element, editor, hasTabHandler) {\n const rootElement = editor.getRootElement();\n const editorWindow = getEditorWindow(editor);\n if (!(rootElement !== null && editorWindow !== null)) {\n formatDevErrorMessage(`applyTableHandlers: editor has no root element set`);\n }\n const tableObserver = new TableObserver(editor, tableNode.getKey());\n const tableElement = getTableElement(tableNode, element);\n attachTableObserverToTableElement(tableElement, tableObserver);\n tableObserver.listenersToRemove.add(() => detachTableObserverFromTableElement(tableElement, tableObserver));\n const createPointerHandlers = startingCell => {\n if (tableObserver.isSelecting) {\n return;\n }\n tableObserver.isSelecting = true;\n\n // Set anchor immediately if starting cell provided (handles direct drag without click)\n if (startingCell !== null && tableObserver.anchorCell === null) {\n editor.update(() => {\n tableObserver.$setAnchorCellForSelection(startingCell);\n });\n }\n const onPointerUp = () => {\n tableObserver.isSelecting = false;\n editorWindow.removeEventListener('pointerup', onPointerUp);\n editorWindow.removeEventListener('pointermove', onPointerMove);\n };\n const onPointerMove = moveEvent => {\n if (!isPointerDownOnEvent(moveEvent) && tableObserver.isSelecting) {\n tableObserver.isSelecting = false;\n editorWindow.removeEventListener('pointerup', onPointerUp);\n editorWindow.removeEventListener('pointermove', onPointerMove);\n return;\n }\n if (!(0,lexical__WEBPACK_IMPORTED_MODULE_0__.isDOMNode)(moveEvent.target)) {\n return;\n }\n let focusCell = null;\n // In firefox the moveEvent.target may be captured so we must always\n // consult the coordinates #7245\n const override = !(IS_FIREFOX || tableElement.contains(moveEvent.target));\n if (override) {\n focusCell = getDOMCellInTableFromTarget(tableElement, moveEvent.target);\n } else {\n for (const el of document.elementsFromPoint(moveEvent.clientX, moveEvent.clientY)) {\n focusCell = getDOMCellInTableFromTarget(tableElement, el);\n if (focusCell) {\n break;\n }\n }\n }\n if (focusCell) {\n const anchorCell = focusCell;\n // Fallback: set anchor if still missing (handles race conditions)\n if (tableObserver.anchorCell === null) {\n editor.update(() => {\n tableObserver.$setAnchorCellForSelection(anchorCell);\n });\n }\n if (tableObserver.focusCell === null || focusCell.elem !== tableObserver.focusCell.elem) {\n tableObserver.setNextFocus({\n focusCell,\n override\n });\n editor.dispatchCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.SELECTION_CHANGE_COMMAND, undefined);\n }\n }\n };\n editorWindow.addEventListener('pointerup', onPointerUp, tableObserver.listenerOptions);\n editorWindow.addEventListener('pointermove', onPointerMove, tableObserver.listenerOptions);\n };\n const onPointerDown = event => {\n tableObserver.pointerType = event.pointerType;\n if (event.button !== 0 || !(0,lexical__WEBPACK_IMPORTED_MODULE_0__.isDOMNode)(event.target) || !editorWindow) {\n return;\n }\n const targetCell = getDOMCellFromTarget(event.target);\n if (targetCell !== null) {\n editor.update(() => {\n const prevSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getPreviousSelection)();\n // We can't trust Firefox to do the right thing with the selection and\n // we don't have a proper state machine to do this \"correctly\" but\n // if we go ahead and make the table selection now it will work\n if (IS_FIREFOX && event.shiftKey && $isSelectionInTable(prevSelection, tableNode) && ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(prevSelection) || $isTableSelection(prevSelection))) {\n const prevAnchorNode = prevSelection.anchor.getNode();\n const prevAnchorCell = $findParentTableCellNodeInTable(tableNode, prevSelection.anchor.getNode());\n if (prevAnchorCell) {\n tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, prevAnchorCell));\n tableObserver.$setFocusCellForSelection(targetCell);\n stopEvent(event);\n } else {\n const newSelection = tableNode.isBefore(prevAnchorNode) ? tableNode.selectStart() : tableNode.selectEnd();\n newSelection.anchor.set(prevSelection.anchor.key, prevSelection.anchor.offset, prevSelection.anchor.type);\n }\n } else {\n // Only set anchor cell for selection if this is not a simple touch tap\n // Touch taps should not initiate table selection mode\n if (event.pointerType !== 'touch') {\n tableObserver.$setAnchorCellForSelection(targetCell);\n }\n }\n });\n }\n\n // Pass the target cell to createPointerHandlers so it can be used as anchor\n // if user drags directly without clicking first\n createPointerHandlers(targetCell);\n };\n tableElement.addEventListener('pointerdown', onPointerDown, tableObserver.listenerOptions);\n tableObserver.listenersToRemove.add(() => {\n tableElement.removeEventListener('pointerdown', onPointerDown);\n });\n const onTripleClick = event => {\n if (event.detail >= 3 && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.isDOMNode)(event.target)) {\n const targetCell = getDOMCellFromTarget(event.target);\n if (targetCell !== null) {\n event.preventDefault();\n }\n }\n };\n tableElement.addEventListener('mousedown', onTripleClick, tableObserver.listenerOptions);\n tableObserver.listenersToRemove.add(() => {\n tableElement.removeEventListener('mousedown', onTripleClick);\n });\n\n // Clear selection when clicking outside of dom.\n const pointerDownCallback = event => {\n const target = event.target;\n if (event.button !== 0 || !(0,lexical__WEBPACK_IMPORTED_MODULE_0__.isDOMNode)(target)) {\n return;\n }\n editor.update(() => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey && rootElement.contains(target)) {\n tableObserver.$clearHighlight();\n }\n });\n };\n editorWindow.addEventListener('pointerdown', pointerDownCallback, tableObserver.listenerOptions);\n tableObserver.listenersToRemove.add(() => {\n editorWindow.removeEventListener('pointerdown', pointerDownCallback);\n });\n for (const [command, direction] of ARROW_KEY_COMMANDS_WITH_DIRECTION) {\n tableObserver.listenersToRemove.add(editor.registerCommand(command, event => $handleArrowKey(editor, event, direction, tableNode, tableObserver), lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n }\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.KEY_ESCAPE_COMMAND, event => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if ($isTableSelection(selection)) {\n const focusCellNode = $findParentTableCellNodeInTable(tableNode, selection.focus.getNode());\n if (focusCellNode !== null) {\n stopEvent(event);\n focusCellNode.selectEnd();\n return true;\n }\n }\n return false;\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n const deleteTextHandler = command => () => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!$isSelectionInTable(selection, tableNode)) {\n return false;\n }\n if ($isTableSelection(selection)) {\n tableObserver.$clearText();\n return true;\n } else if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n const tableCellNode = $findParentTableCellNodeInTable(tableNode, selection.anchor.getNode());\n if (!$isTableCellNode(tableCellNode)) {\n return false;\n }\n const anchorNode = selection.anchor.getNode();\n const focusNode = selection.focus.getNode();\n const isAnchorInside = tableNode.isParentOf(anchorNode);\n const isFocusInside = tableNode.isParentOf(focusNode);\n const selectionContainsPartialTable = isAnchorInside && !isFocusInside || isFocusInside && !isAnchorInside;\n if (selectionContainsPartialTable) {\n tableObserver.$clearText();\n return true;\n }\n const nearestElementNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(selection.anchor.getNode(), n => (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(n));\n const topLevelCellElementNode = nearestElementNode && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(nearestElementNode, n => (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(n) && $isTableCellNode(n.getParent()));\n if (!(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(topLevelCellElementNode) || !(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(nearestElementNode)) {\n return false;\n }\n if (command === lexical__WEBPACK_IMPORTED_MODULE_0__.DELETE_LINE_COMMAND && topLevelCellElementNode.getPreviousSibling() === null) {\n // TODO: Fix Delete Line in Table Cells.\n return true;\n }\n }\n return false;\n };\n for (const command of DELETE_TEXT_COMMANDS) {\n tableObserver.listenersToRemove.add(editor.registerCommand(command, deleteTextHandler(command), lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n }\n const $deleteCellHandler = event => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!($isTableSelection(selection) || (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection))) {\n return false;\n }\n\n // If the selection is inside the table but should remove the whole table\n // we expand the selection so that both the anchor and focus are outside\n // the table and the editor's command listener will handle the delete\n const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode());\n const isFocusInside = tableNode.isParentOf(selection.focus.getNode());\n if (isAnchorInside !== isFocusInside) {\n const tablePoint = isAnchorInside ? 'anchor' : 'focus';\n const outerPoint = isAnchorInside ? 'focus' : 'anchor';\n // Preserve the outer point\n const {\n key,\n offset,\n type\n } = selection[outerPoint];\n // Expand the selection around the table\n const newSelection = tableNode[selection[tablePoint].isBefore(selection[outerPoint]) ? 'selectPrevious' : 'selectNext']();\n // Restore the outer point of the selection\n newSelection[outerPoint].set(key, offset, type);\n // Let the base implementation handle the rest\n return false;\n }\n if (!$isSelectionInTable(selection, tableNode)) {\n return false;\n }\n if ($isTableSelection(selection)) {\n if (event) {\n event.preventDefault();\n event.stopPropagation();\n }\n tableObserver.$clearText();\n return true;\n }\n return false;\n };\n for (const command of DELETE_KEY_COMMANDS) {\n tableObserver.listenersToRemove.add(editor.registerCommand(command, $deleteCellHandler, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n }\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.CUT_COMMAND, event => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (selection) {\n if (!($isTableSelection(selection) || (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection))) {\n return false;\n }\n // Copying to the clipboard is async so we must capture the data\n // before we delete it\n void (0,_lexical_clipboard__WEBPACK_IMPORTED_MODULE_2__.copyToClipboard)(editor, (0,_lexical_utils__WEBPACK_IMPORTED_MODULE_1__.objectKlassEquals)(event, ClipboardEvent) ? event : null, (0,_lexical_clipboard__WEBPACK_IMPORTED_MODULE_2__.$getClipboardDataFromSelection)(selection));\n const intercepted = $deleteCellHandler(event);\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n selection.removeText();\n return true;\n }\n return intercepted;\n }\n return false;\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.FORMAT_TEXT_COMMAND, payload => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!$isSelectionInTable(selection, tableNode)) {\n return false;\n }\n if ($isTableSelection(selection)) {\n tableObserver.$formatCells(payload);\n return true;\n } else if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n const tableCellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(selection.anchor.getNode(), n => $isTableCellNode(n));\n if (!$isTableCellNode(tableCellNode)) {\n return false;\n }\n }\n return false;\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.FORMAT_ELEMENT_COMMAND, formatType => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!$isTableSelection(selection) || !$isSelectionInTable(selection, tableNode)) {\n return false;\n }\n const anchorNode = selection.anchor.getNode();\n const focusNode = selection.focus.getNode();\n if (!$isTableCellNode(anchorNode) || !$isTableCellNode(focusNode)) {\n return false;\n }\n\n // Align the table if the entire table is selected\n if ($isFullTableSelection(selection, tableNode)) {\n tableNode.setFormat(formatType);\n return true;\n }\n const [tableMap, anchorCell, focusCell] = $computeTableMap(tableNode, anchorNode, focusNode);\n const maxRow = Math.max(anchorCell.startRow + anchorCell.cell.__rowSpan - 1, focusCell.startRow + focusCell.cell.__rowSpan - 1);\n const maxColumn = Math.max(anchorCell.startColumn + anchorCell.cell.__colSpan - 1, focusCell.startColumn + focusCell.cell.__colSpan - 1);\n const minRow = Math.min(anchorCell.startRow, focusCell.startRow);\n const minColumn = Math.min(anchorCell.startColumn, focusCell.startColumn);\n const visited = new Set();\n for (let i = minRow; i <= maxRow; i++) {\n for (let j = minColumn; j <= maxColumn; j++) {\n const cell = tableMap[i][j].cell;\n if (visited.has(cell)) {\n continue;\n }\n visited.add(cell);\n cell.setFormat(formatType);\n const cellChildren = cell.getChildren();\n for (let k = 0; k < cellChildren.length; k++) {\n const child = cellChildren[k];\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(child) && !child.isInline()) {\n child.setFormat(formatType);\n }\n }\n }\n }\n return true;\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.CONTROLLED_TEXT_INSERTION_COMMAND, payload => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!$isSelectionInTable(selection, tableNode)) {\n return false;\n }\n if ($isTableSelection(selection)) {\n tableObserver.$clearHighlight();\n return false;\n } else if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n const tableCellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(selection.anchor.getNode(), n => $isTableCellNode(n));\n if (!$isTableCellNode(tableCellNode)) {\n return false;\n }\n if (typeof payload === 'string') {\n const edgePosition = $getTableEdgeCursorPosition(editor, selection, tableNode);\n if (edgePosition) {\n $insertParagraphAtTableEdge(edgePosition, tableNode, [(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createTextNode)(payload)]);\n return true;\n }\n }\n }\n return false;\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n if (hasTabHandler) {\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.KEY_TAB_COMMAND, event => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) || !selection.isCollapsed() || !$isSelectionInTable(selection, tableNode)) {\n return false;\n }\n const tableCellNode = $findCellNode(selection.anchor.getNode());\n if (tableCellNode === null || !tableNode.is($findTableNode(tableCellNode))) {\n return false;\n }\n stopEvent(event);\n $selectAdjacentCell(tableCellNode, event.shiftKey ? 'previous' : 'next');\n return true;\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n }\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.FOCUS_COMMAND, payload => {\n return tableNode.isSelected();\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.SELECTION_CHANGE_COMMAND, () => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n const prevSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getPreviousSelection)();\n const nextFocus = tableObserver.getAndClearNextFocus();\n if (nextFocus !== null) {\n const {\n focusCell\n } = nextFocus;\n if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey) {\n if (focusCell.x === tableObserver.focusX && focusCell.y === tableObserver.focusY) {\n // The selection is already the correct table selection\n return false;\n } else {\n tableObserver.$setFocusCellForSelection(focusCell);\n return true;\n }\n } else if (focusCell !== tableObserver.anchorCell && tableObserver.anchorCell !== null && tableObserver.anchorCellNodeKey !== null && tableObserver.tableSelection !== null) {\n // The selection has crossed cells\n // If we have an anchor cell set and tableSelection initialized,\n // we have all the necessary state to create the selection.\n // The presence of nextFocus means we're dragging, so process it.\n // Use ignoreStart=true to ensure isHighlightingCells is set correctly\n // on the first drag attempt, especially when switching columns.\n tableObserver.$setFocusCellForSelection(focusCell, true);\n return true;\n }\n }\n const shouldCheckSelection = tableObserver.getAndClearShouldCheckSelection();\n // If they pressed the down arrow with the selection outside of the\n // table, and then the selection ends up in the table but not in the\n // first cell, then move the selection to the first cell.\n if (shouldCheckSelection && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(prevSelection) && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) && selection.isCollapsed()) {\n const anchor = selection.anchor.getNode();\n const firstRow = tableNode.getFirstChild();\n const anchorCell = $findCellNode(anchor);\n if (anchorCell !== null && $isTableRowNode(firstRow)) {\n const firstCell = firstRow.getFirstChild();\n if ($isTableCellNode(firstCell) && tableNode.is((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(anchorCell, node => node.is(tableNode) || node.is(firstCell)))) {\n // The selection moved to the table, but not in the first cell\n firstCell.selectStart();\n return true;\n }\n }\n }\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n const {\n anchor,\n focus\n } = selection;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n // Using explicit comparison with table node to ensure it's not a nested table\n // as in that case we'll leave selection resolving to that table\n const anchorCellNode = $findCellNode(anchorNode);\n const focusCellNode = $findCellNode(focusNode);\n const isAnchorInside = !!(anchorCellNode && tableNode.is($findTableNode(anchorCellNode)));\n const isFocusInside = !!(focusCellNode && tableNode.is($findTableNode(focusCellNode)));\n const isPartiallyWithinTable = isAnchorInside !== isFocusInside;\n const isWithinTable = isAnchorInside && isFocusInside;\n const isBackward = selection.isBackward();\n if (isPartiallyWithinTable) {\n const newSelection = selection.clone();\n if (isFocusInside) {\n const [tableMap] = $computeTableMap(tableNode, focusCellNode, focusCellNode);\n const firstCell = tableMap[0][0].cell;\n const lastCell = tableMap[tableMap.length - 1].at(-1).cell;\n // When backward, focus should be at START of first cell (0)\n // When forward, focus should be at END of last cell (getChildrenSize)\n newSelection.focus.set(isBackward ? firstCell.getKey() : lastCell.getKey(), isBackward ? 0 : lastCell.getChildrenSize(), 'element');\n } else if (isAnchorInside) {\n const [tableMap] = $computeTableMap(tableNode, anchorCellNode, anchorCellNode);\n const firstCell = tableMap[0][0].cell;\n const lastCell = tableMap[tableMap.length - 1].at(-1).cell;\n /**\n * If isBackward, set the anchor to be at the end of the table so that when the cursor moves outside of\n * the table in the backward direction, the entire table will be selected from its end.\n * Otherwise, if forward, set the anchor to be at the start of the table so that when the focus is dragged\n * outside th end of the table, it will start from the beginning of the table.\n */\n newSelection.anchor.set(isBackward ? lastCell.getKey() : firstCell.getKey(), isBackward ? lastCell.getChildrenSize() : 0, 'element');\n }\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(newSelection);\n $addHighlightStyleToTable(editor, tableObserver);\n } else if (isWithinTable) {\n // Handle case when selection spans across multiple cells but still\n // has range selection, then we convert it into table selection\n if (!anchorCellNode.is(focusCellNode)) {\n tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, anchorCellNode));\n tableObserver.$setFocusCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, focusCellNode), true);\n }\n\n // Handle case when the pointer type is touch and the current and\n // previous selection are collapsed, and the previous anchor and current\n // focus cell nodes are different, then we convert it into table selection\n // However, only do this if the table observer is actively selecting (user dragging)\n // to prevent unwanted selections when simply tapping between cells on mobile\n if (tableObserver.pointerType === 'touch' && tableObserver.isSelecting && selection.isCollapsed() && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(prevSelection) && prevSelection.isCollapsed()) {\n const prevAnchorCellNode = $findCellNode(prevSelection.anchor.getNode());\n if (prevAnchorCellNode && !prevAnchorCellNode.is(focusCellNode)) {\n tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, prevAnchorCellNode));\n tableObserver.$setFocusCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, focusCellNode), true);\n tableObserver.pointerType = null;\n }\n }\n }\n } else if (selection && $isTableSelection(selection) && selection.is(prevSelection) && selection.tableKey === tableNode.getKey()) {\n // if selection goes outside of the table we need to change it to Range selection\n const domSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.getDOMSelection)(editorWindow);\n if (domSelection && domSelection.anchorNode && domSelection.focusNode) {\n const focusNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNearestNodeFromDOMNode)(domSelection.focusNode);\n const isFocusOutside = focusNode && !tableNode.isParentOf(focusNode);\n const anchorNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNearestNodeFromDOMNode)(domSelection.anchorNode);\n const isAnchorInside = anchorNode && tableNode.isParentOf(anchorNode);\n if (isFocusOutside && isAnchorInside && domSelection.rangeCount > 0) {\n const newSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createRangeSelectionFromDom)(domSelection, editor);\n if (newSelection) {\n newSelection.anchor.set(tableNode.getKey(), selection.isBackward() ? tableNode.getChildrenSize() : 0, 'element');\n domSelection.removeAllRanges();\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(newSelection);\n }\n }\n }\n }\n if (selection && !selection.is(prevSelection) && ($isTableSelection(selection) || $isTableSelection(prevSelection)) && tableObserver.tableSelection && !tableObserver.tableSelection.is(prevSelection)) {\n if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey) {\n tableObserver.$updateTableTableSelection(selection);\n } else if (!$isTableSelection(selection) && $isTableSelection(prevSelection) && prevSelection.tableKey === tableObserver.tableNodeKey) {\n tableObserver.$updateTableTableSelection(null);\n }\n return false;\n }\n if (tableObserver.hasHijackedSelectionStyles && !tableNode.isSelected()) {\n $removeHighlightStyleToTable(editor, tableObserver);\n } else if (!tableObserver.hasHijackedSelectionStyles && tableNode.isSelected()) {\n $addHighlightStyleToTable(editor, tableObserver);\n }\n return false;\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n tableObserver.listenersToRemove.add(editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.INSERT_PARAGRAPH_COMMAND, () => {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) || !selection.isCollapsed() || !$isSelectionInTable(selection, tableNode)) {\n return false;\n }\n const edgePosition = $getTableEdgeCursorPosition(editor, selection, tableNode);\n if (edgePosition) {\n $insertParagraphAtTableEdge(edgePosition, tableNode);\n return true;\n }\n return false;\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_HIGH));\n return tableObserver;\n}\nfunction detachTableObserverFromTableElement(tableElement, tableObserver) {\n if (getTableObserverFromTableElement(tableElement) === tableObserver) {\n delete tableElement[LEXICAL_ELEMENT_KEY];\n }\n}\nfunction attachTableObserverToTableElement(tableElement, tableObserver) {\n if (!(getTableObserverFromTableElement(tableElement) === null)) {\n formatDevErrorMessage(`tableElement already has an attached TableObserver`);\n }\n tableElement[LEXICAL_ELEMENT_KEY] = tableObserver;\n}\nfunction getTableObserverFromTableElement(tableElement) {\n return tableElement[LEXICAL_ELEMENT_KEY] || null;\n}\nfunction getDOMCellFromTarget(node) {\n let currentNode = node;\n while (currentNode != null) {\n const nodeName = currentNode.nodeName;\n if (nodeName === 'TD' || nodeName === 'TH') {\n // @ts-expect-error: internal field\n const cell = currentNode._cell;\n if (cell === undefined) {\n return null;\n }\n return cell;\n }\n currentNode = currentNode.parentNode;\n }\n return null;\n}\nfunction getDOMCellInTableFromTarget(table, node) {\n if (!table.contains(node)) {\n return null;\n }\n let cell = null;\n for (let currentNode = node; currentNode != null; currentNode = currentNode.parentNode) {\n if (currentNode === table) {\n return cell;\n }\n const nodeName = currentNode.nodeName;\n if (nodeName === 'TD' || nodeName === 'TH') {\n // @ts-expect-error: internal field\n cell = currentNode._cell || null;\n }\n }\n return null;\n}\nfunction getTable(tableNode, dom) {\n const tableElement = getTableElement(tableNode, dom);\n const domRows = [];\n const grid = {\n columns: 0,\n domRows,\n rows: 0\n };\n let currentNode = tableElement.querySelector('tr');\n let x = 0;\n let y = 0;\n domRows.length = 0;\n while (currentNode != null) {\n const nodeMame = currentNode.nodeName;\n if (nodeMame === 'TD' || nodeMame === 'TH') {\n const elem = currentNode;\n const cell = {\n elem,\n hasBackgroundColor: elem.style.backgroundColor !== '',\n highlighted: false,\n x,\n y\n };\n\n // @ts-expect-error: internal field\n currentNode._cell = cell;\n let row = domRows[y];\n if (row === undefined) {\n row = domRows[y] = [];\n }\n row[x] = cell;\n } else {\n const child = currentNode.firstChild;\n if (child != null) {\n currentNode = child;\n continue;\n }\n }\n const sibling = currentNode.nextSibling;\n if (sibling != null) {\n x++;\n currentNode = sibling;\n continue;\n }\n const parent = currentNode.parentNode;\n if (parent != null) {\n const parentSibling = parent.nextSibling;\n if (parentSibling == null) {\n break;\n }\n y++;\n x = 0;\n currentNode = parentSibling;\n }\n }\n grid.columns = x + 1;\n grid.rows = y + 1;\n return grid;\n}\nfunction $updateDOMForSelection(editor, table, selection) {\n const selectedCellNodes = new Set(selection ? selection.getNodes() : []);\n $forEachTableCell(table, (cell, lexicalNode) => {\n const elem = cell.elem;\n if (selectedCellNodes.has(lexicalNode)) {\n cell.highlighted = true;\n $addHighlightToDOM(editor, cell);\n } else {\n cell.highlighted = false;\n $removeHighlightFromDOM(editor, cell);\n if (!elem.getAttribute('style')) {\n elem.removeAttribute('style');\n }\n }\n });\n}\nfunction $forEachTableCell(grid, cb) {\n const {\n domRows\n } = grid;\n for (let y = 0; y < domRows.length; y++) {\n const row = domRows[y];\n if (!row) {\n continue;\n }\n for (let x = 0; x < row.length; x++) {\n const cell = row[x];\n if (!cell) {\n continue;\n }\n const lexicalNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNearestNodeFromDOMNode)(cell.elem);\n if (lexicalNode !== null) {\n cb(cell, lexicalNode, {\n x,\n y\n });\n }\n }\n }\n}\nfunction $addHighlightStyleToTable(editor, tableSelection) {\n tableSelection.$disableHighlightStyle();\n $forEachTableCell(tableSelection.table, cell => {\n cell.highlighted = true;\n $addHighlightToDOM(editor, cell);\n });\n}\nfunction $removeHighlightStyleToTable(editor, tableObserver) {\n tableObserver.$enableHighlightStyle();\n $forEachTableCell(tableObserver.table, cell => {\n const elem = cell.elem;\n cell.highlighted = false;\n $removeHighlightFromDOM(editor, cell);\n if (!elem.getAttribute('style')) {\n elem.removeAttribute('style');\n }\n });\n}\nfunction $selectAdjacentCell(tableCellNode, direction) {\n const siblingMethod = direction === 'next' ? 'getNextSibling' : 'getPreviousSibling';\n const childMethod = direction === 'next' ? 'getFirstChild' : 'getLastChild';\n const sibling = tableCellNode[siblingMethod]();\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(sibling)) {\n return sibling.selectEnd();\n }\n const parentRow = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(tableCellNode, $isTableRowNode);\n if (!(parentRow !== null)) {\n formatDevErrorMessage(`selectAdjacentCell: Cell not in table row`);\n }\n for (let nextRow = parentRow[siblingMethod](); $isTableRowNode(nextRow); nextRow = nextRow[siblingMethod]()) {\n const child = nextRow[childMethod]();\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(child)) {\n return child.selectEnd();\n }\n }\n const parentTable = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(parentRow, $isTableNode);\n if (!(parentTable !== null)) {\n formatDevErrorMessage(`selectAdjacentCell: Row not in table`);\n }\n return direction === 'next' ? parentTable.selectNext() : parentTable.selectPrevious();\n}\nconst selectTableNodeInDirection = (tableObserver, tableNode, x, y, direction) => {\n const isForward = direction === 'forward';\n switch (direction) {\n case 'backward':\n case 'forward':\n if (x !== (isForward ? tableObserver.table.columns - 1 : 0)) {\n selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableObserver.table), isForward);\n } else {\n if (y !== (isForward ? tableObserver.table.rows - 1 : 0)) {\n selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : tableObserver.table.columns - 1, y + (isForward ? 1 : -1), tableObserver.table), isForward);\n } else if (!isForward) {\n tableNode.selectPrevious();\n } else {\n tableNode.selectNext();\n }\n }\n return true;\n case 'up':\n if (y !== 0) {\n selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y - 1, tableObserver.table), false);\n } else {\n tableNode.selectPrevious();\n }\n return true;\n case 'down':\n if (y !== tableObserver.table.rows - 1) {\n selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y + 1, tableObserver.table), true);\n } else {\n tableNode.selectNext();\n }\n return true;\n default:\n return false;\n }\n};\nfunction getCorner(rect, cellValue) {\n let colName;\n let rowName;\n if (cellValue.startColumn === rect.minColumn) {\n colName = 'minColumn';\n } else if (cellValue.startColumn + cellValue.cell.__colSpan - 1 === rect.maxColumn) {\n colName = 'maxColumn';\n } else {\n return null;\n }\n if (cellValue.startRow === rect.minRow) {\n rowName = 'minRow';\n } else if (cellValue.startRow + cellValue.cell.__rowSpan - 1 === rect.maxRow) {\n rowName = 'maxRow';\n } else {\n return null;\n }\n return [colName, rowName];\n}\nfunction getCornerOrThrow(rect, cellValue) {\n const corner = getCorner(rect, cellValue);\n if (!(corner !== null)) {\n formatDevErrorMessage(`getCornerOrThrow: cell ${cellValue.cell.getKey()} is not at a corner of rect`);\n }\n return corner;\n}\nfunction oppositeCorner([colName, rowName]) {\n return [colName === 'minColumn' ? 'maxColumn' : 'minColumn', rowName === 'minRow' ? 'maxRow' : 'minRow'];\n}\nfunction cellAtCornerOrThrow(tableMap, rect, [colName, rowName]) {\n const rowNum = rect[rowName];\n const rowMap = tableMap[rowNum];\n if (!(rowMap !== undefined)) {\n formatDevErrorMessage(`cellAtCornerOrThrow: ${rowName} = ${String(rowNum)} missing in tableMap`);\n }\n const colNum = rect[colName];\n const cell = rowMap[colNum];\n if (!(cell !== undefined)) {\n formatDevErrorMessage(`cellAtCornerOrThrow: ${colName} = ${String(colNum)} missing in tableMap`);\n }\n return cell;\n}\nfunction $extractRectCorners(tableMap, anchorCellValue, newFocusCellValue) {\n // We are sure that the focus now either contracts or expands the rect\n // but both the anchor and focus might be moved to ensure a rectangle\n // given a potentially ragged merge shape\n const rect = $computeTableCellRectBoundary(tableMap, anchorCellValue, newFocusCellValue);\n const anchorCorner = getCorner(rect, anchorCellValue);\n if (anchorCorner) {\n return [cellAtCornerOrThrow(tableMap, rect, anchorCorner), cellAtCornerOrThrow(tableMap, rect, oppositeCorner(anchorCorner))];\n }\n const newFocusCorner = getCorner(rect, newFocusCellValue);\n if (newFocusCorner) {\n return [cellAtCornerOrThrow(tableMap, rect, oppositeCorner(newFocusCorner)), cellAtCornerOrThrow(tableMap, rect, newFocusCorner)];\n }\n // TODO this doesn't have to be arbitrary, use the closest corner instead\n const newAnchorCorner = ['minColumn', 'minRow'];\n return [cellAtCornerOrThrow(tableMap, rect, newAnchorCorner), cellAtCornerOrThrow(tableMap, rect, oppositeCorner(newAnchorCorner))];\n}\nfunction $adjustFocusInDirection(tableObserver, tableMap, anchorCellValue, focusCellValue, direction) {\n const rect = $computeTableCellRectBoundary(tableMap, anchorCellValue, focusCellValue);\n const spans = $computeTableCellRectSpans(tableMap, rect);\n const {\n topSpan,\n leftSpan,\n bottomSpan,\n rightSpan\n } = spans;\n const anchorCorner = getCornerOrThrow(rect, anchorCellValue);\n const [focusColumn, focusRow] = oppositeCorner(anchorCorner);\n let fCol = rect[focusColumn];\n let fRow = rect[focusRow];\n if (direction === 'forward') {\n fCol += focusColumn === 'maxColumn' ? 1 : leftSpan;\n } else if (direction === 'backward') {\n fCol -= focusColumn === 'minColumn' ? 1 : rightSpan;\n } else if (direction === 'down') {\n fRow += focusRow === 'maxRow' ? 1 : topSpan;\n } else if (direction === 'up') {\n fRow -= focusRow === 'minRow' ? 1 : bottomSpan;\n }\n const targetRowMap = tableMap[fRow];\n if (targetRowMap === undefined) {\n return false;\n }\n const newFocusCellValue = targetRowMap[fCol];\n if (newFocusCellValue === undefined) {\n return false;\n }\n // We can be certain that anchorCellValue and newFocusCellValue are\n // contained within the desired selection, but we are not certain if\n // they need to be expanded or not to maintain a rectangular shape\n const [finalAnchorCell, finalFocusCell] = $extractRectCorners(tableMap, anchorCellValue, newFocusCellValue);\n const anchorDOM = $getObserverCellFromCellNodeOrThrow(tableObserver, finalAnchorCell.cell);\n const focusDOM = $getObserverCellFromCellNodeOrThrow(tableObserver, finalFocusCell.cell);\n tableObserver.$setAnchorCellForSelection(anchorDOM);\n tableObserver.$setFocusCellForSelection(focusDOM, true);\n return true;\n}\nfunction $isSelectionInTable(selection, tableNode) {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) || $isTableSelection(selection)) {\n // TODO this should probably return false if there's an unrelated\n // shadow root between the node and the table (e.g. another table,\n // collapsible, etc.)\n const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode());\n const isFocusInside = tableNode.isParentOf(selection.focus.getNode());\n return isAnchorInside && isFocusInside;\n }\n return false;\n}\nfunction $isFullTableSelection(selection, tableNode) {\n if ($isTableSelection(selection)) {\n const anchorNode = selection.anchor.getNode();\n const focusNode = selection.focus.getNode();\n if (tableNode && anchorNode && focusNode) {\n const [map] = $computeTableMap(tableNode, anchorNode, focusNode);\n return anchorNode.getKey() === map[0][0].cell.getKey() && focusNode.getKey() === map[map.length - 1].at(-1).cell.getKey();\n }\n }\n return false;\n}\nfunction selectTableCellNode(tableCell, fromStart) {\n if (fromStart) {\n tableCell.selectStart();\n } else {\n tableCell.selectEnd();\n }\n}\nfunction $addHighlightToDOM(editor, cell) {\n const element = cell.elem;\n const editorThemeClasses = editor._config.theme;\n const node = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNearestNodeFromDOMNode)(element);\n if (!$isTableCellNode(node)) {\n formatDevErrorMessage(`Expected to find LexicalNode from Table Cell DOMNode`);\n }\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(element, editorThemeClasses.tableCellSelected);\n}\nfunction $removeHighlightFromDOM(editor, cell) {\n const element = cell.elem;\n const node = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNearestNodeFromDOMNode)(element);\n if (!$isTableCellNode(node)) {\n formatDevErrorMessage(`Expected to find LexicalNode from Table Cell DOMNode`);\n }\n const editorThemeClasses = editor._config.theme;\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.removeClassNamesFromElement)(element, editorThemeClasses.tableCellSelected);\n}\nfunction $findCellNode(node) {\n const cellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(node, $isTableCellNode);\n return $isTableCellNode(cellNode) ? cellNode : null;\n}\nfunction $findTableNode(node) {\n const tableNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(node, $isTableNode);\n return $isTableNode(tableNode) ? tableNode : null;\n}\nfunction $getBlockParentIfFirstNode(node) {\n for (let prevNode = node, currentNode = node; currentNode !== null; prevNode = currentNode, currentNode = currentNode.getParent()) {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(currentNode)) {\n if (currentNode !== prevNode && currentNode.getFirstChild() !== prevNode) {\n // Not the first child or the initial node\n return null;\n } else if (!currentNode.isInline()) {\n return currentNode;\n }\n }\n }\n return null;\n}\nfunction $handleHorizontalArrowKeyRangeSelection(editor, event, selection, alter, isBackward, tableNode, tableObserver) {\n const initialFocus = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$caretFromPoint)(selection.focus, isBackward ? 'previous' : 'next');\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isExtendableTextPointCaret)(initialFocus)) {\n return false;\n }\n let lastCaret = initialFocus;\n // TableCellNode is the only shadow root we are interested in piercing so\n // we find the last internal caret and then check its parent\n for (const nextCaret of (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$extendCaretToRange)(initialFocus).iterNodeCarets('shadowRoot')) {\n if (!((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isSiblingCaret)(nextCaret) && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(nextCaret.origin))) {\n return false;\n }\n lastCaret = nextCaret;\n }\n const lastCaretParent = lastCaret.getParentAtCaret();\n if (!$isTableCellNode(lastCaretParent)) {\n return false;\n }\n const anchorCell = lastCaretParent;\n const focusCaret = $findNextTableCell((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSiblingCaret)(anchorCell, lastCaret.direction));\n const anchorCellTable = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(anchorCell, $isTableNode);\n if (!(anchorCellTable && anchorCellTable.is(tableNode))) {\n return false;\n }\n const anchorCellDOM = editor.getElementByKey(anchorCell.getKey());\n const anchorDOMCell = getDOMCellFromTarget(anchorCellDOM);\n if (!anchorCellDOM || !anchorDOMCell) {\n return false;\n }\n const anchorCellTableElement = $getElementForTableNode(editor, anchorCellTable);\n tableObserver.table = anchorCellTableElement;\n if (!focusCaret) {\n if (alter === 'extend') {\n // extend the selection from a range inside the cell to a table selection of the cell\n tableObserver.$setAnchorCellForSelection(anchorDOMCell);\n tableObserver.$setFocusCellForSelection(anchorDOMCell, true);\n } else {\n // exit the table\n const outerFocusCaret = $getTableExitCaret((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSiblingCaret)(anchorCellTable, initialFocus.direction));\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setPointFromCaret)(selection.anchor, outerFocusCaret);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setPointFromCaret)(selection.focus, outerFocusCaret);\n }\n } else if (alter === 'extend') {\n const focusDOMCell = getDOMCellFromTarget(editor.getElementByKey(focusCaret.origin.getKey()));\n if (!focusDOMCell) {\n return false;\n }\n tableObserver.$setAnchorCellForSelection(anchorDOMCell);\n tableObserver.$setFocusCellForSelection(focusDOMCell, true);\n } else {\n // alter === 'move'\n const innerFocusCaret = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$normalizeCaret)(focusCaret);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setPointFromCaret)(selection.anchor, innerFocusCaret);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setPointFromCaret)(selection.focus, innerFocusCaret);\n }\n stopEvent(event);\n return true;\n}\nfunction $getTableExitCaret(initialCaret) {\n const adjacent = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getAdjacentChildCaret)(initialCaret);\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isChildCaret)(adjacent) ? (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$normalizeCaret)(adjacent) : initialCaret;\n}\nfunction $findNextTableCell(initialCaret) {\n for (const nextCaret of (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$extendCaretToRange)(initialCaret).iterNodeCarets('root')) {\n const {\n origin\n } = nextCaret;\n if ($isTableCellNode(origin)) {\n // not sure why ts isn't narrowing here (even if the guard is on nextCaret.origin)\n // but returning a new caret is fine\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isChildCaret)(nextCaret)) {\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getChildCaret)(origin, initialCaret.direction);\n }\n } else if (!$isTableRowNode(origin)) {\n break;\n }\n }\n return null;\n}\nfunction $handleArrowKey(editor, event, direction, tableNode, tableObserver) {\n if ((direction === 'up' || direction === 'down') && isTypeaheadMenuInView(editor)) {\n return false;\n }\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!$isSelectionInTable(selection, tableNode)) {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n if (direction === 'backward') {\n if (selection.focus.offset > 0) {\n return false;\n }\n const parentNode = $getBlockParentIfFirstNode(selection.focus.getNode());\n if (!parentNode) {\n return false;\n }\n const siblingNode = parentNode.getPreviousSibling();\n if (!$isTableNode(siblingNode)) {\n return false;\n }\n stopEvent(event);\n if (event.shiftKey) {\n selection.focus.set(siblingNode.getParentOrThrow().getKey(), siblingNode.getIndexWithinParent(), 'element');\n } else {\n siblingNode.selectEnd();\n }\n return true;\n } else if (event.shiftKey && (direction === 'up' || direction === 'down')) {\n const focusNode = selection.focus.getNode();\n const isTableUnselect = !selection.isCollapsed() && (direction === 'up' && !selection.isBackward() || direction === 'down' && selection.isBackward());\n if (isTableUnselect) {\n let focusParentNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(focusNode, n => $isTableNode(n));\n if ($isTableCellNode(focusParentNode)) {\n focusParentNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(focusParentNode, $isTableNode);\n }\n if (focusParentNode !== tableNode) {\n return false;\n }\n if (!focusParentNode) {\n return false;\n }\n const sibling = direction === 'down' ? focusParentNode.getNextSibling() : focusParentNode.getPreviousSibling();\n if (!sibling) {\n return false;\n }\n let newOffset = 0;\n if (direction === 'up') {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(sibling)) {\n newOffset = sibling.getChildrenSize();\n }\n }\n let newFocusNode = sibling;\n if (direction === 'up') {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(sibling)) {\n const lastCell = sibling.getLastChild();\n newFocusNode = lastCell ? lastCell : sibling;\n newOffset = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isTextNode)(newFocusNode) ? newFocusNode.getTextContentSize() : 0;\n }\n }\n const newSelection = selection.clone();\n newSelection.focus.set(newFocusNode.getKey(), newOffset, (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isTextNode)(newFocusNode) ? 'text' : 'element');\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(newSelection);\n stopEvent(event);\n return true;\n } else if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRootOrShadowRoot)(focusNode)) {\n const selectedNode = direction === 'up' ? selection.getNodes()[selection.getNodes().length - 1] : selection.getNodes()[0];\n if (selectedNode) {\n const tableCellNode = $findParentTableCellNodeInTable(tableNode, selectedNode);\n if (tableCellNode !== null) {\n const firstDescendant = tableNode.getFirstDescendant();\n const lastDescendant = tableNode.getLastDescendant();\n if (!firstDescendant || !lastDescendant) {\n return false;\n }\n const [firstCellNode] = $getNodeTriplet(firstDescendant);\n const [lastCellNode] = $getNodeTriplet(lastDescendant);\n const firstCellCoords = tableNode.getCordsFromCellNode(firstCellNode, tableObserver.table);\n const lastCellCoords = tableNode.getCordsFromCellNode(lastCellNode, tableObserver.table);\n const firstCellDOM = tableNode.getDOMCellFromCordsOrThrow(firstCellCoords.x, firstCellCoords.y, tableObserver.table);\n const lastCellDOM = tableNode.getDOMCellFromCordsOrThrow(lastCellCoords.x, lastCellCoords.y, tableObserver.table);\n tableObserver.$setAnchorCellForSelection(firstCellDOM);\n tableObserver.$setFocusCellForSelection(lastCellDOM, true);\n return true;\n }\n }\n return false;\n } else {\n let focusParentNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(focusNode, n => (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(n) && !n.isInline());\n if ($isTableCellNode(focusParentNode)) {\n focusParentNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(focusParentNode, $isTableNode);\n }\n if (!focusParentNode) {\n return false;\n }\n const sibling = direction === 'down' ? focusParentNode.getNextSibling() : focusParentNode.getPreviousSibling();\n if ($isTableNode(sibling) && tableObserver.tableNodeKey === sibling.getKey()) {\n const firstDescendant = sibling.getFirstDescendant();\n const lastDescendant = sibling.getLastDescendant();\n if (!firstDescendant || !lastDescendant) {\n return false;\n }\n const [firstCellNode] = $getNodeTriplet(firstDescendant);\n const [lastCellNode] = $getNodeTriplet(lastDescendant);\n const newSelection = selection.clone();\n newSelection.focus.set((direction === 'up' ? firstCellNode : lastCellNode).getKey(), direction === 'up' ? 0 : lastCellNode.getChildrenSize(), 'element');\n stopEvent(event);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(newSelection);\n return true;\n }\n }\n }\n }\n if (direction === 'down' && $isScrollableTablesActive(editor)) {\n // Enable Firefox workaround\n tableObserver.setShouldCheckSelection();\n }\n return false;\n }\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n if (direction === 'backward' || direction === 'forward') {\n const alter = event.shiftKey ? 'extend' : 'move';\n return $handleHorizontalArrowKeyRangeSelection(editor, event, selection, alter, direction === 'backward', tableNode, tableObserver);\n }\n if (selection.isCollapsed()) {\n const {\n anchor,\n focus\n } = selection;\n const anchorCellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(anchor.getNode(), $isTableCellNode);\n const focusCellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(focus.getNode(), $isTableCellNode);\n if (!$isTableCellNode(anchorCellNode) || !anchorCellNode.is(focusCellNode)) {\n return false;\n }\n const anchorCellTable = $findTableNode(anchorCellNode);\n if (anchorCellTable !== tableNode && anchorCellTable != null) {\n const anchorCellTableElement = getTableElement(anchorCellTable, editor.getElementByKey(anchorCellTable.getKey()));\n if (anchorCellTableElement != null) {\n tableObserver.table = getTable(anchorCellTable, anchorCellTableElement);\n return $handleArrowKey(editor, event, direction, anchorCellTable, tableObserver);\n }\n }\n const anchorCellDom = editor.getElementByKey(anchorCellNode.__key);\n const anchorDOM = editor.getElementByKey(anchor.key);\n if (anchorDOM == null || anchorCellDom == null) {\n return false;\n }\n let edgeSelectionRect;\n if (anchor.type === 'element') {\n edgeSelectionRect = anchorDOM.getBoundingClientRect();\n } else {\n const domSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.getDOMSelection)(getEditorWindow(editor));\n if (domSelection === null || domSelection.rangeCount === 0) {\n return false;\n }\n const range = domSelection.getRangeAt(0);\n edgeSelectionRect = range.getBoundingClientRect();\n }\n const edgeChild = direction === 'up' ? anchorCellNode.getFirstChild() : anchorCellNode.getLastChild();\n if (edgeChild == null) {\n return false;\n }\n const edgeChildDOM = editor.getElementByKey(edgeChild.__key);\n if (edgeChildDOM == null) {\n return false;\n }\n const edgeRect = edgeChildDOM.getBoundingClientRect();\n const isExiting = direction === 'up' ? edgeRect.top > edgeSelectionRect.top - edgeSelectionRect.height : edgeSelectionRect.bottom + edgeSelectionRect.height > edgeRect.bottom;\n if (isExiting) {\n stopEvent(event);\n const cords = tableNode.getCordsFromCellNode(anchorCellNode, tableObserver.table);\n if (event.shiftKey) {\n const cell = tableNode.getDOMCellFromCordsOrThrow(cords.x, cords.y, tableObserver.table);\n tableObserver.$setAnchorCellForSelection(cell);\n tableObserver.$setFocusCellForSelection(cell, true);\n } else {\n return selectTableNodeInDirection(tableObserver, tableNode, cords.x, cords.y, direction);\n }\n return true;\n }\n }\n } else if ($isTableSelection(selection)) {\n const {\n anchor,\n focus\n } = selection;\n const anchorCellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(anchor.getNode(), $isTableCellNode);\n const focusCellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(focus.getNode(), $isTableCellNode);\n const [tableNodeFromSelection] = selection.getNodes();\n if (!$isTableNode(tableNodeFromSelection)) {\n formatDevErrorMessage(`$handleArrowKey: TableSelection.getNodes()[0] expected to be TableNode`);\n }\n const tableElement = getTableElement(tableNodeFromSelection, editor.getElementByKey(tableNodeFromSelection.getKey()));\n if (!$isTableCellNode(anchorCellNode) || !$isTableCellNode(focusCellNode) || !$isTableNode(tableNodeFromSelection) || tableElement == null) {\n return false;\n }\n tableObserver.$updateTableTableSelection(selection);\n const grid = getTable(tableNodeFromSelection, tableElement);\n const cordsAnchor = tableNode.getCordsFromCellNode(anchorCellNode, grid);\n const anchorCell = tableNode.getDOMCellFromCordsOrThrow(cordsAnchor.x, cordsAnchor.y, grid);\n tableObserver.$setAnchorCellForSelection(anchorCell);\n stopEvent(event);\n if (event.shiftKey) {\n const [tableMap, anchorValue, focusValue] = $computeTableMap(tableNode, anchorCellNode, focusCellNode);\n return $adjustFocusInDirection(tableObserver, tableMap, anchorValue, focusValue, direction);\n } else {\n focusCellNode.selectEnd();\n }\n return true;\n }\n return false;\n}\nfunction stopEvent(event) {\n event.preventDefault();\n event.stopImmediatePropagation();\n event.stopPropagation();\n}\nfunction isTypeaheadMenuInView(editor) {\n // There is no inbuilt way to check if the component picker is in view\n // but we can check if the root DOM element has the aria-controls attribute \"typeahead-menu\".\n const root = editor.getRootElement();\n if (!root) {\n return false;\n }\n return root.hasAttribute('aria-controls') && root.getAttribute('aria-controls') === 'typeahead-menu';\n}\nfunction $insertParagraphAtTableEdge(edgePosition, tableNode, children) {\n const paragraphNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)();\n if (edgePosition === 'first') {\n tableNode.insertBefore(paragraphNode);\n } else {\n tableNode.insertAfter(paragraphNode);\n }\n paragraphNode.append(...(children || []));\n paragraphNode.selectEnd();\n}\nfunction $getTableEdgeCursorPosition(editor, selection, tableNode) {\n const tableNodeParent = tableNode.getParent();\n if (!tableNodeParent) {\n return undefined;\n }\n\n // TODO: Add support for nested tables\n const domSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.getDOMSelection)(getEditorWindow(editor));\n if (!domSelection) {\n return undefined;\n }\n const domAnchorNode = domSelection.anchorNode;\n const tableNodeParentDOM = editor.getElementByKey(tableNodeParent.getKey());\n const tableElement = getTableElement(tableNode, editor.getElementByKey(tableNode.getKey()));\n // We are only interested in the scenario where the\n // native selection anchor is:\n // - at or inside the table's parent DOM\n // - and NOT at or inside the table DOM\n // It may be adjacent to the table DOM (e.g. in a wrapper)\n if (!domAnchorNode || !tableNodeParentDOM || !tableElement || !tableNodeParentDOM.contains(domAnchorNode) || tableElement.contains(domAnchorNode)) {\n return undefined;\n }\n const anchorCellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(selection.anchor.getNode(), n => $isTableCellNode(n));\n if (!anchorCellNode) {\n return undefined;\n }\n const parentTable = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(anchorCellNode, n => $isTableNode(n));\n if (!$isTableNode(parentTable) || !parentTable.is(tableNode)) {\n return undefined;\n }\n const [tableMap, cellValue] = $computeTableMap(tableNode, anchorCellNode, anchorCellNode);\n const firstCell = tableMap[0][0];\n const lastCell = tableMap[tableMap.length - 1][tableMap[0].length - 1];\n const {\n startRow,\n startColumn\n } = cellValue;\n const isAtFirstCell = startRow === firstCell.startRow && startColumn === firstCell.startColumn;\n const isAtLastCell = startRow === lastCell.startRow && startColumn === lastCell.startColumn;\n if (isAtFirstCell) {\n return 'first';\n } else if (isAtLastCell) {\n return 'last';\n } else {\n return undefined;\n }\n}\nfunction $getObserverCellFromCellNodeOrThrow(tableObserver, tableCellNode) {\n const {\n tableNode\n } = tableObserver.$lookup();\n const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableObserver.table);\n return tableNode.getDOMCellFromCordsOrThrow(currentCords.x, currentCords.y, tableObserver.table);\n}\nfunction $getNearestTableCellInTableFromDOMNode(tableNode, startingDOM, editorState) {\n return $findParentTableCellNodeInTable(tableNode, (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNearestNodeFromDOMNode)(startingDOM, editorState));\n}\n\nfunction isHTMLDivElement(element) {\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.isHTMLElement)(element) && element.nodeName === 'DIV';\n}\nfunction updateColgroup(dom, config, colCount, colWidths) {\n const colGroup = dom.querySelector('colgroup');\n if (!colGroup) {\n return;\n }\n const cols = [];\n for (let i = 0; i < colCount; i++) {\n const col = document.createElement('col');\n const width = colWidths && colWidths[i];\n if (width) {\n col.style.width = `${width}px`;\n }\n cols.push(col);\n }\n colGroup.replaceChildren(...cols);\n}\nfunction setRowStriping(dom, config, rowStriping) {\n if (rowStriping) {\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(dom, config.theme.tableRowStriping);\n dom.setAttribute('data-lexical-row-striping', 'true');\n } else {\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.removeClassNamesFromElement)(dom, config.theme.tableRowStriping);\n dom.removeAttribute('data-lexical-row-striping');\n }\n}\nfunction setFrozenColumns(dom, tableElement, config, frozenColumnCount) {\n if (frozenColumnCount > 0) {\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(dom, config.theme.tableFrozenColumn);\n tableElement.setAttribute('data-lexical-frozen-column', 'true');\n } else {\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.removeClassNamesFromElement)(dom, config.theme.tableFrozenColumn);\n tableElement.removeAttribute('data-lexical-frozen-column');\n }\n}\nfunction setFrozenRows(dom, tableElement, config, frozenRowCount) {\n if (frozenRowCount > 0) {\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(dom, config.theme.tableFrozenRow);\n tableElement.setAttribute('data-lexical-frozen-row', 'true');\n } else {\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.removeClassNamesFromElement)(dom, config.theme.tableFrozenRow);\n tableElement.removeAttribute('data-lexical-frozen-row');\n }\n}\nfunction alignTableElement(dom, config, formatType) {\n if (!config.theme.tableAlignment) {\n return;\n }\n const removeClasses = [];\n const addClasses = [];\n for (const format of ['center', 'right']) {\n const classes = config.theme.tableAlignment[format];\n if (!classes) {\n continue;\n }\n (format === formatType ? addClasses : removeClasses).push(classes);\n }\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.removeClassNamesFromElement)(dom, ...removeClasses);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(dom, ...addClasses);\n}\nconst scrollableEditors = new WeakSet();\nfunction $isScrollableTablesActive(editor = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getEditor)()) {\n return scrollableEditors.has(editor);\n}\nfunction setScrollableTablesActive(editor, active) {\n if (active) {\n if (!editor._config.theme.tableScrollableWrapper) {\n console.warn('TableNode: hasHorizontalScroll is active but theme.tableScrollableWrapper is not defined.');\n }\n scrollableEditors.add(editor);\n } else {\n scrollableEditors.delete(editor);\n }\n}\n\n/** @noInheritDoc */\nclass TableNode extends lexical__WEBPACK_IMPORTED_MODULE_0__.ElementNode {\n /** @internal */\n __rowStriping;\n __frozenColumnCount;\n __frozenRowCount;\n __colWidths;\n static getType() {\n return 'table';\n }\n getColWidths() {\n const self = this.getLatest();\n return self.__colWidths;\n }\n setColWidths(colWidths) {\n const self = this.getWritable();\n // NOTE: Node properties should be immutable. Freeze to prevent accidental mutation.\n self.__colWidths = colWidths !== undefined && true ? Object.freeze(colWidths) : colWidths;\n return self;\n }\n static clone(node) {\n return new TableNode(node.__key);\n }\n afterCloneFrom(prevNode) {\n super.afterCloneFrom(prevNode);\n this.__colWidths = prevNode.__colWidths;\n this.__rowStriping = prevNode.__rowStriping;\n this.__frozenColumnCount = prevNode.__frozenColumnCount;\n this.__frozenRowCount = prevNode.__frozenRowCount;\n }\n static importDOM() {\n return {\n table: _node => ({\n conversion: $convertTableElement,\n priority: 1\n })\n };\n }\n static importJSON(serializedNode) {\n return $createTableNode().updateFromJSON(serializedNode);\n }\n updateFromJSON(serializedNode) {\n return super.updateFromJSON(serializedNode).setRowStriping(serializedNode.rowStriping || false).setFrozenColumns(serializedNode.frozenColumnCount || 0).setFrozenRows(serializedNode.frozenRowCount || 0).setColWidths(serializedNode.colWidths);\n }\n constructor(key) {\n super(key);\n this.__rowStriping = false;\n this.__frozenColumnCount = 0;\n this.__frozenRowCount = 0;\n this.__colWidths = undefined;\n }\n exportJSON() {\n return {\n ...super.exportJSON(),\n colWidths: this.getColWidths(),\n frozenColumnCount: this.__frozenColumnCount ? this.__frozenColumnCount : undefined,\n frozenRowCount: this.__frozenRowCount ? this.__frozenRowCount : undefined,\n rowStriping: this.__rowStriping ? this.__rowStriping : undefined\n };\n }\n extractWithChild(child, selection, destination) {\n return destination === 'html';\n }\n getDOMSlot(element) {\n const tableElement = !isHTMLTableElement(element) ? element.querySelector('table') : element;\n if (!isHTMLTableElement(tableElement)) {\n formatDevErrorMessage(`TableNode.getDOMSlot: createDOM() did not return a table`);\n }\n return super.getDOMSlot(element).withElement(tableElement).withAfter(tableElement.querySelector('colgroup'));\n }\n createDOM(config, editor) {\n const tableElement = document.createElement('table');\n if (this.__style) {\n tableElement.style.cssText = this.__style;\n }\n const colGroup = document.createElement('colgroup');\n tableElement.appendChild(colGroup);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.setDOMUnmanaged)(colGroup);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(tableElement, config.theme.table);\n this.updateTableElement(null, tableElement, config);\n if ($isScrollableTablesActive(editor)) {\n const wrapperElement = document.createElement('div');\n const classes = config.theme.tableScrollableWrapper;\n if (classes) {\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.addClassNamesToElement)(wrapperElement, classes);\n } else {\n wrapperElement.style.cssText = 'overflow-x: auto;';\n }\n wrapperElement.appendChild(tableElement);\n this.updateTableWrapper(null, wrapperElement, tableElement, config);\n return wrapperElement;\n }\n return tableElement;\n }\n updateTableWrapper(prevNode, tableWrapper, tableElement, config) {\n if (this.__frozenColumnCount !== (prevNode ? prevNode.__frozenColumnCount : 0)) {\n setFrozenColumns(tableWrapper, tableElement, config, this.__frozenColumnCount);\n }\n if (this.__frozenRowCount !== (prevNode ? prevNode.__frozenRowCount : 0)) {\n setFrozenRows(tableWrapper, tableElement, config, this.__frozenRowCount);\n }\n }\n updateTableElement(prevNode, tableElement, config) {\n if (this.__style !== (prevNode ? prevNode.__style : '')) {\n tableElement.style.cssText = this.__style;\n }\n if (this.__rowStriping !== (prevNode ? prevNode.__rowStriping : false)) {\n setRowStriping(tableElement, config, this.__rowStriping);\n }\n updateColgroup(tableElement, config, this.getColumnCount(), this.getColWidths());\n alignTableElement(tableElement, config, this.getFormatType());\n }\n updateDOM(prevNode, dom, config) {\n const slot = this.getDOMSlot(dom);\n const tableElement = slot.element;\n if (dom === tableElement === $isScrollableTablesActive()) {\n return true;\n }\n if (isHTMLDivElement(dom)) {\n this.updateTableWrapper(prevNode, dom, tableElement, config);\n }\n this.updateTableElement(prevNode, tableElement, config);\n return false;\n }\n exportDOM(editor) {\n const superExport = super.exportDOM(editor);\n const {\n element\n } = superExport;\n return {\n after: tableElement => {\n if (superExport.after) {\n tableElement = superExport.after(tableElement);\n }\n if (!isHTMLTableElement(tableElement) && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.isHTMLElement)(tableElement)) {\n tableElement = tableElement.querySelector('table');\n }\n if (!isHTMLTableElement(tableElement)) {\n return null;\n }\n alignTableElement(tableElement, editor._config, this.getFormatType());\n\n // Scan the table map to build a map of table cell key to the columns it needs\n const [tableMap] = $computeTableMapSkipCellCheck(this, null, null);\n const cellValues = new Map();\n for (const mapRow of tableMap) {\n for (const mapValue of mapRow) {\n const key = mapValue.cell.getKey();\n if (!cellValues.has(key)) {\n cellValues.set(key, {\n colSpan: mapValue.cell.getColSpan(),\n startColumn: mapValue.startColumn\n });\n }\n }\n }\n\n // scan the DOM to find the table cell keys that were used and mark those columns\n const knownColumns = new Set();\n for (const cellDOM of tableElement.querySelectorAll(':scope > tr > [data-temporary-table-cell-lexical-key]')) {\n const key = cellDOM.getAttribute('data-temporary-table-cell-lexical-key');\n if (key) {\n const cellSpan = cellValues.get(key);\n cellDOM.removeAttribute('data-temporary-table-cell-lexical-key');\n if (cellSpan) {\n cellValues.delete(key);\n for (let i = 0; i < cellSpan.colSpan; i++) {\n knownColumns.add(i + cellSpan.startColumn);\n }\n }\n }\n }\n\n // Compute the colgroup and columns in the export\n const colGroup = tableElement.querySelector(':scope > colgroup');\n if (colGroup) {\n // Only include the for rows that are in the output\n const cols = Array.from(tableElement.querySelectorAll(':scope > colgroup > col')).filter((dom, i) => knownColumns.has(i));\n colGroup.replaceChildren(...cols);\n }\n\n // Wrap direct descendant rows in a tbody for export\n const rows = tableElement.querySelectorAll(':scope > tr');\n if (rows.length > 0) {\n const tBody = document.createElement('tbody');\n for (const row of rows) {\n tBody.appendChild(row);\n }\n tableElement.append(tBody);\n }\n return tableElement;\n },\n element: !isHTMLTableElement(element) && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.isHTMLElement)(element) ? element.querySelector('table') : element\n };\n }\n canBeEmpty() {\n return false;\n }\n isShadowRoot() {\n return true;\n }\n getCordsFromCellNode(tableCellNode, table) {\n const {\n rows,\n domRows\n } = table;\n for (let y = 0; y < rows; y++) {\n const row = domRows[y];\n if (row == null) {\n continue;\n }\n for (let x = 0; x < row.length; x++) {\n const cell = row[x];\n if (cell == null) {\n continue;\n }\n const {\n elem\n } = cell;\n const cellNode = $getNearestTableCellInTableFromDOMNode(this, elem);\n if (cellNode !== null && tableCellNode.is(cellNode)) {\n return {\n x,\n y\n };\n }\n }\n }\n throw new Error('Cell not found in table.');\n }\n getDOMCellFromCords(x, y, table) {\n const {\n domRows\n } = table;\n const row = domRows[y];\n if (row == null) {\n return null;\n }\n const index = x < row.length ? x : row.length - 1;\n const cell = row[index];\n if (cell == null) {\n return null;\n }\n return cell;\n }\n getDOMCellFromCordsOrThrow(x, y, table) {\n const cell = this.getDOMCellFromCords(x, y, table);\n if (!cell) {\n throw new Error('Cell not found at cords.');\n }\n return cell;\n }\n getCellNodeFromCords(x, y, table) {\n const cell = this.getDOMCellFromCords(x, y, table);\n if (cell == null) {\n return null;\n }\n const node = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNearestNodeFromDOMNode)(cell.elem);\n if ($isTableCellNode(node)) {\n return node;\n }\n return null;\n }\n getCellNodeFromCordsOrThrow(x, y, table) {\n const node = this.getCellNodeFromCords(x, y, table);\n if (!node) {\n throw new Error('Node at cords not TableCellNode.');\n }\n return node;\n }\n getRowStriping() {\n return Boolean(this.getLatest().__rowStriping);\n }\n setRowStriping(newRowStriping) {\n const self = this.getWritable();\n self.__rowStriping = newRowStriping;\n return self;\n }\n setFrozenColumns(columnCount) {\n const self = this.getWritable();\n self.__frozenColumnCount = columnCount;\n return self;\n }\n getFrozenColumns() {\n return this.getLatest().__frozenColumnCount;\n }\n setFrozenRows(rowCount) {\n const self = this.getWritable();\n self.__frozenRowCount = rowCount;\n return self;\n }\n getFrozenRows() {\n return this.getLatest().__frozenRowCount;\n }\n canSelectBefore() {\n return true;\n }\n canIndent() {\n return false;\n }\n getColumnCount() {\n const firstRow = this.getFirstChild();\n if (!firstRow) {\n return 0;\n }\n let columnCount = 0;\n firstRow.getChildren().forEach(cell => {\n if ($isTableCellNode(cell)) {\n columnCount += cell.getColSpan();\n }\n });\n return columnCount;\n }\n}\nfunction $getElementForTableNode(editor, tableNode) {\n const tableElement = editor.getElementByKey(tableNode.getKey());\n if (!(tableElement !== null)) {\n formatDevErrorMessage(`$getElementForTableNode: Table Element Not Found`);\n }\n return getTable(tableNode, tableElement);\n}\nfunction $convertTableElement(domNode) {\n const tableNode = $createTableNode();\n if (domNode.hasAttribute('data-lexical-row-striping')) {\n tableNode.setRowStriping(true);\n }\n if (domNode.hasAttribute('data-lexical-frozen-column')) {\n tableNode.setFrozenColumns(1);\n }\n if (domNode.hasAttribute('data-lexical-frozen-row')) {\n tableNode.setFrozenRows(1);\n }\n const colGroup = domNode.querySelector(':scope > colgroup');\n if (colGroup) {\n let columns = [];\n for (const col of colGroup.querySelectorAll(':scope > col')) {\n let width = col.style.width || '';\n if (!PIXEL_VALUE_REG_EXP.test(width)) {\n // Also support deprecated width attribute for google docs\n width = col.getAttribute('width') || '';\n if (!/^\\d+$/.test(width)) {\n columns = undefined;\n break;\n }\n }\n columns.push(parseFloat(width));\n }\n if (columns) {\n tableNode.setColWidths(columns);\n }\n }\n return {\n after: children => (0,_lexical_utils__WEBPACK_IMPORTED_MODULE_1__.$descendantsMatching)(children, $isTableRowNode),\n node: tableNode\n };\n}\nfunction $createTableNode() {\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$applyNodeReplacement)(new TableNode());\n}\nfunction $isTableNode(node) {\n return node instanceof TableNode;\n}\n\nfunction $insertTable({\n rows,\n columns,\n includeHeaders\n}, hasNestedTables) {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)() || (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getPreviousSelection)();\n if (!selection || !(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n return false;\n }\n\n // Prevent nested tables by checking if we're already inside a table\n if (!hasNestedTables && $findTableNode(selection.anchor.getNode())) {\n return false;\n }\n const tableNode = $createTableNodeWithDimensions(Number(rows), Number(columns), includeHeaders);\n (0,_lexical_utils__WEBPACK_IMPORTED_MODULE_1__.$insertNodeToNearestRoot)(tableNode);\n const firstDescendant = tableNode.getFirstDescendant();\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isTextNode)(firstDescendant)) {\n firstDescendant.select();\n }\n return true;\n}\nfunction $tableCellTransform(node) {\n if (!$isTableRowNode(node.getParent())) {\n // TableCellNode must be a child of TableRowNode.\n node.remove();\n } else if (node.isEmpty()) {\n // TableCellNode should never be empty\n node.append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)());\n }\n}\nfunction $tableRowTransform(node) {\n if (!$isTableNode(node.getParent())) {\n // TableRowNode must be a child of TableNode.\n // TODO: Future support of tbody/thead/tfoot may change this\n node.remove();\n } else {\n (0,_lexical_utils__WEBPACK_IMPORTED_MODULE_1__.$unwrapAndFilterDescendants)(node, $isTableCellNode);\n }\n}\nfunction $tableTransform(node) {\n // TableRowNode is the only valid child for TableNode\n // TODO: Future support of tbody/thead/tfoot/caption may change this\n (0,_lexical_utils__WEBPACK_IMPORTED_MODULE_1__.$unwrapAndFilterDescendants)(node, $isTableRowNode);\n const [gridMap] = $computeTableMapSkipCellCheck(node, null, null);\n const maxRowLength = gridMap.reduce((curLength, row) => {\n return Math.max(curLength, row.length);\n }, 0);\n const rowNodes = node.getChildren();\n for (let i = 0; i < gridMap.length; ++i) {\n const rowNode = rowNodes[i];\n if (!rowNode) {\n continue;\n }\n if (!$isTableRowNode(rowNode)) {\n formatDevErrorMessage(`TablePlugin: Expecting all children of TableNode to be TableRowNode, found ${rowNode.constructor.name} (type ${rowNode.getType()})`);\n }\n const rowLength = gridMap[i].reduce((acc, cell) => cell ? 1 + acc : acc, 0);\n if (rowLength === maxRowLength) {\n continue;\n }\n for (let j = rowLength; j < maxRowLength; ++j) {\n // TODO: inherit header state from another header or body\n const newCell = $createTableCellNode();\n newCell.append((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)());\n rowNode.append(newCell);\n }\n }\n const colWidths = node.getColWidths();\n const columnCount = node.getColumnCount();\n if (colWidths && colWidths.length !== columnCount) {\n let newColWidths = undefined;\n if (columnCount < colWidths.length) {\n newColWidths = colWidths.slice(0, columnCount);\n } else if (colWidths.length > 0) {\n // Repeat the last column width.\n const fillWidth = colWidths[colWidths.length - 1];\n newColWidths = [...colWidths, ...Array(columnCount - colWidths.length).fill(fillWidth)];\n }\n node.setColWidths(newColWidths);\n }\n}\nfunction $tableClickCommand(event) {\n if (event.detail < 3 || !(0,lexical__WEBPACK_IMPORTED_MODULE_0__.isDOMNode)(event.target)) {\n return false;\n }\n const startNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getNearestNodeFromDOMNode)(event.target);\n if (startNode === null) {\n return false;\n }\n const blockNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(startNode, node => (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isElementNode)(node) && !node.isInline());\n if (blockNode === null) {\n return false;\n }\n const rootNode = blockNode.getParent();\n if (!$isTableCellNode(rootNode)) {\n return false;\n }\n blockNode.select(0);\n return true;\n}\nfunction $tableSelectAllCommand() {\n const selection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getSelection)();\n if (!(0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection)) {\n return false;\n }\n\n // Check if the selection is inside a table\n const anchorNode = selection.anchor.getNode();\n const tableNode = $findTableNode(anchorNode);\n if (tableNode === null) {\n return false;\n }\n\n // CRITICAL: Only intercept if table is the ONLY child of root\n // This is required to reproduce the bug: table must be the only content, no empty paragraphs\n // This prevents breaking other tests that expect RangeSelection when there's content outside table\n const root = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getRoot)();\n if (!root.is(tableNode.getParent()) || root.getChildrenSize() !== 1) {\n return false;\n }\n\n // At this point, table is the only child\n // This is the exact scenario from issue #8074: table is the only content in editor\n\n // Get the table map to find first and last cells (handles merged cells correctly)\n const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);\n if (tableMap.length === 0 || tableMap[0].length === 0) {\n return false;\n }\n\n // Get the first cell (top-left)\n const firstCellMap = tableMap[0][0];\n if (!firstCellMap || !firstCellMap.cell) {\n return false;\n }\n\n // Get the last cell (bottom-right)\n const lastRow = tableMap[tableMap.length - 1];\n const lastCellMap = lastRow[lastRow.length - 1];\n if (!lastCellMap || !lastCellMap.cell) {\n return false;\n }\n\n // Create a TableSelection that selects all cells\n const tableSelection = $createTableSelectionFrom(tableNode, firstCellMap.cell, lastCellMap.cell);\n (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$setSelection)(tableSelection);\n return true;\n}\n\n/**\n * Register a transform to ensure that all TableCellNode have a colSpan and rowSpan of 1.\n * This should only be registered when you do not want to support merged cells.\n *\n * @param editor The editor\n * @returns An unregister callback\n */\nfunction registerTableCellUnmergeTransform(editor) {\n return editor.registerNodeTransform(TableCellNode, node => {\n if (node.getColSpan() > 1 || node.getRowSpan() > 1) {\n // When we have rowSpan we have to map the entire Table to understand where the new Cells\n // fit best; let's analyze all Cells at once to save us from further transform iterations\n const [,, gridNode] = $getNodeTriplet(node);\n const [gridMap] = $computeTableMap(gridNode, node, node);\n // TODO this function expects Tables to be normalized. Look into this once it exists\n const rowsCount = gridMap.length;\n const columnsCount = gridMap[0].length;\n let row = gridNode.getFirstChild();\n if (!$isTableRowNode(row)) {\n formatDevErrorMessage(`Expected TableNode first child to be a RowNode`);\n }\n const unmerged = [];\n for (let i = 0; i < rowsCount; i++) {\n if (i !== 0) {\n row = row.getNextSibling();\n if (!$isTableRowNode(row)) {\n formatDevErrorMessage(`Expected TableNode first child to be a RowNode`);\n }\n }\n let lastRowCell = null;\n for (let j = 0; j < columnsCount; j++) {\n const cellMap = gridMap[i][j];\n const cell = cellMap.cell;\n if (cellMap.startRow === i && cellMap.startColumn === j) {\n lastRowCell = cell;\n unmerged.push(cell);\n } else if (cell.getColSpan() > 1 || cell.getRowSpan() > 1) {\n if (!$isTableCellNode(cell)) {\n formatDevErrorMessage(`Expected TableNode cell to be a TableCellNode`);\n }\n const newCell = $createTableCellNode(cell.__headerState);\n if (lastRowCell !== null) {\n lastRowCell.insertAfter(newCell);\n } else {\n (0,_lexical_utils__WEBPACK_IMPORTED_MODULE_1__.$insertFirst)(row, newCell);\n }\n }\n }\n }\n for (const cell of unmerged) {\n cell.setColSpan(1);\n cell.setRowSpan(1);\n }\n }\n });\n}\nfunction registerTableSelectionObserver(editor, hasTabHandler = true) {\n const tableSelections = new Map();\n const initializeTableNode = (tableNode, nodeKey, dom) => {\n const tableElement = getTableElement(tableNode, dom);\n const tableSelection = applyTableHandlers(tableNode, tableElement, editor, hasTabHandler);\n tableSelections.set(nodeKey, [tableSelection, tableElement]);\n };\n const unregisterMutationListener = editor.registerMutationListener(TableNode, nodeMutations => {\n editor.getEditorState().read(() => {\n for (const [nodeKey, mutation] of nodeMutations) {\n const tableSelection = tableSelections.get(nodeKey);\n if (mutation === 'created' || mutation === 'updated') {\n const {\n tableNode,\n tableElement\n } = $getTableAndElementByKey(nodeKey);\n if (tableSelection === undefined) {\n initializeTableNode(tableNode, nodeKey, tableElement);\n } else if (tableElement !== tableSelection[1]) {\n // The update created a new DOM node, destroy the existing TableObserver\n tableSelection[0].removeListeners();\n tableSelections.delete(nodeKey);\n initializeTableNode(tableNode, nodeKey, tableElement);\n }\n } else if (mutation === 'destroyed') {\n if (tableSelection !== undefined) {\n tableSelection[0].removeListeners();\n tableSelections.delete(nodeKey);\n }\n }\n }\n }, {\n editor\n });\n }, {\n skipInitialization: false\n });\n return () => {\n unregisterMutationListener();\n // Hook might be called multiple times so cleaning up tables listeners as well,\n // as it'll be reinitialized during recurring call\n for (const [, [tableSelection]] of tableSelections) {\n tableSelection.removeListeners();\n }\n };\n}\n\n/**\n * Register table command listeners and the table integrity transforms. The\n * table selection observer should be registered separately after this with\n * {@link registerTableSelectionObserver}.\n *\n * @param editor The editor\n * @returns An unregister callback\n */\nfunction registerTablePlugin(editor, options) {\n if (!editor.hasNodes([TableNode])) {\n {\n formatDevErrorMessage(`TablePlugin: TableNode is not registered on editor`);\n }\n }\n const {\n hasNestedTables = (0,_lexical_extension__WEBPACK_IMPORTED_MODULE_3__.signal)(false),\n hasFitNestedTables = (0,_lexical_extension__WEBPACK_IMPORTED_MODULE_3__.signal)(false)\n } = options ?? {};\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.mergeRegister)(editor.registerCommand(INSERT_TABLE_COMMAND, payload => {\n return $insertTable(payload, hasNestedTables.peek());\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, (payload, dispatchEditor) => {\n if (editor !== dispatchEditor) {\n return false;\n }\n return $tableSelectionInsertClipboardNodesCommand(payload, hasNestedTables, hasFitNestedTables);\n }, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.SELECT_ALL_COMMAND, $tableSelectAllCommand, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical__WEBPACK_IMPORTED_MODULE_0__.CLICK_COMMAND, $tableClickCommand, lexical__WEBPACK_IMPORTED_MODULE_0__.COMMAND_PRIORITY_EDITOR), editor.registerNodeTransform(TableNode, $tableTransform), editor.registerNodeTransform(TableRowNode, $tableRowTransform), editor.registerNodeTransform(TableCellNode, $tableCellTransform));\n}\nfunction $tableSelectionInsertClipboardNodesCommand(selectionPayload, hasNestedTables, hasFitNestedTables) {\n const {\n nodes,\n selection\n } = selectionPayload;\n const hasTables = nodes.some(n => $isTableNode(n) || (0,_lexical_utils__WEBPACK_IMPORTED_MODULE_1__.$dfs)(n).some(d => $isTableNode(d.node)));\n if (!hasTables) {\n // Not pasting a table - no special handling required.\n return false;\n }\n const isTableSelection = $isTableSelection(selection);\n const isRangeSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection);\n const isSelectionInsideOfGrid = isRangeSelection && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(selection.anchor.getNode(), n => $isTableCellNode(n)) !== null && (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(selection.focus.getNode(), n => $isTableCellNode(n)) !== null || isTableSelection;\n if (!isSelectionInsideOfGrid) {\n // Not pasting in a grid - no special handling required.\n return false;\n }\n\n // When pasting just a table, flatten the table on the destination table, even when nested tables are allowed.\n if (nodes.length === 1 && $isTableNode(nodes[0])) {\n return $insertTableIntoGrid(nodes[0], selection);\n }\n\n // When pasting multiple nodes (including tables) into a cell, update the table to fit.\n if (isRangeSelection && hasNestedTables.peek()) {\n return $insertTableNodesIntoCells(nodes, selection, hasFitNestedTables.peek());\n }\n\n // If we reached this point, there's a table in the selection and nested tables are not allowed - reject the paste.\n return true;\n}\nfunction $insertTableIntoGrid(tableNode, selection) {\n const anchorAndFocus = selection.getStartEndPoints();\n const isTableSelection = $isTableSelection(selection);\n if (anchorAndFocus === null) {\n return false;\n }\n const [anchor, focus] = anchorAndFocus;\n const [anchorCellNode, anchorRowNode, gridNode] = $getNodeTriplet(anchor);\n const focusCellNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(focus.getNode(), n => $isTableCellNode(n));\n if (!$isTableCellNode(anchorCellNode) || !$isTableCellNode(focusCellNode) || !$isTableRowNode(anchorRowNode) || !$isTableNode(gridNode)) {\n return false;\n }\n const [initialGridMap, anchorCellMap, focusCellMap] = $computeTableMap(gridNode, anchorCellNode, focusCellNode);\n const [templateGridMap] = $computeTableMapSkipCellCheck(tableNode, null, null);\n const initialRowCount = initialGridMap.length;\n const initialColCount = initialRowCount > 0 ? initialGridMap[0].length : 0;\n\n // If we have a range selection, we'll fit the template grid into the\n // table, growing the table if necessary.\n let startRow = anchorCellMap.startRow;\n let startCol = anchorCellMap.startColumn;\n let affectedRowCount = templateGridMap.length;\n let affectedColCount = affectedRowCount > 0 ? templateGridMap[0].length : 0;\n if (isTableSelection) {\n // If we have a table selection, we'll only modify the cells within\n // the selection boundary.\n const selectionBoundary = $computeTableCellRectBoundary(initialGridMap, anchorCellMap, focusCellMap);\n const selectionRowCount = selectionBoundary.maxRow - selectionBoundary.minRow + 1;\n const selectionColCount = selectionBoundary.maxColumn - selectionBoundary.minColumn + 1;\n startRow = selectionBoundary.minRow;\n startCol = selectionBoundary.minColumn;\n affectedRowCount = Math.min(affectedRowCount, selectionRowCount);\n affectedColCount = Math.min(affectedColCount, selectionColCount);\n }\n\n // Step 1: Unmerge all merged cells within the affected area\n let didPerformMergeOperations = false;\n const lastRowForUnmerge = Math.min(initialRowCount, startRow + affectedRowCount) - 1;\n const lastColForUnmerge = Math.min(initialColCount, startCol + affectedColCount) - 1;\n const unmergedKeys = new Set();\n for (let row = startRow; row <= lastRowForUnmerge; row++) {\n for (let col = startCol; col <= lastColForUnmerge; col++) {\n const cellMap = initialGridMap[row][col];\n if (unmergedKeys.has(cellMap.cell.getKey())) {\n continue; // cell was a merged cell that was already handled\n }\n if (cellMap.cell.__rowSpan === 1 && cellMap.cell.__colSpan === 1) {\n continue; // cell is not a merged cell\n }\n $unmergeCellNode(cellMap.cell);\n unmergedKeys.add(cellMap.cell.getKey());\n didPerformMergeOperations = true;\n }\n }\n let [interimGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null);\n\n // Step 2: Expand current table (if needed)\n const rowsToInsert = affectedRowCount - initialRowCount + startRow;\n for (let i = 0; i < rowsToInsert; i++) {\n const cellMap = interimGridMap[initialRowCount - 1][0];\n $insertTableRowAtNode(cellMap.cell);\n }\n const colsToInsert = affectedColCount - initialColCount + startCol;\n for (let i = 0; i < colsToInsert; i++) {\n const cellMap = interimGridMap[0][initialColCount - 1];\n $insertTableColumnAtNode(cellMap.cell, true, false);\n }\n [interimGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null);\n\n // Step 3: Merge cells and set cell content, to match template grid\n for (let row = startRow; row < startRow + affectedRowCount; row++) {\n for (let col = startCol; col < startCol + affectedColCount; col++) {\n const templateRow = row - startRow;\n const templateCol = col - startCol;\n const templateCellMap = templateGridMap[templateRow][templateCol];\n if (templateCellMap.startRow !== templateRow || templateCellMap.startColumn !== templateCol) {\n continue; // cell is a merged cell that was already handled\n }\n const templateCell = templateCellMap.cell;\n if (templateCell.__rowSpan !== 1 || templateCell.__colSpan !== 1) {\n const cellsToMerge = [];\n const lastRowForMerge = Math.min(row + templateCell.__rowSpan, startRow + affectedRowCount) - 1;\n const lastColForMerge = Math.min(col + templateCell.__colSpan, startCol + affectedColCount) - 1;\n for (let r = row; r <= lastRowForMerge; r++) {\n for (let c = col; c <= lastColForMerge; c++) {\n const cellMap = interimGridMap[r][c];\n cellsToMerge.push(cellMap.cell);\n }\n }\n $mergeCells(cellsToMerge);\n didPerformMergeOperations = true;\n }\n const {\n cell\n } = interimGridMap[row][col];\n const backgroundColor = templateCell.getBackgroundColor();\n if (backgroundColor !== null && backgroundColor !== undefined) {\n cell.setBackgroundColor(backgroundColor);\n }\n const originalChildren = cell.getChildren();\n templateCell.getChildren().forEach(child => {\n if ((0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isTextNode)(child)) {\n const paragraphNode = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$createParagraphNode)();\n paragraphNode.append(child);\n cell.append(child);\n } else {\n cell.append(child);\n }\n });\n originalChildren.forEach(n => n.remove());\n }\n }\n if (isTableSelection && didPerformMergeOperations) {\n // reset the table selection in case the anchor or focus cell was\n // removed via merge operations\n const [finalGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null);\n const newAnchorCellMap = finalGridMap[anchorCellMap.startRow][anchorCellMap.startColumn];\n newAnchorCellMap.cell.selectEnd();\n }\n return true;\n}\n\n// Inserts the given nodes (which will include TableNodes) into the table at the given selection.\nfunction $insertTableNodesIntoCells(nodes, selection, hasFitNestedTables) {\n // Currently only support pasting into a single cell. In other cases we reject the insertion.\n const isMultiCellTableSelection = $isTableSelection(selection) && !selection.focus.getNode().is(selection.anchor.getNode());\n const isMultiCellRangeSelection = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$isRangeSelection)(selection) && $isTableCellNode(selection.anchor.getNode()) && !selection.anchor.getNode().is(selection.focus.getNode());\n if (isMultiCellTableSelection || isMultiCellRangeSelection) {\n return true;\n }\n if (!hasFitNestedTables) {\n return false;\n }\n const focusNode = selection.focus.getNode();\n const parentCell = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$findMatchingParent)(focusNode, $isTableCellNode);\n if (!parentCell) {\n return false;\n }\n const cellWidth = $getCellWidth(parentCell);\n if (cellWidth === undefined) {\n return false;\n }\n const borderBoxInsets = $calculateCellInsets(parentCell);\n const tables = nodes.filter($isTableNode);\n for (const table of tables) {\n // Note: here we assume the inset is consistent for cells at all nesting levels.\n $resizeTableToFitCell(table, cellWidth, borderBoxInsets);\n }\n return false;\n}\n\n/**\n * Return the width of a specific cell, using the table-level colWidths.\n */\nfunction $getCellWidth(cell) {\n const destinationTableNode = $getTableNodeFromLexicalNodeOrThrow(cell);\n const cellRect = $getTableCellNodeRect(cell);\n const colWidths = destinationTableNode.getColWidths();\n if (!cellRect || !colWidths) {\n return undefined;\n }\n const {\n columnIndex,\n colSpan\n } = cellRect;\n let totalWidth = 0;\n for (let i = columnIndex; i < columnIndex + colSpan; i++) {\n totalWidth += colWidths[i];\n }\n return totalWidth;\n}\n\n/**\n * Returns horizontal insets of the given cell (padding + border).\n */\nfunction $calculateCellInsets(cell) {\n const cellDOM = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.$getEditor)().getElementByKey(cell.getKey());\n if (cellDOM === null) {\n return 0;\n }\n const computedStyle = window.getComputedStyle(cellDOM);\n const paddingLeft = computedStyle.getPropertyValue('padding-left') || '0px';\n const paddingRight = computedStyle.getPropertyValue('padding-right') || '0px';\n const borderLeftWidth = computedStyle.getPropertyValue('border-left-width') || '0px';\n const borderRightWidth = computedStyle.getPropertyValue('padding-right-width') || '0px';\n if (!PIXEL_VALUE_REG_EXP.test(paddingLeft) || !PIXEL_VALUE_REG_EXP.test(paddingRight) || !PIXEL_VALUE_REG_EXP.test(borderLeftWidth) || !PIXEL_VALUE_REG_EXP.test(borderRightWidth)) {\n return 0;\n }\n const paddingLeftPx = parseFloat(paddingLeft);\n const paddingRightPx = parseFloat(paddingRight);\n const borderLeftWidthPx = parseFloat(borderLeftWidth);\n const borderRightWidthPx = parseFloat(borderRightWidth);\n return paddingLeftPx + paddingRightPx + borderLeftWidthPx + borderRightWidthPx;\n}\nfunction $getTotalTableWidth(colWidths) {\n return colWidths.reduce((curWidth, width) => curWidth + width, 0);\n}\n\n/**\n * Recursively resizes table cells to fit a given width.\n *\n * @param node the table node to resize. The table must have colWidths to be resized.\n * @param parentCellWidth the width of the parent cell\n * @param borderBoxInsets the insets of the parent cell (padding + border)\n */\nfunction $resizeTableToFitCell(node, parentCellWidth, borderBoxInsets) {\n const oldColWidths = node.getColWidths();\n if (!oldColWidths) {\n return node;\n }\n const usableWidth = parentCellWidth - borderBoxInsets;\n const tableWidth = $getTotalTableWidth(oldColWidths);\n if (tableWidth <= usableWidth) {\n return node;\n }\n const proportionalWidth = usableWidth / tableWidth;\n node.setColWidths(oldColWidths.map(width => width * proportionalWidth));\n const rowChildren = node.getChildren().filter($isTableRowNode);\n for (const rowChild of rowChildren) {\n const cellChildren = rowChild.getChildren().filter($isTableCellNode);\n for (const cellChild of cellChildren) {\n const cellWidth = $getCellWidth(cellChild);\n if (cellWidth === undefined) {\n continue;\n }\n for (const table of cellChild.getChildren().filter($isTableNode)) {\n $resizeTableToFitCell(table, cellWidth, borderBoxInsets);\n }\n }\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Configures {@link TableNode}, {@link TableRowNode}, {@link TableCellNode} and\n * registers table behaviors (see {@link TableConfig})\n */\nconst TableExtension = (0,lexical__WEBPACK_IMPORTED_MODULE_0__.defineExtension)({\n build(editor, config, state) {\n return (0,_lexical_extension__WEBPACK_IMPORTED_MODULE_3__.namedSignals)(config);\n },\n config: (0,lexical__WEBPACK_IMPORTED_MODULE_0__.safeCast)({\n hasCellBackgroundColor: true,\n hasCellMerge: true,\n hasFitNestedTables: false,\n hasHorizontalScroll: true,\n hasNestedTables: false,\n hasTabHandler: true\n }),\n name: '@lexical/table/Table',\n nodes: () => [TableNode, TableRowNode, TableCellNode],\n register(editor, config, state) {\n const stores = state.getOutput();\n return (0,lexical__WEBPACK_IMPORTED_MODULE_0__.mergeRegister)((0,_lexical_extension__WEBPACK_IMPORTED_MODULE_3__.effect)(() => {\n const hasHorizontalScroll = stores.hasHorizontalScroll.value;\n const hadHorizontalScroll = $isScrollableTablesActive(editor);\n if (hadHorizontalScroll !== hasHorizontalScroll) {\n setScrollableTablesActive(editor, hasHorizontalScroll);\n // Registering the transform has the side-effect of marking all existing\n // TableNodes as dirty. The handler is immediately unregistered.\n editor.registerNodeTransform(TableNode, () => {})();\n }\n }), registerTablePlugin(editor, stores), (0,_lexical_extension__WEBPACK_IMPORTED_MODULE_3__.effect)(() => registerTableSelectionObserver(editor, stores.hasTabHandler.value)), (0,_lexical_extension__WEBPACK_IMPORTED_MODULE_3__.effect)(() => stores.hasCellMerge.value ? undefined : registerTableCellUnmergeTransform(editor)), (0,_lexical_extension__WEBPACK_IMPORTED_MODULE_3__.effect)(() => stores.hasCellBackgroundColor.value ? undefined : editor.registerNodeTransform(TableCellNode, node => {\n if (node.getBackgroundColor() !== null) {\n node.setBackgroundColor(null);\n }\n })));\n }\n});\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHJzYykvLi9ub2RlX21vZHVsZXMvLnBucG0vQGxleGljYWwrdGFibGVAMC40MS4wL25vZGVfbW9kdWxlcy9AbGV4aWNhbC90YWJsZS9MZXhpY2FsVGFibGUuZGV2Lm1qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVpUztBQUNrakM7QUFDanhDO0FBQ21COztBQUVyRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIsZ0RBQVc7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQixhQUFhO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSSwrREFBc0I7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLHNEQUFhO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQixnQ0FBZ0M7QUFDL0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLHlEQUFnQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSx3RUFBK0IsV0FBVyxvREFBVyxXQUFXLHlEQUFnQjtBQUM1RixjQUFjLG9EQUFXO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWiw0QkFBNEIsNkRBQW9CO0FBQ2hEO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IsNkRBQW9CO0FBQ3hDO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLDhEQUFxQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSw2QkFBNkIsc0RBQWE7O0FBRTFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDJCQUEyQixnREFBVztBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQyxjQUFjO0FBQzlDO0FBQ0EsSUFBSSwrREFBc0I7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLG9FQUFvQjtBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVMsOERBQXFCO0FBQzlCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EscUJBQXFCLGlCQUFpQjtBQUN0QztBQUNBLDBCQUEwQix1QkFBdUI7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLDZEQUFvQjtBQUNoRCwyQkFBMkIsd0RBQWU7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsNERBQW1CO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsNERBQW1CO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsNERBQW1CO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsaUVBQWlFLGtDQUFrQyxJQUFJLDZCQUE2QjtBQUNwSTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLGNBQWM7QUFDbEM7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLHNCQUFzQjtBQUM1QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2QkFBNkIsNkRBQW9CO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0Isc0RBQWE7QUFDakMsUUFBUSwwREFBaUI7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSwyQkFBMkI7QUFDM0I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IsaUJBQWlCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUErRCw2REFBb0I7QUFDbkYsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IsaUJBQWlCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUErRCw2REFBb0I7QUFDbkYsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGlFQUFpRSxxQ0FBcUMsSUFBSSxnQ0FBZ0M7QUFDMUk7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isc0JBQXNCO0FBQ3hDO0FBQ0E7QUFDQSxzQkFBc0IsaUJBQWlCO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0Qiw2REFBb0I7QUFDaEQ7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0Isc0RBQWE7QUFDakMsUUFBUSwwREFBaUI7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSwyQkFBMkI7QUFDM0I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMERBQTBELDZEQUFvQjtBQUM5RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkIsY0FBYztBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsaUVBQWlFLHFDQUFxQztBQUN0RztBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isc0JBQXNCO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQixzREFBYTtBQUNqQyxRQUFRLDBEQUFpQjtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCLHVCQUF1QjtBQUNyRCx1Q0FBdUMsYUFBYTtBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxzQkFBc0I7QUFDeEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUErRCxZQUFZO0FBQzNFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0EsMkJBQTJCO0FBQzNCO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQixzREFBYTtBQUNqQyxRQUFRLDBEQUFpQjtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IsZ0JBQWdCO0FBQ3BDLG1DQUFtQyxxQkFBcUI7QUFDeEQ7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDJCQUEyQjtBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLHlCQUF5QixlQUFlO0FBQ3hDLDJCQUEyQixlQUFlO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxzQkFBc0IsNkRBQW9CO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPLHlEQUFnQjtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLHNEQUFhO0FBQ2pDLFFBQVEsMERBQWlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQiw0REFBbUI7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0EseUJBQXlCLHVDQUF1QztBQUNoRTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0EseUJBQXlCLDBDQUEwQztBQUNuRTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxvQkFBb0IsYUFBYTtBQUNqQyxnRkFBZ0YsNkRBQW9CO0FBQ3BHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IsYUFBYTtBQUNqQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQixzQkFBc0I7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQ0FBa0MsUUFBUTtBQUMxQyxnR0FBZ0csNkRBQW9CO0FBQ3BIO0FBQ0EsUUFBUTtBQUNSLGtDQUFrQyxRQUFRO0FBQzFDLCtGQUErRiw2REFBb0I7QUFDbkg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUIsOEJBQThCO0FBQ3JEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxREFBcUQsY0FBYztBQUNuRTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1Isc0JBQXNCLGFBQWE7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixhQUFhO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osa0JBQWtCLDREQUFtQjtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixrQkFBa0IsNERBQW1CO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIsa0JBQWtCO0FBQzlDO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QixlQUFlO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esc0JBQXNCLGtCQUFrQjtBQUN4Qyx3QkFBd0IscUJBQXFCO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGtCQUFrQixjQUFjO0FBQ2hDO0FBQ0E7QUFDQSx5QkFBeUIscUJBQXFCO0FBQzlDO0FBQ0E7QUFDQTtBQUNBLDRCQUE0QiwwQkFBMEI7QUFDdEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzQkFBc0IsYUFBYTtBQUNuQyx3QkFBd0IsYUFBYTtBQUNyQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsNERBQW1CO0FBQ3hDO0FBQ0EsdURBQXVELEdBQUcsK0NBQStDLGVBQWUsVUFBVSxlQUFlO0FBQ2pKO0FBQ0E7QUFDQTtBQUNBLHVEQUF1RCxHQUFHO0FBQzFEO0FBQ0E7QUFDQTtBQUNBLHVEQUF1RCxHQUFHO0FBQzFEO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsTUFBTSw2QkFBNkI7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esc0JBQXNCLHNEQUFhO0FBQ25DLHVCQUF1QixzREFBYTtBQUNwQyxzQkFBc0Isc0RBQWE7QUFDbkM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkNBQTZDLHFEQUFZLHlEQUF5RCxxREFBWTtBQUM5SDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLHlEQUFnQjtBQUMxQjtBQUNBO0FBQ0EsS0FBSztBQUNMLHVCQUF1Qix3REFBbUI7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLHVEQUFjO0FBQ3ZCO0FBQ0E7QUFDQSxzQkFBc0IsMEVBQWlDO0FBQ3ZEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QixhQUFhO0FBQ3RDLDhCQUE4QixnQkFBZ0I7QUFDOUM7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxnRUFBdUI7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0Isa0JBQWtCO0FBQ3RDO0FBQ0E7QUFDQSx5Q0FBeUM7QUFDekM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixxREFBWTtBQUM3QixnQkFBZ0IscURBQVk7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9FQUFvRSxjQUFjO0FBQ2xGO0FBQ0E7QUFDQSxxRUFBcUUsZUFBZSxrQkFBa0IsYUFBYTtBQUNuSDtBQUNBO0FBQ0Esb0VBQW9FLGNBQWMsa0JBQWtCLGFBQWE7QUFDakgsTUFBTTtBQUNOO0FBQ0Esd0JBQXdCLHNEQUFhO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0NBQXdDLGdEQUFnRDtBQUN4RjtBQUNBO0FBQ0E7QUFDQSxNQUFNLDBDQUEwQyx1REFBYztBQUM5RDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx5REFBeUQsbURBQVU7QUFDbkUsb0JBQW9CLHNEQUFhO0FBQ2pDO0FBQ0Esa0VBQWtFLGNBQWM7QUFDaEY7QUFDQTtBQUNBO0FBQ0EseUZBQXlGLGFBQWE7QUFDdEc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0Isb0JBQW9CO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxPQUFPO0FBQ1A7QUFDQSxPQUFPO0FBQ1AsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSztBQUNMO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsUUFBUSxzREFBYTtBQUNyQixNQUFNLHNEQUFhO0FBQ25CLDZCQUE2Qiw2REFBd0I7QUFDckQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOLElBQUksb0VBQTJCO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTixJQUFJLCtEQUFzQjtBQUMxQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0hBQXNILG1CQUFtQixTQUFTLGtCQUFrQjtBQUNwSztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkIsd0RBQWU7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsc0RBQWE7QUFDdkIsaUNBQWlDLDZEQUF3QjtBQUN6RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DLHNEQUFhO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyxzREFBYTtBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0Isc0RBQWE7QUFDbkM7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLDhEQUFxQjtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0Qix5REFBZ0I7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsSUFBSSxzREFBYTtBQUNqQixnQ0FBZ0MsNkRBQXdCO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOLHNCQUFzQixzREFBYTtBQUNuQztBQUNBO0FBQ0E7QUFDQSxzQkFBc0Isc0RBQWE7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLG9EQUFXO0FBQ3JCLCtCQUErQiw2REFBd0I7QUFDdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLHVEQUFjO0FBQ3hCLDhCQUE4Qiw2REFBb0I7QUFDbEQseUJBQXlCLHdEQUFlO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7QUFDTDtBQUNBLElBQUksc0RBQWE7QUFDakIsMkJBQTJCLDZEQUF3QjtBQUNuRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLHNEQUFhO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0dBQWdHLGFBQWE7QUFDN0c7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5REFBeUQsc0JBQXNCO0FBQy9FO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QywyREFBc0IsWUFBWSx5REFBb0IsVUFBVSwyREFBc0IsZ0JBQWdCLDREQUF1QjtBQUN6Syw4QkFBOEIsd0RBQW1CLEVBQUUsd0RBQW1CLEVBQUUsNkRBQXdCO0FBQ2hHLDZCQUE2QiwwREFBcUIsRUFBRSx1REFBa0I7QUFDdEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxrREFBUztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsaUNBQWlDLDZEQUF3QjtBQUN6RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0JBQStCLGtEQUFTO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEIsOERBQXFCO0FBQ25EO0FBQ0E7QUFDQTtBQUNBLDhGQUE4RiwwREFBaUI7QUFDL0c7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSw2QkFBNkIsa0RBQVM7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQSwrQkFBK0Isa0RBQVM7QUFDeEM7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLHNEQUFhO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLHNKQUFzSiwwREFBcUI7QUFDM0s7QUFDQSw2REFBNkQsdURBQWtCO0FBQy9FLHNCQUFzQixzREFBYTtBQUNuQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHLEVBQUUsMERBQXFCO0FBQzFCO0FBQ0Esc0JBQXNCLHNEQUFhO0FBQ25DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU0sU0FBUywwREFBaUI7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsNERBQW1CLGtDQUFrQyx1REFBYztBQUNwRyw0REFBNEQsNERBQW1CLDBCQUEwQix1REFBYztBQUN2SCxXQUFXLHVEQUFjLDhCQUE4Qix1REFBYztBQUNyRTtBQUNBO0FBQ0Esc0JBQXNCLHdEQUFtQjtBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9HQUFvRywwREFBcUI7QUFDekg7QUFDQTtBQUNBLHNCQUFzQixzREFBYTtBQUNuQywwQ0FBMEMsMERBQWlCO0FBQzNEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEZBQTRGLDBEQUFxQjtBQUNqSDtBQUNBLDZEQUE2RCxnREFBVztBQUN4RSxzQkFBc0Isc0RBQWE7QUFDbkM7QUFDQSw0Q0FBNEMsMERBQWlCO0FBQzdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxtRUFBZSxTQUFTLGlFQUFpQix3Q0FBd0Msa0ZBQThCO0FBQzFIO0FBQ0EsVUFBVSwwREFBaUI7QUFDM0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRyxFQUFFLDBEQUFxQjtBQUMxQiw2REFBNkQsd0RBQW1CO0FBQ2hGLHNCQUFzQixzREFBYTtBQUNuQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLFNBQVMsMERBQWlCO0FBQ2hDLDRCQUE0Qiw0REFBbUI7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUcsRUFBRSwwREFBcUI7QUFDMUIsNkRBQTZELDJEQUFzQjtBQUNuRixzQkFBc0Isc0RBQWE7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLGFBQWE7QUFDdEMsOEJBQThCLGdCQUFnQjtBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3Qix5QkFBeUI7QUFDakQ7QUFDQSxjQUFjLHVEQUFjO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUcsRUFBRSwwREFBcUI7QUFDMUIsNkRBQTZELHNFQUFpQztBQUM5RixzQkFBc0Isc0RBQWE7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTSxTQUFTLDBEQUFpQjtBQUNoQyw0QkFBNEIsNERBQW1CO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdFQUFnRSx3REFBZTtBQUMvRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRyxFQUFFLDBEQUFxQjtBQUMxQjtBQUNBLCtEQUErRCxvREFBZTtBQUM5RSx3QkFBd0Isc0RBQWE7QUFDckMsV0FBVywwREFBaUI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSyxFQUFFLDBEQUFxQjtBQUM1QjtBQUNBLDZEQUE2RCxrREFBYTtBQUMxRTtBQUNBLEdBQUcsRUFBRSwwREFBcUI7QUFDMUIsNkRBQTZELDZEQUF3QjtBQUNyRixzQkFBc0Isc0RBQWE7QUFDbkMsMEJBQTBCLDhEQUFxQjtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQywwREFBaUIsbUJBQW1CLDBEQUFpQjtBQUNyRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0RBQXdELDREQUFtQjtBQUMzRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLDBEQUFpQjtBQUN6QjtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUSxzREFBYTtBQUNyQjtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZHQUE2RywwREFBaUI7QUFDOUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLDJCQUEyQix3REFBZTtBQUMxQztBQUNBLDBCQUEwQixtRUFBMEI7QUFDcEQ7QUFDQSwyQkFBMkIsbUVBQTBCO0FBQ3JEO0FBQ0E7QUFDQSwrQkFBK0IscUVBQTRCO0FBQzNEO0FBQ0E7QUFDQTtBQUNBLFlBQVksc0RBQWE7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBLEdBQUcsRUFBRSwwREFBcUI7QUFDMUIsNkRBQTZELDZEQUF3QjtBQUNyRixzQkFBc0Isc0RBQWE7QUFDbkMsU0FBUywwREFBaUI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUcsRUFBRSwwREFBcUI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0IscUJBQXFCO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixrQkFBa0Isb0JBQW9CO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLGdCQUFnQjtBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixtRUFBMEI7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLHVEQUFjO0FBQ3BCO0FBQ0E7QUFDQSxvQkFBb0IsNERBQW1CO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBLGlEQUFpRCwwQkFBMEI7QUFDM0U7QUFDQSxRQUFRLHVEQUFjO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQiw0REFBbUI7QUFDekM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9EQUFvRCx5QkFBeUI7QUFDN0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrREFBa0QsU0FBUyxJQUFJLGdCQUFnQjtBQUMvRTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtEQUFrRCxTQUFTLElBQUksZ0JBQWdCO0FBQy9FO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLElBQUk7QUFDSjtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLDBEQUFpQjtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsbUVBQTBCO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBLEVBQUUsK0RBQXNCO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBLGVBQWUsbUVBQTBCO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRSxvRUFBMkI7QUFDN0I7QUFDQTtBQUNBLG1CQUFtQiw0REFBbUI7QUFDdEM7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLDREQUFtQjtBQUN2QztBQUNBO0FBQ0E7QUFDQSxnREFBZ0Qsc0JBQXNCO0FBQ3RFLFFBQVEsdURBQWM7QUFDdEI7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLHdEQUFlO0FBQ3RDLE1BQU0sb0VBQTJCO0FBQ2pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEIsNERBQW1CO0FBQzdDLFVBQVUsd0RBQWUsZUFBZSx1REFBYztBQUN0RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0MseURBQWdCO0FBQ3hELDBCQUEwQiw0REFBbUI7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsaURBQWlELHlEQUFnQjtBQUNqRSxNQUFNLDJEQUFrQjtBQUN4QixNQUFNLDJEQUFrQjtBQUN4QjtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSw0QkFBNEIsd0RBQWU7QUFDM0MsSUFBSSwyREFBa0I7QUFDdEIsSUFBSSwyREFBa0I7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQiwrREFBc0I7QUFDekMsU0FBUyxzREFBYSxhQUFhLHdEQUFlO0FBQ2xEO0FBQ0E7QUFDQSwwQkFBMEIsNERBQW1CO0FBQzdDO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsVUFBVSxzREFBYTtBQUN2QixlQUFlLHVEQUFjO0FBQzdCO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQixzREFBYTtBQUNqQztBQUNBLFFBQVEsMERBQWlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLDREQUFtQjtBQUNuRDtBQUNBLDhCQUE4Qiw0REFBbUI7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsdURBQWM7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQix1REFBYztBQUM5QjtBQUNBO0FBQ0EsMEJBQTBCLG9EQUFXO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBLG1FQUFtRSxvREFBVztBQUM5RSxVQUFVLHNEQUFhO0FBQ3ZCO0FBQ0E7QUFDQSxVQUFVLFNBQVMsNERBQW1CO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVixnQ0FBZ0MsNERBQW1CLGlCQUFpQix1REFBYztBQUNsRjtBQUNBLDhCQUE4Qiw0REFBbUI7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLHNEQUFhO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLDBEQUFpQjtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSLDZCQUE2Qiw0REFBbUI7QUFDaEQsNEJBQTRCLDREQUFtQjtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUiw2QkFBNkIsd0RBQWU7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTiwyQkFBMkIsNERBQW1CO0FBQzlDLDBCQUEwQiw0REFBbUI7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsNkRBQW9CO0FBQzVDO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx1QkFBdUIsd0RBQWU7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5Qiw0REFBbUI7QUFDNUM7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLDREQUFtQjtBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0RBQW9ELG1FQUEwQjtBQUM5RTs7QUFFQTtBQUNBLFNBQVMsc0RBQWU7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0IsY0FBYztBQUNoQztBQUNBO0FBQ0E7QUFDQSwyQkFBMkIsTUFBTTtBQUNqQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUksK0RBQXNCO0FBQzFCO0FBQ0EsSUFBSTtBQUNKLElBQUksb0VBQTJCO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJLCtEQUFzQjtBQUMxQjtBQUNBLElBQUk7QUFDSixJQUFJLG9FQUEyQjtBQUMvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSSwrREFBc0I7QUFDMUI7QUFDQSxJQUFJO0FBQ0osSUFBSSxvRUFBMkI7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFLG9FQUEyQjtBQUM3QixFQUFFLCtEQUFzQjtBQUN4QjtBQUNBO0FBQ0EsNENBQTRDLG1EQUFVO0FBQ3REO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0Esd0JBQXdCLGdEQUFXO0FBQ25DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSSx3REFBZTtBQUNuQixJQUFJLCtEQUFzQjtBQUMxQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUSwrREFBc0I7QUFDOUIsUUFBUTtBQUNSLHlEQUF5RDtBQUN6RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBaUQsc0RBQWU7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZTtBQUNmO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEIsc0JBQXNCO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsK0NBQStDLHNEQUFlO0FBQzlEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTixvQkFBb0IsVUFBVTtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQixnQkFBZ0I7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixtRUFBMEI7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QixvRUFBb0I7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLDhEQUFxQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRCxvQkFBb0Isc0RBQWEsTUFBTSw4REFBcUI7QUFDNUQscUJBQXFCLDBEQUFpQjtBQUN0QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFLHdFQUF3QjtBQUMxQjtBQUNBLE1BQU0sb0RBQVc7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLGdCQUFnQiw2REFBb0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osSUFBSSwyRUFBMkI7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUUsMkVBQTJCO0FBQzdCO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLGtCQUFrQixvQkFBb0I7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBHQUEwRywwQkFBMEIsUUFBUSxrQkFBa0I7QUFDOUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0QixrQkFBa0I7QUFDOUM7QUFDQTtBQUNBLHFCQUFxQiw2REFBb0I7QUFDekM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkIsa0RBQVM7QUFDcEM7QUFDQTtBQUNBLG9CQUFvQixtRUFBMEI7QUFDOUM7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLDREQUFtQixvQkFBb0IsdURBQWM7QUFDekU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQixzREFBYTtBQUNqQyxPQUFPLDBEQUFpQjtBQUN4QjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLGlEQUFRO0FBQ3ZCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUUsc0RBQWE7QUFDZjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQkFBbUI7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsZUFBZTtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixrQkFBa0I7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2QsY0FBYyw0REFBYztBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLEtBQUs7QUFDTCxHQUFHO0FBQ0g7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUkscUNBQXFDO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsMERBQU07QUFDNUIseUJBQXlCLDBEQUFNO0FBQy9CLElBQUk7QUFDSixTQUFTLHNEQUFhO0FBQ3RCO0FBQ0EsR0FBRyxFQUFFLDREQUF1QiwwQkFBMEIsNkVBQXdDO0FBQzlGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRyxFQUFFLDREQUF1QiwwQkFBMEIsdURBQWtCLDBCQUEwQix5REFBb0IsMEJBQTBCLGtEQUFhLHNCQUFzQiw0REFBdUI7QUFDMU07QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSix1REFBdUQsb0RBQUk7QUFDM0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQiwwREFBaUI7QUFDNUMsc0RBQXNELDREQUFtQixtRUFBbUUsNERBQW1CO0FBQy9KO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsNERBQW1CO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQiwwQkFBMEI7QUFDckQsNkJBQTZCLDBCQUEwQjtBQUN2RDtBQUNBO0FBQ0Esa0JBQWtCO0FBQ2xCO0FBQ0E7QUFDQSxrQkFBa0I7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGtCQUFrQixrQkFBa0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isa0JBQWtCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsMkJBQTJCLG1DQUFtQztBQUM5RCw2QkFBNkIsbUNBQW1DO0FBQ2hFO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCO0FBQ2xCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixzQkFBc0I7QUFDaEQsNEJBQTRCLHNCQUFzQjtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxvREFBVztBQUN2QixnQ0FBZ0MsNkRBQW9CO0FBQ3BEO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQ0FBb0MsMERBQWlCO0FBQ3JEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLDREQUFtQjtBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSw0QkFBNEIsMkJBQTJCO0FBQ3ZEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLG1EQUFVO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsZUFBZSxnQkFBZ0IsR0FBRyxtQkFBbUIsR0FBRyxxQkFBcUI7QUFDN0UsbUNBQW1DLGtCQUFrQjtBQUNyRDtBQUNBLHVCQUF1Qix3REFBZTtBQUN0QztBQUNBLFdBQVcsZ0VBQVk7QUFDdkIsR0FBRztBQUNILFVBQVUsaURBQVE7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxzREFBYSxDQUFDLDBEQUFNO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdEQUF3RDtBQUN4RDtBQUNBLEtBQUssd0NBQXdDLDBEQUFNLDRFQUE0RSwwREFBTSwyRkFBMkYsMERBQU07QUFDdE87QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsQ0FBQzs7QUFFd3lDIiwic291cmNlcyI6WyIvVXNlcnMvbWFyY21pbnRlbC9Qcm9qZWN0cy9lLXRpYi5jb20vbm9kZV9tb2R1bGVzLy5wbnBtL0BsZXhpY2FsK3RhYmxlQDAuNDEuMC9ub2RlX21vZHVsZXMvQGxleGljYWwvdGFibGUvTGV4aWNhbFRhYmxlLmRldi5tanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIE1ldGEgUGxhdGZvcm1zLCBJbmMuIGFuZCBhZmZpbGlhdGVzLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqL1xuXG5pbXBvcnQgeyBhZGRDbGFzc05hbWVzVG9FbGVtZW50LCAkZGVzY2VuZGFudHNNYXRjaGluZywgJGZpbmRNYXRjaGluZ1BhcmVudCwgcmVtb3ZlQ2xhc3NOYW1lc0Zyb21FbGVtZW50LCBvYmplY3RLbGFzc0VxdWFscywgaXNIVE1MRWxlbWVudCBhcyBpc0hUTUxFbGVtZW50JDEsICRpbnNlcnRGaXJzdCBhcyAkaW5zZXJ0Rmlyc3QkMSwgbWVyZ2VSZWdpc3RlciwgJGluc2VydE5vZGVUb05lYXJlc3RSb290LCAkZGZzLCAkdW53cmFwQW5kRmlsdGVyRGVzY2VuZGFudHMgfSBmcm9tICdAbGV4aWNhbC91dGlscyc7XG5pbXBvcnQgeyBFbGVtZW50Tm9kZSwgaXNIVE1MRWxlbWVudCwgJGlzSW5saW5lRWxlbWVudE9yRGVjb3JhdG9yTm9kZSwgJGlzVGV4dE5vZGUsICRpc0xpbmVCcmVha05vZGUsICRjcmVhdGVQYXJhZ3JhcGhOb2RlLCAkYXBwbHlOb2RlUmVwbGFjZW1lbnQsIGNyZWF0ZUNvbW1hbmQsICRjcmVhdGVUZXh0Tm9kZSwgJGdldFNlbGVjdGlvbiwgJGlzUmFuZ2VTZWxlY3Rpb24sICRpc1BhcmFncmFwaE5vZGUsICRjcmVhdGVQb2ludCwgJGdldE5vZGVCeUtleSwgJGlzRWxlbWVudE5vZGUsICRub3JtYWxpemVTZWxlY3Rpb25fX0VYUEVSSU1FTlRBTCwgaXNDdXJyZW50bHlSZWFkT25seU1vZGUsIFRFWFRfVFlQRV9UT19GT1JNQVQsICRnZXRFZGl0b3IsICRzZXRTZWxlY3Rpb24sIFNFTEVDVElPTl9DSEFOR0VfQ09NTUFORCwgZ2V0RE9NU2VsZWN0aW9uLCAkY3JlYXRlUmFuZ2VTZWxlY3Rpb24sICRpc1Jvb3ROb2RlLCBJTlNFUlRfUEFSQUdSQVBIX0NPTU1BTkQsIEtFWV9BUlJPV19ET1dOX0NPTU1BTkQsIEtFWV9BUlJPV19VUF9DT01NQU5ELCBLRVlfQVJST1dfTEVGVF9DT01NQU5ELCBLRVlfQVJST1dfUklHSFRfQ09NTUFORCwgQ09NTUFORF9QUklPUklUWV9ISUdILCBLRVlfRVNDQVBFX0NPTU1BTkQsIERFTEVURV9XT1JEX0NPTU1BTkQsIERFTEVURV9MSU5FX0NPTU1BTkQsIERFTEVURV9DSEFSQUNURVJfQ09NTUFORCwgS0VZX0JBQ0tTUEFDRV9DT01NQU5ELCBLRVlfREVMRVRFX0NPTU1BTkQsIENVVF9DT01NQU5ELCBGT1JNQVRfVEVYVF9DT01NQU5ELCBGT1JNQVRfRUxFTUVOVF9DT01NQU5ELCBDT05UUk9MTEVEX1RFWFRfSU5TRVJUSU9OX0NPTU1BTkQsIEtFWV9UQUJfQ09NTUFORCwgRk9DVVNfQ09NTUFORCwgJGdldFByZXZpb3VzU2VsZWN0aW9uLCAkZ2V0TmVhcmVzdE5vZGVGcm9tRE9NTm9kZSwgJGNyZWF0ZVJhbmdlU2VsZWN0aW9uRnJvbURvbSwgaXNET01Ob2RlLCAkaXNSb290T3JTaGFkb3dSb290LCAkY2FyZXRGcm9tUG9pbnQsICRpc0V4dGVuZGFibGVUZXh0UG9pbnRDYXJldCwgJGV4dGVuZENhcmV0VG9SYW5nZSwgJGlzU2libGluZ0NhcmV0LCAkZ2V0U2libGluZ0NhcmV0LCAkc2V0UG9pbnRGcm9tQ2FyZXQsICRub3JtYWxpemVDYXJldCwgJGlzQ2hpbGRDYXJldCwgJGdldENoaWxkQ2FyZXQsICRnZXRBZGphY2VudENoaWxkQ2FyZXQsIHNldERPTVVubWFuYWdlZCwgQ09NTUFORF9QUklPUklUWV9FRElUT1IsIFNFTEVDVElPTl9JTlNFUlRfQ0xJUEJPQVJEX05PREVTX0NPTU1BTkQsIFNFTEVDVF9BTExfQ09NTUFORCwgQ09NTUFORF9QUklPUklUWV9MT1csIENMSUNLX0NPTU1BTkQsICRnZXRSb290LCBkZWZpbmVFeHRlbnNpb24sIHNhZmVDYXN0IH0gZnJvbSAnbGV4aWNhbCc7XG5pbXBvcnQgeyBzaWduYWwsIGVmZmVjdCwgbmFtZWRTaWduYWxzIH0gZnJvbSAnQGxleGljYWwvZXh0ZW5zaW9uJztcbmltcG9ydCB7IGNvcHlUb0NsaXBib2FyZCwgJGdldENsaXBib2FyZERhdGFGcm9tU2VsZWN0aW9uIH0gZnJvbSAnQGxleGljYWwvY2xpcGJvYXJkJztcblxuLyoqXG4gKiBDb3B5cmlnaHQgKGMpIE1ldGEgUGxhdGZvcm1zLCBJbmMuIGFuZCBhZmZpbGlhdGVzLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqL1xuXG5jb25zdCBQSVhFTF9WQUxVRV9SRUdfRVhQID0gL14oXFxkKyg/OlxcLlxcZCspPylweCQvO1xuXG4vLyAuUGxheWdyb3VuZEVkaXRvclRoZW1lX190YWJsZUNlbGwgd2lkdGggdmFsdWUgZnJvbVxuLy8gcGFja2FnZXMvbGV4aWNhbC1wbGF5Z3JvdW5kL3NyYy90aGVtZXMvUGxheWdyb3VuZEVkaXRvclRoZW1lLmNzc1xuY29uc3QgQ09MVU1OX1dJRFRIID0gNzU7XG5cbi8qKlxuICogQ29weXJpZ2h0IChjKSBNZXRhIFBsYXRmb3JtcywgSW5jLiBhbmQgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKi9cblxuY29uc3QgVGFibGVDZWxsSGVhZGVyU3RhdGVzID0ge1xuICBCT1RIOiAzLFxuICBDT0xVTU46IDIsXG4gIE5PX1NUQVRVUzogMCxcbiAgUk9XOiAxXG59O1xuLyoqIEBub0luaGVyaXREb2MgKi9cbmNsYXNzIFRhYmxlQ2VsbE5vZGUgZXh0ZW5kcyBFbGVtZW50Tm9kZSB7XG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgX19jb2xTcGFuO1xuICAvKiogQGludGVybmFsICovXG4gIF9fcm93U3BhbjtcbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBfX2hlYWRlclN0YXRlO1xuICAvKiogQGludGVybmFsICovXG4gIF9fd2lkdGg7XG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgX19iYWNrZ3JvdW5kQ29sb3I7XG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgX192ZXJ0aWNhbEFsaWduO1xuICBzdGF0aWMgZ2V0VHlwZSgpIHtcbiAgICByZXR1cm4gJ3RhYmxlY2VsbCc7XG4gIH1cbiAgc3RhdGljIGNsb25lKG5vZGUpIHtcbiAgICByZXR1cm4gbmV3IFRhYmxlQ2VsbE5vZGUobm9kZS5fX2hlYWRlclN0YXRlLCBub2RlLl9fY29sU3Bhbiwgbm9kZS5fX3dpZHRoLCBub2RlLl9fa2V5KTtcbiAgfVxuICBhZnRlckNsb25lRnJvbShub2RlKSB7XG4gICAgc3VwZXIuYWZ0ZXJDbG9uZUZyb20obm9kZSk7XG4gICAgdGhpcy5fX3Jvd1NwYW4gPSBub2RlLl9fcm93U3BhbjtcbiAgICB0aGlzLl9fYmFja2dyb3VuZENvbG9yID0gbm9kZS5fX2JhY2tncm91bmRDb2xvcjtcbiAgICB0aGlzLl9fdmVydGljYWxBbGlnbiA9IG5vZGUuX192ZXJ0aWNhbEFsaWduO1xuICB9XG4gIHN0YXRpYyBpbXBvcnRET00oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRkOiBub2RlID0+ICh7XG4gICAgICAgIGNvbnZlcnNpb246ICRjb252ZXJ0VGFibGVDZWxsTm9kZUVsZW1lbnQsXG4gICAgICAgIHByaW9yaXR5OiAwXG4gICAgICB9KSxcbiAgICAgIHRoOiBub2RlID0+ICh7XG4gICAgICAgIGNvbnZlcnNpb246ICRjb252ZXJ0VGFibGVDZWxsTm9kZUVsZW1lbnQsXG4gICAgICAgIHByaW9yaXR5OiAwXG4gICAgICB9KVxuICAgIH07XG4gIH1cbiAgc3RhdGljIGltcG9ydEpTT04oc2VyaWFsaXplZE5vZGUpIHtcbiAgICByZXR1cm4gJGNyZWF0ZVRhYmxlQ2VsbE5vZGUoKS51cGRhdGVGcm9tSlNPTihzZXJpYWxpemVkTm9kZSk7XG4gIH1cbiAgdXBkYXRlRnJvbUpTT04oc2VyaWFsaXplZE5vZGUpIHtcbiAgICByZXR1cm4gc3VwZXIudXBkYXRlRnJvbUpTT04oc2VyaWFsaXplZE5vZGUpLnNldEhlYWRlclN0eWxlcyhzZXJpYWxpemVkTm9kZS5oZWFkZXJTdGF0ZSkuc2V0Q29sU3BhbihzZXJpYWxpemVkTm9kZS5jb2xTcGFuIHx8IDEpLnNldFJvd1NwYW4oc2VyaWFsaXplZE5vZGUucm93U3BhbiB8fCAxKS5zZXRXaWR0aChzZXJpYWxpemVkTm9kZS53aWR0aCB8fCB1bmRlZmluZWQpLnNldEJhY2tncm91bmRDb2xvcihzZXJpYWxpemVkTm9kZS5iYWNrZ3JvdW5kQ29sb3IgfHwgbnVsbCkuc2V0VmVydGljYWxBbGlnbihzZXJpYWxpemVkTm9kZS52ZXJ0aWNhbEFsaWduIHx8IHVuZGVmaW5lZCk7XG4gIH1cbiAgY29uc3RydWN0b3IoaGVhZGVyU3RhdGUgPSBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuTk9fU1RBVFVTLCBjb2xTcGFuID0gMSwgd2lkdGgsIGtleSkge1xuICAgIHN1cGVyKGtleSk7XG4gICAgdGhpcy5fX2NvbFNwYW4gPSBjb2xTcGFuO1xuICAgIHRoaXMuX19yb3dTcGFuID0gMTtcbiAgICB0aGlzLl9faGVhZGVyU3RhdGUgPSBoZWFkZXJTdGF0ZTtcbiAgICB0aGlzLl9fd2lkdGggPSB3aWR0aDtcbiAgICB0aGlzLl9fYmFja2dyb3VuZENvbG9yID0gbnVsbDtcbiAgICB0aGlzLl9fdmVydGljYWxBbGlnbiA9IHVuZGVmaW5lZDtcbiAgfVxuICBjcmVhdGVET00oY29uZmlnKSB7XG4gICAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGhpcy5nZXRUYWcoKSk7XG4gICAgaWYgKHRoaXMuX193aWR0aCkge1xuICAgICAgZWxlbWVudC5zdHlsZS53aWR0aCA9IGAke3RoaXMuX193aWR0aH1weGA7XG4gICAgfVxuICAgIGlmICh0aGlzLl9fY29sU3BhbiA+IDEpIHtcbiAgICAgIGVsZW1lbnQuY29sU3BhbiA9IHRoaXMuX19jb2xTcGFuO1xuICAgIH1cbiAgICBpZiAodGhpcy5fX3Jvd1NwYW4gPiAxKSB7XG4gICAgICBlbGVtZW50LnJvd1NwYW4gPSB0aGlzLl9fcm93U3BhbjtcbiAgICB9XG4gICAgaWYgKHRoaXMuX19iYWNrZ3JvdW5kQ29sb3IgIT09IG51bGwpIHtcbiAgICAgIGVsZW1lbnQuc3R5bGUuYmFja2dyb3VuZENvbG9yID0gdGhpcy5fX2JhY2tncm91bmRDb2xvcjtcbiAgICB9XG4gICAgaWYgKGlzVmFsaWRWZXJ0aWNhbEFsaWduKHRoaXMuX192ZXJ0aWNhbEFsaWduKSkge1xuICAgICAgZWxlbWVudC5zdHlsZS52ZXJ0aWNhbEFsaWduID0gdGhpcy5fX3ZlcnRpY2FsQWxpZ247XG4gICAgfVxuICAgIGFkZENsYXNzTmFtZXNUb0VsZW1lbnQoZWxlbWVudCwgY29uZmlnLnRoZW1lLnRhYmxlQ2VsbCwgdGhpcy5oYXNIZWFkZXIoKSAmJiBjb25maWcudGhlbWUudGFibGVDZWxsSGVhZGVyKTtcbiAgICByZXR1cm4gZWxlbWVudDtcbiAgfVxuICBleHBvcnRET00oZWRpdG9yKSB7XG4gICAgY29uc3Qgb3V0cHV0ID0gc3VwZXIuZXhwb3J0RE9NKGVkaXRvcik7XG4gICAgaWYgKGlzSFRNTEVsZW1lbnQob3V0cHV0LmVsZW1lbnQpKSB7XG4gICAgICBjb25zdCBlbGVtZW50ID0gb3V0cHV0LmVsZW1lbnQ7XG4gICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZSgnZGF0YS10ZW1wb3JhcnktdGFibGUtY2VsbC1sZXhpY2FsLWtleScsIHRoaXMuZ2V0S2V5KCkpO1xuICAgICAgZWxlbWVudC5zdHlsZS5ib3JkZXIgPSAnMXB4IHNvbGlkIGJsYWNrJztcbiAgICAgIGlmICh0aGlzLl9fY29sU3BhbiA+IDEpIHtcbiAgICAgICAgZWxlbWVudC5jb2xTcGFuID0gdGhpcy5fX2NvbFNwYW47XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5fX3Jvd1NwYW4gPiAxKSB7XG4gICAgICAgIGVsZW1lbnQucm93U3BhbiA9IHRoaXMuX19yb3dTcGFuO1xuICAgICAgfVxuICAgICAgZWxlbWVudC5zdHlsZS53aWR0aCA9IGAke3RoaXMuZ2V0V2lkdGgoKSB8fCBDT0xVTU5fV0lEVEh9cHhgO1xuICAgICAgZWxlbWVudC5zdHlsZS52ZXJ0aWNhbEFsaWduID0gdGhpcy5nZXRWZXJ0aWNhbEFsaWduKCkgfHwgJ3RvcCc7XG4gICAgICBlbGVtZW50LnN0eWxlLnRleHRBbGlnbiA9ICdzdGFydCc7XG4gICAgICBpZiAodGhpcy5fX2JhY2tncm91bmRDb2xvciA9PT0gbnVsbCAmJiB0aGlzLmhhc0hlYWRlcigpKSB7XG4gICAgICAgIGVsZW1lbnQuc3R5bGUuYmFja2dyb3VuZENvbG9yID0gJyNmMmYzZjUnO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xuICB9XG4gIGV4cG9ydEpTT04oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnN1cGVyLmV4cG9ydEpTT04oKSxcbiAgICAgIC4uLihpc1ZhbGlkVmVydGljYWxBbGlnbih0aGlzLl9fdmVydGljYWxBbGlnbikgJiYge1xuICAgICAgICB2ZXJ0aWNhbEFsaWduOiB0aGlzLl9fdmVydGljYWxBbGlnblxuICAgICAgfSksXG4gICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuZ2V0QmFja2dyb3VuZENvbG9yKCksXG4gICAgICBjb2xTcGFuOiB0aGlzLl9fY29sU3BhbixcbiAgICAgIGhlYWRlclN0YXRlOiB0aGlzLl9faGVhZGVyU3RhdGUsXG4gICAgICByb3dTcGFuOiB0aGlzLl9fcm93U3BhbixcbiAgICAgIHdpZHRoOiB0aGlzLmdldFdpZHRoKClcbiAgICB9O1xuICB9XG4gIGdldENvbFNwYW4oKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TGF0ZXN0KCkuX19jb2xTcGFuO1xuICB9XG4gIHNldENvbFNwYW4oY29sU3Bhbikge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzLmdldFdyaXRhYmxlKCk7XG4gICAgc2VsZi5fX2NvbFNwYW4gPSBjb2xTcGFuO1xuICAgIHJldHVybiBzZWxmO1xuICB9XG4gIGdldFJvd1NwYW4oKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TGF0ZXN0KCkuX19yb3dTcGFuO1xuICB9XG4gIHNldFJvd1NwYW4ocm93U3Bhbikge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzLmdldFdyaXRhYmxlKCk7XG4gICAgc2VsZi5fX3Jvd1NwYW4gPSByb3dTcGFuO1xuICAgIHJldHVybiBzZWxmO1xuICB9XG4gIGdldFRhZygpIHtcbiAgICByZXR1cm4gdGhpcy5oYXNIZWFkZXIoKSA/ICd0aCcgOiAndGQnO1xuICB9XG4gIHNldEhlYWRlclN0eWxlcyhoZWFkZXJTdGF0ZSwgbWFzayA9IFRhYmxlQ2VsbEhlYWRlclN0YXRlcy5CT1RIKSB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXMuZ2V0V3JpdGFibGUoKTtcbiAgICBzZWxmLl9faGVhZGVyU3RhdGUgPSBoZWFkZXJTdGF0ZSAmIG1hc2sgfCBzZWxmLl9faGVhZGVyU3RhdGUgJiB+bWFzaztcbiAgICByZXR1cm4gc2VsZjtcbiAgfVxuICBnZXRIZWFkZXJTdHlsZXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TGF0ZXN0KCkuX19oZWFkZXJTdGF0ZTtcbiAgfVxuICBzZXRXaWR0aCh3aWR0aCkge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzLmdldFdyaXRhYmxlKCk7XG4gICAgc2VsZi5fX3dpZHRoID0gd2lkdGg7XG4gICAgcmV0dXJuIHNlbGY7XG4gIH1cbiAgZ2V0V2lkdGgoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TGF0ZXN0KCkuX193aWR0aDtcbiAgfVxuICBnZXRCYWNrZ3JvdW5kQ29sb3IoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TGF0ZXN0KCkuX19iYWNrZ3JvdW5kQ29sb3I7XG4gIH1cbiAgc2V0QmFja2dyb3VuZENvbG9yKG5ld0JhY2tncm91bmRDb2xvcikge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzLmdldFdyaXRhYmxlKCk7XG4gICAgc2VsZi5fX2JhY2tncm91bmRDb2xvciA9IG5ld0JhY2tncm91bmRDb2xvcjtcbiAgICByZXR1cm4gc2VsZjtcbiAgfVxuICBnZXRWZXJ0aWNhbEFsaWduKCkge1xuICAgIHJldHVybiB0aGlzLmdldExhdGVzdCgpLl9fdmVydGljYWxBbGlnbjtcbiAgfVxuICBzZXRWZXJ0aWNhbEFsaWduKG5ld1ZlcnRpY2FsQWxpZ24pIHtcbiAgICBjb25zdCBzZWxmID0gdGhpcy5nZXRXcml0YWJsZSgpO1xuICAgIHNlbGYuX192ZXJ0aWNhbEFsaWduID0gbmV3VmVydGljYWxBbGlnbiB8fCB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHNlbGY7XG4gIH1cbiAgdG9nZ2xlSGVhZGVyU3R5bGUoaGVhZGVyU3RhdGVUb1RvZ2dsZSkge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzLmdldFdyaXRhYmxlKCk7XG4gICAgaWYgKChzZWxmLl9faGVhZGVyU3RhdGUgJiBoZWFkZXJTdGF0ZVRvVG9nZ2xlKSA9PT0gaGVhZGVyU3RhdGVUb1RvZ2dsZSkge1xuICAgICAgc2VsZi5fX2hlYWRlclN0YXRlIC09IGhlYWRlclN0YXRlVG9Ub2dnbGU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNlbGYuX19oZWFkZXJTdGF0ZSArPSBoZWFkZXJTdGF0ZVRvVG9nZ2xlO1xuICAgIH1cbiAgICByZXR1cm4gc2VsZjtcbiAgfVxuICBoYXNIZWFkZXJTdGF0ZShoZWFkZXJTdGF0ZSkge1xuICAgIHJldHVybiAodGhpcy5nZXRIZWFkZXJTdHlsZXMoKSAmIGhlYWRlclN0YXRlKSA9PT0gaGVhZGVyU3RhdGU7XG4gIH1cbiAgaGFzSGVhZGVyKCkge1xuICAgIHJldHVybiB0aGlzLmdldExhdGVzdCgpLl9faGVhZGVyU3RhdGUgIT09IFRhYmxlQ2VsbEhlYWRlclN0YXRlcy5OT19TVEFUVVM7XG4gIH1cbiAgdXBkYXRlRE9NKHByZXZOb2RlKSB7XG4gICAgcmV0dXJuIHByZXZOb2RlLl9faGVhZGVyU3RhdGUgIT09IHRoaXMuX19oZWFkZXJTdGF0ZSB8fCBwcmV2Tm9kZS5fX3dpZHRoICE9PSB0aGlzLl9fd2lkdGggfHwgcHJldk5vZGUuX19jb2xTcGFuICE9PSB0aGlzLl9fY29sU3BhbiB8fCBwcmV2Tm9kZS5fX3Jvd1NwYW4gIT09IHRoaXMuX19yb3dTcGFuIHx8IHByZXZOb2RlLl9fYmFja2dyb3VuZENvbG9yICE9PSB0aGlzLl9fYmFja2dyb3VuZENvbG9yIHx8IHByZXZOb2RlLl9fdmVydGljYWxBbGlnbiAhPT0gdGhpcy5fX3ZlcnRpY2FsQWxpZ247XG4gIH1cbiAgaXNTaGFkb3dSb290KCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIGNvbGxhcHNlQXRTdGFydCgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICBjYW5CZUVtcHR5KCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjYW5JbmRlbnQoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5mdW5jdGlvbiBpc1ZhbGlkVmVydGljYWxBbGlnbih2ZXJ0aWNhbEFsaWduKSB7XG4gIHJldHVybiB2ZXJ0aWNhbEFsaWduID09PSAnbWlkZGxlJyB8fCB2ZXJ0aWNhbEFsaWduID09PSAnYm90dG9tJztcbn1cbmZ1bmN0aW9uICRjb252ZXJ0VGFibGVDZWxsTm9kZUVsZW1lbnQoZG9tTm9kZSkge1xuICBjb25zdCBkb21Ob2RlXyA9IGRvbU5vZGU7XG4gIGNvbnN0IG5vZGVOYW1lID0gZG9tTm9kZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuICBsZXQgd2lkdGggPSB1bmRlZmluZWQ7XG4gIGlmIChQSVhFTF9WQUxVRV9SRUdfRVhQLnRlc3QoZG9tTm9kZV8uc3R5bGUud2lkdGgpKSB7XG4gICAgd2lkdGggPSBwYXJzZUZsb2F0KGRvbU5vZGVfLnN0eWxlLndpZHRoKTtcbiAgfVxuXG4gIC8vIERldGVybWluZSBoZWFkZXIgc3RhdGUgYmFzZWQgb24gdGhlICdzY29wZScgYXR0cmlidXRlXG4gIGxldCBoZWFkZXJTdGF0ZSA9IFRhYmxlQ2VsbEhlYWRlclN0YXRlcy5OT19TVEFUVVM7XG4gIGlmIChub2RlTmFtZSA9PT0gJ3RoJykge1xuICAgIGNvbnN0IHNjb3BlID0gZG9tTm9kZV8uZ2V0QXR0cmlidXRlKCdzY29wZScpO1xuICAgIGlmIChzY29wZSA9PT0gJ2NvbCcpIHtcbiAgICAgIGhlYWRlclN0YXRlID0gVGFibGVDZWxsSGVhZGVyU3RhdGVzLkNPTFVNTjtcbiAgICB9IGVsc2UgaWYgKHNjb3BlID09PSAncm93Jykge1xuICAgICAgaGVhZGVyU3RhdGUgPSBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuUk9XO1xuICAgIH0gZWxzZSB7XG4gICAgICBoZWFkZXJTdGF0ZSA9IFRhYmxlQ2VsbEhlYWRlclN0YXRlcy5ST1c7XG4gICAgfVxuICB9XG4gIGNvbnN0IHRhYmxlQ2VsbE5vZGUgPSAkY3JlYXRlVGFibGVDZWxsTm9kZShoZWFkZXJTdGF0ZSwgZG9tTm9kZV8uY29sU3Bhbiwgd2lkdGgpO1xuICB0YWJsZUNlbGxOb2RlLl9fcm93U3BhbiA9IGRvbU5vZGVfLnJvd1NwYW47XG4gIGNvbnN0IGJhY2tncm91bmRDb2xvciA9IGRvbU5vZGVfLnN0eWxlLmJhY2tncm91bmRDb2xvcjtcbiAgaWYgKGJhY2tncm91bmRDb2xvciAhPT0gJycpIHtcbiAgICB0YWJsZUNlbGxOb2RlLl9fYmFja2dyb3VuZENvbG9yID0gYmFja2dyb3VuZENvbG9yO1xuICB9XG4gIGNvbnN0IHZlcnRpY2FsQWxpZ24gPSBkb21Ob2RlXy5zdHlsZS52ZXJ0aWNhbEFsaWduO1xuICBpZiAoaXNWYWxpZFZlcnRpY2FsQWxpZ24odmVydGljYWxBbGlnbikpIHtcbiAgICB0YWJsZUNlbGxOb2RlLl9fdmVydGljYWxBbGlnbiA9IHZlcnRpY2FsQWxpZ247XG4gIH1cbiAgY29uc3Qgc3R5bGUgPSBkb21Ob2RlXy5zdHlsZTtcbiAgY29uc3QgdGV4dERlY29yYXRpb24gPSAoc3R5bGUgJiYgc3R5bGUudGV4dERlY29yYXRpb24gfHwgJycpLnNwbGl0KCcgJyk7XG4gIGNvbnN0IGhhc0JvbGRGb250V2VpZ2h0ID0gc3R5bGUuZm9udFdlaWdodCA9PT0gJzcwMCcgfHwgc3R5bGUuZm9udFdlaWdodCA9PT0gJ2JvbGQnO1xuICBjb25zdCBoYXNMaW5ldGhyb3VnaFRleHREZWNvcmF0aW9uID0gdGV4dERlY29yYXRpb24uaW5jbHVkZXMoJ2xpbmUtdGhyb3VnaCcpO1xuICBjb25zdCBoYXNJdGFsaWNGb250U3R5bGUgPSBzdHlsZS5mb250U3R5bGUgPT09ICdpdGFsaWMnO1xuICBjb25zdCBoYXNVbmRlcmxpbmVUZXh0RGVjb3JhdGlvbiA9IHRleHREZWNvcmF0aW9uLmluY2x1ZGVzKCd1bmRlcmxpbmUnKTtcbiAgcmV0dXJuIHtcbiAgICBhZnRlcjogY2hpbGRMZXhpY2FsTm9kZXMgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gW107XG4gICAgICBsZXQgcGFyYWdyYXBoTm9kZSA9IG51bGw7XG4gICAgICBjb25zdCByZW1vdmVTaW5nbGVMaW5lQnJlYWtOb2RlID0gKCkgPT4ge1xuICAgICAgICBpZiAocGFyYWdyYXBoTm9kZSkge1xuICAgICAgICAgIGNvbnN0IGZpcnN0Q2hpbGQgPSBwYXJhZ3JhcGhOb2RlLmdldEZpcnN0Q2hpbGQoKTtcbiAgICAgICAgICBpZiAoJGlzTGluZUJyZWFrTm9kZShmaXJzdENoaWxkKSAmJiBwYXJhZ3JhcGhOb2RlLmdldENoaWxkcmVuU2l6ZSgpID09PSAxKSB7XG4gICAgICAgICAgICBmaXJzdENoaWxkLnJlbW92ZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIGZvciAoY29uc3QgY2hpbGQgb2YgY2hpbGRMZXhpY2FsTm9kZXMpIHtcbiAgICAgICAgaWYgKCRpc0lubGluZUVsZW1lbnRPckRlY29yYXRvck5vZGUoY2hpbGQpIHx8ICRpc1RleHROb2RlKGNoaWxkKSB8fCAkaXNMaW5lQnJlYWtOb2RlKGNoaWxkKSkge1xuICAgICAgICAgIGlmICgkaXNUZXh0Tm9kZShjaGlsZCkpIHtcbiAgICAgICAgICAgIGlmIChoYXNCb2xkRm9udFdlaWdodCkge1xuICAgICAgICAgICAgICBjaGlsZC50b2dnbGVGb3JtYXQoJ2JvbGQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChoYXNMaW5ldGhyb3VnaFRleHREZWNvcmF0aW9uKSB7XG4gICAgICAgICAgICAgIGNoaWxkLnRvZ2dsZUZvcm1hdCgnc3RyaWtldGhyb3VnaCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGhhc0l0YWxpY0ZvbnRTdHlsZSkge1xuICAgICAgICAgICAgICBjaGlsZC50b2dnbGVGb3JtYXQoJ2l0YWxpYycpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGhhc1VuZGVybGluZVRleHREZWNvcmF0aW9uKSB7XG4gICAgICAgICAgICAgIGNoaWxkLnRvZ2dsZUZvcm1hdCgndW5kZXJsaW5lJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChwYXJhZ3JhcGhOb2RlKSB7XG4gICAgICAgICAgICBwYXJhZ3JhcGhOb2RlLmFwcGVuZChjaGlsZCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBhcmFncmFwaE5vZGUgPSAkY3JlYXRlUGFyYWdyYXBoTm9kZSgpLmFwcGVuZChjaGlsZCk7XG4gICAgICAgICAgICByZXN1bHQucHVzaChwYXJhZ3JhcGhOb2RlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzdWx0LnB1c2goY2hpbGQpO1xuICAgICAgICAgIHJlbW92ZVNpbmdsZUxpbmVCcmVha05vZGUoKTtcbiAgICAgICAgICBwYXJhZ3JhcGhOb2RlID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmVtb3ZlU2luZ2xlTGluZUJyZWFrTm9kZSgpO1xuICAgICAgaWYgKHJlc3VsdC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmVzdWx0LnB1c2goJGNyZWF0ZVBhcmFncmFwaE5vZGUoKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0sXG4gICAgbm9kZTogdGFibGVDZWxsTm9kZVxuICB9O1xufVxuZnVuY3Rpb24gJGNyZWF0ZVRhYmxlQ2VsbE5vZGUoaGVhZGVyU3RhdGUgPSBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuTk9fU1RBVFVTLCBjb2xTcGFuID0gMSwgd2lkdGgpIHtcbiAgcmV0dXJuICRhcHBseU5vZGVSZXBsYWNlbWVudChuZXcgVGFibGVDZWxsTm9kZShoZWFkZXJTdGF0ZSwgY29sU3Bhbiwgd2lkdGgpKTtcbn1cbmZ1bmN0aW9uICRpc1RhYmxlQ2VsbE5vZGUobm9kZSkge1xuICByZXR1cm4gbm9kZSBpbnN0YW5jZW9mIFRhYmxlQ2VsbE5vZGU7XG59XG5cbi8qKlxuICogQ29weXJpZ2h0IChjKSBNZXRhIFBsYXRmb3JtcywgSW5jLiBhbmQgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKi9cblxuY29uc3QgSU5TRVJUX1RBQkxFX0NPTU1BTkQgPSBjcmVhdGVDb21tYW5kKCdJTlNFUlRfVEFCTEVfQ09NTUFORCcpO1xuXG4vKipcbiAqIENvcHlyaWdodCAoYykgTWV0YSBQbGF0Zm9ybXMsIEluYy4gYW5kIGFmZmlsaWF0ZXMuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuXG4gKlxuICovXG5cbi8vIERvIG5vdCByZXF1aXJlIHRoaXMgbW9kdWxlIGRpcmVjdGx5ISBVc2Ugbm9ybWFsIGBpbnZhcmlhbnRgIGNhbGxzLlxuXG5mdW5jdGlvbiBmb3JtYXREZXZFcnJvck1lc3NhZ2UobWVzc2FnZSkge1xuICB0aHJvdyBuZXcgRXJyb3IobWVzc2FnZSk7XG59XG5cbi8qKlxuICogQ29weXJpZ2h0IChjKSBNZXRhIFBsYXRmb3JtcywgSW5jLiBhbmQgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKi9cblxuLyoqIEBub0luaGVyaXREb2MgKi9cbmNsYXNzIFRhYmxlUm93Tm9kZSBleHRlbmRzIEVsZW1lbnROb2RlIHtcbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBfX2hlaWdodDtcbiAgc3RhdGljIGdldFR5cGUoKSB7XG4gICAgcmV0dXJuICd0YWJsZXJvdyc7XG4gIH1cbiAgc3RhdGljIGNsb25lKG5vZGUpIHtcbiAgICByZXR1cm4gbmV3IFRhYmxlUm93Tm9kZShub2RlLl9faGVpZ2h0LCBub2RlLl9fa2V5KTtcbiAgfVxuICBzdGF0aWMgaW1wb3J0RE9NKCkge1xuICAgIHJldHVybiB7XG4gICAgICB0cjogbm9kZSA9PiAoe1xuICAgICAgICBjb252ZXJzaW9uOiAkY29udmVydFRhYmxlUm93RWxlbWVudCxcbiAgICAgICAgcHJpb3JpdHk6IDBcbiAgICAgIH0pXG4gICAgfTtcbiAgfVxuICBzdGF0aWMgaW1wb3J0SlNPTihzZXJpYWxpemVkTm9kZSkge1xuICAgIHJldHVybiAkY3JlYXRlVGFibGVSb3dOb2RlKCkudXBkYXRlRnJvbUpTT04oc2VyaWFsaXplZE5vZGUpO1xuICB9XG4gIHVwZGF0ZUZyb21KU09OKHNlcmlhbGl6ZWROb2RlKSB7XG4gICAgcmV0dXJuIHN1cGVyLnVwZGF0ZUZyb21KU09OKHNlcmlhbGl6ZWROb2RlKS5zZXRIZWlnaHQoc2VyaWFsaXplZE5vZGUuaGVpZ2h0KTtcbiAgfVxuICBjb25zdHJ1Y3RvcihoZWlnaHQsIGtleSkge1xuICAgIHN1cGVyKGtleSk7XG4gICAgdGhpcy5fX2hlaWdodCA9IGhlaWdodDtcbiAgfVxuICBleHBvcnRKU09OKCkge1xuICAgIGNvbnN0IGhlaWdodCA9IHRoaXMuZ2V0SGVpZ2h0KCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnN1cGVyLmV4cG9ydEpTT04oKSxcbiAgICAgIC4uLihoZWlnaHQgPT09IHVuZGVmaW5lZCA/IHVuZGVmaW5lZCA6IHtcbiAgICAgICAgaGVpZ2h0XG4gICAgICB9KVxuICAgIH07XG4gIH1cbiAgY3JlYXRlRE9NKGNvbmZpZykge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0cicpO1xuICAgIGlmICh0aGlzLl9faGVpZ2h0KSB7XG4gICAgICBlbGVtZW50LnN0eWxlLmhlaWdodCA9IGAke3RoaXMuX19oZWlnaHR9cHhgO1xuICAgIH1cbiAgICBhZGRDbGFzc05hbWVzVG9FbGVtZW50KGVsZW1lbnQsIGNvbmZpZy50aGVtZS50YWJsZVJvdyk7XG4gICAgcmV0dXJuIGVsZW1lbnQ7XG4gIH1cbiAgZXh0cmFjdFdpdGhDaGlsZChjaGlsZCwgc2VsZWN0aW9uLCBkZXN0aW5hdGlvbikge1xuICAgIHJldHVybiBkZXN0aW5hdGlvbiA9PT0gJ2h0bWwnO1xuICB9XG4gIGlzU2hhZG93Um9vdCgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICBzZXRIZWlnaHQoaGVpZ2h0KSB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXMuZ2V0V3JpdGFibGUoKTtcbiAgICBzZWxmLl9faGVpZ2h0ID0gaGVpZ2h0O1xuICAgIHJldHVybiBzZWxmO1xuICB9XG4gIGdldEhlaWdodCgpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRMYXRlc3QoKS5fX2hlaWdodDtcbiAgfVxuICB1cGRhdGVET00ocHJldk5vZGUpIHtcbiAgICByZXR1cm4gcHJldk5vZGUuX19oZWlnaHQgIT09IHRoaXMuX19oZWlnaHQ7XG4gIH1cbiAgY2FuQmVFbXB0eSgpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY2FuSW5kZW50KCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuZnVuY3Rpb24gJGNvbnZlcnRUYWJsZVJvd0VsZW1lbnQoZG9tTm9kZSkge1xuICBjb25zdCBkb21Ob2RlXyA9IGRvbU5vZGU7XG4gIGxldCBoZWlnaHQgPSB1bmRlZmluZWQ7XG4gIGlmIChQSVhFTF9WQUxVRV9SRUdfRVhQLnRlc3QoZG9tTm9kZV8uc3R5bGUuaGVpZ2h0KSkge1xuICAgIGhlaWdodCA9IHBhcnNlRmxvYXQoZG9tTm9kZV8uc3R5bGUuaGVpZ2h0KTtcbiAgfVxuICByZXR1cm4ge1xuICAgIGFmdGVyOiBjaGlsZHJlbiA9PiAkZGVzY2VuZGFudHNNYXRjaGluZyhjaGlsZHJlbiwgJGlzVGFibGVDZWxsTm9kZSksXG4gICAgbm9kZTogJGNyZWF0ZVRhYmxlUm93Tm9kZShoZWlnaHQpXG4gIH07XG59XG5mdW5jdGlvbiAkY3JlYXRlVGFibGVSb3dOb2RlKGhlaWdodCkge1xuICByZXR1cm4gJGFwcGx5Tm9kZVJlcGxhY2VtZW50KG5ldyBUYWJsZVJvd05vZGUoaGVpZ2h0KSk7XG59XG5mdW5jdGlvbiAkaXNUYWJsZVJvd05vZGUobm9kZSkge1xuICByZXR1cm4gbm9kZSBpbnN0YW5jZW9mIFRhYmxlUm93Tm9kZTtcbn1cblxuLyoqXG4gKiBDb3B5cmlnaHQgKGMpIE1ldGEgUGxhdGZvcm1zLCBJbmMuIGFuZCBhZmZpbGlhdGVzLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqL1xuXG5jb25zdCBDQU5fVVNFX0RPTSA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiB3aW5kb3cuZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiB3aW5kb3cuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCc7XG5cbi8qKlxuICogQ29weXJpZ2h0IChjKSBNZXRhIFBsYXRmb3JtcywgSW5jLiBhbmQgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKi9cblxuY29uc3QgZG9jdW1lbnRNb2RlID0gQ0FOX1VTRV9ET00gJiYgJ2RvY3VtZW50TW9kZScgaW4gZG9jdW1lbnQgPyBkb2N1bWVudC5kb2N1bWVudE1vZGUgOiBudWxsO1xuY29uc3QgSVNfRklSRUZPWCA9IENBTl9VU0VfRE9NICYmIC9eKD8hLipTZWFtb25rZXkpKD89LipGaXJlZm94KS4qL2kudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KTtcbkNBTl9VU0VfRE9NICYmICdJbnB1dEV2ZW50JyBpbiB3aW5kb3cgJiYgIWRvY3VtZW50TW9kZSA/ICdnZXRUYXJnZXRSYW5nZXMnIGluIG5ldyB3aW5kb3cuSW5wdXRFdmVudCgnaW5wdXQnKSA6IGZhbHNlO1xuXG5mdW5jdGlvbiAkY3JlYXRlVGFibGVOb2RlV2l0aERpbWVuc2lvbnMocm93Q291bnQsIGNvbHVtbkNvdW50LCBpbmNsdWRlSGVhZGVycyA9IHRydWUpIHtcbiAgY29uc3QgdGFibGVOb2RlID0gJGNyZWF0ZVRhYmxlTm9kZSgpO1xuICBmb3IgKGxldCBpUm93ID0gMDsgaVJvdyA8IHJvd0NvdW50OyBpUm93KyspIHtcbiAgICBjb25zdCB0YWJsZVJvd05vZGUgPSAkY3JlYXRlVGFibGVSb3dOb2RlKCk7XG4gICAgZm9yIChsZXQgaUNvbHVtbiA9IDA7IGlDb2x1bW4gPCBjb2x1bW5Db3VudDsgaUNvbHVtbisrKSB7XG4gICAgICBsZXQgaGVhZGVyU3RhdGUgPSBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuTk9fU1RBVFVTO1xuICAgICAgaWYgKHR5cGVvZiBpbmNsdWRlSGVhZGVycyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgaWYgKGlSb3cgPT09IDAgJiYgaW5jbHVkZUhlYWRlcnMucm93cykge1xuICAgICAgICAgIGhlYWRlclN0YXRlIHw9IFRhYmxlQ2VsbEhlYWRlclN0YXRlcy5ST1c7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlDb2x1bW4gPT09IDAgJiYgaW5jbHVkZUhlYWRlcnMuY29sdW1ucykge1xuICAgICAgICAgIGhlYWRlclN0YXRlIHw9IFRhYmxlQ2VsbEhlYWRlclN0YXRlcy5DT0xVTU47XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoaW5jbHVkZUhlYWRlcnMpIHtcbiAgICAgICAgaWYgKGlSb3cgPT09IDApIHtcbiAgICAgICAgICBoZWFkZXJTdGF0ZSB8PSBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuUk9XO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpQ29sdW1uID09PSAwKSB7XG4gICAgICAgICAgaGVhZGVyU3RhdGUgfD0gVGFibGVDZWxsSGVhZGVyU3RhdGVzLkNPTFVNTjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3QgdGFibGVDZWxsTm9kZSA9ICRjcmVhdGVUYWJsZUNlbGxOb2RlKGhlYWRlclN0YXRlKTtcbiAgICAgIGNvbnN0IHBhcmFncmFwaE5vZGUgPSAkY3JlYXRlUGFyYWdyYXBoTm9kZSgpO1xuICAgICAgcGFyYWdyYXBoTm9kZS5hcHBlbmQoJGNyZWF0ZVRleHROb2RlKCkpO1xuICAgICAgdGFibGVDZWxsTm9kZS5hcHBlbmQocGFyYWdyYXBoTm9kZSk7XG4gICAgICB0YWJsZVJvd05vZGUuYXBwZW5kKHRhYmxlQ2VsbE5vZGUpO1xuICAgIH1cbiAgICB0YWJsZU5vZGUuYXBwZW5kKHRhYmxlUm93Tm9kZSk7XG4gIH1cbiAgcmV0dXJuIHRhYmxlTm9kZTtcbn1cbmZ1bmN0aW9uICRnZXRUYWJsZUNlbGxOb2RlRnJvbUxleGljYWxOb2RlKHN0YXJ0aW5nTm9kZSkge1xuICBjb25zdCBub2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChzdGFydGluZ05vZGUsIG4gPT4gJGlzVGFibGVDZWxsTm9kZShuKSk7XG4gIGlmICgkaXNUYWJsZUNlbGxOb2RlKG5vZGUpKSB7XG4gICAgcmV0dXJuIG5vZGU7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5mdW5jdGlvbiAkZ2V0VGFibGVSb3dOb2RlRnJvbVRhYmxlQ2VsbE5vZGVPclRocm93KHN0YXJ0aW5nTm9kZSkge1xuICBjb25zdCBub2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChzdGFydGluZ05vZGUsIG4gPT4gJGlzVGFibGVSb3dOb2RlKG4pKTtcbiAgaWYgKCRpc1RhYmxlUm93Tm9kZShub2RlKSkge1xuICAgIHJldHVybiBub2RlO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcignRXhwZWN0ZWQgdGFibGUgY2VsbCB0byBiZSBpbnNpZGUgb2YgdGFibGUgcm93LicpO1xufVxuZnVuY3Rpb24gJGdldFRhYmxlTm9kZUZyb21MZXhpY2FsTm9kZU9yVGhyb3coc3RhcnRpbmdOb2RlKSB7XG4gIGNvbnN0IG5vZGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KHN0YXJ0aW5nTm9kZSwgbiA9PiAkaXNUYWJsZU5vZGUobikpO1xuICBpZiAoJGlzVGFibGVOb2RlKG5vZGUpKSB7XG4gICAgcmV0dXJuIG5vZGU7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKCdFeHBlY3RlZCB0YWJsZSBjZWxsIHRvIGJlIGluc2lkZSBvZiB0YWJsZS4nKTtcbn1cbmZ1bmN0aW9uICRnZXRUYWJsZVJvd0luZGV4RnJvbVRhYmxlQ2VsbE5vZGUodGFibGVDZWxsTm9kZSkge1xuICBjb25zdCB0YWJsZVJvd05vZGUgPSAkZ2V0VGFibGVSb3dOb2RlRnJvbVRhYmxlQ2VsbE5vZGVPclRocm93KHRhYmxlQ2VsbE5vZGUpO1xuICBjb25zdCB0YWJsZU5vZGUgPSAkZ2V0VGFibGVOb2RlRnJvbUxleGljYWxOb2RlT3JUaHJvdyh0YWJsZVJvd05vZGUpO1xuICByZXR1cm4gdGFibGVOb2RlLmdldENoaWxkcmVuKCkuZmluZEluZGV4KG4gPT4gbi5pcyh0YWJsZVJvd05vZGUpKTtcbn1cbmZ1bmN0aW9uICRnZXRUYWJsZUNvbHVtbkluZGV4RnJvbVRhYmxlQ2VsbE5vZGUodGFibGVDZWxsTm9kZSkge1xuICBjb25zdCB0YWJsZVJvd05vZGUgPSAkZ2V0VGFibGVSb3dOb2RlRnJvbVRhYmxlQ2VsbE5vZGVPclRocm93KHRhYmxlQ2VsbE5vZGUpO1xuICByZXR1cm4gdGFibGVSb3dOb2RlLmdldENoaWxkcmVuKCkuZmluZEluZGV4KG4gPT4gbi5pcyh0YWJsZUNlbGxOb2RlKSk7XG59XG5mdW5jdGlvbiAkZ2V0VGFibGVDZWxsU2libGluZ3NGcm9tVGFibGVDZWxsTm9kZSh0YWJsZUNlbGxOb2RlLCB0YWJsZSkge1xuICBjb25zdCB0YWJsZU5vZGUgPSAkZ2V0VGFibGVOb2RlRnJvbUxleGljYWxOb2RlT3JUaHJvdyh0YWJsZUNlbGxOb2RlKTtcbiAgY29uc3Qge1xuICAgIHgsXG4gICAgeVxuICB9ID0gdGFibGVOb2RlLmdldENvcmRzRnJvbUNlbGxOb2RlKHRhYmxlQ2VsbE5vZGUsIHRhYmxlKTtcbiAgcmV0dXJuIHtcbiAgICBhYm92ZTogdGFibGVOb2RlLmdldENlbGxOb2RlRnJvbUNvcmRzKHgsIHkgLSAxLCB0YWJsZSksXG4gICAgYmVsb3c6IHRhYmxlTm9kZS5nZXRDZWxsTm9kZUZyb21Db3Jkcyh4LCB5ICsgMSwgdGFibGUpLFxuICAgIGxlZnQ6IHRhYmxlTm9kZS5nZXRDZWxsTm9kZUZyb21Db3Jkcyh4IC0gMSwgeSwgdGFibGUpLFxuICAgIHJpZ2h0OiB0YWJsZU5vZGUuZ2V0Q2VsbE5vZGVGcm9tQ29yZHMoeCArIDEsIHksIHRhYmxlKVxuICB9O1xufVxuZnVuY3Rpb24gJHJlbW92ZVRhYmxlUm93QXRJbmRleCh0YWJsZU5vZGUsIGluZGV4VG9EZWxldGUpIHtcbiAgY29uc3QgdGFibGVSb3dzID0gdGFibGVOb2RlLmdldENoaWxkcmVuKCk7XG4gIGlmIChpbmRleFRvRGVsZXRlID49IHRhYmxlUm93cy5sZW5ndGggfHwgaW5kZXhUb0RlbGV0ZSA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0V4cGVjdGVkIHRhYmxlIGNlbGwgdG8gYmUgaW5zaWRlIG9mIHRhYmxlIHJvdy4nKTtcbiAgfVxuICBjb25zdCB0YXJnZXRSb3dOb2RlID0gdGFibGVSb3dzW2luZGV4VG9EZWxldGVdO1xuICB0YXJnZXRSb3dOb2RlLnJlbW92ZSgpO1xuICByZXR1cm4gdGFibGVOb2RlO1xufVxuXG4vKipcbiAqIEBkZXByZWNhdGVkIFRoaXMgZnVuY3Rpb24gZG9lcyBub3Qgc3VwcG9ydCBtZXJnZWQgY2VsbHMuIFVzZSB7QGxpbmsgJGluc2VydFRhYmxlUm93QXRTZWxlY3Rpb259IG9yIHtAbGluayAkaW5zZXJ0VGFibGVSb3dBdE5vZGV9IGluc3RlYWQuXG4gKi9cbmZ1bmN0aW9uICRpbnNlcnRUYWJsZVJvdyh0YWJsZU5vZGUsIHRhcmdldEluZGV4LCBzaG91bGRJbnNlcnRBZnRlciA9IHRydWUsIHJvd0NvdW50LCB0YWJsZSkge1xuICBjb25zdCB0YWJsZVJvd3MgPSB0YWJsZU5vZGUuZ2V0Q2hpbGRyZW4oKTtcbiAgaWYgKHRhcmdldEluZGV4ID49IHRhYmxlUm93cy5sZW5ndGggfHwgdGFyZ2V0SW5kZXggPCAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdUYWJsZSByb3cgdGFyZ2V0IGluZGV4IG91dCBvZiByYW5nZScpO1xuICB9XG4gIGNvbnN0IHRhcmdldFJvd05vZGUgPSB0YWJsZVJvd3NbdGFyZ2V0SW5kZXhdO1xuICBpZiAoJGlzVGFibGVSb3dOb2RlKHRhcmdldFJvd05vZGUpKSB7XG4gICAgZm9yIChsZXQgciA9IDA7IHIgPCByb3dDb3VudDsgcisrKSB7XG4gICAgICBjb25zdCB0YWJsZVJvd0NlbGxzID0gdGFyZ2V0Um93Tm9kZS5nZXRDaGlsZHJlbigpO1xuICAgICAgY29uc3QgdGFibGVDb2x1bW5Db3VudCA9IHRhYmxlUm93Q2VsbHMubGVuZ3RoO1xuICAgICAgY29uc3QgbmV3VGFibGVSb3dOb2RlID0gJGNyZWF0ZVRhYmxlUm93Tm9kZSgpO1xuICAgICAgZm9yIChsZXQgYyA9IDA7IGMgPCB0YWJsZUNvbHVtbkNvdW50OyBjKyspIHtcbiAgICAgICAgY29uc3QgdGFibGVDZWxsRnJvbVRhcmdldFJvdyA9IHRhYmxlUm93Q2VsbHNbY107XG4gICAgICAgIGlmICghJGlzVGFibGVDZWxsTm9kZSh0YWJsZUNlbGxGcm9tVGFyZ2V0Um93KSkge1xuICAgICAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgdGFibGUgY2VsbGApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBhYm92ZSxcbiAgICAgICAgICBiZWxvd1xuICAgICAgICB9ID0gJGdldFRhYmxlQ2VsbFNpYmxpbmdzRnJvbVRhYmxlQ2VsbE5vZGUodGFibGVDZWxsRnJvbVRhcmdldFJvdywgdGFibGUpO1xuICAgICAgICBsZXQgaGVhZGVyU3RhdGUgPSBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuTk9fU1RBVFVTO1xuICAgICAgICBjb25zdCB3aWR0aCA9IGFib3ZlICYmIGFib3ZlLmdldFdpZHRoKCkgfHwgYmVsb3cgJiYgYmVsb3cuZ2V0V2lkdGgoKSB8fCB1bmRlZmluZWQ7XG4gICAgICAgIGlmIChhYm92ZSAmJiBhYm92ZS5oYXNIZWFkZXJTdGF0ZShUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuQ09MVU1OKSB8fCBiZWxvdyAmJiBiZWxvdy5oYXNIZWFkZXJTdGF0ZShUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuQ09MVU1OKSkge1xuICAgICAgICAgIGhlYWRlclN0YXRlIHw9IFRhYmxlQ2VsbEhlYWRlclN0YXRlcy5DT0xVTU47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdGFibGVDZWxsTm9kZSA9ICRjcmVhdGVUYWJsZUNlbGxOb2RlKGhlYWRlclN0YXRlLCAxLCB3aWR0aCk7XG4gICAgICAgIHRhYmxlQ2VsbE5vZGUuYXBwZW5kKCRjcmVhdGVQYXJhZ3JhcGhOb2RlKCkpO1xuICAgICAgICBuZXdUYWJsZVJvd05vZGUuYXBwZW5kKHRhYmxlQ2VsbE5vZGUpO1xuICAgICAgfVxuICAgICAgaWYgKHNob3VsZEluc2VydEFmdGVyKSB7XG4gICAgICAgIHRhcmdldFJvd05vZGUuaW5zZXJ0QWZ0ZXIobmV3VGFibGVSb3dOb2RlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRhcmdldFJvd05vZGUuaW5zZXJ0QmVmb3JlKG5ld1RhYmxlUm93Tm9kZSk7XG4gICAgICB9XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBFcnJvcignUm93IGJlZm9yZSBpbnNlcnRpb24gaW5kZXggZG9lcyBub3QgZXhpc3QuJyk7XG4gIH1cbiAgcmV0dXJuIHRhYmxlTm9kZTtcbn1cbmNvbnN0IGdldEhlYWRlclN0YXRlID0gKGN1cnJlbnRTdGF0ZSwgcG9zc2libGVTdGF0ZSkgPT4ge1xuICBpZiAoY3VycmVudFN0YXRlID09PSBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuQk9USCB8fCBjdXJyZW50U3RhdGUgPT09IHBvc3NpYmxlU3RhdGUpIHtcbiAgICByZXR1cm4gcG9zc2libGVTdGF0ZTtcbiAgfVxuICByZXR1cm4gVGFibGVDZWxsSGVhZGVyU3RhdGVzLk5PX1NUQVRVUztcbn07XG5cbi8qKlxuICogSW5zZXJ0cyBhIHRhYmxlIHJvdyBiZWZvcmUgb3IgYWZ0ZXIgdGhlIGN1cnJlbnQgZm9jdXMgY2VsbCBub2RlLFxuICogdGFraW5nIGludG8gYWNjb3VudCBhbnkgc3BhbnMuIElmIHN1Y2Nlc3NmdWwsIHJldHVybnMgdGhlXG4gKiBpbnNlcnRlZCB0YWJsZSByb3cgbm9kZS5cbiAqL1xuZnVuY3Rpb24gJGluc2VydFRhYmxlUm93QXRTZWxlY3Rpb24oaW5zZXJ0QWZ0ZXIgPSB0cnVlKSB7XG4gIGNvbnN0IHNlbGVjdGlvbiA9ICRnZXRTZWxlY3Rpb24oKTtcbiAgaWYgKCEoJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSB8fCAkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgYSBSYW5nZVNlbGVjdGlvbiBvciBUYWJsZVNlbGVjdGlvbmApO1xuICB9XG4gIGNvbnN0IGFuY2hvciA9IHNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpO1xuICBjb25zdCBmb2N1cyA9IHNlbGVjdGlvbi5mb2N1cy5nZXROb2RlKCk7XG4gIGNvbnN0IFthbmNob3JDZWxsXSA9ICRnZXROb2RlVHJpcGxldChhbmNob3IpO1xuICBjb25zdCBbZm9jdXNDZWxsLCwgZ3JpZF0gPSAkZ2V0Tm9kZVRyaXBsZXQoZm9jdXMpO1xuICBjb25zdCBbLCBmb2N1c0NlbGxNYXAsIGFuY2hvckNlbGxNYXBdID0gJGNvbXB1dGVUYWJsZU1hcChncmlkLCBmb2N1c0NlbGwsIGFuY2hvckNlbGwpO1xuICBjb25zdCB7XG4gICAgc3RhcnRSb3c6IGFuY2hvclN0YXJ0Um93XG4gIH0gPSBhbmNob3JDZWxsTWFwO1xuICBjb25zdCB7XG4gICAgc3RhcnRSb3c6IGZvY3VzU3RhcnRSb3dcbiAgfSA9IGZvY3VzQ2VsbE1hcDtcbiAgaWYgKGluc2VydEFmdGVyKSB7XG4gICAgcmV0dXJuICRpbnNlcnRUYWJsZVJvd0F0Tm9kZShhbmNob3JTdGFydFJvdyArIGFuY2hvckNlbGwuX19yb3dTcGFuID4gZm9jdXNTdGFydFJvdyArIGZvY3VzQ2VsbC5fX3Jvd1NwYW4gPyBhbmNob3JDZWxsIDogZm9jdXNDZWxsLCB0cnVlKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gJGluc2VydFRhYmxlUm93QXROb2RlKGZvY3VzU3RhcnRSb3cgPCBhbmNob3JTdGFydFJvdyA/IGZvY3VzQ2VsbCA6IGFuY2hvckNlbGwsIGZhbHNlKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXByZWNhdGVkIHJlbmFtZWQgdG8ge0BsaW5rICRpbnNlcnRUYWJsZVJvd0F0U2VsZWN0aW9ufVxuICovXG5jb25zdCAkaW5zZXJ0VGFibGVSb3dfX0VYUEVSSU1FTlRBTCA9ICRpbnNlcnRUYWJsZVJvd0F0U2VsZWN0aW9uO1xuXG4vKipcbiAqIEluc2VydHMgYSB0YWJsZSByb3cgYmVmb3JlIG9yIGFmdGVyIHRoZSBnaXZlbiBjZWxsIG5vZGUsXG4gKiB0YWtpbmcgaW50byBhY2NvdW50IGFueSBzcGFucy4gSWYgc3VjY2Vzc2Z1bCwgcmV0dXJucyB0aGVcbiAqIGluc2VydGVkIHRhYmxlIHJvdyBub2RlLlxuICovXG5mdW5jdGlvbiAkaW5zZXJ0VGFibGVSb3dBdE5vZGUoY2VsbE5vZGUsIGluc2VydEFmdGVyID0gdHJ1ZSkge1xuICBjb25zdCBbLCwgZ3JpZF0gPSAkZ2V0Tm9kZVRyaXBsZXQoY2VsbE5vZGUpO1xuICBjb25zdCBbZ3JpZE1hcCwgY2VsbE1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwKGdyaWQsIGNlbGxOb2RlLCBjZWxsTm9kZSk7XG4gIGNvbnN0IGNvbHVtbkNvdW50ID0gZ3JpZE1hcFswXS5sZW5ndGg7XG4gIGNvbnN0IHtcbiAgICBzdGFydFJvdzogY2VsbFN0YXJ0Um93XG4gIH0gPSBjZWxsTWFwO1xuICBsZXQgaW5zZXJ0ZWRSb3cgPSBudWxsO1xuICBpZiAoaW5zZXJ0QWZ0ZXIpIHtcbiAgICBjb25zdCBpbnNlcnRBZnRlckVuZFJvdyA9IGNlbGxTdGFydFJvdyArIGNlbGxOb2RlLl9fcm93U3BhbiAtIDE7XG4gICAgY29uc3QgaW5zZXJ0QWZ0ZXJFbmRSb3dNYXAgPSBncmlkTWFwW2luc2VydEFmdGVyRW5kUm93XTtcbiAgICBjb25zdCBuZXdSb3cgPSAkY3JlYXRlVGFibGVSb3dOb2RlKCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2x1bW5Db3VudDsgaSsrKSB7XG4gICAgICBjb25zdCB7XG4gICAgICAgIGNlbGwsXG4gICAgICAgIHN0YXJ0Um93XG4gICAgICB9ID0gaW5zZXJ0QWZ0ZXJFbmRSb3dNYXBbaV07XG4gICAgICBpZiAoc3RhcnRSb3cgKyBjZWxsLl9fcm93U3BhbiAtIDEgPD0gaW5zZXJ0QWZ0ZXJFbmRSb3cpIHtcbiAgICAgICAgY29uc3QgY3VycmVudENlbGwgPSBpbnNlcnRBZnRlckVuZFJvd01hcFtpXS5jZWxsO1xuICAgICAgICBjb25zdCBjdXJyZW50Q2VsbEhlYWRlclN0YXRlID0gY3VycmVudENlbGwuX19oZWFkZXJTdGF0ZTtcbiAgICAgICAgY29uc3QgaGVhZGVyU3RhdGUgPSBnZXRIZWFkZXJTdGF0ZShjdXJyZW50Q2VsbEhlYWRlclN0YXRlLCBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuQ09MVU1OKTtcbiAgICAgICAgbmV3Um93LmFwcGVuZCgkY3JlYXRlVGFibGVDZWxsTm9kZShoZWFkZXJTdGF0ZSkuYXBwZW5kKCRjcmVhdGVQYXJhZ3JhcGhOb2RlKCkpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNlbGwuc2V0Um93U3BhbihjZWxsLl9fcm93U3BhbiArIDEpO1xuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBpbnNlcnRBZnRlckVuZFJvd05vZGUgPSBncmlkLmdldENoaWxkQXRJbmRleChpbnNlcnRBZnRlckVuZFJvdyk7XG4gICAgaWYgKCEkaXNUYWJsZVJvd05vZGUoaW5zZXJ0QWZ0ZXJFbmRSb3dOb2RlKSkge1xuICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBpbnNlcnRBZnRlckVuZFJvdyBpcyBub3QgYSBUYWJsZVJvd05vZGVgKTtcbiAgICB9XG4gICAgaW5zZXJ0QWZ0ZXJFbmRSb3dOb2RlLmluc2VydEFmdGVyKG5ld1Jvdyk7XG4gICAgaW5zZXJ0ZWRSb3cgPSBuZXdSb3c7XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgaW5zZXJ0QmVmb3JlU3RhcnRSb3cgPSBjZWxsU3RhcnRSb3c7XG4gICAgY29uc3QgaW5zZXJ0QmVmb3JlU3RhcnRSb3dNYXAgPSBncmlkTWFwW2luc2VydEJlZm9yZVN0YXJ0Um93XTtcbiAgICBjb25zdCBuZXdSb3cgPSAkY3JlYXRlVGFibGVSb3dOb2RlKCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2x1bW5Db3VudDsgaSsrKSB7XG4gICAgICBjb25zdCB7XG4gICAgICAgIGNlbGwsXG4gICAgICAgIHN0YXJ0Um93XG4gICAgICB9ID0gaW5zZXJ0QmVmb3JlU3RhcnRSb3dNYXBbaV07XG4gICAgICBpZiAoc3RhcnRSb3cgPT09IGluc2VydEJlZm9yZVN0YXJ0Um93KSB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRDZWxsID0gaW5zZXJ0QmVmb3JlU3RhcnRSb3dNYXBbaV0uY2VsbDtcbiAgICAgICAgY29uc3QgY3VycmVudENlbGxIZWFkZXJTdGF0ZSA9IGN1cnJlbnRDZWxsLl9faGVhZGVyU3RhdGU7XG4gICAgICAgIGNvbnN0IGhlYWRlclN0YXRlID0gZ2V0SGVhZGVyU3RhdGUoY3VycmVudENlbGxIZWFkZXJTdGF0ZSwgVGFibGVDZWxsSGVhZGVyU3RhdGVzLkNPTFVNTik7XG4gICAgICAgIG5ld1Jvdy5hcHBlbmQoJGNyZWF0ZVRhYmxlQ2VsbE5vZGUoaGVhZGVyU3RhdGUpLmFwcGVuZCgkY3JlYXRlUGFyYWdyYXBoTm9kZSgpKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjZWxsLnNldFJvd1NwYW4oY2VsbC5fX3Jvd1NwYW4gKyAxKTtcbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgaW5zZXJ0QmVmb3JlU3RhcnRSb3dOb2RlID0gZ3JpZC5nZXRDaGlsZEF0SW5kZXgoaW5zZXJ0QmVmb3JlU3RhcnRSb3cpO1xuICAgIGlmICghJGlzVGFibGVSb3dOb2RlKGluc2VydEJlZm9yZVN0YXJ0Um93Tm9kZSkpIHtcbiAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgaW5zZXJ0QmVmb3JlU3RhcnRSb3cgaXMgbm90IGEgVGFibGVSb3dOb2RlYCk7XG4gICAgfVxuICAgIGluc2VydEJlZm9yZVN0YXJ0Um93Tm9kZS5pbnNlcnRCZWZvcmUobmV3Um93KTtcbiAgICBpbnNlcnRlZFJvdyA9IG5ld1JvdztcbiAgfVxuICByZXR1cm4gaW5zZXJ0ZWRSb3c7XG59XG5cbi8qKlxuICogQGRlcHJlY2F0ZWQgVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCBzdXBwb3J0IG1lcmdlZCBjZWxscy4gVXNlIHtAbGluayAkaW5zZXJ0VGFibGVDb2x1bW5BdFNlbGVjdGlvbn0gb3Ige0BsaW5rICRpbnNlcnRUYWJsZUNvbHVtbkF0Tm9kZX0gaW5zdGVhZC5cbiAqL1xuZnVuY3Rpb24gJGluc2VydFRhYmxlQ29sdW1uKHRhYmxlTm9kZSwgdGFyZ2V0SW5kZXgsIHNob3VsZEluc2VydEFmdGVyID0gdHJ1ZSwgY29sdW1uQ291bnQsIHRhYmxlKSB7XG4gIGNvbnN0IHRhYmxlUm93cyA9IHRhYmxlTm9kZS5nZXRDaGlsZHJlbigpO1xuICBjb25zdCB0YWJsZUNlbGxzVG9CZUluc2VydGVkID0gW107XG4gIGZvciAobGV0IHIgPSAwOyByIDwgdGFibGVSb3dzLmxlbmd0aDsgcisrKSB7XG4gICAgY29uc3QgY3VycmVudFRhYmxlUm93Tm9kZSA9IHRhYmxlUm93c1tyXTtcbiAgICBpZiAoJGlzVGFibGVSb3dOb2RlKGN1cnJlbnRUYWJsZVJvd05vZGUpKSB7XG4gICAgICBmb3IgKGxldCBjID0gMDsgYyA8IGNvbHVtbkNvdW50OyBjKyspIHtcbiAgICAgICAgY29uc3QgdGFibGVSb3dDaGlsZHJlbiA9IGN1cnJlbnRUYWJsZVJvd05vZGUuZ2V0Q2hpbGRyZW4oKTtcbiAgICAgICAgaWYgKHRhcmdldEluZGV4ID49IHRhYmxlUm93Q2hpbGRyZW4ubGVuZ3RoIHx8IHRhcmdldEluZGV4IDwgMCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignVGFibGUgY29sdW1uIHRhcmdldCBpbmRleCBvdXQgb2YgcmFuZ2UnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0YXJnZXRDZWxsID0gdGFibGVSb3dDaGlsZHJlblt0YXJnZXRJbmRleF07XG4gICAgICAgIGlmICghJGlzVGFibGVDZWxsTm9kZSh0YXJnZXRDZWxsKSkge1xuICAgICAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgdGFibGUgY2VsbGApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBsZWZ0LFxuICAgICAgICAgIHJpZ2h0XG4gICAgICAgIH0gPSAkZ2V0VGFibGVDZWxsU2libGluZ3NGcm9tVGFibGVDZWxsTm9kZSh0YXJnZXRDZWxsLCB0YWJsZSk7XG4gICAgICAgIGxldCBoZWFkZXJTdGF0ZSA9IFRhYmxlQ2VsbEhlYWRlclN0YXRlcy5OT19TVEFUVVM7XG4gICAgICAgIGlmIChsZWZ0ICYmIGxlZnQuaGFzSGVhZGVyU3RhdGUoVGFibGVDZWxsSGVhZGVyU3RhdGVzLlJPVykgfHwgcmlnaHQgJiYgcmlnaHQuaGFzSGVhZGVyU3RhdGUoVGFibGVDZWxsSGVhZGVyU3RhdGVzLlJPVykpIHtcbiAgICAgICAgICBoZWFkZXJTdGF0ZSB8PSBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuUk9XO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG5ld1RhYmxlQ2VsbCA9ICRjcmVhdGVUYWJsZUNlbGxOb2RlKGhlYWRlclN0YXRlKTtcbiAgICAgICAgbmV3VGFibGVDZWxsLmFwcGVuZCgkY3JlYXRlUGFyYWdyYXBoTm9kZSgpKTtcbiAgICAgICAgdGFibGVDZWxsc1RvQmVJbnNlcnRlZC5wdXNoKHtcbiAgICAgICAgICBuZXdUYWJsZUNlbGwsXG4gICAgICAgICAgdGFyZ2V0Q2VsbFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgdGFibGVDZWxsc1RvQmVJbnNlcnRlZC5mb3JFYWNoKCh7XG4gICAgbmV3VGFibGVDZWxsLFxuICAgIHRhcmdldENlbGxcbiAgfSkgPT4ge1xuICAgIGlmIChzaG91bGRJbnNlcnRBZnRlcikge1xuICAgICAgdGFyZ2V0Q2VsbC5pbnNlcnRBZnRlcihuZXdUYWJsZUNlbGwpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0YXJnZXRDZWxsLmluc2VydEJlZm9yZShuZXdUYWJsZUNlbGwpO1xuICAgIH1cbiAgfSk7XG4gIHJldHVybiB0YWJsZU5vZGU7XG59XG5cbi8qKlxuICogSW5zZXJ0cyBhIGNvbHVtbiBiZWZvcmUgb3IgYWZ0ZXIgdGhlIGN1cnJlbnQgZm9jdXMgY2VsbCBub2RlLFxuICogdGFraW5nIGludG8gYWNjb3VudCBhbnkgc3BhbnMuIElmIHN1Y2Nlc3NmdWwsIHJldHVybnMgdGhlXG4gKiBmaXJzdCBpbnNlcnRlZCBjZWxsIG5vZGUuXG4gKi9cbmZ1bmN0aW9uICRpbnNlcnRUYWJsZUNvbHVtbkF0U2VsZWN0aW9uKGluc2VydEFmdGVyID0gdHJ1ZSkge1xuICBjb25zdCBzZWxlY3Rpb24gPSAkZ2V0U2VsZWN0aW9uKCk7XG4gIGlmICghKCRpc1JhbmdlU2VsZWN0aW9uKHNlbGVjdGlvbikgfHwgJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSkpIHtcbiAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIGEgUmFuZ2VTZWxlY3Rpb24gb3IgVGFibGVTZWxlY3Rpb25gKTtcbiAgfVxuICBjb25zdCBhbmNob3IgPSBzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKTtcbiAgY29uc3QgZm9jdXMgPSBzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpO1xuICBjb25zdCBbYW5jaG9yQ2VsbF0gPSAkZ2V0Tm9kZVRyaXBsZXQoYW5jaG9yKTtcbiAgY29uc3QgW2ZvY3VzQ2VsbCwsIGdyaWRdID0gJGdldE5vZGVUcmlwbGV0KGZvY3VzKTtcbiAgY29uc3QgWywgZm9jdXNDZWxsTWFwLCBhbmNob3JDZWxsTWFwXSA9ICRjb21wdXRlVGFibGVNYXAoZ3JpZCwgZm9jdXNDZWxsLCBhbmNob3JDZWxsKTtcbiAgY29uc3Qge1xuICAgIHN0YXJ0Q29sdW1uOiBhbmNob3JTdGFydENvbHVtblxuICB9ID0gYW5jaG9yQ2VsbE1hcDtcbiAgY29uc3Qge1xuICAgIHN0YXJ0Q29sdW1uOiBmb2N1c1N0YXJ0Q29sdW1uXG4gIH0gPSBmb2N1c0NlbGxNYXA7XG4gIGlmIChpbnNlcnRBZnRlcikge1xuICAgIHJldHVybiAkaW5zZXJ0VGFibGVDb2x1bW5BdE5vZGUoYW5jaG9yU3RhcnRDb2x1bW4gKyBhbmNob3JDZWxsLl9fY29sU3BhbiA+IGZvY3VzU3RhcnRDb2x1bW4gKyBmb2N1c0NlbGwuX19jb2xTcGFuID8gYW5jaG9yQ2VsbCA6IGZvY3VzQ2VsbCwgdHJ1ZSk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuICRpbnNlcnRUYWJsZUNvbHVtbkF0Tm9kZShmb2N1c1N0YXJ0Q29sdW1uIDwgYW5jaG9yU3RhcnRDb2x1bW4gPyBmb2N1c0NlbGwgOiBhbmNob3JDZWxsLCBmYWxzZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVwcmVjYXRlZCByZW5hbWVkIHRvIHtAbGluayAkaW5zZXJ0VGFibGVDb2x1bW5BdFNlbGVjdGlvbn1cbiAqL1xuY29uc3QgJGluc2VydFRhYmxlQ29sdW1uX19FWFBFUklNRU5UQUwgPSAkaW5zZXJ0VGFibGVDb2x1bW5BdFNlbGVjdGlvbjtcblxuLyoqXG4gKiBJbnNlcnRzIGEgY29sdW1uIGJlZm9yZSBvciBhZnRlciB0aGUgZ2l2ZW4gY2VsbCBub2RlLFxuICogdGFraW5nIGludG8gYWNjb3VudCBhbnkgc3BhbnMuIElmIHN1Y2Nlc3NmdWwsIHJldHVybnMgdGhlXG4gKiBmaXJzdCBpbnNlcnRlZCBjZWxsIG5vZGUuXG4gKi9cbmZ1bmN0aW9uICRpbnNlcnRUYWJsZUNvbHVtbkF0Tm9kZShjZWxsTm9kZSwgaW5zZXJ0QWZ0ZXIgPSB0cnVlLCBzaG91bGRTZXRTZWxlY3Rpb24gPSB0cnVlKSB7XG4gIGNvbnN0IFssLCBncmlkXSA9ICRnZXROb2RlVHJpcGxldChjZWxsTm9kZSk7XG4gIGNvbnN0IFtncmlkTWFwLCBjZWxsTWFwXSA9ICRjb21wdXRlVGFibGVNYXAoZ3JpZCwgY2VsbE5vZGUsIGNlbGxOb2RlKTtcbiAgY29uc3Qgcm93Q291bnQgPSBncmlkTWFwLmxlbmd0aDtcbiAgY29uc3Qge1xuICAgIHN0YXJ0Q29sdW1uXG4gIH0gPSBjZWxsTWFwO1xuICBjb25zdCBpbnNlcnRBZnRlckNvbHVtbiA9IGluc2VydEFmdGVyID8gc3RhcnRDb2x1bW4gKyBjZWxsTm9kZS5fX2NvbFNwYW4gLSAxIDogc3RhcnRDb2x1bW4gLSAxO1xuICBjb25zdCBncmlkRmlyc3RDaGlsZCA9IGdyaWQuZ2V0Rmlyc3RDaGlsZCgpO1xuICBpZiAoISRpc1RhYmxlUm93Tm9kZShncmlkRmlyc3RDaGlsZCkpIHtcbiAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIGZpcnN0VGFibGUgY2hpbGQgdG8gYmUgYSByb3dgKTtcbiAgfVxuICBsZXQgZmlyc3RJbnNlcnRlZENlbGwgPSBudWxsO1xuICBmdW5jdGlvbiAkY3JlYXRlVGFibGVDZWxsTm9kZUZvckluc2VydFRhYmxlQ29sdW1uKGhlYWRlclN0YXRlID0gVGFibGVDZWxsSGVhZGVyU3RhdGVzLk5PX1NUQVRVUykge1xuICAgIGNvbnN0IGNlbGwgPSAkY3JlYXRlVGFibGVDZWxsTm9kZShoZWFkZXJTdGF0ZSkuYXBwZW5kKCRjcmVhdGVQYXJhZ3JhcGhOb2RlKCkpO1xuICAgIGlmIChmaXJzdEluc2VydGVkQ2VsbCA9PT0gbnVsbCkge1xuICAgICAgZmlyc3RJbnNlcnRlZENlbGwgPSBjZWxsO1xuICAgIH1cbiAgICByZXR1cm4gY2VsbDtcbiAgfVxuICBsZXQgbG9vcFJvdyA9IGdyaWRGaXJzdENoaWxkO1xuICByb3dMb29wOiBmb3IgKGxldCBpID0gMDsgaSA8IHJvd0NvdW50OyBpKyspIHtcbiAgICBpZiAoaSAhPT0gMCkge1xuICAgICAgY29uc3QgY3VycmVudFJvdyA9IGxvb3BSb3cuZ2V0TmV4dFNpYmxpbmcoKTtcbiAgICAgIGlmICghJGlzVGFibGVSb3dOb2RlKGN1cnJlbnRSb3cpKSB7XG4gICAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgcm93IG5leHRTaWJsaW5nIHRvIGJlIGEgcm93YCk7XG4gICAgICB9XG4gICAgICBsb29wUm93ID0gY3VycmVudFJvdztcbiAgICB9XG4gICAgY29uc3Qgcm93TWFwID0gZ3JpZE1hcFtpXTtcbiAgICBjb25zdCBjdXJyZW50Q2VsbEhlYWRlclN0YXRlID0gcm93TWFwW2luc2VydEFmdGVyQ29sdW1uIDwgMCA/IDAgOiBpbnNlcnRBZnRlckNvbHVtbl0uY2VsbC5fX2hlYWRlclN0YXRlO1xuICAgIGNvbnN0IGhlYWRlclN0YXRlID0gZ2V0SGVhZGVyU3RhdGUoY3VycmVudENlbGxIZWFkZXJTdGF0ZSwgVGFibGVDZWxsSGVhZGVyU3RhdGVzLlJPVyk7XG4gICAgaWYgKGluc2VydEFmdGVyQ29sdW1uIDwgMCkge1xuICAgICAgJGluc2VydEZpcnN0KGxvb3BSb3csICRjcmVhdGVUYWJsZUNlbGxOb2RlRm9ySW5zZXJ0VGFibGVDb2x1bW4oaGVhZGVyU3RhdGUpKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCB7XG4gICAgICBjZWxsOiBjdXJyZW50Q2VsbCxcbiAgICAgIHN0YXJ0Q29sdW1uOiBjdXJyZW50U3RhcnRDb2x1bW4sXG4gICAgICBzdGFydFJvdzogY3VycmVudFN0YXJ0Um93XG4gICAgfSA9IHJvd01hcFtpbnNlcnRBZnRlckNvbHVtbl07XG4gICAgaWYgKGN1cnJlbnRTdGFydENvbHVtbiArIGN1cnJlbnRDZWxsLl9fY29sU3BhbiAtIDEgPD0gaW5zZXJ0QWZ0ZXJDb2x1bW4pIHtcbiAgICAgIGxldCBpbnNlcnRBZnRlckNlbGwgPSBjdXJyZW50Q2VsbDtcbiAgICAgIGxldCBpbnNlcnRBZnRlckNlbGxSb3dTdGFydCA9IGN1cnJlbnRTdGFydFJvdztcbiAgICAgIGxldCBwcmV2Q2VsbEluZGV4ID0gaW5zZXJ0QWZ0ZXJDb2x1bW47XG4gICAgICB3aGlsZSAoaW5zZXJ0QWZ0ZXJDZWxsUm93U3RhcnQgIT09IGkgJiYgaW5zZXJ0QWZ0ZXJDZWxsLl9fcm93U3BhbiA+IDEpIHtcbiAgICAgICAgcHJldkNlbGxJbmRleCAtPSBjdXJyZW50Q2VsbC5fX2NvbFNwYW47XG4gICAgICAgIGlmIChwcmV2Q2VsbEluZGV4ID49IDApIHtcbiAgICAgICAgICBjb25zdCB7XG4gICAgICAgICAgICBjZWxsOiBjZWxsXyxcbiAgICAgICAgICAgIHN0YXJ0Um93OiBzdGFydFJvd19cbiAgICAgICAgICB9ID0gcm93TWFwW3ByZXZDZWxsSW5kZXhdO1xuICAgICAgICAgIGluc2VydEFmdGVyQ2VsbCA9IGNlbGxfO1xuICAgICAgICAgIGluc2VydEFmdGVyQ2VsbFJvd1N0YXJ0ID0gc3RhcnRSb3dfO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxvb3BSb3cuYXBwZW5kKCRjcmVhdGVUYWJsZUNlbGxOb2RlRm9ySW5zZXJ0VGFibGVDb2x1bW4oaGVhZGVyU3RhdGUpKTtcbiAgICAgICAgICBjb250aW51ZSByb3dMb29wO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpbnNlcnRBZnRlckNlbGwuaW5zZXJ0QWZ0ZXIoJGNyZWF0ZVRhYmxlQ2VsbE5vZGVGb3JJbnNlcnRUYWJsZUNvbHVtbihoZWFkZXJTdGF0ZSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjdXJyZW50Q2VsbC5zZXRDb2xTcGFuKGN1cnJlbnRDZWxsLl9fY29sU3BhbiArIDEpO1xuICAgIH1cbiAgfVxuICBpZiAoZmlyc3RJbnNlcnRlZENlbGwgIT09IG51bGwgJiYgc2hvdWxkU2V0U2VsZWN0aW9uKSB7XG4gICAgJG1vdmVTZWxlY3Rpb25Ub0NlbGwoZmlyc3RJbnNlcnRlZENlbGwpO1xuICB9XG4gIGNvbnN0IGNvbFdpZHRocyA9IGdyaWQuZ2V0Q29sV2lkdGhzKCk7XG4gIGlmIChjb2xXaWR0aHMpIHtcbiAgICBjb25zdCBuZXdDb2xXaWR0aHMgPSBbLi4uY29sV2lkdGhzXTtcbiAgICBjb25zdCBjb2x1bW5JbmRleCA9IGluc2VydEFmdGVyQ29sdW1uIDwgMCA/IDAgOiBpbnNlcnRBZnRlckNvbHVtbjtcbiAgICBjb25zdCBuZXdXaWR0aCA9IG5ld0NvbFdpZHRoc1tjb2x1bW5JbmRleF07XG4gICAgbmV3Q29sV2lkdGhzLnNwbGljZShjb2x1bW5JbmRleCwgMCwgbmV3V2lkdGgpO1xuICAgIGdyaWQuc2V0Q29sV2lkdGhzKG5ld0NvbFdpZHRocyk7XG4gIH1cbiAgcmV0dXJuIGZpcnN0SW5zZXJ0ZWRDZWxsO1xufVxuXG4vKipcbiAqIEBkZXByZWNhdGVkIFRoaXMgZnVuY3Rpb24gZG9lcyBub3Qgc3VwcG9ydCBtZXJnZWQgY2VsbHMuIFVzZSB7QGxpbmsgJGRlbGV0ZVRhYmxlQ29sdW1uQXRTZWxlY3Rpb259IGluc3RlYWQuXG4gKi9cbmZ1bmN0aW9uICRkZWxldGVUYWJsZUNvbHVtbih0YWJsZU5vZGUsIHRhcmdldEluZGV4KSB7XG4gIGNvbnN0IHRhYmxlUm93cyA9IHRhYmxlTm9kZS5nZXRDaGlsZHJlbigpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHRhYmxlUm93cy5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IGN1cnJlbnRUYWJsZVJvd05vZGUgPSB0YWJsZVJvd3NbaV07XG4gICAgaWYgKCRpc1RhYmxlUm93Tm9kZShjdXJyZW50VGFibGVSb3dOb2RlKSkge1xuICAgICAgY29uc3QgdGFibGVSb3dDaGlsZHJlbiA9IGN1cnJlbnRUYWJsZVJvd05vZGUuZ2V0Q2hpbGRyZW4oKTtcbiAgICAgIGlmICh0YXJnZXRJbmRleCA+PSB0YWJsZVJvd0NoaWxkcmVuLmxlbmd0aCB8fCB0YXJnZXRJbmRleCA8IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUYWJsZSBjb2x1bW4gdGFyZ2V0IGluZGV4IG91dCBvZiByYW5nZScpO1xuICAgICAgfVxuICAgICAgdGFibGVSb3dDaGlsZHJlblt0YXJnZXRJbmRleF0ucmVtb3ZlKCk7XG4gICAgfVxuICB9XG4gIHJldHVybiB0YWJsZU5vZGU7XG59XG5mdW5jdGlvbiAkZGVsZXRlVGFibGVSb3dBdFNlbGVjdGlvbigpIHtcbiAgY29uc3Qgc2VsZWN0aW9uID0gJGdldFNlbGVjdGlvbigpO1xuICBpZiAoISgkaXNSYW5nZVNlbGVjdGlvbihzZWxlY3Rpb24pIHx8ICRpc1RhYmxlU2VsZWN0aW9uKHNlbGVjdGlvbikpKSB7XG4gICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCBhIFJhbmdlU2VsZWN0aW9uIG9yIFRhYmxlU2VsZWN0aW9uYCk7XG4gIH1cbiAgY29uc3QgW2FuY2hvciwgZm9jdXNdID0gc2VsZWN0aW9uLmlzQmFja3dhcmQoKSA/IFtzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpLCBzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKV0gOiBbc2VsZWN0aW9uLmFuY2hvci5nZXROb2RlKCksIHNlbGVjdGlvbi5mb2N1cy5nZXROb2RlKCldO1xuICBjb25zdCBbYW5jaG9yQ2VsbCwsIGdyaWRdID0gJGdldE5vZGVUcmlwbGV0KGFuY2hvcik7XG4gIGNvbnN0IFtmb2N1c0NlbGxdID0gJGdldE5vZGVUcmlwbGV0KGZvY3VzKTtcbiAgY29uc3QgW2dyaWRNYXAsIGFuY2hvckNlbGxNYXAsIGZvY3VzQ2VsbE1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwKGdyaWQsIGFuY2hvckNlbGwsIGZvY3VzQ2VsbCk7XG4gIGNvbnN0IHtcbiAgICBzdGFydFJvdzogYW5jaG9yU3RhcnRSb3dcbiAgfSA9IGFuY2hvckNlbGxNYXA7XG4gIGNvbnN0IHtcbiAgICBzdGFydFJvdzogZm9jdXNTdGFydFJvd1xuICB9ID0gZm9jdXNDZWxsTWFwO1xuICBjb25zdCBmb2N1c0VuZFJvdyA9IGZvY3VzU3RhcnRSb3cgKyBmb2N1c0NlbGwuX19yb3dTcGFuIC0gMTtcbiAgaWYgKGdyaWRNYXAubGVuZ3RoID09PSBmb2N1c0VuZFJvdyAtIGFuY2hvclN0YXJ0Um93ICsgMSkge1xuICAgIC8vIEVtcHR5IGdyaWRcbiAgICBncmlkLnJlbW92ZSgpO1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCBjb2x1bW5Db3VudCA9IGdyaWRNYXBbMF0ubGVuZ3RoO1xuICBjb25zdCBuZXh0Um93ID0gZ3JpZE1hcFtmb2N1c0VuZFJvdyArIDFdO1xuICBjb25zdCBuZXh0Um93Tm9kZSA9IGdyaWQuZ2V0Q2hpbGRBdEluZGV4KGZvY3VzRW5kUm93ICsgMSk7XG4gIGZvciAobGV0IHJvdyA9IGZvY3VzRW5kUm93OyByb3cgPj0gYW5jaG9yU3RhcnRSb3c7IHJvdy0tKSB7XG4gICAgZm9yIChsZXQgY29sdW1uID0gY29sdW1uQ291bnQgLSAxOyBjb2x1bW4gPj0gMDsgY29sdW1uLS0pIHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgY2VsbCxcbiAgICAgICAgc3RhcnRSb3c6IGNlbGxTdGFydFJvdyxcbiAgICAgICAgc3RhcnRDb2x1bW46IGNlbGxTdGFydENvbHVtblxuICAgICAgfSA9IGdyaWRNYXBbcm93XVtjb2x1bW5dO1xuICAgICAgaWYgKGNlbGxTdGFydENvbHVtbiAhPT0gY29sdW1uKSB7XG4gICAgICAgIC8vIERvbid0IHJlcGVhdCB3b3JrIGZvciB0aGUgc2FtZSBDZWxsXG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgLy8gUm93cyBvdmVyZmxvd2luZyB0b3Agb3IgYm90dG9tIGhhdmUgdG8gYmUgdHJpbW1lZFxuICAgICAgaWYgKGNlbGxTdGFydFJvdyA8IGFuY2hvclN0YXJ0Um93IHx8IGNlbGxTdGFydFJvdyArIGNlbGwuX19yb3dTcGFuIC0gMSA+IGZvY3VzRW5kUm93KSB7XG4gICAgICAgIGNvbnN0IGludGVyc2VjdGlvblN0YXJ0ID0gTWF0aC5tYXgoY2VsbFN0YXJ0Um93LCBhbmNob3JTdGFydFJvdyk7XG4gICAgICAgIGNvbnN0IGludGVyc2VjdGlvbkVuZCA9IE1hdGgubWluKGNlbGwuX19yb3dTcGFuICsgY2VsbFN0YXJ0Um93IC0gMSwgZm9jdXNFbmRSb3cpO1xuICAgICAgICBjb25zdCBvdmVyZmxvd1Jvd3NDb3VudCA9IGludGVyc2VjdGlvblN0YXJ0IDw9IGludGVyc2VjdGlvbkVuZCA/IGludGVyc2VjdGlvbkVuZCAtIGludGVyc2VjdGlvblN0YXJ0ICsgMSA6IDA7XG4gICAgICAgIGNlbGwuc2V0Um93U3BhbihjZWxsLl9fcm93U3BhbiAtIG92ZXJmbG93Um93c0NvdW50KTtcbiAgICAgIH1cbiAgICAgIC8vIFJvd3Mgb3ZlcmZsb3dpbmcgYm90dG9tIGhhdmUgdG8gYmUgbW92ZWQgdG8gdGhlIG5leHQgcm93XG4gICAgICBpZiAoY2VsbFN0YXJ0Um93ID49IGFuY2hvclN0YXJ0Um93ICYmIGNlbGxTdGFydFJvdyArIGNlbGwuX19yb3dTcGFuIC0gMSA+IGZvY3VzRW5kUm93ICYmXG4gICAgICAvLyBIYW5kbGUgb3ZlcmZsb3cgb25seSBvbmNlXG4gICAgICByb3cgPT09IGZvY3VzRW5kUm93KSB7XG4gICAgICAgIGlmICghKG5leHRSb3dOb2RlICE9PSBudWxsKSkge1xuICAgICAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgbmV4dFJvd05vZGUgbm90IHRvIGJlIG51bGxgKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgaW5zZXJ0QWZ0ZXJDZWxsID0gbnVsbDtcbiAgICAgICAgZm9yIChsZXQgY29sdW1uSW5kZXggPSAwOyBjb2x1bW5JbmRleCA8IGNvbHVtbjsgY29sdW1uSW5kZXgrKykge1xuICAgICAgICAgIGNvbnN0IGN1cnJlbnRDZWxsTWFwID0gbmV4dFJvd1tjb2x1bW5JbmRleF07XG4gICAgICAgICAgY29uc3QgY3VycmVudENlbGwgPSBjdXJyZW50Q2VsbE1hcC5jZWxsO1xuICAgICAgICAgIC8vIENoZWNraW5nIHRoZSBjZWxsIGhhdmluZyBzdGFydFJvdyBhcyBzYW1lIGFzIG5leHRSb3dcbiAgICAgICAgICBpZiAoY3VycmVudENlbGxNYXAuc3RhcnRSb3cgPT09IHJvdyArIDEpIHtcbiAgICAgICAgICAgIGluc2VydEFmdGVyQ2VsbCA9IGN1cnJlbnRDZWxsO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoY3VycmVudENlbGwuX19jb2xTcGFuID4gMSkge1xuICAgICAgICAgICAgY29sdW1uSW5kZXggKz0gY3VycmVudENlbGwuX19jb2xTcGFuIC0gMTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGluc2VydEFmdGVyQ2VsbCA9PT0gbnVsbCkge1xuICAgICAgICAgICRpbnNlcnRGaXJzdChuZXh0Um93Tm9kZSwgY2VsbCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaW5zZXJ0QWZ0ZXJDZWxsLmluc2VydEFmdGVyKGNlbGwpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIGNvbnN0IHJvd05vZGUgPSBncmlkLmdldENoaWxkQXRJbmRleChyb3cpO1xuICAgIGlmICghJGlzVGFibGVSb3dOb2RlKHJvd05vZGUpKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIFRhYmxlTm9kZSBjaGlsZEF0SW5kZXgoJHtTdHJpbmcocm93KX0pIHRvIGJlIFJvd05vZGVgKTtcbiAgICB9XG4gICAgcm93Tm9kZS5yZW1vdmUoKTtcbiAgfVxuICBpZiAobmV4dFJvdyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3Qge1xuICAgICAgY2VsbFxuICAgIH0gPSBuZXh0Um93WzBdO1xuICAgICRtb3ZlU2VsZWN0aW9uVG9DZWxsKGNlbGwpO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IHByZXZpb3VzUm93ID0gZ3JpZE1hcFthbmNob3JTdGFydFJvdyAtIDFdO1xuICAgIGNvbnN0IHtcbiAgICAgIGNlbGxcbiAgICB9ID0gcHJldmlvdXNSb3dbMF07XG4gICAgJG1vdmVTZWxlY3Rpb25Ub0NlbGwoY2VsbCk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVwcmVjYXRlZCByZW5hbWVkIHRvIHtAbGluayAkZGVsZXRlVGFibGVSb3dBdFNlbGVjdGlvbn1cbiAqL1xuY29uc3QgJGRlbGV0ZVRhYmxlUm93X19FWFBFUklNRU5UQUwgPSAkZGVsZXRlVGFibGVSb3dBdFNlbGVjdGlvbjtcbmZ1bmN0aW9uICRkZWxldGVUYWJsZUNvbHVtbkF0U2VsZWN0aW9uKCkge1xuICBjb25zdCBzZWxlY3Rpb24gPSAkZ2V0U2VsZWN0aW9uKCk7XG4gIGlmICghKCRpc1JhbmdlU2VsZWN0aW9uKHNlbGVjdGlvbikgfHwgJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSkpIHtcbiAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIGEgUmFuZ2VTZWxlY3Rpb24gb3IgVGFibGVTZWxlY3Rpb25gKTtcbiAgfVxuICBjb25zdCBhbmNob3IgPSBzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKTtcbiAgY29uc3QgZm9jdXMgPSBzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpO1xuICBjb25zdCBbYW5jaG9yQ2VsbCwsIGdyaWRdID0gJGdldE5vZGVUcmlwbGV0KGFuY2hvcik7XG4gIGNvbnN0IFtmb2N1c0NlbGxdID0gJGdldE5vZGVUcmlwbGV0KGZvY3VzKTtcbiAgY29uc3QgW2dyaWRNYXAsIGFuY2hvckNlbGxNYXAsIGZvY3VzQ2VsbE1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwKGdyaWQsIGFuY2hvckNlbGwsIGZvY3VzQ2VsbCk7XG4gIGNvbnN0IHtcbiAgICBzdGFydENvbHVtbjogYW5jaG9yU3RhcnRDb2x1bW5cbiAgfSA9IGFuY2hvckNlbGxNYXA7XG4gIGNvbnN0IHtcbiAgICBzdGFydFJvdzogZm9jdXNTdGFydFJvdyxcbiAgICBzdGFydENvbHVtbjogZm9jdXNTdGFydENvbHVtblxuICB9ID0gZm9jdXNDZWxsTWFwO1xuICBjb25zdCBzdGFydENvbHVtbiA9IE1hdGgubWluKGFuY2hvclN0YXJ0Q29sdW1uLCBmb2N1c1N0YXJ0Q29sdW1uKTtcbiAgY29uc3QgZW5kQ29sdW1uID0gTWF0aC5tYXgoYW5jaG9yU3RhcnRDb2x1bW4gKyBhbmNob3JDZWxsLl9fY29sU3BhbiAtIDEsIGZvY3VzU3RhcnRDb2x1bW4gKyBmb2N1c0NlbGwuX19jb2xTcGFuIC0gMSk7XG4gIGNvbnN0IHNlbGVjdGVkQ29sdW1uQ291bnQgPSBlbmRDb2x1bW4gLSBzdGFydENvbHVtbiArIDE7XG4gIGNvbnN0IGNvbHVtbkNvdW50ID0gZ3JpZE1hcFswXS5sZW5ndGg7XG4gIGlmIChjb2x1bW5Db3VudCA9PT0gZW5kQ29sdW1uIC0gc3RhcnRDb2x1bW4gKyAxKSB7XG4gICAgLy8gRW1wdHkgZ3JpZFxuICAgIGdyaWQuc2VsZWN0UHJldmlvdXMoKTtcbiAgICBncmlkLnJlbW92ZSgpO1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCByb3dDb3VudCA9IGdyaWRNYXAubGVuZ3RoO1xuICBmb3IgKGxldCByb3cgPSAwOyByb3cgPCByb3dDb3VudDsgcm93KyspIHtcbiAgICBmb3IgKGxldCBjb2x1bW4gPSBzdGFydENvbHVtbjsgY29sdW1uIDw9IGVuZENvbHVtbjsgY29sdW1uKyspIHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgY2VsbCxcbiAgICAgICAgc3RhcnRDb2x1bW46IGNlbGxTdGFydENvbHVtblxuICAgICAgfSA9IGdyaWRNYXBbcm93XVtjb2x1bW5dO1xuICAgICAgaWYgKGNlbGxTdGFydENvbHVtbiA8IHN0YXJ0Q29sdW1uKSB7XG4gICAgICAgIGlmIChjb2x1bW4gPT09IHN0YXJ0Q29sdW1uKSB7XG4gICAgICAgICAgY29uc3Qgb3ZlcmZsb3dMZWZ0ID0gc3RhcnRDb2x1bW4gLSBjZWxsU3RhcnRDb2x1bW47XG4gICAgICAgICAgLy8gT3ZlcmZsb3dpbmcgbGVmdFxuICAgICAgICAgIGNlbGwuc2V0Q29sU3BhbihjZWxsLl9fY29sU3BhbiAtXG4gICAgICAgICAgLy8gUG9zc2libGUgb3ZlcmZsb3cgcmlnaHQgdG9vXG4gICAgICAgICAgTWF0aC5taW4oc2VsZWN0ZWRDb2x1bW5Db3VudCwgY2VsbC5fX2NvbFNwYW4gLSBvdmVyZmxvd0xlZnQpKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChjZWxsU3RhcnRDb2x1bW4gKyBjZWxsLl9fY29sU3BhbiAtIDEgPiBlbmRDb2x1bW4pIHtcbiAgICAgICAgaWYgKGNvbHVtbiA9PT0gZW5kQ29sdW1uKSB7XG4gICAgICAgICAgLy8gT3ZlcmZsb3dpbmcgcmlnaHRcbiAgICAgICAgICBjb25zdCBpblNlbGVjdGVkQXJlYSA9IGVuZENvbHVtbiAtIGNlbGxTdGFydENvbHVtbiArIDE7XG4gICAgICAgICAgY2VsbC5zZXRDb2xTcGFuKGNlbGwuX19jb2xTcGFuIC0gaW5TZWxlY3RlZEFyZWEpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjZWxsLnJlbW92ZSgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBjb25zdCBmb2N1c1Jvd01hcCA9IGdyaWRNYXBbZm9jdXNTdGFydFJvd107XG4gIGNvbnN0IG5leHRDb2x1bW4gPSBhbmNob3JTdGFydENvbHVtbiA+IGZvY3VzU3RhcnRDb2x1bW4gPyBmb2N1c1Jvd01hcFthbmNob3JTdGFydENvbHVtbiArIGFuY2hvckNlbGwuX19jb2xTcGFuXSA6IGZvY3VzUm93TWFwW2ZvY3VzU3RhcnRDb2x1bW4gKyBmb2N1c0NlbGwuX19jb2xTcGFuXTtcbiAgaWYgKG5leHRDb2x1bW4gIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IHtcbiAgICAgIGNlbGxcbiAgICB9ID0gbmV4dENvbHVtbjtcbiAgICAkbW92ZVNlbGVjdGlvblRvQ2VsbChjZWxsKTtcbiAgfSBlbHNlIHtcbiAgICBjb25zdCBwcmV2aW91c1JvdyA9IGZvY3VzU3RhcnRDb2x1bW4gPCBhbmNob3JTdGFydENvbHVtbiA/IGZvY3VzUm93TWFwW2ZvY3VzU3RhcnRDb2x1bW4gLSAxXSA6IGZvY3VzUm93TWFwW2FuY2hvclN0YXJ0Q29sdW1uIC0gMV07XG4gICAgY29uc3Qge1xuICAgICAgY2VsbFxuICAgIH0gPSBwcmV2aW91c1JvdztcbiAgICAkbW92ZVNlbGVjdGlvblRvQ2VsbChjZWxsKTtcbiAgfVxuICBjb25zdCBjb2xXaWR0aHMgPSBncmlkLmdldENvbFdpZHRocygpO1xuICBpZiAoY29sV2lkdGhzKSB7XG4gICAgY29uc3QgbmV3Q29sV2lkdGhzID0gWy4uLmNvbFdpZHRoc107XG4gICAgbmV3Q29sV2lkdGhzLnNwbGljZShzdGFydENvbHVtbiwgc2VsZWN0ZWRDb2x1bW5Db3VudCk7XG4gICAgZ3JpZC5zZXRDb2xXaWR0aHMobmV3Q29sV2lkdGhzKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXByZWNhdGVkIHJlbmFtZWQgdG8ge0BsaW5rICRkZWxldGVUYWJsZUNvbHVtbkF0U2VsZWN0aW9ufVxuICovXG5jb25zdCAkZGVsZXRlVGFibGVDb2x1bW5fX0VYUEVSSU1FTlRBTCA9ICRkZWxldGVUYWJsZUNvbHVtbkF0U2VsZWN0aW9uO1xuZnVuY3Rpb24gJG1vdmVTZWxlY3Rpb25Ub0NlbGwoY2VsbCkge1xuICBjb25zdCBmaXJzdERlc2NlbmRhbnQgPSBjZWxsLmdldEZpcnN0RGVzY2VuZGFudCgpO1xuICBpZiAoZmlyc3REZXNjZW5kYW50ID09IG51bGwpIHtcbiAgICBjZWxsLnNlbGVjdFN0YXJ0KCk7XG4gIH0gZWxzZSB7XG4gICAgZmlyc3REZXNjZW5kYW50LmdldFBhcmVudE9yVGhyb3coKS5zZWxlY3RTdGFydCgpO1xuICB9XG59XG5mdW5jdGlvbiAkaW5zZXJ0Rmlyc3QocGFyZW50LCBub2RlKSB7XG4gIGNvbnN0IGZpcnN0Q2hpbGQgPSBwYXJlbnQuZ2V0Rmlyc3RDaGlsZCgpO1xuICBpZiAoZmlyc3RDaGlsZCAhPT0gbnVsbCkge1xuICAgIGZpcnN0Q2hpbGQuaW5zZXJ0QmVmb3JlKG5vZGUpO1xuICB9IGVsc2Uge1xuICAgIHBhcmVudC5hcHBlbmQobm9kZSk7XG4gIH1cbn1cbmZ1bmN0aW9uICRtZXJnZUNlbGxzKGNlbGxOb2Rlcykge1xuICBpZiAoY2VsbE5vZGVzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLy8gRmluZCB0aGUgdGFibGUgbm9kZVxuICBjb25zdCB0YWJsZU5vZGUgPSAkZ2V0VGFibGVOb2RlRnJvbUxleGljYWxOb2RlT3JUaHJvdyhjZWxsTm9kZXNbMF0pO1xuICBjb25zdCBbZ3JpZE1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwU2tpcENlbGxDaGVjayh0YWJsZU5vZGUsIG51bGwsIG51bGwpO1xuXG4gIC8vIEZpbmQgdGhlIGJvdW5kYXJpZXMgb2YgdGhlIHNlbGVjdGlvbiBpbmNsdWRpbmcgbWVyZ2VkIGNlbGxzXG4gIGxldCBtaW5Sb3cgPSBJbmZpbml0eTtcbiAgbGV0IG1heFJvdyA9IC1JbmZpbml0eTtcbiAgbGV0IG1pbkNvbCA9IEluZmluaXR5O1xuICBsZXQgbWF4Q29sID0gLUluZmluaXR5O1xuXG4gIC8vIEZpcnN0IHBhc3M6IGZpbmQgdGhlIGFjdHVhbCBib3VuZGFyaWVzIGNvbnNpZGVyaW5nIG1lcmdlZCBjZWxsc1xuICBjb25zdCBwcm9jZXNzZWRDZWxscyA9IG5ldyBTZXQoKTtcbiAgZm9yIChjb25zdCByb3cgb2YgZ3JpZE1hcCkge1xuICAgIGZvciAoY29uc3QgbWFwQ2VsbCBvZiByb3cpIHtcbiAgICAgIGlmICghbWFwQ2VsbCB8fCAhbWFwQ2VsbC5jZWxsKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgY2VsbEtleSA9IG1hcENlbGwuY2VsbC5nZXRLZXkoKTtcbiAgICAgIGlmIChwcm9jZXNzZWRDZWxscy5oYXMoY2VsbEtleSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAoY2VsbE5vZGVzLnNvbWUoY2VsbCA9PiBjZWxsLmlzKG1hcENlbGwuY2VsbCkpKSB7XG4gICAgICAgIHByb2Nlc3NlZENlbGxzLmFkZChjZWxsS2V5KTtcbiAgICAgICAgLy8gR2V0IHRoZSBhY3R1YWwgcG9zaXRpb24gb2YgdGhpcyBjZWxsIGluIHRoZSBncmlkXG4gICAgICAgIGNvbnN0IGNlbGxTdGFydFJvdyA9IG1hcENlbGwuc3RhcnRSb3c7XG4gICAgICAgIGNvbnN0IGNlbGxTdGFydENvbCA9IG1hcENlbGwuc3RhcnRDb2x1bW47XG4gICAgICAgIGNvbnN0IGNlbGxSb3dTcGFuID0gbWFwQ2VsbC5jZWxsLl9fcm93U3BhbiB8fCAxO1xuICAgICAgICBjb25zdCBjZWxsQ29sU3BhbiA9IG1hcENlbGwuY2VsbC5fX2NvbFNwYW4gfHwgMTtcblxuICAgICAgICAvLyBVcGRhdGUgYm91bmRhcmllcyBjb25zaWRlcmluZyB0aGUgY2VsbCdzIGFjdHVhbCBwb3NpdGlvbiBhbmQgc3BhblxuICAgICAgICBtaW5Sb3cgPSBNYXRoLm1pbihtaW5Sb3csIGNlbGxTdGFydFJvdyk7XG4gICAgICAgIG1heFJvdyA9IE1hdGgubWF4KG1heFJvdywgY2VsbFN0YXJ0Um93ICsgY2VsbFJvd1NwYW4gLSAxKTtcbiAgICAgICAgbWluQ29sID0gTWF0aC5taW4obWluQ29sLCBjZWxsU3RhcnRDb2wpO1xuICAgICAgICBtYXhDb2wgPSBNYXRoLm1heChtYXhDb2wsIGNlbGxTdGFydENvbCArIGNlbGxDb2xTcGFuIC0gMSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gVmFsaWRhdGUgYm91bmRhcmllc1xuICBpZiAobWluUm93ID09PSBJbmZpbml0eSB8fCBtaW5Db2wgPT09IEluZmluaXR5KSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvLyBUaGUgdG90YWwgc3BhbiBvZiB0aGUgbWVyZ2VkIGNlbGxcbiAgY29uc3QgdG90YWxSb3dTcGFuID0gbWF4Um93IC0gbWluUm93ICsgMTtcbiAgY29uc3QgdG90YWxDb2xTcGFuID0gbWF4Q29sIC0gbWluQ29sICsgMTtcblxuICAvLyBVc2UgdGhlIHRvcC1sZWZ0IGNlbGwgYXMgdGhlIHRhcmdldCBjZWxsXG4gIGNvbnN0IHRhcmdldENlbGxNYXAgPSBncmlkTWFwW21pblJvd11bbWluQ29sXTtcbiAgaWYgKCF0YXJnZXRDZWxsTWFwLmNlbGwpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBjb25zdCB0YXJnZXRDZWxsID0gdGFyZ2V0Q2VsbE1hcC5jZWxsO1xuXG4gIC8vIFNldCB0aGUgc3BhbnMgZm9yIHRoZSB0YXJnZXQgY2VsbFxuICB0YXJnZXRDZWxsLnNldENvbFNwYW4odG90YWxDb2xTcGFuKTtcbiAgdGFyZ2V0Q2VsbC5zZXRSb3dTcGFuKHRvdGFsUm93U3Bhbik7XG5cbiAgLy8gTW92ZSBjb250ZW50IGZyb20gb3RoZXIgY2VsbHMgdG8gdGhlIHRhcmdldCBjZWxsXG4gIGNvbnN0IHNlZW5DZWxscyA9IG5ldyBTZXQoW3RhcmdldENlbGwuZ2V0S2V5KCldKTtcblxuICAvLyBTZWNvbmQgcGFzczogbWVyZ2UgY29udGVudCBhbmQgcmVtb3ZlIG90aGVyIGNlbGxzXG4gIGZvciAobGV0IHJvdyA9IG1pblJvdzsgcm93IDw9IG1heFJvdzsgcm93KyspIHtcbiAgICBmb3IgKGxldCBjb2wgPSBtaW5Db2w7IGNvbCA8PSBtYXhDb2w7IGNvbCsrKSB7XG4gICAgICBjb25zdCBtYXBDZWxsID0gZ3JpZE1hcFtyb3ddW2NvbF07XG4gICAgICBpZiAoIW1hcENlbGwuY2VsbCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGN1cnJlbnRDZWxsID0gbWFwQ2VsbC5jZWxsO1xuICAgICAgY29uc3Qga2V5ID0gY3VycmVudENlbGwuZ2V0S2V5KCk7XG4gICAgICBpZiAoIXNlZW5DZWxscy5oYXMoa2V5KSkge1xuICAgICAgICBzZWVuQ2VsbHMuYWRkKGtleSk7XG4gICAgICAgIGNvbnN0IGlzRW1wdHkgPSAkY2VsbENvbnRhaW5zRW1wdHlQYXJhZ3JhcGgoY3VycmVudENlbGwpO1xuICAgICAgICBpZiAoIWlzRW1wdHkpIHtcbiAgICAgICAgICB0YXJnZXRDZWxsLmFwcGVuZCguLi5jdXJyZW50Q2VsbC5nZXRDaGlsZHJlbigpKTtcbiAgICAgICAgfVxuICAgICAgICBjdXJyZW50Q2VsbC5yZW1vdmUoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBFbnN1cmUgdGFyZ2V0IGNlbGwgaGFzIGNvbnRlbnRcbiAgaWYgKHRhcmdldENlbGwuZ2V0Q2hpbGRyZW5TaXplKCkgPT09IDApIHtcbiAgICB0YXJnZXRDZWxsLmFwcGVuZCgkY3JlYXRlUGFyYWdyYXBoTm9kZSgpKTtcbiAgfVxuICByZXR1cm4gdGFyZ2V0Q2VsbDtcbn1cbmZ1bmN0aW9uICRjZWxsQ29udGFpbnNFbXB0eVBhcmFncmFwaChjZWxsKSB7XG4gIGlmIChjZWxsLmdldENoaWxkcmVuU2l6ZSgpICE9PSAxKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IGZpcnN0Q2hpbGQgPSBjZWxsLmdldEZpcnN0Q2hpbGRPclRocm93KCk7XG4gIGlmICghJGlzUGFyYWdyYXBoTm9kZShmaXJzdENoaWxkKSB8fCAhZmlyc3RDaGlsZC5pc0VtcHR5KCkpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiAkdW5tZXJnZUNlbGwoKSB7XG4gIGNvbnN0IHNlbGVjdGlvbiA9ICRnZXRTZWxlY3Rpb24oKTtcbiAgaWYgKCEoJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSB8fCAkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgYSBSYW5nZVNlbGVjdGlvbiBvciBUYWJsZVNlbGVjdGlvbmApO1xuICB9XG4gIGNvbnN0IGFuY2hvciA9IHNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpO1xuICBjb25zdCBjZWxsTm9kZSA9ICRmaW5kTWF0Y2hpbmdQYXJlbnQoYW5jaG9yLCAkaXNUYWJsZUNlbGxOb2RlKTtcbiAgaWYgKCEkaXNUYWJsZUNlbGxOb2RlKGNlbGxOb2RlKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgdG8gZmluZCBhIHBhcmVudCBUYWJsZUNlbGxOb2RlYCk7XG4gIH1cbiAgcmV0dXJuICR1bm1lcmdlQ2VsbE5vZGUoY2VsbE5vZGUpO1xufVxuZnVuY3Rpb24gJHVubWVyZ2VDZWxsTm9kZShjZWxsTm9kZSkge1xuICBjb25zdCBbY2VsbCwgcm93LCBncmlkXSA9ICRnZXROb2RlVHJpcGxldChjZWxsTm9kZSk7XG4gIGNvbnN0IGNvbFNwYW4gPSBjZWxsLl9fY29sU3BhbjtcbiAgY29uc3Qgcm93U3BhbiA9IGNlbGwuX19yb3dTcGFuO1xuICBpZiAoY29sU3BhbiA9PT0gMSAmJiByb3dTcGFuID09PSAxKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IFttYXAsIGNlbGxNYXBdID0gJGNvbXB1dGVUYWJsZU1hcChncmlkLCBjZWxsLCBjZWxsKTtcbiAgY29uc3Qge1xuICAgIHN0YXJ0Q29sdW1uLFxuICAgIHN0YXJ0Um93XG4gIH0gPSBjZWxsTWFwO1xuICAvLyBDcmVhdGUgYSBoZXVyaXN0aWMgZm9yIHdoYXQgdGhlIHN0eWxlIG9mIHRoZSB1bm1lcmdlZCBjZWxscyBzaG91bGQgYmVcbiAgLy8gYmFzZWQgb24gd2hldGhlciBldmVyeSByb3cgb3IgY29sdW1uIGFscmVhZHkgaGFkIHRoYXQgc3RhdGUgYmVmb3JlIHRoZVxuICAvLyB1bm1lcmdlLlxuICBjb25zdCBiYXNlQ29sU3R5bGUgPSBjZWxsLl9faGVhZGVyU3RhdGUgJiBUYWJsZUNlbGxIZWFkZXJTdGF0ZXMuQ09MVU1OO1xuICBjb25zdCBjb2xTdHlsZXMgPSBBcnJheS5mcm9tKHtcbiAgICBsZW5ndGg6IGNvbFNwYW5cbiAgfSwgKF92LCBpKSA9PiB7XG4gICAgbGV0IGNvbFN0eWxlID0gYmFzZUNvbFN0eWxlO1xuICAgIGZvciAobGV0IHJvd0lkeCA9IDA7IGNvbFN0eWxlICE9PSAwICYmIHJvd0lkeCA8IG1hcC5sZW5ndGg7IHJvd0lkeCsrKSB7XG4gICAgICBjb2xTdHlsZSAmPSBtYXBbcm93SWR4XVtpICsgc3RhcnRDb2x1bW5dLmNlbGwuX19oZWFkZXJTdGF0ZTtcbiAgICB9XG4gICAgcmV0dXJuIGNvbFN0eWxlO1xuICB9KTtcbiAgY29uc3QgYmFzZVJvd1N0eWxlID0gY2VsbC5fX2hlYWRlclN0YXRlICYgVGFibGVDZWxsSGVhZGVyU3RhdGVzLlJPVztcbiAgY29uc3Qgcm93U3R5bGVzID0gQXJyYXkuZnJvbSh7XG4gICAgbGVuZ3RoOiByb3dTcGFuXG4gIH0sIChfdiwgaSkgPT4ge1xuICAgIGxldCByb3dTdHlsZSA9IGJhc2VSb3dTdHlsZTtcbiAgICBmb3IgKGxldCBjb2xJZHggPSAwOyByb3dTdHlsZSAhPT0gMCAmJiBjb2xJZHggPCBtYXBbMF0ubGVuZ3RoOyBjb2xJZHgrKykge1xuICAgICAgcm93U3R5bGUgJj0gbWFwW2kgKyBzdGFydFJvd11bY29sSWR4XS5jZWxsLl9faGVhZGVyU3RhdGU7XG4gICAgfVxuICAgIHJldHVybiByb3dTdHlsZTtcbiAgfSk7XG4gIGlmIChjb2xTcGFuID4gMSkge1xuICAgIGZvciAobGV0IGkgPSAxOyBpIDwgY29sU3BhbjsgaSsrKSB7XG4gICAgICBjZWxsLmluc2VydEFmdGVyKCRjcmVhdGVUYWJsZUNlbGxOb2RlKGNvbFN0eWxlc1tpXSB8IHJvd1N0eWxlc1swXSkuYXBwZW5kKCRjcmVhdGVQYXJhZ3JhcGhOb2RlKCkpKTtcbiAgICB9XG4gICAgY2VsbC5zZXRDb2xTcGFuKDEpO1xuICB9XG4gIGlmIChyb3dTcGFuID4gMSkge1xuICAgIGxldCBjdXJyZW50Um93Tm9kZTtcbiAgICBmb3IgKGxldCBpID0gMTsgaSA8IHJvd1NwYW47IGkrKykge1xuICAgICAgY29uc3QgY3VycmVudFJvdyA9IHN0YXJ0Um93ICsgaTtcbiAgICAgIGNvbnN0IGN1cnJlbnRSb3dNYXAgPSBtYXBbY3VycmVudFJvd107XG4gICAgICBjdXJyZW50Um93Tm9kZSA9IChjdXJyZW50Um93Tm9kZSB8fCByb3cpLmdldE5leHRTaWJsaW5nKCk7XG4gICAgICBpZiAoISRpc1RhYmxlUm93Tm9kZShjdXJyZW50Um93Tm9kZSkpIHtcbiAgICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCByb3cgbmV4dCBzaWJsaW5nIHRvIGJlIGEgcm93YCk7XG4gICAgICB9XG4gICAgICBsZXQgaW5zZXJ0QWZ0ZXJDZWxsID0gbnVsbDtcbiAgICAgIGZvciAobGV0IGNvbHVtbiA9IDA7IGNvbHVtbiA8IHN0YXJ0Q29sdW1uOyBjb2x1bW4rKykge1xuICAgICAgICBjb25zdCBjdXJyZW50Q2VsbE1hcCA9IGN1cnJlbnRSb3dNYXBbY29sdW1uXTtcbiAgICAgICAgY29uc3QgY3VycmVudENlbGwgPSBjdXJyZW50Q2VsbE1hcC5jZWxsO1xuICAgICAgICBpZiAoY3VycmVudENlbGxNYXAuc3RhcnRSb3cgPT09IGN1cnJlbnRSb3cpIHtcbiAgICAgICAgICBpbnNlcnRBZnRlckNlbGwgPSBjdXJyZW50Q2VsbDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY3VycmVudENlbGwuX19jb2xTcGFuID4gMSkge1xuICAgICAgICAgIGNvbHVtbiArPSBjdXJyZW50Q2VsbC5fX2NvbFNwYW4gLSAxO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoaW5zZXJ0QWZ0ZXJDZWxsID09PSBudWxsKSB7XG4gICAgICAgIGZvciAobGV0IGogPSBjb2xTcGFuIC0gMTsgaiA+PSAwOyBqLS0pIHtcbiAgICAgICAgICAkaW5zZXJ0Rmlyc3QoY3VycmVudFJvd05vZGUsICRjcmVhdGVUYWJsZUNlbGxOb2RlKGNvbFN0eWxlc1tqXSB8IHJvd1N0eWxlc1tpXSkuYXBwZW5kKCRjcmVhdGVQYXJhZ3JhcGhOb2RlKCkpKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm9yIChsZXQgaiA9IGNvbFNwYW4gLSAxOyBqID49IDA7IGotLSkge1xuICAgICAgICAgIGluc2VydEFmdGVyQ2VsbC5pbnNlcnRBZnRlcigkY3JlYXRlVGFibGVDZWxsTm9kZShjb2xTdHlsZXNbal0gfCByb3dTdHlsZXNbaV0pLmFwcGVuZCgkY3JlYXRlUGFyYWdyYXBoTm9kZSgpKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgY2VsbC5zZXRSb3dTcGFuKDEpO1xuICB9XG59XG5mdW5jdGlvbiAkY29tcHV0ZVRhYmxlTWFwKHRhYmxlTm9kZSwgY2VsbEEsIGNlbGxCKSB7XG4gIGNvbnN0IFt0YWJsZU1hcCwgY2VsbEFWYWx1ZSwgY2VsbEJWYWx1ZV0gPSAkY29tcHV0ZVRhYmxlTWFwU2tpcENlbGxDaGVjayh0YWJsZU5vZGUsIGNlbGxBLCBjZWxsQik7XG4gIGlmICghKGNlbGxBVmFsdWUgIT09IG51bGwpKSB7XG4gICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBBbmNob3Igbm90IGZvdW5kIGluIFRhYmxlYCk7XG4gIH1cbiAgaWYgKCEoY2VsbEJWYWx1ZSAhPT0gbnVsbCkpIHtcbiAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEZvY3VzIG5vdCBmb3VuZCBpbiBUYWJsZWApO1xuICB9XG4gIHJldHVybiBbdGFibGVNYXAsIGNlbGxBVmFsdWUsIGNlbGxCVmFsdWVdO1xufVxuZnVuY3Rpb24gJGNvbXB1dGVUYWJsZU1hcFNraXBDZWxsQ2hlY2sodGFibGVOb2RlLCBjZWxsQSwgY2VsbEIpIHtcbiAgY29uc3QgdGFibGVNYXAgPSBbXTtcbiAgbGV0IGNlbGxBVmFsdWUgPSBudWxsO1xuICBsZXQgY2VsbEJWYWx1ZSA9IG51bGw7XG4gIGZ1bmN0aW9uIGdldE1hcFJvdyhpKSB7XG4gICAgbGV0IHJvdyA9IHRhYmxlTWFwW2ldO1xuICAgIGlmIChyb3cgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGFibGVNYXBbaV0gPSByb3cgPSBbXTtcbiAgICB9XG4gICAgcmV0dXJuIHJvdztcbiAgfVxuICBjb25zdCBncmlkQ2hpbGRyZW4gPSB0YWJsZU5vZGUuZ2V0Q2hpbGRyZW4oKTtcbiAgZm9yIChsZXQgcm93SWR4ID0gMDsgcm93SWR4IDwgZ3JpZENoaWxkcmVuLmxlbmd0aDsgcm93SWR4KyspIHtcbiAgICBjb25zdCByb3cgPSBncmlkQ2hpbGRyZW5bcm93SWR4XTtcbiAgICBpZiAoISRpc1RhYmxlUm93Tm9kZShyb3cpKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIFRhYmxlTm9kZSBjaGlsZHJlbiB0byBiZSBUYWJsZVJvd05vZGVgKTtcbiAgICB9XG4gICAgY29uc3Qgc3RhcnRNYXBSb3cgPSBnZXRNYXBSb3cocm93SWR4KTtcbiAgICBmb3IgKGxldCBjZWxsID0gcm93LmdldEZpcnN0Q2hpbGQoKSwgY29sSWR4ID0gMDsgY2VsbCAhPSBudWxsOyBjZWxsID0gY2VsbC5nZXROZXh0U2libGluZygpKSB7XG4gICAgICBpZiAoISRpc1RhYmxlQ2VsbE5vZGUoY2VsbCkpIHtcbiAgICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCBUYWJsZVJvd05vZGUgY2hpbGRyZW4gdG8gYmUgVGFibGVDZWxsTm9kZWApO1xuICAgICAgfSAvLyBTa2lwIHBhc3QgYW55IGNvbHVtbnMgdGhhdCB3ZXJlIG1lcmdlZCBmcm9tIGEgaGlnaGVyIHJvd1xuICAgICAgd2hpbGUgKHN0YXJ0TWFwUm93W2NvbElkeF0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb2xJZHgrKztcbiAgICAgIH1cbiAgICAgIGNvbnN0IHZhbHVlID0ge1xuICAgICAgICBjZWxsLFxuICAgICAgICBzdGFydENvbHVtbjogY29sSWR4LFxuICAgICAgICBzdGFydFJvdzogcm93SWR4XG4gICAgICB9O1xuICAgICAgY29uc3Qge1xuICAgICAgICBfX3Jvd1NwYW46IHJvd1NwYW4sXG4gICAgICAgIF9fY29sU3BhbjogY29sU3BhblxuICAgICAgfSA9IGNlbGw7XG4gICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHJvd1NwYW47IGorKykge1xuICAgICAgICBpZiAocm93SWR4ICsgaiA+PSBncmlkQ2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgLy8gVGhlIHRhYmxlIGlzIG5vbi1yZWN0YW5ndWxhciB3aXRoIGEgcm93U3BhblxuICAgICAgICAgIC8vIGJlbG93IHRoZSBsYXN0IDx0cj4gaW4gdGhlIHRhYmxlLlxuICAgICAgICAgIC8vIFdlIHNob3VsZCBwcm9iYWJseSBoYW5kbGUgdGhpcyB3aXRoIGEgbm9kZSB0cmFuc2Zvcm1cbiAgICAgICAgICAvLyB0byBlbnN1cmUgdGhhdCB0YWJsZXMgYXJlIGFsd2F5cyByZWN0YW5ndWxhciBidXQgdGhpc1xuICAgICAgICAgIC8vIHdpbGwgYXZvaWQgY3Jhc2hlcyBzdWNoIGFzICM2NTg0XG4gICAgICAgICAgLy8gTm90ZSB0aGF0IHRoZXJlIGFyZSBwcm9iYWJseSBzdGlsbCBsYXRlbnQgYnVnc1xuICAgICAgICAgIC8vIHJlZ2FyZGluZyBjb2xTcGFuIG9yIGdlbmVyYWwgY2VsbCBjb3VudCBtaXNtYXRjaGVzLlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG1hcFJvdyA9IGdldE1hcFJvdyhyb3dJZHggKyBqKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2xTcGFuOyBpKyspIHtcbiAgICAgICAgICBtYXBSb3dbY29sSWR4ICsgaV0gPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGNlbGxBICE9PSBudWxsICYmIGNlbGxBVmFsdWUgPT09IG51bGwgJiYgY2VsbEEuaXMoY2VsbCkpIHtcbiAgICAgICAgY2VsbEFWYWx1ZSA9IHZhbHVlO1xuICAgICAgfVxuICAgICAgaWYgKGNlbGxCICE9PSBudWxsICYmIGNlbGxCVmFsdWUgPT09IG51bGwgJiYgY2VsbEIuaXMoY2VsbCkpIHtcbiAgICAgICAgY2VsbEJWYWx1ZSA9IHZhbHVlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gW3RhYmxlTWFwLCBjZWxsQVZhbHVlLCBjZWxsQlZhbHVlXTtcbn1cbmZ1bmN0aW9uICRnZXROb2RlVHJpcGxldChzb3VyY2UpIHtcbiAgbGV0IGNlbGw7XG4gIGlmIChzb3VyY2UgaW5zdGFuY2VvZiBUYWJsZUNlbGxOb2RlKSB7XG4gICAgY2VsbCA9IHNvdXJjZTtcbiAgfSBlbHNlIGlmICgnX190eXBlJyBpbiBzb3VyY2UpIHtcbiAgICBjb25zdCBjZWxsXyA9ICRmaW5kTWF0Y2hpbmdQYXJlbnQoc291cmNlLCAkaXNUYWJsZUNlbGxOb2RlKTtcbiAgICBpZiAoISRpc1RhYmxlQ2VsbE5vZGUoY2VsbF8pKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIHRvIGZpbmQgYSBwYXJlbnQgVGFibGVDZWxsTm9kZWApO1xuICAgIH1cbiAgICBjZWxsID0gY2VsbF87XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgY2VsbF8gPSAkZmluZE1hdGNoaW5nUGFyZW50KHNvdXJjZS5nZXROb2RlKCksICRpc1RhYmxlQ2VsbE5vZGUpO1xuICAgIGlmICghJGlzVGFibGVDZWxsTm9kZShjZWxsXykpIHtcbiAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgdG8gZmluZCBhIHBhcmVudCBUYWJsZUNlbGxOb2RlYCk7XG4gICAgfVxuICAgIGNlbGwgPSBjZWxsXztcbiAgfVxuICBjb25zdCByb3cgPSBjZWxsLmdldFBhcmVudCgpO1xuICBpZiAoISRpc1RhYmxlUm93Tm9kZShyb3cpKSB7XG4gICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCBUYWJsZUNlbGxOb2RlIHRvIGhhdmUgYSBwYXJlbnQgVGFibGVSb3dOb2RlYCk7XG4gIH1cbiAgY29uc3QgZ3JpZCA9IHJvdy5nZXRQYXJlbnQoKTtcbiAgaWYgKCEkaXNUYWJsZU5vZGUoZ3JpZCkpIHtcbiAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIFRhYmxlUm93Tm9kZSB0byBoYXZlIGEgcGFyZW50IFRhYmxlTm9kZWApO1xuICB9XG4gIHJldHVybiBbY2VsbCwgcm93LCBncmlkXTtcbn1cbmZ1bmN0aW9uICRjb21wdXRlVGFibGVDZWxsUmVjdFNwYW5zKG1hcCwgYm91bmRhcnkpIHtcbiAgY29uc3Qge1xuICAgIG1pbkNvbHVtbixcbiAgICBtYXhDb2x1bW4sXG4gICAgbWluUm93LFxuICAgIG1heFJvd1xuICB9ID0gYm91bmRhcnk7XG4gIGxldCB0b3BTcGFuID0gMTtcbiAgbGV0IGxlZnRTcGFuID0gMTtcbiAgbGV0IHJpZ2h0U3BhbiA9IDE7XG4gIGxldCBib3R0b21TcGFuID0gMTtcbiAgY29uc3QgdG9wUm93ID0gbWFwW21pblJvd107XG4gIGNvbnN0IGJvdHRvbVJvdyA9IG1hcFttYXhSb3ddO1xuICBmb3IgKGxldCBjb2wgPSBtaW5Db2x1bW47IGNvbCA8PSBtYXhDb2x1bW47IGNvbCsrKSB7XG4gICAgdG9wU3BhbiA9IE1hdGgubWF4KHRvcFNwYW4sIHRvcFJvd1tjb2xdLmNlbGwuX19yb3dTcGFuKTtcbiAgICBib3R0b21TcGFuID0gTWF0aC5tYXgoYm90dG9tU3BhbiwgYm90dG9tUm93W2NvbF0uY2VsbC5fX3Jvd1NwYW4pO1xuICB9XG4gIGZvciAobGV0IHJvdyA9IG1pblJvdzsgcm93IDw9IG1heFJvdzsgcm93KyspIHtcbiAgICBsZWZ0U3BhbiA9IE1hdGgubWF4KGxlZnRTcGFuLCBtYXBbcm93XVttaW5Db2x1bW5dLmNlbGwuX19jb2xTcGFuKTtcbiAgICByaWdodFNwYW4gPSBNYXRoLm1heChyaWdodFNwYW4sIG1hcFtyb3ddW21heENvbHVtbl0uY2VsbC5fX2NvbFNwYW4pO1xuICB9XG4gIHJldHVybiB7XG4gICAgYm90dG9tU3BhbixcbiAgICBsZWZ0U3BhbixcbiAgICByaWdodFNwYW4sXG4gICAgdG9wU3BhblxuICB9O1xufVxuZnVuY3Rpb24gJGNvbXB1dGVUYWJsZUNlbGxSZWN0Qm91bmRhcnkobWFwLCBjZWxsQU1hcCwgY2VsbEJNYXApIHtcbiAgLy8gSW5pdGlhbCBib3VuZGFyaWVzIGJhc2VkIG9uIHRoZSBhbmNob3IgYW5kIGZvY3VzIGNlbGxzXG4gIGxldCBtaW5Db2x1bW4gPSBNYXRoLm1pbihjZWxsQU1hcC5zdGFydENvbHVtbiwgY2VsbEJNYXAuc3RhcnRDb2x1bW4pO1xuICBsZXQgbWluUm93ID0gTWF0aC5taW4oY2VsbEFNYXAuc3RhcnRSb3csIGNlbGxCTWFwLnN0YXJ0Um93KTtcbiAgbGV0IG1heENvbHVtbiA9IE1hdGgubWF4KGNlbGxBTWFwLnN0YXJ0Q29sdW1uICsgY2VsbEFNYXAuY2VsbC5fX2NvbFNwYW4gLSAxLCBjZWxsQk1hcC5zdGFydENvbHVtbiArIGNlbGxCTWFwLmNlbGwuX19jb2xTcGFuIC0gMSk7XG4gIGxldCBtYXhSb3cgPSBNYXRoLm1heChjZWxsQU1hcC5zdGFydFJvdyArIGNlbGxBTWFwLmNlbGwuX19yb3dTcGFuIC0gMSwgY2VsbEJNYXAuc3RhcnRSb3cgKyBjZWxsQk1hcC5jZWxsLl9fcm93U3BhbiAtIDEpO1xuXG4gIC8vIEtlZXAgZXhwYW5kaW5nIHVudGlsIHdlIGhhdmUgYSBjb21wbGV0ZSByZWN0YW5nbGVcbiAgbGV0IGhhc0NoYW5nZXM7XG4gIGRvIHtcbiAgICBoYXNDaGFuZ2VzID0gZmFsc2U7XG5cbiAgICAvLyBDaGVjayBhbGwgY2VsbHMgaW4gdGhlIHRhYmxlXG4gICAgZm9yIChsZXQgcm93ID0gMDsgcm93IDwgbWFwLmxlbmd0aDsgcm93KyspIHtcbiAgICAgIGZvciAobGV0IGNvbCA9IDA7IGNvbCA8IG1hcFswXS5sZW5ndGg7IGNvbCsrKSB7XG4gICAgICAgIGNvbnN0IGNlbGwgPSBtYXBbcm93XVtjb2xdO1xuICAgICAgICBpZiAoIWNlbGwpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjZWxsRW5kQ29sID0gY2VsbC5zdGFydENvbHVtbiArIGNlbGwuY2VsbC5fX2NvbFNwYW4gLSAxO1xuICAgICAgICBjb25zdCBjZWxsRW5kUm93ID0gY2VsbC5zdGFydFJvdyArIGNlbGwuY2VsbC5fX3Jvd1NwYW4gLSAxO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIHRoaXMgY2VsbCBpbnRlcnNlY3RzIHdpdGggb3VyIGN1cnJlbnQgc2VsZWN0aW9uIHJlY3RhbmdsZVxuICAgICAgICBjb25zdCBpbnRlcnNlY3RzSG9yaXpvbnRhbGx5ID0gY2VsbC5zdGFydENvbHVtbiA8PSBtYXhDb2x1bW4gJiYgY2VsbEVuZENvbCA+PSBtaW5Db2x1bW47XG4gICAgICAgIGNvbnN0IGludGVyc2VjdHNWZXJ0aWNhbGx5ID0gY2VsbC5zdGFydFJvdyA8PSBtYXhSb3cgJiYgY2VsbEVuZFJvdyA+PSBtaW5Sb3c7XG5cbiAgICAgICAgLy8gSWYgdGhlIGNlbGwgaW50ZXJzZWN0cyBlaXRoZXIgaG9yaXpvbnRhbGx5IG9yIHZlcnRpY2FsbHlcbiAgICAgICAgaWYgKGludGVyc2VjdHNIb3Jpem9udGFsbHkgJiYgaW50ZXJzZWN0c1ZlcnRpY2FsbHkpIHtcbiAgICAgICAgICAvLyBFeHBhbmQgYm91bmRhcmllcyB0byBpbmNsdWRlIHRoaXMgY2VsbCBjb21wbGV0ZWx5XG4gICAgICAgICAgY29uc3QgbmV3TWluQ29sdW1uID0gTWF0aC5taW4obWluQ29sdW1uLCBjZWxsLnN0YXJ0Q29sdW1uKTtcbiAgICAgICAgICBjb25zdCBuZXdNYXhDb2x1bW4gPSBNYXRoLm1heChtYXhDb2x1bW4sIGNlbGxFbmRDb2wpO1xuICAgICAgICAgIGNvbnN0IG5ld01pblJvdyA9IE1hdGgubWluKG1pblJvdywgY2VsbC5zdGFydFJvdyk7XG4gICAgICAgICAgY29uc3QgbmV3TWF4Um93ID0gTWF0aC5tYXgobWF4Um93LCBjZWxsRW5kUm93KTtcblxuICAgICAgICAgIC8vIENoZWNrIGlmIGJvdW5kYXJpZXMgY2hhbmdlZFxuICAgICAgICAgIGlmIChuZXdNaW5Db2x1bW4gIT09IG1pbkNvbHVtbiB8fCBuZXdNYXhDb2x1bW4gIT09IG1heENvbHVtbiB8fCBuZXdNaW5Sb3cgIT09IG1pblJvdyB8fCBuZXdNYXhSb3cgIT09IG1heFJvdykge1xuICAgICAgICAgICAgbWluQ29sdW1uID0gbmV3TWluQ29sdW1uO1xuICAgICAgICAgICAgbWF4Q29sdW1uID0gbmV3TWF4Q29sdW1uO1xuICAgICAgICAgICAgbWluUm93ID0gbmV3TWluUm93O1xuICAgICAgICAgICAgbWF4Um93ID0gbmV3TWF4Um93O1xuICAgICAgICAgICAgaGFzQ2hhbmdlcyA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9IHdoaWxlIChoYXNDaGFuZ2VzKTtcbiAgcmV0dXJuIHtcbiAgICBtYXhDb2x1bW4sXG4gICAgbWF4Um93LFxuICAgIG1pbkNvbHVtbixcbiAgICBtaW5Sb3dcbiAgfTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgdGhlIHRhYmxlIGRvZXMgbm90IGhhdmUgYW55IG1lcmdlZCBjZWxscy5cbiAqXG4gKiBAcGFyYW0gdGFibGUgVGFibGUgdG8gY2hlY2sgZm9yIGlmIGl0IGhhcyBhbnkgbWVyZ2VkIGNlbGxzLlxuICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgdGFibGUgZG9lcyBub3QgaGF2ZSBhbnkgbWVyZ2VkIGNlbGxzLCBmYWxzZSBvdGhlcndpc2UuXG4gKi9cbmZ1bmN0aW9uICRpc1NpbXBsZVRhYmxlKHRhYmxlKSB7XG4gIGNvbnN0IHJvd3MgPSB0YWJsZS5nZXRDaGlsZHJlbigpO1xuICBsZXQgY29sdW1ucyA9IG51bGw7XG4gIGZvciAoY29uc3Qgcm93IG9mIHJvd3MpIHtcbiAgICBpZiAoISRpc1RhYmxlUm93Tm9kZShyb3cpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChjb2x1bW5zID09PSBudWxsKSB7XG4gICAgICBjb2x1bW5zID0gcm93LmdldENoaWxkcmVuU2l6ZSgpO1xuICAgIH1cbiAgICBpZiAocm93LmdldENoaWxkcmVuU2l6ZSgpICE9PSBjb2x1bW5zKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IGNlbGxzID0gcm93LmdldENoaWxkcmVuKCk7XG4gICAgZm9yIChjb25zdCBjZWxsIG9mIGNlbGxzKSB7XG4gICAgICBpZiAoISRpc1RhYmxlQ2VsbE5vZGUoY2VsbCkgfHwgY2VsbC5nZXRSb3dTcGFuKCkgIT09IDEgfHwgY2VsbC5nZXRDb2xTcGFuKCkgIT09IDEpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gKGNvbHVtbnMgfHwgMCkgPiAwO1xufVxuXG4vKipcbiAqIE1vdmVzIGEgY29sdW1uIGZyb20gb25lIHBvc2l0aW9uIHRvIGFub3RoZXIgd2l0aGluIGEgc2ltcGxlIChub24tbWVyZ2VkKSB0YWJsZS5cbiAqXG4gKiBAcGFyYW0gdGFibGVOb2RlIFRoZSB0YWJsZSBub2RlIHRvIG1vZGlmeS5cbiAqIEBwYXJhbSBvcmlnaW5Db2x1bW4gVGhlIGluZGV4IG9mIHRoZSBjb2x1bW4gdG8gbW92ZS5cbiAqIEBwYXJhbSB0YXJnZXRDb2x1bW4gVGhlIGluZGV4IHRvIG1vdmUgdGhlIGNvbHVtbiB0by5cbiAqL1xuZnVuY3Rpb24gJG1vdmVUYWJsZUNvbHVtbih0YWJsZU5vZGUsIG9yaWdpbkNvbHVtbiwgdGFyZ2V0Q29sdW1uKSB7XG4gIGlmIChvcmlnaW5Db2x1bW4gPT09IHRhcmdldENvbHVtbikge1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCBjb2x1bW5Db3VudCA9IHRhYmxlTm9kZS5nZXRDb2x1bW5Db3VudCgpO1xuICBpZiAob3JpZ2luQ29sdW1uIDwgMCB8fCBvcmlnaW5Db2x1bW4gPj0gY29sdW1uQ291bnQgfHwgdGFyZ2V0Q29sdW1uIDwgMCB8fCB0YXJnZXRDb2x1bW4gPj0gY29sdW1uQ291bnQpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKCEkaXNTaW1wbGVUYWJsZSh0YWJsZU5vZGUpKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IHJvd3MgPSB0YWJsZU5vZGUuZ2V0Q2hpbGRyZW4oKS5maWx0ZXIoJGlzVGFibGVSb3dOb2RlKTtcbiAgcm93cy5mb3JFYWNoKHJvdyA9PiB7XG4gICAgY29uc3QgY2VsbHMgPSByb3cuZ2V0Q2hpbGRyZW4oKTtcbiAgICBjb25zdCBbbW92ZWRdID0gY2VsbHMuc3BsaWNlKG9yaWdpbkNvbHVtbiwgMSk7XG4gICAgY2VsbHMuc3BsaWNlKHRhcmdldENvbHVtbiwgMCwgbW92ZWQpO1xuICAgIHJvdy5zcGxpY2UoMCwgY2VsbHMubGVuZ3RoLCBjZWxscyk7XG4gIH0pO1xuICBjb25zdCBjb2xXaWR0aHMgPSB0YWJsZU5vZGUuZ2V0Q29sV2lkdGhzKCk7XG4gIGlmIChjb2xXaWR0aHMgJiYgY29sV2lkdGhzLmxlbmd0aCA9PT0gY29sdW1uQ291bnQpIHtcbiAgICBjb25zdCBuZXdXaWR0aHMgPSBbLi4uY29sV2lkdGhzXTtcbiAgICBjb25zdCBbbW92ZWRXaWR0aF0gPSBuZXdXaWR0aHMuc3BsaWNlKG9yaWdpbkNvbHVtbiwgMSk7XG4gICAgbmV3V2lkdGhzLnNwbGljZSh0YXJnZXRDb2x1bW4sIDAsIG1vdmVkV2lkdGgpO1xuICAgIHRhYmxlTm9kZS5zZXRDb2xXaWR0aHMobmV3V2lkdGhzKTtcbiAgfVxufVxuZnVuY3Rpb24gJGdldFRhYmxlQ2VsbE5vZGVSZWN0KHRhYmxlQ2VsbE5vZGUpIHtcbiAgY29uc3QgW2NlbGxOb2RlLCwgZ3JpZE5vZGVdID0gJGdldE5vZGVUcmlwbGV0KHRhYmxlQ2VsbE5vZGUpO1xuICBjb25zdCByb3dzID0gZ3JpZE5vZGUuZ2V0Q2hpbGRyZW4oKTtcbiAgY29uc3Qgcm93Q291bnQgPSByb3dzLmxlbmd0aDtcbiAgY29uc3QgY29sdW1uQ291bnQgPSByb3dzWzBdLmdldENoaWxkcmVuKCkubGVuZ3RoO1xuXG4gIC8vIENyZWF0ZSBhIG1hdHJpeCBvZiB0aGUgc2FtZSBzaXplIGFzIHRoZSB0YWJsZSB0byB0cmFjayB0aGUgcG9zaXRpb24gb2YgZWFjaCBjZWxsXG4gIGNvbnN0IGNlbGxNYXRyaXggPSBuZXcgQXJyYXkocm93Q291bnQpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHJvd0NvdW50OyBpKyspIHtcbiAgICBjZWxsTWF0cml4W2ldID0gbmV3IEFycmF5KGNvbHVtbkNvdW50KTtcbiAgfVxuICBmb3IgKGxldCByb3dJbmRleCA9IDA7IHJvd0luZGV4IDwgcm93Q291bnQ7IHJvd0luZGV4KyspIHtcbiAgICBjb25zdCByb3cgPSByb3dzW3Jvd0luZGV4XTtcbiAgICBjb25zdCBjZWxscyA9IHJvdy5nZXRDaGlsZHJlbigpO1xuICAgIGxldCBjb2x1bW5JbmRleCA9IDA7XG4gICAgZm9yIChsZXQgY2VsbEluZGV4ID0gMDsgY2VsbEluZGV4IDwgY2VsbHMubGVuZ3RoOyBjZWxsSW5kZXgrKykge1xuICAgICAgLy8gRmluZCB0aGUgbmV4dCBhdmFpbGFibGUgcG9zaXRpb24gaW4gdGhlIG1hdHJpeCwgc2tpcCB0aGUgcG9zaXRpb24gb2YgbWVyZ2VkIGNlbGxzXG4gICAgICB3aGlsZSAoY2VsbE1hdHJpeFtyb3dJbmRleF1bY29sdW1uSW5kZXhdKSB7XG4gICAgICAgIGNvbHVtbkluZGV4Kys7XG4gICAgICB9XG4gICAgICBjb25zdCBjZWxsID0gY2VsbHNbY2VsbEluZGV4XTtcbiAgICAgIGNvbnN0IHJvd1NwYW4gPSBjZWxsLl9fcm93U3BhbiB8fCAxO1xuICAgICAgY29uc3QgY29sU3BhbiA9IGNlbGwuX19jb2xTcGFuIHx8IDE7XG5cbiAgICAgIC8vIFB1dCB0aGUgY2VsbCBpbnRvIHRoZSBjb3JyZXNwb25kaW5nIHBvc2l0aW9uIGluIHRoZSBtYXRyaXhcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcm93U3BhbjsgaSsrKSB7XG4gICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgY29sU3BhbjsgaisrKSB7XG4gICAgICAgICAgY2VsbE1hdHJpeFtyb3dJbmRleCArIGldW2NvbHVtbkluZGV4ICsgal0gPSBjZWxsO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFJldHVybiB0byB0aGUgb3JpZ2luYWwgaW5kZXgsIHJvdyBzcGFuIGFuZCBjb2x1bW4gc3BhbiBvZiB0aGUgY2VsbC5cbiAgICAgIGlmIChjZWxsTm9kZSA9PT0gY2VsbCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGNvbFNwYW4sXG4gICAgICAgICAgY29sdW1uSW5kZXgsXG4gICAgICAgICAgcm93SW5kZXgsXG4gICAgICAgICAgcm93U3BhblxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgY29sdW1uSW5kZXggKz0gY29sU3BhbjtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uICRnZXRDZWxsTm9kZXModGFibGVTZWxlY3Rpb24pIHtcbiAgY29uc3QgW1thbmNob3JOb2RlLCBhbmNob3JDZWxsLCBhbmNob3JSb3csIGFuY2hvclRhYmxlXSwgW2ZvY3VzTm9kZSwgZm9jdXNDZWxsLCBmb2N1c1JvdywgZm9jdXNUYWJsZV1dID0gWydhbmNob3InLCAnZm9jdXMnXS5tYXAoayA9PiB7XG4gICAgY29uc3Qgbm9kZSA9IHRhYmxlU2VsZWN0aW9uW2tdLmdldE5vZGUoKTtcbiAgICBjb25zdCBjZWxsTm9kZSA9ICRmaW5kTWF0Y2hpbmdQYXJlbnQobm9kZSwgJGlzVGFibGVDZWxsTm9kZSk7XG4gICAgaWYgKCEkaXNUYWJsZUNlbGxOb2RlKGNlbGxOb2RlKSkge1xuICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCBUYWJsZVNlbGVjdGlvbiAke2t9IHRvIGJlIChvciBhIGNoaWxkIG9mKSBUYWJsZUNlbGxOb2RlLCBnb3Qga2V5ICR7bm9kZS5nZXRLZXkoKX0gb2YgdHlwZSAke25vZGUuZ2V0VHlwZSgpfWApO1xuICAgIH1cbiAgICBjb25zdCByb3dOb2RlID0gY2VsbE5vZGUuZ2V0UGFyZW50KCk7XG4gICAgaWYgKCEkaXNUYWJsZVJvd05vZGUocm93Tm9kZSkpIHtcbiAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgVGFibGVTZWxlY3Rpb24gJHtrfSBjZWxsIHBhcmVudCB0byBiZSBhIFRhYmxlUm93Tm9kZWApO1xuICAgIH1cbiAgICBjb25zdCB0YWJsZU5vZGUgPSByb3dOb2RlLmdldFBhcmVudCgpO1xuICAgIGlmICghJGlzVGFibGVOb2RlKHRhYmxlTm9kZSkpIHtcbiAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgVGFibGVTZWxlY3Rpb24gJHtrfSByb3cgcGFyZW50IHRvIGJlIGEgVGFibGVOb2RlYCk7XG4gICAgfVxuICAgIHJldHVybiBbbm9kZSwgY2VsbE5vZGUsIHJvd05vZGUsIHRhYmxlTm9kZV07XG4gIH0pO1xuICAvLyBUT0RPOiBuZXN0ZWQgdGFibGVzIG1heSB2aW9sYXRlIHRoaXNcbiAgaWYgKCFhbmNob3JUYWJsZS5pcyhmb2N1c1RhYmxlKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgVGFibGVTZWxlY3Rpb24gYW5jaG9yIGFuZCBmb2N1cyB0byBiZSBpbiB0aGUgc2FtZSB0YWJsZWApO1xuICB9XG4gIHJldHVybiB7XG4gICAgYW5jaG9yQ2VsbCxcbiAgICBhbmNob3JOb2RlLFxuICAgIGFuY2hvclJvdyxcbiAgICBhbmNob3JUYWJsZSxcbiAgICBmb2N1c0NlbGwsXG4gICAgZm9jdXNOb2RlLFxuICAgIGZvY3VzUm93LFxuICAgIGZvY3VzVGFibGVcbiAgfTtcbn1cbmNsYXNzIFRhYmxlU2VsZWN0aW9uIHtcbiAgdGFibGVLZXk7XG4gIGFuY2hvcjtcbiAgZm9jdXM7XG4gIF9jYWNoZWROb2RlcztcbiAgZGlydHk7XG4gIGNvbnN0cnVjdG9yKHRhYmxlS2V5LCBhbmNob3IsIGZvY3VzKSB7XG4gICAgdGhpcy5hbmNob3IgPSBhbmNob3I7XG4gICAgdGhpcy5mb2N1cyA9IGZvY3VzO1xuICAgIGFuY2hvci5fc2VsZWN0aW9uID0gdGhpcztcbiAgICBmb2N1cy5fc2VsZWN0aW9uID0gdGhpcztcbiAgICB0aGlzLl9jYWNoZWROb2RlcyA9IG51bGw7XG4gICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgIHRoaXMudGFibGVLZXkgPSB0YWJsZUtleTtcbiAgfVxuICBnZXRTdGFydEVuZFBvaW50cygpIHtcbiAgICByZXR1cm4gW3RoaXMuYW5jaG9yLCB0aGlzLmZvY3VzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiB7QGxpbmsgJGNyZWF0ZVRhYmxlU2VsZWN0aW9ufSB1bmZvcnR1bmF0ZWx5IG1ha2VzIGl0IHZlcnkgZWFzeSB0byBjcmVhdGVcbiAgICogbm9uc2Vuc2Ugc2VsZWN0aW9ucywgc28gd2UgaGF2ZSBhIG1ldGhvZCB0byBzZWUgaWYgdGhlIHNlbGVjdGlvbiBwcm9iYWJseVxuICAgKiBtYWtlcyBzZW5zZS5cbiAgICpcbiAgICogQHJldHVybnMgdHJ1ZSBpZiB0aGUgVGFibGVTZWxlY3Rpb24gaXMgKHByb2JhYmx5KSB2YWxpZFxuICAgKi9cbiAgaXNWYWxpZCgpIHtcbiAgICBpZiAodGhpcy50YWJsZUtleSA9PT0gJ3Jvb3QnIHx8IHRoaXMuYW5jaG9yLmtleSA9PT0gJ3Jvb3QnIHx8IHRoaXMuYW5jaG9yLnR5cGUgIT09ICdlbGVtZW50JyB8fCB0aGlzLmZvY3VzLmtleSA9PT0gJ3Jvb3QnIHx8IHRoaXMuZm9jdXMudHlwZSAhPT0gJ2VsZW1lbnQnKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHJlZmVyZW5jZWQgbm9kZXMgc3RpbGwgZXhpc3QgaW4gdGhlIGVkaXRvclxuICAgIGNvbnN0IHRhYmxlTm9kZSA9ICRnZXROb2RlQnlLZXkodGhpcy50YWJsZUtleSk7XG4gICAgY29uc3QgYW5jaG9yTm9kZSA9ICRnZXROb2RlQnlLZXkodGhpcy5hbmNob3Iua2V5KTtcbiAgICBjb25zdCBmb2N1c05vZGUgPSAkZ2V0Tm9kZUJ5S2V5KHRoaXMuZm9jdXMua2V5KTtcbiAgICByZXR1cm4gdGFibGVOb2RlICE9PSBudWxsICYmIGFuY2hvck5vZGUgIT09IG51bGwgJiYgZm9jdXNOb2RlICE9PSBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgd2hldGhlciB0aGUgU2VsZWN0aW9uIGlzIFwiYmFja3dhcmRzXCIsIG1lYW5pbmcgdGhlIGZvY3VzXG4gICAqIGxvZ2ljYWxseSBwcmVjZWRlcyB0aGUgYW5jaG9yIGluIHRoZSBFZGl0b3JTdGF0ZS5cbiAgICogQHJldHVybnMgdHJ1ZSBpZiB0aGUgU2VsZWN0aW9uIGlzIGJhY2t3YXJkcywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNCYWNrd2FyZCgpIHtcbiAgICByZXR1cm4gdGhpcy5mb2N1cy5pc0JlZm9yZSh0aGlzLmFuY2hvcik7XG4gIH1cbiAgZ2V0Q2FjaGVkTm9kZXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2NhY2hlZE5vZGVzO1xuICB9XG4gIHNldENhY2hlZE5vZGVzKG5vZGVzKSB7XG4gICAgdGhpcy5fY2FjaGVkTm9kZXMgPSBub2RlcztcbiAgfVxuICBpcyhzZWxlY3Rpb24pIHtcbiAgICByZXR1cm4gJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSAmJiB0aGlzLnRhYmxlS2V5ID09PSBzZWxlY3Rpb24udGFibGVLZXkgJiYgdGhpcy5hbmNob3IuaXMoc2VsZWN0aW9uLmFuY2hvcikgJiYgdGhpcy5mb2N1cy5pcyhzZWxlY3Rpb24uZm9jdXMpO1xuICB9XG4gIHNldCh0YWJsZUtleSwgYW5jaG9yQ2VsbEtleSwgZm9jdXNDZWxsS2V5KSB7XG4gICAgLy8gbm90ZTogY2xvc3VyZSBjb21waWxlcidzIGFjb3JuIGRvZXMgbm90IHN1cHBvcnQgfHw9XG4gICAgdGhpcy5kaXJ0eSA9IHRoaXMuZGlydHkgfHwgdGFibGVLZXkgIT09IHRoaXMudGFibGVLZXkgfHwgYW5jaG9yQ2VsbEtleSAhPT0gdGhpcy5hbmNob3Iua2V5IHx8IGZvY3VzQ2VsbEtleSAhPT0gdGhpcy5mb2N1cy5rZXk7XG4gICAgdGhpcy50YWJsZUtleSA9IHRhYmxlS2V5O1xuICAgIHRoaXMuYW5jaG9yLmtleSA9IGFuY2hvckNlbGxLZXk7XG4gICAgdGhpcy5mb2N1cy5rZXkgPSBmb2N1c0NlbGxLZXk7XG4gICAgdGhpcy5fY2FjaGVkTm9kZXMgPSBudWxsO1xuICB9XG4gIGNsb25lKCkge1xuICAgIHJldHVybiBuZXcgVGFibGVTZWxlY3Rpb24odGhpcy50YWJsZUtleSwgJGNyZWF0ZVBvaW50KHRoaXMuYW5jaG9yLmtleSwgdGhpcy5hbmNob3Iub2Zmc2V0LCB0aGlzLmFuY2hvci50eXBlKSwgJGNyZWF0ZVBvaW50KHRoaXMuZm9jdXMua2V5LCB0aGlzLmZvY3VzLm9mZnNldCwgdGhpcy5mb2N1cy50eXBlKSk7XG4gIH1cbiAgaXNDb2xsYXBzZWQoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGV4dHJhY3QoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0Tm9kZXMoKTtcbiAgfVxuICBpbnNlcnRSYXdUZXh0KHRleHQpIHtcbiAgICAvLyBEbyBub3RoaW5nP1xuICB9XG4gIGluc2VydFRleHQoKSB7XG4gICAgLy8gRG8gbm90aGluZz9cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhlIHByb3ZpZGVkIFRleHRGb3JtYXRUeXBlIGlzIHByZXNlbnQgb24gdGhlIFNlbGVjdGlvbi5cbiAgICogVGhpcyB3aWxsIGJlIHRydWUgaWYgYW55IHBhcmFncmFwaCBpbiB0YWJsZSBjZWxscyBoYXMgdGhlIHNwZWNpZmllZCBmb3JtYXQuXG4gICAqXG4gICAqIEBwYXJhbSB0eXBlIHRoZSBUZXh0Rm9ybWF0VHlwZSB0byBjaGVjayBmb3IuXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIHByb3ZpZGVkIGZvcm1hdCBpcyBjdXJyZW50bHkgdG9nZ2xlZCBvbiBvbiB0aGUgU2VsZWN0aW9uLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqL1xuICBoYXNGb3JtYXQodHlwZSkge1xuICAgIGxldCBmb3JtYXQgPSAwO1xuICAgIGNvbnN0IGNlbGxOb2RlcyA9IHRoaXMuZ2V0Tm9kZXMoKS5maWx0ZXIoJGlzVGFibGVDZWxsTm9kZSk7XG4gICAgY2VsbE5vZGVzLmZvckVhY2goY2VsbE5vZGUgPT4ge1xuICAgICAgY29uc3QgcGFyYWdyYXBoID0gY2VsbE5vZGUuZ2V0Rmlyc3RDaGlsZCgpO1xuICAgICAgaWYgKCRpc1BhcmFncmFwaE5vZGUocGFyYWdyYXBoKSkge1xuICAgICAgICBmb3JtYXQgfD0gcGFyYWdyYXBoLmdldFRleHRGb3JtYXQoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBjb25zdCBmb3JtYXRGbGFnID0gVEVYVF9UWVBFX1RPX0ZPUk1BVFt0eXBlXTtcbiAgICByZXR1cm4gKGZvcm1hdCAmIGZvcm1hdEZsYWcpICE9PSAwO1xuICB9XG4gIGluc2VydE5vZGVzKG5vZGVzKSB7XG4gICAgY29uc3QgZm9jdXNOb2RlID0gdGhpcy5mb2N1cy5nZXROb2RlKCk7XG4gICAgaWYgKCEkaXNFbGVtZW50Tm9kZShmb2N1c05vZGUpKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIFRhYmxlU2VsZWN0aW9uIGZvY3VzIHRvIGJlIGFuIEVsZW1lbnROb2RlYCk7XG4gICAgfVxuICAgIGNvbnN0IHNlbGVjdGlvbiA9ICRub3JtYWxpemVTZWxlY3Rpb25fX0VYUEVSSU1FTlRBTChmb2N1c05vZGUuc2VsZWN0KDAsIGZvY3VzTm9kZS5nZXRDaGlsZHJlblNpemUoKSkpO1xuICAgIHNlbGVjdGlvbi5pbnNlcnROb2Rlcyhub2Rlcyk7XG4gIH1cblxuICAvLyBUT0RPIERlcHJlY2F0ZSB0aGlzIG1ldGhvZC4gSXQncyBjb25mdXNpbmcgd2hlbiB1c2VkIHdpdGggY29sc3Bhbnxyb3dzcGFuXG4gIGdldFNoYXBlKCkge1xuICAgIGNvbnN0IHtcbiAgICAgIGFuY2hvckNlbGwsXG4gICAgICBmb2N1c0NlbGxcbiAgICB9ID0gJGdldENlbGxOb2Rlcyh0aGlzKTtcbiAgICBjb25zdCBhbmNob3JDZWxsTm9kZVJlY3QgPSAkZ2V0VGFibGVDZWxsTm9kZVJlY3QoYW5jaG9yQ2VsbCk7XG4gICAgaWYgKCEoYW5jaG9yQ2VsbE5vZGVSZWN0ICE9PSBudWxsKSkge1xuICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBnZXRDZWxsUmVjdDogZXhwZWN0ZWQgdG8gZmluZCBBbmNob3JOb2RlYCk7XG4gICAgfVxuICAgIGNvbnN0IGZvY3VzQ2VsbE5vZGVSZWN0ID0gJGdldFRhYmxlQ2VsbE5vZGVSZWN0KGZvY3VzQ2VsbCk7XG4gICAgaWYgKCEoZm9jdXNDZWxsTm9kZVJlY3QgIT09IG51bGwpKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYGdldENlbGxSZWN0OiBleHBlY3RlZCB0byBmaW5kIGZvY3VzQ2VsbE5vZGVgKTtcbiAgICB9XG4gICAgY29uc3Qgc3RhcnRYID0gTWF0aC5taW4oYW5jaG9yQ2VsbE5vZGVSZWN0LmNvbHVtbkluZGV4LCBmb2N1c0NlbGxOb2RlUmVjdC5jb2x1bW5JbmRleCk7XG4gICAgY29uc3Qgc3RvcFggPSBNYXRoLm1heChhbmNob3JDZWxsTm9kZVJlY3QuY29sdW1uSW5kZXggKyBhbmNob3JDZWxsTm9kZVJlY3QuY29sU3BhbiAtIDEsIGZvY3VzQ2VsbE5vZGVSZWN0LmNvbHVtbkluZGV4ICsgZm9jdXNDZWxsTm9kZVJlY3QuY29sU3BhbiAtIDEpO1xuICAgIGNvbnN0IHN0YXJ0WSA9IE1hdGgubWluKGFuY2hvckNlbGxOb2RlUmVjdC5yb3dJbmRleCwgZm9jdXNDZWxsTm9kZVJlY3Qucm93SW5kZXgpO1xuICAgIGNvbnN0IHN0b3BZID0gTWF0aC5tYXgoYW5jaG9yQ2VsbE5vZGVSZWN0LnJvd0luZGV4ICsgYW5jaG9yQ2VsbE5vZGVSZWN0LnJvd1NwYW4gLSAxLCBmb2N1c0NlbGxOb2RlUmVjdC5yb3dJbmRleCArIGZvY3VzQ2VsbE5vZGVSZWN0LnJvd1NwYW4gLSAxKTtcbiAgICByZXR1cm4ge1xuICAgICAgZnJvbVg6IE1hdGgubWluKHN0YXJ0WCwgc3RvcFgpLFxuICAgICAgZnJvbVk6IE1hdGgubWluKHN0YXJ0WSwgc3RvcFkpLFxuICAgICAgdG9YOiBNYXRoLm1heChzdGFydFgsIHN0b3BYKSxcbiAgICAgIHRvWTogTWF0aC5tYXgoc3RhcnRZLCBzdG9wWSlcbiAgICB9O1xuICB9XG4gIGdldE5vZGVzKCkge1xuICAgIGlmICghdGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgY29uc3QgY2FjaGVkTm9kZXMgPSB0aGlzLl9jYWNoZWROb2RlcztcbiAgICBpZiAoY2FjaGVkTm9kZXMgIT09IG51bGwpIHtcbiAgICAgIHJldHVybiBjYWNoZWROb2RlcztcbiAgICB9XG4gICAgY29uc3Qge1xuICAgICAgYW5jaG9yVGFibGU6IHRhYmxlTm9kZSxcbiAgICAgIGFuY2hvckNlbGwsXG4gICAgICBmb2N1c0NlbGxcbiAgICB9ID0gJGdldENlbGxOb2Rlcyh0aGlzKTtcbiAgICBjb25zdCBmb2N1c0NlbGxHcmlkID0gZm9jdXNDZWxsLmdldFBhcmVudHMoKVsxXTtcbiAgICBpZiAoZm9jdXNDZWxsR3JpZCAhPT0gdGFibGVOb2RlKSB7XG4gICAgICBpZiAoIXRhYmxlTm9kZS5pc1BhcmVudE9mKGZvY3VzQ2VsbCkpIHtcbiAgICAgICAgLy8gZm9jdXMgaXMgb24gaGlnaGVyIEdyaWQgbGV2ZWwgdGhhbiBhbmNob3JcbiAgICAgICAgY29uc3QgZ3JpZFBhcmVudCA9IHRhYmxlTm9kZS5nZXRQYXJlbnQoKTtcbiAgICAgICAgaWYgKCEoZ3JpZFBhcmVudCAhPSBudWxsKSkge1xuICAgICAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgZ3JpZFBhcmVudCB0byBoYXZlIGEgcGFyZW50YCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zZXQodGhpcy50YWJsZUtleSwgZ3JpZFBhcmVudC5nZXRLZXkoKSwgZm9jdXNDZWxsLmdldEtleSgpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGFuY2hvciBpcyBvbiBoaWdoZXIgR3JpZCBsZXZlbCB0aGFuIGZvY3VzXG4gICAgICAgIGNvbnN0IGZvY3VzQ2VsbFBhcmVudCA9IGZvY3VzQ2VsbEdyaWQuZ2V0UGFyZW50KCk7XG4gICAgICAgIGlmICghKGZvY3VzQ2VsbFBhcmVudCAhPSBudWxsKSkge1xuICAgICAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgZm9jdXNDZWxsUGFyZW50IHRvIGhhdmUgYSBwYXJlbnRgKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnNldCh0aGlzLnRhYmxlS2V5LCBmb2N1c0NlbGwuZ2V0S2V5KCksIGZvY3VzQ2VsbFBhcmVudC5nZXRLZXkoKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5nZXROb2RlcygpO1xuICAgIH1cblxuICAgIC8vIFRPRE8gTWFwcGluZyB0aGUgd2hvbGUgR3JpZCBldmVyeSB0aW1lIG5vdCBlZmZpY2llbnQuIFdlIG5lZWQgdG8gY29tcHV0ZSB0aGUgZW50aXJlIHN0YXRlIG9ubHlcbiAgICAvLyBvbmNlIChvbiBsb2FkKSBhbmQgaXRlcmF0ZSBvbiBpdCBhcyB1cGRhdGVzIG9jY3VyLiBIb3dldmVyLCB0byBkbyB0aGlzIHdlIG5lZWQgdG8gaGF2ZSB0aGVcbiAgICAvLyBhYmlsaXR5IHRvIHN0b3JlIGEgc3RhdGUuIEtpbGxpbmcgVGFibGVTZWxlY3Rpb24gYW5kIG1vdmluZyB0aGUgbG9naWMgdG8gdGhlIHBsdWdpbiB3b3VsZCBtYWtlXG4gICAgLy8gdGhpcyBwb3NzaWJsZS5cbiAgICBjb25zdCBbbWFwLCBjZWxsQU1hcCwgY2VsbEJNYXBdID0gJGNvbXB1dGVUYWJsZU1hcCh0YWJsZU5vZGUsIGFuY2hvckNlbGwsIGZvY3VzQ2VsbCk7XG4gICAgY29uc3Qge1xuICAgICAgbWluQ29sdW1uLFxuICAgICAgbWF4Q29sdW1uLFxuICAgICAgbWluUm93LFxuICAgICAgbWF4Um93XG4gICAgfSA9ICRjb21wdXRlVGFibGVDZWxsUmVjdEJvdW5kYXJ5KG1hcCwgY2VsbEFNYXAsIGNlbGxCTWFwKTtcblxuICAgIC8vIFdlIHVzZSBhIE1hcCBoZXJlIGJlY2F1c2UgbWVyZ2VkIGNlbGxzIGluIHRoZSBncmlkIHdvdWxkIG90aGVyd2lzZVxuICAgIC8vIHNob3cgdXAgbXVsdGlwbGUgdGltZXMgaW4gdGhlIG5vZGVzIGFycmF5XG4gICAgY29uc3Qgbm9kZU1hcCA9IG5ldyBNYXAoW1t0YWJsZU5vZGUuZ2V0S2V5KCksIHRhYmxlTm9kZV1dKTtcbiAgICBsZXQgbGFzdFJvdyA9IG51bGw7XG4gICAgZm9yIChsZXQgaSA9IG1pblJvdzsgaSA8PSBtYXhSb3c7IGkrKykge1xuICAgICAgZm9yIChsZXQgaiA9IG1pbkNvbHVtbjsgaiA8PSBtYXhDb2x1bW47IGorKykge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgY2VsbFxuICAgICAgICB9ID0gbWFwW2ldW2pdO1xuICAgICAgICBjb25zdCBjdXJyZW50Um93ID0gY2VsbC5nZXRQYXJlbnQoKTtcbiAgICAgICAgaWYgKCEkaXNUYWJsZVJvd05vZGUoY3VycmVudFJvdykpIHtcbiAgICAgICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIFRhYmxlQ2VsbE5vZGUgcGFyZW50IHRvIGJlIGEgVGFibGVSb3dOb2RlYCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGN1cnJlbnRSb3cgIT09IGxhc3RSb3cpIHtcbiAgICAgICAgICBub2RlTWFwLnNldChjdXJyZW50Um93LmdldEtleSgpLCBjdXJyZW50Um93KTtcbiAgICAgICAgICBsYXN0Um93ID0gY3VycmVudFJvdztcbiAgICAgICAgfVxuICAgICAgICBpZiAoIW5vZGVNYXAuaGFzKGNlbGwuZ2V0S2V5KCkpKSB7XG4gICAgICAgICAgJHZpc2l0UmVjdXJzaXZlbHkoY2VsbCwgY2hpbGROb2RlID0+IHtcbiAgICAgICAgICAgIG5vZGVNYXAuc2V0KGNoaWxkTm9kZS5nZXRLZXkoKSwgY2hpbGROb2RlKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBub2RlcyA9IEFycmF5LmZyb20obm9kZU1hcC52YWx1ZXMoKSk7XG4gICAgaWYgKCFpc0N1cnJlbnRseVJlYWRPbmx5TW9kZSgpKSB7XG4gICAgICB0aGlzLl9jYWNoZWROb2RlcyA9IG5vZGVzO1xuICAgIH1cbiAgICByZXR1cm4gbm9kZXM7XG4gIH1cbiAgZ2V0VGV4dENvbnRlbnQoKSB7XG4gICAgY29uc3Qgbm9kZXMgPSB0aGlzLmdldE5vZGVzKCkuZmlsdGVyKG5vZGUgPT4gJGlzVGFibGVDZWxsTm9kZShub2RlKSk7XG4gICAgbGV0IHRleHRDb250ZW50ID0gJyc7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3Qgbm9kZSA9IG5vZGVzW2ldO1xuICAgICAgY29uc3Qgcm93ID0gbm9kZS5fX3BhcmVudDtcbiAgICAgIGNvbnN0IG5leHRSb3cgPSAobm9kZXNbaSArIDFdIHx8IHt9KS5fX3BhcmVudDtcbiAgICAgIHRleHRDb250ZW50ICs9IG5vZGUuZ2V0VGV4dENvbnRlbnQoKSArIChuZXh0Um93ICE9PSByb3cgPyAnXFxuJyA6ICdcXHQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRleHRDb250ZW50O1xuICB9XG59XG5mdW5jdGlvbiAkaXNUYWJsZVNlbGVjdGlvbih4KSB7XG4gIHJldHVybiB4IGluc3RhbmNlb2YgVGFibGVTZWxlY3Rpb247XG59XG5mdW5jdGlvbiAkY3JlYXRlVGFibGVTZWxlY3Rpb24oKSB7XG4gIC8vIFRPRE8gdGhpcyBpcyBhIHN1Ym9wdGltYWwgZGVzaWduLCBpdCBkb2Vzbid0IG1ha2Ugc2Vuc2UgdG8gaGF2ZVxuICAvLyBhIHRhYmxlIHNlbGVjdGlvbiB0aGF0IGlzbid0IGFzc29jaWF0ZWQgd2l0aCBhIHRhYmxlLiBUaGlzXG4gIC8vIGNvbnN0cnVjdG9yIHNob3VsZCBoYXZlIHJlcXVpcmVkIGFyZ3VtZW50cyBhbmQgaW4gdHJ1ZSB3ZVxuICAvLyBzaG91bGQgY2hlY2sgdGhhdCB0aGV5IHBvaW50IHRvIGEgdGFibGUgYW5kIGFyZSBlbGVtZW50IHBvaW50cyB0b1xuICAvLyBjZWxsIG5vZGVzIG9mIHRoYXQgdGFibGUuXG4gIGNvbnN0IGFuY2hvciA9ICRjcmVhdGVQb2ludCgncm9vdCcsIDAsICdlbGVtZW50Jyk7XG4gIGNvbnN0IGZvY3VzID0gJGNyZWF0ZVBvaW50KCdyb290JywgMCwgJ2VsZW1lbnQnKTtcbiAgcmV0dXJuIG5ldyBUYWJsZVNlbGVjdGlvbigncm9vdCcsIGFuY2hvciwgZm9jdXMpO1xufVxuZnVuY3Rpb24gJGNyZWF0ZVRhYmxlU2VsZWN0aW9uRnJvbSh0YWJsZU5vZGUsIGFuY2hvckNlbGwsIGZvY3VzQ2VsbCkge1xuICBjb25zdCB0YWJsZU5vZGVLZXkgPSB0YWJsZU5vZGUuZ2V0S2V5KCk7XG4gIGNvbnN0IGFuY2hvckNlbGxLZXkgPSBhbmNob3JDZWxsLmdldEtleSgpO1xuICBjb25zdCBmb2N1c0NlbGxLZXkgPSBmb2N1c0NlbGwuZ2V0S2V5KCk7XG4gIHtcbiAgICBpZiAoIXRhYmxlTm9kZS5pc0F0dGFjaGVkKCkpIHtcbiAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgJGNyZWF0ZVRhYmxlU2VsZWN0aW9uRnJvbTogdGFibGVOb2RlICR7dGFibGVOb2RlS2V5fSBpcyBub3QgYXR0YWNoZWRgKTtcbiAgICB9XG4gICAgaWYgKCF0YWJsZU5vZGUuaXMoJGZpbmRUYWJsZU5vZGUoYW5jaG9yQ2VsbCkpKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYCRjcmVhdGVUYWJsZVNlbGVjdGlvbkZyb206IGFuY2hvckNlbGwgJHthbmNob3JDZWxsS2V5fSBpcyBub3QgaW4gdGFibGUgJHt0YWJsZU5vZGVLZXl9YCk7XG4gICAgfVxuICAgIGlmICghdGFibGVOb2RlLmlzKCRmaW5kVGFibGVOb2RlKGZvY3VzQ2VsbCkpKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYCRjcmVhdGVUYWJsZVNlbGVjdGlvbkZyb206IGZvY3VzQ2VsbCAke2ZvY3VzQ2VsbEtleX0gaXMgbm90IGluIHRhYmxlICR7dGFibGVOb2RlS2V5fWApO1xuICAgIH0gLy8gVE9ETzogQ2hlY2sgZm9yIHJlY3Rhbmd1bGFyIGdyaWRcbiAgfVxuICBjb25zdCBwcmV2U2VsZWN0aW9uID0gJGdldFNlbGVjdGlvbigpO1xuICBjb25zdCBuZXh0U2VsZWN0aW9uID0gJGlzVGFibGVTZWxlY3Rpb24ocHJldlNlbGVjdGlvbikgPyBwcmV2U2VsZWN0aW9uLmNsb25lKCkgOiAkY3JlYXRlVGFibGVTZWxlY3Rpb24oKTtcbiAgbmV4dFNlbGVjdGlvbi5zZXQodGFibGVOb2RlLmdldEtleSgpLCBhbmNob3JDZWxsLmdldEtleSgpLCBmb2N1c0NlbGwuZ2V0S2V5KCkpO1xuICByZXR1cm4gbmV4dFNlbGVjdGlvbjtcbn1cblxuLyoqXG4gKiBEZXB0aCBmaXJzdCB2aXNpdG9yXG4gKiBAcGFyYW0gbm9kZSBUaGUgc3RhcnRpbmcgbm9kZVxuICogQHBhcmFtICR2aXNpdCBUaGUgZnVuY3Rpb24gdG8gY2FsbCBmb3IgZWFjaCBub2RlLiBJZiB0aGUgZnVuY3Rpb24gcmV0dXJucyBmYWxzZSwgdGhlbiBjaGlsZHJlbiBvZiB0aGlzIG5vZGUgd2lsbCBub3QgYmUgZXhwbG9yZWRcbiAqL1xuZnVuY3Rpb24gJHZpc2l0UmVjdXJzaXZlbHkobm9kZSwgJHZpc2l0KSB7XG4gIGNvbnN0IHN0YWNrID0gW1tub2RlXV07XG4gIGZvciAobGV0IGN1cnJlbnRBcnJheSA9IHN0YWNrLmF0KC0xKTsgY3VycmVudEFycmF5ICE9PSB1bmRlZmluZWQgJiYgc3RhY2subGVuZ3RoID4gMDsgY3VycmVudEFycmF5ID0gc3RhY2suYXQoLTEpKSB7XG4gICAgY29uc3QgY3VycmVudE5vZGUgPSBjdXJyZW50QXJyYXkucG9wKCk7XG4gICAgaWYgKGN1cnJlbnROb2RlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHN0YWNrLnBvcCgpO1xuICAgIH0gZWxzZSBpZiAoJHZpc2l0KGN1cnJlbnROb2RlKSAhPT0gZmFsc2UgJiYgJGlzRWxlbWVudE5vZGUoY3VycmVudE5vZGUpKSB7XG4gICAgICBzdGFjay5wdXNoKGN1cnJlbnROb2RlLmdldENoaWxkcmVuKCkpO1xuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiAkZ2V0VGFibGVBbmRFbGVtZW50QnlLZXkodGFibGVOb2RlS2V5LCBlZGl0b3IgPSAkZ2V0RWRpdG9yKCkpIHtcbiAgY29uc3QgdGFibGVOb2RlID0gJGdldE5vZGVCeUtleSh0YWJsZU5vZGVLZXkpO1xuICBpZiAoISRpc1RhYmxlTm9kZSh0YWJsZU5vZGUpKSB7XG4gICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBUYWJsZU9ic2VydmVyOiBFeHBlY3RlZCB0YWJsZU5vZGVLZXkgJHt0YWJsZU5vZGVLZXl9IHRvIGJlIGEgVGFibGVOb2RlYCk7XG4gIH1cbiAgY29uc3QgdGFibGVFbGVtZW50ID0gZ2V0VGFibGVFbGVtZW50KHRhYmxlTm9kZSwgZWRpdG9yLmdldEVsZW1lbnRCeUtleSh0YWJsZU5vZGVLZXkpKTtcbiAgaWYgKCEodGFibGVFbGVtZW50ICE9PSBudWxsKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgVGFibGVPYnNlcnZlcjogRXhwZWN0ZWQgdG8gZmluZCBUYWJsZUVsZW1lbnQgaW4gRE9NIGZvciBrZXkgJHt0YWJsZU5vZGVLZXl9YCk7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICB0YWJsZUVsZW1lbnQsXG4gICAgdGFibGVOb2RlXG4gIH07XG59XG5jbGFzcyBUYWJsZU9ic2VydmVyIHtcbiAgZm9jdXNYO1xuICBmb2N1c1k7XG4gIGxpc3RlbmVyc1RvUmVtb3ZlO1xuICB0YWJsZTtcbiAgaXNIaWdobGlnaHRpbmdDZWxscztcbiAgYW5jaG9yWDtcbiAgYW5jaG9yWTtcbiAgdGFibGVOb2RlS2V5O1xuICBhbmNob3JDZWxsO1xuICBmb2N1c0NlbGw7XG4gIGFuY2hvckNlbGxOb2RlS2V5O1xuICBmb2N1c0NlbGxOb2RlS2V5O1xuICBlZGl0b3I7XG4gIHRhYmxlU2VsZWN0aW9uO1xuICBoYXNIaWphY2tlZFNlbGVjdGlvblN0eWxlcztcbiAgaXNTZWxlY3Rpbmc7XG4gIHBvaW50ZXJUeXBlO1xuICBzaG91bGRDaGVja1NlbGVjdGlvbjtcbiAgYWJvcnRDb250cm9sbGVyO1xuICBsaXN0ZW5lck9wdGlvbnM7XG4gIG5leHRGb2N1cztcbiAgY29uc3RydWN0b3IoZWRpdG9yLCB0YWJsZU5vZGVLZXkpIHtcbiAgICB0aGlzLmlzSGlnaGxpZ2h0aW5nQ2VsbHMgPSBmYWxzZTtcbiAgICB0aGlzLmFuY2hvclggPSAtMTtcbiAgICB0aGlzLmFuY2hvclkgPSAtMTtcbiAgICB0aGlzLmZvY3VzWCA9IC0xO1xuICAgIHRoaXMuZm9jdXNZID0gLTE7XG4gICAgdGhpcy5saXN0ZW5lcnNUb1JlbW92ZSA9IG5ldyBTZXQoKTtcbiAgICB0aGlzLnRhYmxlTm9kZUtleSA9IHRhYmxlTm9kZUtleTtcbiAgICB0aGlzLmVkaXRvciA9IGVkaXRvcjtcbiAgICB0aGlzLnRhYmxlID0ge1xuICAgICAgY29sdW1uczogMCxcbiAgICAgIGRvbVJvd3M6IFtdLFxuICAgICAgcm93czogMFxuICAgIH07XG4gICAgdGhpcy50YWJsZVNlbGVjdGlvbiA9IG51bGw7XG4gICAgdGhpcy5hbmNob3JDZWxsTm9kZUtleSA9IG51bGw7XG4gICAgdGhpcy5mb2N1c0NlbGxOb2RlS2V5ID0gbnVsbDtcbiAgICB0aGlzLmFuY2hvckNlbGwgPSBudWxsO1xuICAgIHRoaXMuZm9jdXNDZWxsID0gbnVsbDtcbiAgICB0aGlzLmhhc0hpamFja2VkU2VsZWN0aW9uU3R5bGVzID0gZmFsc2U7XG4gICAgdGhpcy5pc1NlbGVjdGluZyA9IGZhbHNlO1xuICAgIHRoaXMucG9pbnRlclR5cGUgPSBudWxsO1xuICAgIHRoaXMuc2hvdWxkQ2hlY2tTZWxlY3Rpb24gPSBmYWxzZTtcbiAgICB0aGlzLmFib3J0Q29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgICB0aGlzLmxpc3RlbmVyT3B0aW9ucyA9IHtcbiAgICAgIHNpZ25hbDogdGhpcy5hYm9ydENvbnRyb2xsZXIuc2lnbmFsXG4gICAgfTtcbiAgICB0aGlzLm5leHRGb2N1cyA9IG51bGw7XG4gICAgdGhpcy50cmFja1RhYmxlKCk7XG4gIH1cbiAgZ2V0VGFibGUoKSB7XG4gICAgcmV0dXJuIHRoaXMudGFibGU7XG4gIH1cbiAgcmVtb3ZlTGlzdGVuZXJzKCkge1xuICAgIHRoaXMuYWJvcnRDb250cm9sbGVyLmFib3J0KCdyZW1vdmVMaXN0ZW5lcnMnKTtcbiAgICBBcnJheS5mcm9tKHRoaXMubGlzdGVuZXJzVG9SZW1vdmUpLmZvckVhY2gocmVtb3ZlTGlzdGVuZXIgPT4gcmVtb3ZlTGlzdGVuZXIoKSk7XG4gICAgdGhpcy5saXN0ZW5lcnNUb1JlbW92ZS5jbGVhcigpO1xuICB9XG4gICRsb29rdXAoKSB7XG4gICAgcmV0dXJuICRnZXRUYWJsZUFuZEVsZW1lbnRCeUtleSh0aGlzLnRhYmxlTm9kZUtleSwgdGhpcy5lZGl0b3IpO1xuICB9XG4gIHRyYWNrVGFibGUoKSB7XG4gICAgY29uc3Qgb2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlcihyZWNvcmRzID0+IHtcbiAgICAgIHRoaXMuZWRpdG9yLmdldEVkaXRvclN0YXRlKCkucmVhZCgoKSA9PiB7XG4gICAgICAgIGxldCBncmlkTmVlZHNSZWRyYXcgPSBmYWxzZTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZWNvcmRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgY29uc3QgcmVjb3JkID0gcmVjb3Jkc1tpXTtcbiAgICAgICAgICBjb25zdCB0YXJnZXQgPSByZWNvcmQudGFyZ2V0O1xuICAgICAgICAgIGNvbnN0IG5vZGVOYW1lID0gdGFyZ2V0Lm5vZGVOYW1lO1xuICAgICAgICAgIGlmIChub2RlTmFtZSA9PT0gJ1RBQkxFJyB8fCBub2RlTmFtZSA9PT0gJ1RCT0RZJyB8fCBub2RlTmFtZSA9PT0gJ1RIRUFEJyB8fCBub2RlTmFtZSA9PT0gJ1RSJykge1xuICAgICAgICAgICAgZ3JpZE5lZWRzUmVkcmF3ID0gdHJ1ZTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWdyaWROZWVkc1JlZHJhdykge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgdGFibGVOb2RlLFxuICAgICAgICAgIHRhYmxlRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy4kbG9va3VwKCk7XG4gICAgICAgIHRoaXMudGFibGUgPSBnZXRUYWJsZSh0YWJsZU5vZGUsIHRhYmxlRWxlbWVudCk7XG4gICAgICB9LCB7XG4gICAgICAgIGVkaXRvcjogdGhpcy5lZGl0b3JcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIHRoaXMuZWRpdG9yLmdldEVkaXRvclN0YXRlKCkucmVhZCgoKSA9PiB7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHRhYmxlTm9kZSxcbiAgICAgICAgdGFibGVFbGVtZW50XG4gICAgICB9ID0gdGhpcy4kbG9va3VwKCk7XG4gICAgICB0aGlzLnRhYmxlID0gZ2V0VGFibGUodGFibGVOb2RlLCB0YWJsZUVsZW1lbnQpO1xuICAgICAgb2JzZXJ2ZXIub2JzZXJ2ZSh0YWJsZUVsZW1lbnQsIHtcbiAgICAgICAgYXR0cmlidXRlczogdHJ1ZSxcbiAgICAgICAgY2hpbGRMaXN0OiB0cnVlLFxuICAgICAgICBzdWJ0cmVlOiB0cnVlXG4gICAgICB9KTtcbiAgICB9LCB7XG4gICAgICBlZGl0b3I6IHRoaXMuZWRpdG9yXG4gICAgfSk7XG4gIH1cbiAgJGNsZWFySGlnaGxpZ2h0KCkge1xuICAgIGNvbnN0IGVkaXRvciA9IHRoaXMuZWRpdG9yO1xuICAgIHRoaXMuaXNIaWdobGlnaHRpbmdDZWxscyA9IGZhbHNlO1xuICAgIHRoaXMuYW5jaG9yWCA9IC0xO1xuICAgIHRoaXMuYW5jaG9yWSA9IC0xO1xuICAgIHRoaXMuZm9jdXNYID0gLTE7XG4gICAgdGhpcy5mb2N1c1kgPSAtMTtcbiAgICB0aGlzLnRhYmxlU2VsZWN0aW9uID0gbnVsbDtcbiAgICB0aGlzLmFuY2hvckNlbGxOb2RlS2V5ID0gbnVsbDtcbiAgICB0aGlzLmZvY3VzQ2VsbE5vZGVLZXkgPSBudWxsO1xuICAgIHRoaXMuYW5jaG9yQ2VsbCA9IG51bGw7XG4gICAgdGhpcy5mb2N1c0NlbGwgPSBudWxsO1xuICAgIHRoaXMuaGFzSGlqYWNrZWRTZWxlY3Rpb25TdHlsZXMgPSBmYWxzZTtcbiAgICB0aGlzLiRlbmFibGVIaWdobGlnaHRTdHlsZSgpO1xuICAgIGNvbnN0IHtcbiAgICAgIHRhYmxlTm9kZSxcbiAgICAgIHRhYmxlRWxlbWVudFxuICAgIH0gPSB0aGlzLiRsb29rdXAoKTtcbiAgICBjb25zdCBncmlkID0gZ2V0VGFibGUodGFibGVOb2RlLCB0YWJsZUVsZW1lbnQpO1xuICAgICR1cGRhdGVET01Gb3JTZWxlY3Rpb24oZWRpdG9yLCBncmlkLCBudWxsKTtcbiAgICBpZiAoJGdldFNlbGVjdGlvbigpICE9PSBudWxsKSB7XG4gICAgICAkc2V0U2VsZWN0aW9uKG51bGwpO1xuICAgICAgZWRpdG9yLmRpc3BhdGNoQ29tbWFuZChTRUxFQ1RJT05fQ0hBTkdFX0NPTU1BTkQsIHVuZGVmaW5lZCk7XG4gICAgfVxuICB9XG4gICRlbmFibGVIaWdobGlnaHRTdHlsZSgpIHtcbiAgICBjb25zdCBlZGl0b3IgPSB0aGlzLmVkaXRvcjtcbiAgICBjb25zdCB7XG4gICAgICB0YWJsZUVsZW1lbnRcbiAgICB9ID0gdGhpcy4kbG9va3VwKCk7XG4gICAgcmVtb3ZlQ2xhc3NOYW1lc0Zyb21FbGVtZW50KHRhYmxlRWxlbWVudCwgZWRpdG9yLl9jb25maWcudGhlbWUudGFibGVTZWxlY3Rpb24pO1xuICAgIHRhYmxlRWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKCdkaXNhYmxlLXNlbGVjdGlvbicpO1xuICAgIHRoaXMuaGFzSGlqYWNrZWRTZWxlY3Rpb25TdHlsZXMgPSBmYWxzZTtcbiAgfVxuICAkZGlzYWJsZUhpZ2hsaWdodFN0eWxlKCkge1xuICAgIGNvbnN0IHtcbiAgICAgIHRhYmxlRWxlbWVudFxuICAgIH0gPSB0aGlzLiRsb29rdXAoKTtcbiAgICBhZGRDbGFzc05hbWVzVG9FbGVtZW50KHRhYmxlRWxlbWVudCwgdGhpcy5lZGl0b3IuX2NvbmZpZy50aGVtZS50YWJsZVNlbGVjdGlvbik7XG4gICAgdGhpcy5oYXNIaWphY2tlZFNlbGVjdGlvblN0eWxlcyA9IHRydWU7XG4gIH1cbiAgJHVwZGF0ZVRhYmxlVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSB7XG4gICAgaWYgKHNlbGVjdGlvbiAhPT0gbnVsbCkge1xuICAgICAgaWYgKCEoc2VsZWN0aW9uLnRhYmxlS2V5ID09PSB0aGlzLnRhYmxlTm9kZUtleSkpIHtcbiAgICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBUYWJsZU9ic2VydmVyLiR1cGRhdGVUYWJsZVRhYmxlU2VsZWN0aW9uOiBzZWxlY3Rpb24udGFibGVLZXkgIT09IHRoaXMudGFibGVOb2RlS2V5ICgnJHtzZWxlY3Rpb24udGFibGVLZXl9JyAhPT0gJyR7dGhpcy50YWJsZU5vZGVLZXl9JylgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGVkaXRvciA9IHRoaXMuZWRpdG9yO1xuICAgICAgdGhpcy50YWJsZVNlbGVjdGlvbiA9IHNlbGVjdGlvbjtcbiAgICAgIHRoaXMuaXNIaWdobGlnaHRpbmdDZWxscyA9IHRydWU7XG4gICAgICB0aGlzLiRkaXNhYmxlSGlnaGxpZ2h0U3R5bGUoKTtcbiAgICAgIHRoaXMudXBkYXRlRE9NU2VsZWN0aW9uKCk7XG4gICAgICAkdXBkYXRlRE9NRm9yU2VsZWN0aW9uKGVkaXRvciwgdGhpcy50YWJsZSwgdGhpcy50YWJsZVNlbGVjdGlvbik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuJGNsZWFySGlnaGxpZ2h0KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBpbnRlcm5hbFxuICAgKiBGaXJlZm94IGhhcyBhIHN0cmFuZ2UgYmVoYXZpb3Igd2hlcmUgcHJlc3NpbmcgdGhlIGRvd24gYXJyb3cga2V5IGZyb21cbiAgICogYWJvdmUgdGhlIHRhYmxlIHdpbGwgbW92ZSB0aGUgY2FyZXQgYWZ0ZXIgdGhlIHRhYmxlIGFuZCB0aGVuIGxleGljYWxcbiAgICogd2lsbCBzZWxlY3QgdGhlIGxhc3QgY2VsbCBpbnN0ZWFkIG9mIHRoZSBmaXJzdC5cbiAgICogV2UgZG8gc3RpbGwgd2FudCB0byBsZXQgdGhlIGJyb3dzZXIgaGFuZGxlIGNhcmV0IG1vdmVtZW50IGJ1dCB3ZSB3aWxsXG4gICAqIHVzZSB0aGlzIHByb3BlcnR5IHRvIFwidGFnXCIgdGhlIHVwZGF0ZSBzbyB0aGF0IHdlIGNhbiByZWNoZWNrIHRoZVxuICAgKiBzZWxlY3Rpb24gYWZ0ZXIgdGhlIGV2ZW50IGlzIHByb2Nlc3NlZC5cbiAgICovXG4gIHNldFNob3VsZENoZWNrU2VsZWN0aW9uKCkge1xuICAgIHRoaXMuc2hvdWxkQ2hlY2tTZWxlY3Rpb24gPSB0cnVlO1xuICB9XG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGdldEFuZENsZWFyU2hvdWxkQ2hlY2tTZWxlY3Rpb24oKSB7XG4gICAgaWYgKHRoaXMuc2hvdWxkQ2hlY2tTZWxlY3Rpb24pIHtcbiAgICAgIHRoaXMuc2hvdWxkQ2hlY2tTZWxlY3Rpb24gPSBmYWxzZTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQGludGVybmFsXG4gICAqIFdoZW4gaGFuZGxpbmcgbW91c2Vtb3ZlIGV2ZW50cyB3ZSB0cmFjayB3aGF0IHRoZSBmb2N1cyBjZWxsIHNob3VsZCBiZSwgYnV0XG4gICAqIHRoZSBET00gc2VsZWN0aW9uIG1heSBlbmQgdXAgc29tZXdoZXJlIGVsc2UgZW50aXJlbHkuIFdlIGRvbid0IGhhdmUgYW4gZWxlZ2FudFxuICAgKiB3YXkgdG8gaGFuZGxlIHRoaXMgYWZ0ZXIgdGhlIERPTSBzZWxlY3Rpb24gaGFzIGJlZW4gcmVzb2x2ZWQgaW4gYVxuICAgKiBTRUxFQ1RJT05fQ0hBTkdFX0NPTU1BTkQgY2FsbGJhY2suXG4gICAqL1xuICBzZXROZXh0Rm9jdXMobmV4dEZvY3VzKSB7XG4gICAgdGhpcy5uZXh0Rm9jdXMgPSBuZXh0Rm9jdXM7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIGdldEFuZENsZWFyTmV4dEZvY3VzKCkge1xuICAgIGNvbnN0IHtcbiAgICAgIG5leHRGb2N1c1xuICAgIH0gPSB0aGlzO1xuICAgIGlmIChuZXh0Rm9jdXMgIT09IG51bGwpIHtcbiAgICAgIHRoaXMubmV4dEZvY3VzID0gbnVsbDtcbiAgICB9XG4gICAgcmV0dXJuIG5leHRGb2N1cztcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgdXBkYXRlRE9NU2VsZWN0aW9uKCkge1xuICAgIGlmICh0aGlzLmFuY2hvckNlbGwgIT09IG51bGwgJiYgdGhpcy5mb2N1c0NlbGwgIT09IG51bGwpIHtcbiAgICAgIGNvbnN0IGRvbVNlbGVjdGlvbiA9IGdldERPTVNlbGVjdGlvbih0aGlzLmVkaXRvci5fd2luZG93KTtcbiAgICAgIC8vIFdlIGFyZSBub3QgdXNpbmcgYSBuYXRpdmUgc2VsZWN0aW9uIGZvciB0YWJsZXMsIGFuZCBpZiB3ZVxuICAgICAgLy8gc2V0IG9uZSB0aGVuIHRoZSByZWNvbmNpbGVyIHdpbGwgdW5kbyBpdC5cbiAgICAgIC8vIFRPRE8gLSBpdCB3b3VsZCBtYWtlIHNlbnNlIHRvIGhhdmUgb25lIHNvIHRoYXQgbmF0aXZlXG4gICAgICAvLyAgICAgICAgY29weS9wYXN0ZSB3b3JrZWQuIFJpZ2h0IG5vdyB3ZSBoYXZlIHRvIGVtdWxhdGUgd2l0aFxuICAgICAgLy8gICAgICAgIGtleWJvYXJkIGV2ZW50cyBidXQgaXQgd29uJ3QgZmlyZSBpZiB0cmlnZ2VyZWQgZnJvbSB0aGUgbWVudVxuICAgICAgaWYgKGRvbVNlbGVjdGlvbiAmJiBkb21TZWxlY3Rpb24ucmFuZ2VDb3VudCA+IDApIHtcbiAgICAgICAgZG9tU2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICAkc2V0Rm9jdXNDZWxsRm9yU2VsZWN0aW9uKGNlbGwsIGlnbm9yZVN0YXJ0ID0gZmFsc2UpIHtcbiAgICBjb25zdCBlZGl0b3IgPSB0aGlzLmVkaXRvcjtcbiAgICBjb25zdCB7XG4gICAgICB0YWJsZU5vZGVcbiAgICB9ID0gdGhpcy4kbG9va3VwKCk7XG4gICAgY29uc3QgY2VsbFggPSBjZWxsLng7XG4gICAgY29uc3QgY2VsbFkgPSBjZWxsLnk7XG4gICAgdGhpcy5mb2N1c0NlbGwgPSBjZWxsO1xuXG4gICAgLy8gRW5hYmxlIGhpZ2hsaWdodGluZyBpZjogaWdub3JlU3RhcnQgaXMgdHJ1ZSwgb3IgYW5jaG9yIGRpZmZlcnMgZnJvbSBmb2N1cyxcbiAgICAvLyBvciB3ZSBoYXZlIHZhbGlkIHRhYmxlU2VsZWN0aW9uIHdpdGggYW5jaG9yIChmb3IgZmlyc3QgZHJhZyBhZnRlciBjb2x1bW4gc3dpdGNoKVxuICAgIGlmICghdGhpcy5pc0hpZ2hsaWdodGluZ0NlbGxzKSB7XG4gICAgICBjb25zdCBzaG91bGRFbmFibGUgPSBpZ25vcmVTdGFydCB8fCB0aGlzLmFuY2hvclggIT09IGNlbGxYIHx8IHRoaXMuYW5jaG9yWSAhPT0gY2VsbFkgfHwgdGhpcy50YWJsZVNlbGVjdGlvbiAhPSBudWxsICYmIHRoaXMuYW5jaG9yQ2VsbE5vZGVLZXkgIT0gbnVsbDtcbiAgICAgIGlmIChzaG91bGRFbmFibGUpIHtcbiAgICAgICAgdGhpcy5pc0hpZ2hsaWdodGluZ0NlbGxzID0gdHJ1ZTtcbiAgICAgICAgdGhpcy4kZGlzYWJsZUhpZ2hsaWdodFN0eWxlKCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gU2tpcCBpZiB3ZSdyZSB0cnlpbmcgdG8gc2VsZWN0IHRoZSBzYW1lIGNlbGwgd2UgYWxyZWFkeSBoYXZlIHNlbGVjdGVkXG4gICAgLy8gQnV0IG9ubHkgaWYgZm9jdXNYL2ZvY3VzWSBhcmUgdmFsaWQgKG5vdCAtMSwgd2hpY2ggbWVhbnMgbm90IHJlc2V0KVxuICAgIGlmICh0aGlzLmZvY3VzWCAhPT0gLTEgJiYgdGhpcy5mb2N1c1kgIT09IC0xICYmIGNlbGxYID09PSB0aGlzLmZvY3VzWCAmJiBjZWxsWSA9PT0gdGhpcy5mb2N1c1kpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgdGhpcy5mb2N1c1ggPSBjZWxsWDtcbiAgICB0aGlzLmZvY3VzWSA9IGNlbGxZO1xuICAgIGlmICh0aGlzLmlzSGlnaGxpZ2h0aW5nQ2VsbHMpIHtcbiAgICAgIGNvbnN0IGZvY3VzVGFibGVDZWxsTm9kZSA9ICRnZXROZWFyZXN0VGFibGVDZWxsSW5UYWJsZUZyb21ET01Ob2RlKHRhYmxlTm9kZSwgY2VsbC5lbGVtKTtcbiAgICAgIGlmICh0aGlzLnRhYmxlU2VsZWN0aW9uICE9IG51bGwgJiYgdGhpcy5hbmNob3JDZWxsTm9kZUtleSAhPSBudWxsKSB7XG4gICAgICAgIGxldCB0YXJnZXRDZWxsTm9kZSA9IGZvY3VzVGFibGVDZWxsTm9kZTtcblxuICAgICAgICAvLyBGYWxsYmFjazogdXNlIGNvb3JkaW5hdGVzIGlmIERPTSBsb29rdXAgZmFpbGVkIChoYW5kbGVzIHRpbWluZyBpc3N1ZXMgb24gZmlyc3QgZHJhZylcbiAgICAgICAgaWYgKHRhcmdldENlbGxOb2RlID09PSBudWxsICYmIGlnbm9yZVN0YXJ0KSB7XG4gICAgICAgICAgdGFyZ2V0Q2VsbE5vZGUgPSB0YWJsZU5vZGUuZ2V0Q2VsbE5vZGVGcm9tQ29yZHMoY2VsbFgsIGNlbGxZLCB0aGlzLnRhYmxlKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGFyZ2V0Q2VsbE5vZGUgIT09IG51bGwpIHtcbiAgICAgICAgICBjb25zdCBhbmNob3JUYWJsZUNlbGwgPSB0aGlzLiRnZXRBbmNob3JUYWJsZUNlbGxPclRocm93KCk7XG4gICAgICAgICAgdGhpcy5mb2N1c0NlbGxOb2RlS2V5ID0gdGFyZ2V0Q2VsbE5vZGUuZ2V0S2V5KCk7XG4gICAgICAgICAgdGhpcy50YWJsZVNlbGVjdGlvbiA9ICRjcmVhdGVUYWJsZVNlbGVjdGlvbkZyb20odGFibGVOb2RlLCBhbmNob3JUYWJsZUNlbGwsIHRhcmdldENlbGxOb2RlKTtcbiAgICAgICAgICAkc2V0U2VsZWN0aW9uKHRoaXMudGFibGVTZWxlY3Rpb24pO1xuICAgICAgICAgIGVkaXRvci5kaXNwYXRjaENvbW1hbmQoU0VMRUNUSU9OX0NIQU5HRV9DT01NQU5ELCB1bmRlZmluZWQpO1xuICAgICAgICAgICR1cGRhdGVET01Gb3JTZWxlY3Rpb24oZWRpdG9yLCB0aGlzLnRhYmxlLCB0aGlzLnRhYmxlU2VsZWN0aW9uKTtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgJGdldEFuY2hvclRhYmxlQ2VsbCgpIHtcbiAgICByZXR1cm4gdGhpcy5hbmNob3JDZWxsTm9kZUtleSA/ICRnZXROb2RlQnlLZXkodGhpcy5hbmNob3JDZWxsTm9kZUtleSkgOiBudWxsO1xuICB9XG4gICRnZXRBbmNob3JUYWJsZUNlbGxPclRocm93KCkge1xuICAgIGNvbnN0IGFuY2hvclRhYmxlQ2VsbCA9IHRoaXMuJGdldEFuY2hvclRhYmxlQ2VsbCgpO1xuICAgIGlmICghKGFuY2hvclRhYmxlQ2VsbCAhPT0gbnVsbCkpIHtcbiAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgVGFibGVPYnNlcnZlciBhbmNob3JUYWJsZUNlbGwgaXMgbnVsbGApO1xuICAgIH1cbiAgICByZXR1cm4gYW5jaG9yVGFibGVDZWxsO1xuICB9XG4gICRnZXRGb2N1c1RhYmxlQ2VsbCgpIHtcbiAgICByZXR1cm4gdGhpcy5mb2N1c0NlbGxOb2RlS2V5ID8gJGdldE5vZGVCeUtleSh0aGlzLmZvY3VzQ2VsbE5vZGVLZXkpIDogbnVsbDtcbiAgfVxuICAkZ2V0Rm9jdXNUYWJsZUNlbGxPclRocm93KCkge1xuICAgIGNvbnN0IGZvY3VzVGFibGVDZWxsID0gdGhpcy4kZ2V0Rm9jdXNUYWJsZUNlbGwoKTtcbiAgICBpZiAoIShmb2N1c1RhYmxlQ2VsbCAhPT0gbnVsbCkpIHtcbiAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgVGFibGVPYnNlcnZlciBmb2N1c1RhYmxlQ2VsbCBpcyBudWxsYCk7XG4gICAgfVxuICAgIHJldHVybiBmb2N1c1RhYmxlQ2VsbDtcbiAgfVxuICAkc2V0QW5jaG9yQ2VsbEZvclNlbGVjdGlvbihjZWxsKSB7XG4gICAgdGhpcy5pc0hpZ2hsaWdodGluZ0NlbGxzID0gZmFsc2U7XG4gICAgdGhpcy5hbmNob3JDZWxsID0gY2VsbDtcbiAgICB0aGlzLmFuY2hvclggPSBjZWxsLng7XG4gICAgdGhpcy5hbmNob3JZID0gY2VsbC55O1xuICAgIC8vIFJlc2V0IGZvY3VzIHN0YXRlIHRvIHByZXZlbnQgc3RhbGUgdmFsdWVzIGZyb20gcHJldmlvdXMgc2VsZWN0aW9uc1xuICAgIHRoaXMuZm9jdXNYID0gLTE7XG4gICAgdGhpcy5mb2N1c1kgPSAtMTtcbiAgICB0aGlzLmZvY3VzQ2VsbCA9IG51bGw7XG4gICAgdGhpcy5mb2N1c0NlbGxOb2RlS2V5ID0gbnVsbDtcbiAgICBjb25zdCB7XG4gICAgICB0YWJsZU5vZGVcbiAgICB9ID0gdGhpcy4kbG9va3VwKCk7XG4gICAgY29uc3QgYW5jaG9yVGFibGVDZWxsTm9kZSA9ICRnZXROZWFyZXN0VGFibGVDZWxsSW5UYWJsZUZyb21ET01Ob2RlKHRhYmxlTm9kZSwgY2VsbC5lbGVtKTtcbiAgICBpZiAoYW5jaG9yVGFibGVDZWxsTm9kZSAhPT0gbnVsbCkge1xuICAgICAgY29uc3QgYW5jaG9yTm9kZUtleSA9IGFuY2hvclRhYmxlQ2VsbE5vZGUuZ2V0S2V5KCk7XG4gICAgICBpZiAodGhpcy50YWJsZVNlbGVjdGlvbiAhPSBudWxsKSB7XG4gICAgICAgIHRoaXMudGFibGVTZWxlY3Rpb24gPSB0aGlzLnRhYmxlU2VsZWN0aW9uLmNsb25lKCk7XG4gICAgICAgIHRoaXMudGFibGVTZWxlY3Rpb24uc2V0KHRhYmxlTm9kZS5nZXRLZXkoKSwgYW5jaG9yTm9kZUtleSwgYW5jaG9yTm9kZUtleSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnRhYmxlU2VsZWN0aW9uID0gJGNyZWF0ZVRhYmxlU2VsZWN0aW9uRnJvbSh0YWJsZU5vZGUsIGFuY2hvclRhYmxlQ2VsbE5vZGUsIGFuY2hvclRhYmxlQ2VsbE5vZGUpO1xuICAgICAgfVxuICAgICAgdGhpcy5hbmNob3JDZWxsTm9kZUtleSA9IGFuY2hvck5vZGVLZXk7XG4gICAgfVxuICB9XG4gICRmb3JtYXRDZWxscyh0eXBlKSB7XG4gICAgY29uc3Qgc2VsZWN0aW9uID0gJGdldFNlbGVjdGlvbigpO1xuICAgIGlmICghJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCBUYWJsZSBzZWxlY3Rpb25gKTtcbiAgICB9XG4gICAgY29uc3QgZm9ybWF0U2VsZWN0aW9uID0gJGNyZWF0ZVJhbmdlU2VsZWN0aW9uKCk7XG4gICAgY29uc3QgYW5jaG9yID0gZm9ybWF0U2VsZWN0aW9uLmFuY2hvcjtcbiAgICBjb25zdCBmb2N1cyA9IGZvcm1hdFNlbGVjdGlvbi5mb2N1cztcbiAgICBjb25zdCBjZWxsTm9kZXMgPSBzZWxlY3Rpb24uZ2V0Tm9kZXMoKS5maWx0ZXIoJGlzVGFibGVDZWxsTm9kZSk7XG4gICAgaWYgKCEoY2VsbE5vZGVzLmxlbmd0aCA+IDApKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYE5vIHRhYmxlIGNlbGxzIHByZXNlbnRgKTtcbiAgICB9XG4gICAgY29uc3QgcGFyYWdyYXBoID0gY2VsbE5vZGVzWzBdLmdldEZpcnN0Q2hpbGQoKTtcbiAgICBjb25zdCBhbGlnbkZvcm1hdFdpdGggPSAkaXNQYXJhZ3JhcGhOb2RlKHBhcmFncmFwaCkgPyBwYXJhZ3JhcGguZ2V0Rm9ybWF0RmxhZ3ModHlwZSwgbnVsbCkgOiBudWxsO1xuICAgIGNlbGxOb2Rlcy5mb3JFYWNoKGNlbGxOb2RlID0+IHtcbiAgICAgIGFuY2hvci5zZXQoY2VsbE5vZGUuZ2V0S2V5KCksIDAsICdlbGVtZW50Jyk7XG4gICAgICBmb2N1cy5zZXQoY2VsbE5vZGUuZ2V0S2V5KCksIGNlbGxOb2RlLmdldENoaWxkcmVuU2l6ZSgpLCAnZWxlbWVudCcpO1xuICAgICAgZm9ybWF0U2VsZWN0aW9uLmZvcm1hdFRleHQodHlwZSwgYWxpZ25Gb3JtYXRXaXRoKTtcbiAgICB9KTtcbiAgICAkc2V0U2VsZWN0aW9uKHNlbGVjdGlvbik7XG4gICAgdGhpcy5lZGl0b3IuZGlzcGF0Y2hDb21tYW5kKFNFTEVDVElPTl9DSEFOR0VfQ09NTUFORCwgdW5kZWZpbmVkKTtcbiAgfVxuICAkY2xlYXJUZXh0KCkge1xuICAgIGNvbnN0IHtcbiAgICAgIGVkaXRvclxuICAgIH0gPSB0aGlzO1xuICAgIGNvbnN0IHRhYmxlTm9kZSA9ICRnZXROb2RlQnlLZXkodGhpcy50YWJsZU5vZGVLZXkpO1xuICAgIGlmICghJGlzVGFibGVOb2RlKHRhYmxlTm9kZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRXhwZWN0ZWQgVGFibGVOb2RlLicpO1xuICAgIH1cbiAgICBjb25zdCBzZWxlY3Rpb24gPSAkZ2V0U2VsZWN0aW9uKCk7XG4gICAgaWYgKCEkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYEV4cGVjdGVkIFRhYmxlU2VsZWN0aW9uYCk7XG4gICAgfVxuICAgIGNvbnN0IHNlbGVjdGVkTm9kZXMgPSBzZWxlY3Rpb24uZ2V0Tm9kZXMoKS5maWx0ZXIoJGlzVGFibGVDZWxsTm9kZSk7XG5cbiAgICAvLyBDaGVjayBpZiB0aGUgZW50aXJlIHRhYmxlIGlzIHNlbGVjdGVkIGJ5IHZlcmlmeWluZyBmaXJzdCBhbmQgbGFzdCBjZWxsc1xuICAgIGNvbnN0IGZpcnN0Um93ID0gdGFibGVOb2RlLmdldEZpcnN0Q2hpbGQoKTtcbiAgICBjb25zdCBsYXN0Um93ID0gdGFibGVOb2RlLmdldExhc3RDaGlsZCgpO1xuICAgIGNvbnN0IGlzRW50aXJlVGFibGVTZWxlY3RlZCA9IHNlbGVjdGVkTm9kZXMubGVuZ3RoID4gMCAmJiBmaXJzdFJvdyAhPT0gbnVsbCAmJiBsYXN0Um93ICE9PSBudWxsICYmICRpc1RhYmxlUm93Tm9kZShmaXJzdFJvdykgJiYgJGlzVGFibGVSb3dOb2RlKGxhc3RSb3cpICYmIHNlbGVjdGVkTm9kZXNbMF0gPT09IGZpcnN0Um93LmdldEZpcnN0Q2hpbGQoKSAmJiBzZWxlY3RlZE5vZGVzW3NlbGVjdGVkTm9kZXMubGVuZ3RoIC0gMV0gPT09IGxhc3RSb3cuZ2V0TGFzdENoaWxkKCk7XG4gICAgaWYgKGlzRW50aXJlVGFibGVTZWxlY3RlZCkge1xuICAgICAgdGFibGVOb2RlLnNlbGVjdFByZXZpb3VzKCk7XG4gICAgICBjb25zdCBwYXJlbnQgPSB0YWJsZU5vZGUuZ2V0UGFyZW50KCk7XG4gICAgICAvLyBEZWxldGUgZW50aXJlIHRhYmxlXG4gICAgICB0YWJsZU5vZGUucmVtb3ZlKCk7XG4gICAgICAvLyBIYW5kbGUgY2FzZSB3aGVuIHRhYmxlIHdhcyB0aGUgb25seSBub2RlXG4gICAgICBpZiAoJGlzUm9vdE5vZGUocGFyZW50KSAmJiBwYXJlbnQuaXNFbXB0eSgpKSB7XG4gICAgICAgIGVkaXRvci5kaXNwYXRjaENvbW1hbmQoSU5TRVJUX1BBUkFHUkFQSF9DT01NQU5ELCB1bmRlZmluZWQpO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBzZWxlY3RlZE5vZGVzLmZvckVhY2goY2VsbE5vZGUgPT4ge1xuICAgICAgaWYgKCRpc0VsZW1lbnROb2RlKGNlbGxOb2RlKSkge1xuICAgICAgICBjb25zdCBwYXJhZ3JhcGhOb2RlID0gJGNyZWF0ZVBhcmFncmFwaE5vZGUoKTtcbiAgICAgICAgY29uc3QgdGV4dE5vZGUgPSAkY3JlYXRlVGV4dE5vZGUoKTtcbiAgICAgICAgcGFyYWdyYXBoTm9kZS5hcHBlbmQodGV4dE5vZGUpO1xuICAgICAgICBjZWxsTm9kZS5hcHBlbmQocGFyYWdyYXBoTm9kZSk7XG4gICAgICAgIGNlbGxOb2RlLmdldENoaWxkcmVuKCkuZm9yRWFjaChjaGlsZCA9PiB7XG4gICAgICAgICAgaWYgKGNoaWxkICE9PSBwYXJhZ3JhcGhOb2RlKSB7XG4gICAgICAgICAgICBjaGlsZC5yZW1vdmUoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgICR1cGRhdGVET01Gb3JTZWxlY3Rpb24oZWRpdG9yLCB0aGlzLnRhYmxlLCBudWxsKTtcbiAgICAkc2V0U2VsZWN0aW9uKG51bGwpO1xuICAgIGVkaXRvci5kaXNwYXRjaENvbW1hbmQoU0VMRUNUSU9OX0NIQU5HRV9DT01NQU5ELCB1bmRlZmluZWQpO1xuICB9XG59XG5cbmNvbnN0IExFWElDQUxfRUxFTUVOVF9LRVkgPSAnX19sZXhpY2FsVGFibGVTZWxlY3Rpb24nO1xuY29uc3QgaXNQb2ludGVyRG93bk9uRXZlbnQgPSBldmVudCA9PiB7XG4gIHJldHVybiAoZXZlbnQuYnV0dG9ucyAmIDEpID09PSAxO1xufTtcbmZ1bmN0aW9uIGlzSFRNTFRhYmxlRWxlbWVudChlbCkge1xuICByZXR1cm4gaXNIVE1MRWxlbWVudChlbCkgJiYgZWwubm9kZU5hbWUgPT09ICdUQUJMRSc7XG59XG5mdW5jdGlvbiBnZXRUYWJsZUVsZW1lbnQodGFibGVOb2RlLCBkb20pIHtcbiAgaWYgKCFkb20pIHtcbiAgICByZXR1cm4gZG9tO1xuICB9XG4gIGNvbnN0IGVsZW1lbnQgPSBpc0hUTUxUYWJsZUVsZW1lbnQoZG9tKSA/IGRvbSA6IHRhYmxlTm9kZS5nZXRET01TbG90KGRvbSkuZWxlbWVudDtcbiAgaWYgKCEoZWxlbWVudC5ub2RlTmFtZSA9PT0gJ1RBQkxFJykpIHtcbiAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYGdldFRhYmxlRWxlbWVudDogRXhwZWN0aW5nIHRhYmxlIGluIGFzIERPTSBub2RlIGZvciBUYWJsZU5vZGUsIG5vdCAke2RvbS5ub2RlTmFtZX1gKTtcbiAgfVxuICByZXR1cm4gZWxlbWVudDtcbn1cbmZ1bmN0aW9uIGdldEVkaXRvcldpbmRvdyhlZGl0b3IpIHtcbiAgcmV0dXJuIGVkaXRvci5fd2luZG93O1xufVxuZnVuY3Rpb24gJGZpbmRQYXJlbnRUYWJsZUNlbGxOb2RlSW5UYWJsZSh0YWJsZU5vZGUsIG5vZGUpIHtcbiAgZm9yIChsZXQgY3VycmVudE5vZGUgPSBub2RlLCBsYXN0VGFibGVDZWxsTm9kZSA9IG51bGw7IGN1cnJlbnROb2RlICE9PSBudWxsOyBjdXJyZW50Tm9kZSA9IGN1cnJlbnROb2RlLmdldFBhcmVudCgpKSB7XG4gICAgaWYgKHRhYmxlTm9kZS5pcyhjdXJyZW50Tm9kZSkpIHtcbiAgICAgIHJldHVybiBsYXN0VGFibGVDZWxsTm9kZTtcbiAgICB9IGVsc2UgaWYgKCRpc1RhYmxlQ2VsbE5vZGUoY3VycmVudE5vZGUpKSB7XG4gICAgICBsYXN0VGFibGVDZWxsTm9kZSA9IGN1cnJlbnROb2RlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cbmNvbnN0IEFSUk9XX0tFWV9DT01NQU5EU19XSVRIX0RJUkVDVElPTiA9IFtbS0VZX0FSUk9XX0RPV05fQ09NTUFORCwgJ2Rvd24nXSwgW0tFWV9BUlJPV19VUF9DT01NQU5ELCAndXAnXSwgW0tFWV9BUlJPV19MRUZUX0NPTU1BTkQsICdiYWNrd2FyZCddLCBbS0VZX0FSUk9XX1JJR0hUX0NPTU1BTkQsICdmb3J3YXJkJ11dO1xuY29uc3QgREVMRVRFX1RFWFRfQ09NTUFORFMgPSBbREVMRVRFX1dPUkRfQ09NTUFORCwgREVMRVRFX0xJTkVfQ09NTUFORCwgREVMRVRFX0NIQVJBQ1RFUl9DT01NQU5EXTtcbmNvbnN0IERFTEVURV9LRVlfQ09NTUFORFMgPSBbS0VZX0JBQ0tTUEFDRV9DT01NQU5ELCBLRVlfREVMRVRFX0NPTU1BTkRdO1xuZnVuY3Rpb24gYXBwbHlUYWJsZUhhbmRsZXJzKHRhYmxlTm9kZSwgZWxlbWVudCwgZWRpdG9yLCBoYXNUYWJIYW5kbGVyKSB7XG4gIGNvbnN0IHJvb3RFbGVtZW50ID0gZWRpdG9yLmdldFJvb3RFbGVtZW50KCk7XG4gIGNvbnN0IGVkaXRvcldpbmRvdyA9IGdldEVkaXRvcldpbmRvdyhlZGl0b3IpO1xuICBpZiAoIShyb290RWxlbWVudCAhPT0gbnVsbCAmJiBlZGl0b3JXaW5kb3cgIT09IG51bGwpKSB7XG4gICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBhcHBseVRhYmxlSGFuZGxlcnM6IGVkaXRvciBoYXMgbm8gcm9vdCBlbGVtZW50IHNldGApO1xuICB9XG4gIGNvbnN0IHRhYmxlT2JzZXJ2ZXIgPSBuZXcgVGFibGVPYnNlcnZlcihlZGl0b3IsIHRhYmxlTm9kZS5nZXRLZXkoKSk7XG4gIGNvbnN0IHRhYmxlRWxlbWVudCA9IGdldFRhYmxlRWxlbWVudCh0YWJsZU5vZGUsIGVsZW1lbnQpO1xuICBhdHRhY2hUYWJsZU9ic2VydmVyVG9UYWJsZUVsZW1lbnQodGFibGVFbGVtZW50LCB0YWJsZU9ic2VydmVyKTtcbiAgdGFibGVPYnNlcnZlci5saXN0ZW5lcnNUb1JlbW92ZS5hZGQoKCkgPT4gZGV0YWNoVGFibGVPYnNlcnZlckZyb21UYWJsZUVsZW1lbnQodGFibGVFbGVtZW50LCB0YWJsZU9ic2VydmVyKSk7XG4gIGNvbnN0IGNyZWF0ZVBvaW50ZXJIYW5kbGVycyA9IHN0YXJ0aW5nQ2VsbCA9PiB7XG4gICAgaWYgKHRhYmxlT2JzZXJ2ZXIuaXNTZWxlY3RpbmcpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGFibGVPYnNlcnZlci5pc1NlbGVjdGluZyA9IHRydWU7XG5cbiAgICAvLyBTZXQgYW5jaG9yIGltbWVkaWF0ZWx5IGlmIHN0YXJ0aW5nIGNlbGwgcHJvdmlkZWQgKGhhbmRsZXMgZGlyZWN0IGRyYWcgd2l0aG91dCBjbGljaylcbiAgICBpZiAoc3RhcnRpbmdDZWxsICE9PSBudWxsICYmIHRhYmxlT2JzZXJ2ZXIuYW5jaG9yQ2VsbCA9PT0gbnVsbCkge1xuICAgICAgZWRpdG9yLnVwZGF0ZSgoKSA9PiB7XG4gICAgICAgIHRhYmxlT2JzZXJ2ZXIuJHNldEFuY2hvckNlbGxGb3JTZWxlY3Rpb24oc3RhcnRpbmdDZWxsKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICBjb25zdCBvblBvaW50ZXJVcCA9ICgpID0+IHtcbiAgICAgIHRhYmxlT2JzZXJ2ZXIuaXNTZWxlY3RpbmcgPSBmYWxzZTtcbiAgICAgIGVkaXRvcldpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVydXAnLCBvblBvaW50ZXJVcCk7XG4gICAgICBlZGl0b3JXaW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncG9pbnRlcm1vdmUnLCBvblBvaW50ZXJNb3ZlKTtcbiAgICB9O1xuICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSBtb3ZlRXZlbnQgPT4ge1xuICAgICAgaWYgKCFpc1BvaW50ZXJEb3duT25FdmVudChtb3ZlRXZlbnQpICYmIHRhYmxlT2JzZXJ2ZXIuaXNTZWxlY3RpbmcpIHtcbiAgICAgICAgdGFibGVPYnNlcnZlci5pc1NlbGVjdGluZyA9IGZhbHNlO1xuICAgICAgICBlZGl0b3JXaW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncG9pbnRlcnVwJywgb25Qb2ludGVyVXApO1xuICAgICAgICBlZGl0b3JXaW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncG9pbnRlcm1vdmUnLCBvblBvaW50ZXJNb3ZlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKCFpc0RPTU5vZGUobW92ZUV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgbGV0IGZvY3VzQ2VsbCA9IG51bGw7XG4gICAgICAvLyBJbiBmaXJlZm94IHRoZSBtb3ZlRXZlbnQudGFyZ2V0IG1heSBiZSBjYXB0dXJlZCBzbyB3ZSBtdXN0IGFsd2F5c1xuICAgICAgLy8gY29uc3VsdCB0aGUgY29vcmRpbmF0ZXMgIzcyNDVcbiAgICAgIGNvbnN0IG92ZXJyaWRlID0gIShJU19GSVJFRk9YIHx8IHRhYmxlRWxlbWVudC5jb250YWlucyhtb3ZlRXZlbnQudGFyZ2V0KSk7XG4gICAgICBpZiAob3ZlcnJpZGUpIHtcbiAgICAgICAgZm9jdXNDZWxsID0gZ2V0RE9NQ2VsbEluVGFibGVGcm9tVGFyZ2V0KHRhYmxlRWxlbWVudCwgbW92ZUV2ZW50LnRhcmdldCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBmb3IgKGNvbnN0IGVsIG9mIGRvY3VtZW50LmVsZW1lbnRzRnJvbVBvaW50KG1vdmVFdmVudC5jbGllbnRYLCBtb3ZlRXZlbnQuY2xpZW50WSkpIHtcbiAgICAgICAgICBmb2N1c0NlbGwgPSBnZXRET01DZWxsSW5UYWJsZUZyb21UYXJnZXQodGFibGVFbGVtZW50LCBlbCk7XG4gICAgICAgICAgaWYgKGZvY3VzQ2VsbCkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoZm9jdXNDZWxsKSB7XG4gICAgICAgIGNvbnN0IGFuY2hvckNlbGwgPSBmb2N1c0NlbGw7XG4gICAgICAgIC8vIEZhbGxiYWNrOiBzZXQgYW5jaG9yIGlmIHN0aWxsIG1pc3NpbmcgKGhhbmRsZXMgcmFjZSBjb25kaXRpb25zKVxuICAgICAgICBpZiAodGFibGVPYnNlcnZlci5hbmNob3JDZWxsID09PSBudWxsKSB7XG4gICAgICAgICAgZWRpdG9yLnVwZGF0ZSgoKSA9PiB7XG4gICAgICAgICAgICB0YWJsZU9ic2VydmVyLiRzZXRBbmNob3JDZWxsRm9yU2VsZWN0aW9uKGFuY2hvckNlbGwpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0YWJsZU9ic2VydmVyLmZvY3VzQ2VsbCA9PT0gbnVsbCB8fCBmb2N1c0NlbGwuZWxlbSAhPT0gdGFibGVPYnNlcnZlci5mb2N1c0NlbGwuZWxlbSkge1xuICAgICAgICAgIHRhYmxlT2JzZXJ2ZXIuc2V0TmV4dEZvY3VzKHtcbiAgICAgICAgICAgIGZvY3VzQ2VsbCxcbiAgICAgICAgICAgIG92ZXJyaWRlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZWRpdG9yLmRpc3BhdGNoQ29tbWFuZChTRUxFQ1RJT05fQ0hBTkdFX0NPTU1BTkQsIHVuZGVmaW5lZCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuICAgIGVkaXRvcldpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVydXAnLCBvblBvaW50ZXJVcCwgdGFibGVPYnNlcnZlci5saXN0ZW5lck9wdGlvbnMpO1xuICAgIGVkaXRvcldpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVybW92ZScsIG9uUG9pbnRlck1vdmUsIHRhYmxlT2JzZXJ2ZXIubGlzdGVuZXJPcHRpb25zKTtcbiAgfTtcbiAgY29uc3Qgb25Qb2ludGVyRG93biA9IGV2ZW50ID0+IHtcbiAgICB0YWJsZU9ic2VydmVyLnBvaW50ZXJUeXBlID0gZXZlbnQucG9pbnRlclR5cGU7XG4gICAgaWYgKGV2ZW50LmJ1dHRvbiAhPT0gMCB8fCAhaXNET01Ob2RlKGV2ZW50LnRhcmdldCkgfHwgIWVkaXRvcldpbmRvdykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCB0YXJnZXRDZWxsID0gZ2V0RE9NQ2VsbEZyb21UYXJnZXQoZXZlbnQudGFyZ2V0KTtcbiAgICBpZiAodGFyZ2V0Q2VsbCAhPT0gbnVsbCkge1xuICAgICAgZWRpdG9yLnVwZGF0ZSgoKSA9PiB7XG4gICAgICAgIGNvbnN0IHByZXZTZWxlY3Rpb24gPSAkZ2V0UHJldmlvdXNTZWxlY3Rpb24oKTtcbiAgICAgICAgLy8gV2UgY2FuJ3QgdHJ1c3QgRmlyZWZveCB0byBkbyB0aGUgcmlnaHQgdGhpbmcgd2l0aCB0aGUgc2VsZWN0aW9uIGFuZFxuICAgICAgICAvLyB3ZSBkb24ndCBoYXZlIGEgcHJvcGVyIHN0YXRlIG1hY2hpbmUgdG8gZG8gdGhpcyBcImNvcnJlY3RseVwiIGJ1dFxuICAgICAgICAvLyBpZiB3ZSBnbyBhaGVhZCBhbmQgbWFrZSB0aGUgdGFibGUgc2VsZWN0aW9uIG5vdyBpdCB3aWxsIHdvcmtcbiAgICAgICAgaWYgKElTX0ZJUkVGT1ggJiYgZXZlbnQuc2hpZnRLZXkgJiYgJGlzU2VsZWN0aW9uSW5UYWJsZShwcmV2U2VsZWN0aW9uLCB0YWJsZU5vZGUpICYmICgkaXNSYW5nZVNlbGVjdGlvbihwcmV2U2VsZWN0aW9uKSB8fCAkaXNUYWJsZVNlbGVjdGlvbihwcmV2U2VsZWN0aW9uKSkpIHtcbiAgICAgICAgICBjb25zdCBwcmV2QW5jaG9yTm9kZSA9IHByZXZTZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKTtcbiAgICAgICAgICBjb25zdCBwcmV2QW5jaG9yQ2VsbCA9ICRmaW5kUGFyZW50VGFibGVDZWxsTm9kZUluVGFibGUodGFibGVOb2RlLCBwcmV2U2VsZWN0aW9uLmFuY2hvci5nZXROb2RlKCkpO1xuICAgICAgICAgIGlmIChwcmV2QW5jaG9yQ2VsbCkge1xuICAgICAgICAgICAgdGFibGVPYnNlcnZlci4kc2V0QW5jaG9yQ2VsbEZvclNlbGVjdGlvbigkZ2V0T2JzZXJ2ZXJDZWxsRnJvbUNlbGxOb2RlT3JUaHJvdyh0YWJsZU9ic2VydmVyLCBwcmV2QW5jaG9yQ2VsbCkpO1xuICAgICAgICAgICAgdGFibGVPYnNlcnZlci4kc2V0Rm9jdXNDZWxsRm9yU2VsZWN0aW9uKHRhcmdldENlbGwpO1xuICAgICAgICAgICAgc3RvcEV2ZW50KGV2ZW50KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgbmV3U2VsZWN0aW9uID0gdGFibGVOb2RlLmlzQmVmb3JlKHByZXZBbmNob3JOb2RlKSA/IHRhYmxlTm9kZS5zZWxlY3RTdGFydCgpIDogdGFibGVOb2RlLnNlbGVjdEVuZCgpO1xuICAgICAgICAgICAgbmV3U2VsZWN0aW9uLmFuY2hvci5zZXQocHJldlNlbGVjdGlvbi5hbmNob3Iua2V5LCBwcmV2U2VsZWN0aW9uLmFuY2hvci5vZmZzZXQsIHByZXZTZWxlY3Rpb24uYW5jaG9yLnR5cGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBPbmx5IHNldCBhbmNob3IgY2VsbCBmb3Igc2VsZWN0aW9uIGlmIHRoaXMgaXMgbm90IGEgc2ltcGxlIHRvdWNoIHRhcFxuICAgICAgICAgIC8vIFRvdWNoIHRhcHMgc2hvdWxkIG5vdCBpbml0aWF0ZSB0YWJsZSBzZWxlY3Rpb24gbW9kZVxuICAgICAgICAgIGlmIChldmVudC5wb2ludGVyVHlwZSAhPT0gJ3RvdWNoJykge1xuICAgICAgICAgICAgdGFibGVPYnNlcnZlci4kc2V0QW5jaG9yQ2VsbEZvclNlbGVjdGlvbih0YXJnZXRDZWxsKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIFBhc3MgdGhlIHRhcmdldCBjZWxsIHRvIGNyZWF0ZVBvaW50ZXJIYW5kbGVycyBzbyBpdCBjYW4gYmUgdXNlZCBhcyBhbmNob3JcbiAgICAvLyBpZiB1c2VyIGRyYWdzIGRpcmVjdGx5IHdpdGhvdXQgY2xpY2tpbmcgZmlyc3RcbiAgICBjcmVhdGVQb2ludGVySGFuZGxlcnModGFyZ2V0Q2VsbCk7XG4gIH07XG4gIHRhYmxlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVyZG93bicsIG9uUG9pbnRlckRvd24sIHRhYmxlT2JzZXJ2ZXIubGlzdGVuZXJPcHRpb25zKTtcbiAgdGFibGVPYnNlcnZlci5saXN0ZW5lcnNUb1JlbW92ZS5hZGQoKCkgPT4ge1xuICAgIHRhYmxlRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVyZG93bicsIG9uUG9pbnRlckRvd24pO1xuICB9KTtcbiAgY29uc3Qgb25UcmlwbGVDbGljayA9IGV2ZW50ID0+IHtcbiAgICBpZiAoZXZlbnQuZGV0YWlsID49IDMgJiYgaXNET01Ob2RlKGV2ZW50LnRhcmdldCkpIHtcbiAgICAgIGNvbnN0IHRhcmdldENlbGwgPSBnZXRET01DZWxsRnJvbVRhcmdldChldmVudC50YXJnZXQpO1xuICAgICAgaWYgKHRhcmdldENlbGwgIT09IG51bGwpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG4gIHRhYmxlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCBvblRyaXBsZUNsaWNrLCB0YWJsZU9ic2VydmVyLmxpc3RlbmVyT3B0aW9ucyk7XG4gIHRhYmxlT2JzZXJ2ZXIubGlzdGVuZXJzVG9SZW1vdmUuYWRkKCgpID0+IHtcbiAgICB0YWJsZUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgb25UcmlwbGVDbGljayk7XG4gIH0pO1xuXG4gIC8vIENsZWFyIHNlbGVjdGlvbiB3aGVuIGNsaWNraW5nIG91dHNpZGUgb2YgZG9tLlxuICBjb25zdCBwb2ludGVyRG93bkNhbGxiYWNrID0gZXZlbnQgPT4ge1xuICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldDtcbiAgICBpZiAoZXZlbnQuYnV0dG9uICE9PSAwIHx8ICFpc0RPTU5vZGUodGFyZ2V0KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBlZGl0b3IudXBkYXRlKCgpID0+IHtcbiAgICAgIGNvbnN0IHNlbGVjdGlvbiA9ICRnZXRTZWxlY3Rpb24oKTtcbiAgICAgIGlmICgkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pICYmIHNlbGVjdGlvbi50YWJsZUtleSA9PT0gdGFibGVPYnNlcnZlci50YWJsZU5vZGVLZXkgJiYgcm9vdEVsZW1lbnQuY29udGFpbnModGFyZ2V0KSkge1xuICAgICAgICB0YWJsZU9ic2VydmVyLiRjbGVhckhpZ2hsaWdodCgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuICBlZGl0b3JXaW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcmRvd24nLCBwb2ludGVyRG93bkNhbGxiYWNrLCB0YWJsZU9ic2VydmVyLmxpc3RlbmVyT3B0aW9ucyk7XG4gIHRhYmxlT2JzZXJ2ZXIubGlzdGVuZXJzVG9SZW1vdmUuYWRkKCgpID0+IHtcbiAgICBlZGl0b3JXaW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncG9pbnRlcmRvd24nLCBwb2ludGVyRG93bkNhbGxiYWNrKTtcbiAgfSk7XG4gIGZvciAoY29uc3QgW2NvbW1hbmQsIGRpcmVjdGlvbl0gb2YgQVJST1dfS0VZX0NPTU1BTkRTX1dJVEhfRElSRUNUSU9OKSB7XG4gICAgdGFibGVPYnNlcnZlci5saXN0ZW5lcnNUb1JlbW92ZS5hZGQoZWRpdG9yLnJlZ2lzdGVyQ29tbWFuZChjb21tYW5kLCBldmVudCA9PiAkaGFuZGxlQXJyb3dLZXkoZWRpdG9yLCBldmVudCwgZGlyZWN0aW9uLCB0YWJsZU5vZGUsIHRhYmxlT2JzZXJ2ZXIpLCBDT01NQU5EX1BSSU9SSVRZX0hJR0gpKTtcbiAgfVxuICB0YWJsZU9ic2VydmVyLmxpc3RlbmVyc1RvUmVtb3ZlLmFkZChlZGl0b3IucmVnaXN0ZXJDb21tYW5kKEtFWV9FU0NBUEVfQ09NTUFORCwgZXZlbnQgPT4ge1xuICAgIGNvbnN0IHNlbGVjdGlvbiA9ICRnZXRTZWxlY3Rpb24oKTtcbiAgICBpZiAoJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgICAgY29uc3QgZm9jdXNDZWxsTm9kZSA9ICRmaW5kUGFyZW50VGFibGVDZWxsTm9kZUluVGFibGUodGFibGVOb2RlLCBzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpKTtcbiAgICAgIGlmIChmb2N1c0NlbGxOb2RlICE9PSBudWxsKSB7XG4gICAgICAgIHN0b3BFdmVudChldmVudCk7XG4gICAgICAgIGZvY3VzQ2VsbE5vZGUuc2VsZWN0RW5kKCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH0sIENPTU1BTkRfUFJJT1JJVFlfSElHSCkpO1xuICBjb25zdCBkZWxldGVUZXh0SGFuZGxlciA9IGNvbW1hbmQgPT4gKCkgPT4ge1xuICAgIGNvbnN0IHNlbGVjdGlvbiA9ICRnZXRTZWxlY3Rpb24oKTtcbiAgICBpZiAoISRpc1NlbGVjdGlvbkluVGFibGUoc2VsZWN0aW9uLCB0YWJsZU5vZGUpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICgkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pKSB7XG4gICAgICB0YWJsZU9ic2VydmVyLiRjbGVhclRleHQoKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSBpZiAoJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgICAgY29uc3QgdGFibGVDZWxsTm9kZSA9ICRmaW5kUGFyZW50VGFibGVDZWxsTm9kZUluVGFibGUodGFibGVOb2RlLCBzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKSk7XG4gICAgICBpZiAoISRpc1RhYmxlQ2VsbE5vZGUodGFibGVDZWxsTm9kZSkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgY29uc3QgYW5jaG9yTm9kZSA9IHNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpO1xuICAgICAgY29uc3QgZm9jdXNOb2RlID0gc2VsZWN0aW9uLmZvY3VzLmdldE5vZGUoKTtcbiAgICAgIGNvbnN0IGlzQW5jaG9ySW5zaWRlID0gdGFibGVOb2RlLmlzUGFyZW50T2YoYW5jaG9yTm9kZSk7XG4gICAgICBjb25zdCBpc0ZvY3VzSW5zaWRlID0gdGFibGVOb2RlLmlzUGFyZW50T2YoZm9jdXNOb2RlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGlvbkNvbnRhaW5zUGFydGlhbFRhYmxlID0gaXNBbmNob3JJbnNpZGUgJiYgIWlzRm9jdXNJbnNpZGUgfHwgaXNGb2N1c0luc2lkZSAmJiAhaXNBbmNob3JJbnNpZGU7XG4gICAgICBpZiAoc2VsZWN0aW9uQ29udGFpbnNQYXJ0aWFsVGFibGUpIHtcbiAgICAgICAgdGFibGVPYnNlcnZlci4kY2xlYXJUZXh0KCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgbmVhcmVzdEVsZW1lbnROb2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKSwgbiA9PiAkaXNFbGVtZW50Tm9kZShuKSk7XG4gICAgICBjb25zdCB0b3BMZXZlbENlbGxFbGVtZW50Tm9kZSA9IG5lYXJlc3RFbGVtZW50Tm9kZSAmJiAkZmluZE1hdGNoaW5nUGFyZW50KG5lYXJlc3RFbGVtZW50Tm9kZSwgbiA9PiAkaXNFbGVtZW50Tm9kZShuKSAmJiAkaXNUYWJsZUNlbGxOb2RlKG4uZ2V0UGFyZW50KCkpKTtcbiAgICAgIGlmICghJGlzRWxlbWVudE5vZGUodG9wTGV2ZWxDZWxsRWxlbWVudE5vZGUpIHx8ICEkaXNFbGVtZW50Tm9kZShuZWFyZXN0RWxlbWVudE5vZGUpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGlmIChjb21tYW5kID09PSBERUxFVEVfTElORV9DT01NQU5EICYmIHRvcExldmVsQ2VsbEVsZW1lbnROb2RlLmdldFByZXZpb3VzU2libGluZygpID09PSBudWxsKSB7XG4gICAgICAgIC8vIFRPRE86IEZpeCBEZWxldGUgTGluZSBpbiBUYWJsZSBDZWxscy5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfTtcbiAgZm9yIChjb25zdCBjb21tYW5kIG9mIERFTEVURV9URVhUX0NPTU1BTkRTKSB7XG4gICAgdGFibGVPYnNlcnZlci5saXN0ZW5lcnNUb1JlbW92ZS5hZGQoZWRpdG9yLnJlZ2lzdGVyQ29tbWFuZChjb21tYW5kLCBkZWxldGVUZXh0SGFuZGxlcihjb21tYW5kKSwgQ09NTUFORF9QUklPUklUWV9ISUdIKSk7XG4gIH1cbiAgY29uc3QgJGRlbGV0ZUNlbGxIYW5kbGVyID0gZXZlbnQgPT4ge1xuICAgIGNvbnN0IHNlbGVjdGlvbiA9ICRnZXRTZWxlY3Rpb24oKTtcbiAgICBpZiAoISgkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pIHx8ICRpc1JhbmdlU2VsZWN0aW9uKHNlbGVjdGlvbikpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gSWYgdGhlIHNlbGVjdGlvbiBpcyBpbnNpZGUgdGhlIHRhYmxlIGJ1dCBzaG91bGQgcmVtb3ZlIHRoZSB3aG9sZSB0YWJsZVxuICAgIC8vIHdlIGV4cGFuZCB0aGUgc2VsZWN0aW9uIHNvIHRoYXQgYm90aCB0aGUgYW5jaG9yIGFuZCBmb2N1cyBhcmUgb3V0c2lkZVxuICAgIC8vIHRoZSB0YWJsZSBhbmQgdGhlIGVkaXRvcidzIGNvbW1hbmQgbGlzdGVuZXIgd2lsbCBoYW5kbGUgdGhlIGRlbGV0ZVxuICAgIGNvbnN0IGlzQW5jaG9ySW5zaWRlID0gdGFibGVOb2RlLmlzUGFyZW50T2Yoc2VsZWN0aW9uLmFuY2hvci5nZXROb2RlKCkpO1xuICAgIGNvbnN0IGlzRm9jdXNJbnNpZGUgPSB0YWJsZU5vZGUuaXNQYXJlbnRPZihzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpKTtcbiAgICBpZiAoaXNBbmNob3JJbnNpZGUgIT09IGlzRm9jdXNJbnNpZGUpIHtcbiAgICAgIGNvbnN0IHRhYmxlUG9pbnQgPSBpc0FuY2hvckluc2lkZSA/ICdhbmNob3InIDogJ2ZvY3VzJztcbiAgICAgIGNvbnN0IG91dGVyUG9pbnQgPSBpc0FuY2hvckluc2lkZSA/ICdmb2N1cycgOiAnYW5jaG9yJztcbiAgICAgIC8vIFByZXNlcnZlIHRoZSBvdXRlciBwb2ludFxuICAgICAgY29uc3Qge1xuICAgICAgICBrZXksXG4gICAgICAgIG9mZnNldCxcbiAgICAgICAgdHlwZVxuICAgICAgfSA9IHNlbGVjdGlvbltvdXRlclBvaW50XTtcbiAgICAgIC8vIEV4cGFuZCB0aGUgc2VsZWN0aW9uIGFyb3VuZCB0aGUgdGFibGVcbiAgICAgIGNvbnN0IG5ld1NlbGVjdGlvbiA9IHRhYmxlTm9kZVtzZWxlY3Rpb25bdGFibGVQb2ludF0uaXNCZWZvcmUoc2VsZWN0aW9uW291dGVyUG9pbnRdKSA/ICdzZWxlY3RQcmV2aW91cycgOiAnc2VsZWN0TmV4dCddKCk7XG4gICAgICAvLyBSZXN0b3JlIHRoZSBvdXRlciBwb2ludCBvZiB0aGUgc2VsZWN0aW9uXG4gICAgICBuZXdTZWxlY3Rpb25bb3V0ZXJQb2ludF0uc2V0KGtleSwgb2Zmc2V0LCB0eXBlKTtcbiAgICAgIC8vIExldCB0aGUgYmFzZSBpbXBsZW1lbnRhdGlvbiBoYW5kbGUgdGhlIHJlc3RcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKCEkaXNTZWxlY3Rpb25JblRhYmxlKHNlbGVjdGlvbiwgdGFibGVOb2RlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgICAgaWYgKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgfVxuICAgICAgdGFibGVPYnNlcnZlci4kY2xlYXJUZXh0KCk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9O1xuICBmb3IgKGNvbnN0IGNvbW1hbmQgb2YgREVMRVRFX0tFWV9DT01NQU5EUykge1xuICAgIHRhYmxlT2JzZXJ2ZXIubGlzdGVuZXJzVG9SZW1vdmUuYWRkKGVkaXRvci5yZWdpc3RlckNvbW1hbmQoY29tbWFuZCwgJGRlbGV0ZUNlbGxIYW5kbGVyLCBDT01NQU5EX1BSSU9SSVRZX0hJR0gpKTtcbiAgfVxuICB0YWJsZU9ic2VydmVyLmxpc3RlbmVyc1RvUmVtb3ZlLmFkZChlZGl0b3IucmVnaXN0ZXJDb21tYW5kKENVVF9DT01NQU5ELCBldmVudCA9PiB7XG4gICAgY29uc3Qgc2VsZWN0aW9uID0gJGdldFNlbGVjdGlvbigpO1xuICAgIGlmIChzZWxlY3Rpb24pIHtcbiAgICAgIGlmICghKCRpc1RhYmxlU2VsZWN0aW9uKHNlbGVjdGlvbikgfHwgJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgLy8gQ29weWluZyB0byB0aGUgY2xpcGJvYXJkIGlzIGFzeW5jIHNvIHdlIG11c3QgY2FwdHVyZSB0aGUgZGF0YVxuICAgICAgLy8gYmVmb3JlIHdlIGRlbGV0ZSBpdFxuICAgICAgdm9pZCBjb3B5VG9DbGlwYm9hcmQoZWRpdG9yLCBvYmplY3RLbGFzc0VxdWFscyhldmVudCwgQ2xpcGJvYXJkRXZlbnQpID8gZXZlbnQgOiBudWxsLCAkZ2V0Q2xpcGJvYXJkRGF0YUZyb21TZWxlY3Rpb24oc2VsZWN0aW9uKSk7XG4gICAgICBjb25zdCBpbnRlcmNlcHRlZCA9ICRkZWxldGVDZWxsSGFuZGxlcihldmVudCk7XG4gICAgICBpZiAoJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgICAgICBzZWxlY3Rpb24ucmVtb3ZlVGV4dCgpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBpbnRlcmNlcHRlZDtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9LCBDT01NQU5EX1BSSU9SSVRZX0hJR0gpKTtcbiAgdGFibGVPYnNlcnZlci5saXN0ZW5lcnNUb1JlbW92ZS5hZGQoZWRpdG9yLnJlZ2lzdGVyQ29tbWFuZChGT1JNQVRfVEVYVF9DT01NQU5ELCBwYXlsb2FkID0+IHtcbiAgICBjb25zdCBzZWxlY3Rpb24gPSAkZ2V0U2VsZWN0aW9uKCk7XG4gICAgaWYgKCEkaXNTZWxlY3Rpb25JblRhYmxlKHNlbGVjdGlvbiwgdGFibGVOb2RlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgICAgdGFibGVPYnNlcnZlci4kZm9ybWF0Q2VsbHMocGF5bG9hZCk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKCRpc1JhbmdlU2VsZWN0aW9uKHNlbGVjdGlvbikpIHtcbiAgICAgIGNvbnN0IHRhYmxlQ2VsbE5vZGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KHNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpLCBuID0+ICRpc1RhYmxlQ2VsbE5vZGUobikpO1xuICAgICAgaWYgKCEkaXNUYWJsZUNlbGxOb2RlKHRhYmxlQ2VsbE5vZGUpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9LCBDT01NQU5EX1BSSU9SSVRZX0hJR0gpKTtcbiAgdGFibGVPYnNlcnZlci5saXN0ZW5lcnNUb1JlbW92ZS5hZGQoZWRpdG9yLnJlZ2lzdGVyQ29tbWFuZChGT1JNQVRfRUxFTUVOVF9DT01NQU5ELCBmb3JtYXRUeXBlID0+IHtcbiAgICBjb25zdCBzZWxlY3Rpb24gPSAkZ2V0U2VsZWN0aW9uKCk7XG4gICAgaWYgKCEkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pIHx8ICEkaXNTZWxlY3Rpb25JblRhYmxlKHNlbGVjdGlvbiwgdGFibGVOb2RlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBhbmNob3JOb2RlID0gc2VsZWN0aW9uLmFuY2hvci5nZXROb2RlKCk7XG4gICAgY29uc3QgZm9jdXNOb2RlID0gc2VsZWN0aW9uLmZvY3VzLmdldE5vZGUoKTtcbiAgICBpZiAoISRpc1RhYmxlQ2VsbE5vZGUoYW5jaG9yTm9kZSkgfHwgISRpc1RhYmxlQ2VsbE5vZGUoZm9jdXNOb2RlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIEFsaWduIHRoZSB0YWJsZSBpZiB0aGUgZW50aXJlIHRhYmxlIGlzIHNlbGVjdGVkXG4gICAgaWYgKCRpc0Z1bGxUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24sIHRhYmxlTm9kZSkpIHtcbiAgICAgIHRhYmxlTm9kZS5zZXRGb3JtYXQoZm9ybWF0VHlwZSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgY29uc3QgW3RhYmxlTWFwLCBhbmNob3JDZWxsLCBmb2N1c0NlbGxdID0gJGNvbXB1dGVUYWJsZU1hcCh0YWJsZU5vZGUsIGFuY2hvck5vZGUsIGZvY3VzTm9kZSk7XG4gICAgY29uc3QgbWF4Um93ID0gTWF0aC5tYXgoYW5jaG9yQ2VsbC5zdGFydFJvdyArIGFuY2hvckNlbGwuY2VsbC5fX3Jvd1NwYW4gLSAxLCBmb2N1c0NlbGwuc3RhcnRSb3cgKyBmb2N1c0NlbGwuY2VsbC5fX3Jvd1NwYW4gLSAxKTtcbiAgICBjb25zdCBtYXhDb2x1bW4gPSBNYXRoLm1heChhbmNob3JDZWxsLnN0YXJ0Q29sdW1uICsgYW5jaG9yQ2VsbC5jZWxsLl9fY29sU3BhbiAtIDEsIGZvY3VzQ2VsbC5zdGFydENvbHVtbiArIGZvY3VzQ2VsbC5jZWxsLl9fY29sU3BhbiAtIDEpO1xuICAgIGNvbnN0IG1pblJvdyA9IE1hdGgubWluKGFuY2hvckNlbGwuc3RhcnRSb3csIGZvY3VzQ2VsbC5zdGFydFJvdyk7XG4gICAgY29uc3QgbWluQ29sdW1uID0gTWF0aC5taW4oYW5jaG9yQ2VsbC5zdGFydENvbHVtbiwgZm9jdXNDZWxsLnN0YXJ0Q29sdW1uKTtcbiAgICBjb25zdCB2aXNpdGVkID0gbmV3IFNldCgpO1xuICAgIGZvciAobGV0IGkgPSBtaW5Sb3c7IGkgPD0gbWF4Um93OyBpKyspIHtcbiAgICAgIGZvciAobGV0IGogPSBtaW5Db2x1bW47IGogPD0gbWF4Q29sdW1uOyBqKyspIHtcbiAgICAgICAgY29uc3QgY2VsbCA9IHRhYmxlTWFwW2ldW2pdLmNlbGw7XG4gICAgICAgIGlmICh2aXNpdGVkLmhhcyhjZWxsKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHZpc2l0ZWQuYWRkKGNlbGwpO1xuICAgICAgICBjZWxsLnNldEZvcm1hdChmb3JtYXRUeXBlKTtcbiAgICAgICAgY29uc3QgY2VsbENoaWxkcmVuID0gY2VsbC5nZXRDaGlsZHJlbigpO1xuICAgICAgICBmb3IgKGxldCBrID0gMDsgayA8IGNlbGxDaGlsZHJlbi5sZW5ndGg7IGsrKykge1xuICAgICAgICAgIGNvbnN0IGNoaWxkID0gY2VsbENoaWxkcmVuW2tdO1xuICAgICAgICAgIGlmICgkaXNFbGVtZW50Tm9kZShjaGlsZCkgJiYgIWNoaWxkLmlzSW5saW5lKCkpIHtcbiAgICAgICAgICAgIGNoaWxkLnNldEZvcm1hdChmb3JtYXRUeXBlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH0sIENPTU1BTkRfUFJJT1JJVFlfSElHSCkpO1xuICB0YWJsZU9ic2VydmVyLmxpc3RlbmVyc1RvUmVtb3ZlLmFkZChlZGl0b3IucmVnaXN0ZXJDb21tYW5kKENPTlRST0xMRURfVEVYVF9JTlNFUlRJT05fQ09NTUFORCwgcGF5bG9hZCA9PiB7XG4gICAgY29uc3Qgc2VsZWN0aW9uID0gJGdldFNlbGVjdGlvbigpO1xuICAgIGlmICghJGlzU2VsZWN0aW9uSW5UYWJsZShzZWxlY3Rpb24sIHRhYmxlTm9kZSkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKCRpc1RhYmxlU2VsZWN0aW9uKHNlbGVjdGlvbikpIHtcbiAgICAgIHRhYmxlT2JzZXJ2ZXIuJGNsZWFySGlnaGxpZ2h0KCk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSBlbHNlIGlmICgkaXNSYW5nZVNlbGVjdGlvbihzZWxlY3Rpb24pKSB7XG4gICAgICBjb25zdCB0YWJsZUNlbGxOb2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKSwgbiA9PiAkaXNUYWJsZUNlbGxOb2RlKG4pKTtcbiAgICAgIGlmICghJGlzVGFibGVDZWxsTm9kZSh0YWJsZUNlbGxOb2RlKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBpZiAodHlwZW9mIHBheWxvYWQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGNvbnN0IGVkZ2VQb3NpdGlvbiA9ICRnZXRUYWJsZUVkZ2VDdXJzb3JQb3NpdGlvbihlZGl0b3IsIHNlbGVjdGlvbiwgdGFibGVOb2RlKTtcbiAgICAgICAgaWYgKGVkZ2VQb3NpdGlvbikge1xuICAgICAgICAgICRpbnNlcnRQYXJhZ3JhcGhBdFRhYmxlRWRnZShlZGdlUG9zaXRpb24sIHRhYmxlTm9kZSwgWyRjcmVhdGVUZXh0Tm9kZShwYXlsb2FkKV0pO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfSwgQ09NTUFORF9QUklPUklUWV9ISUdIKSk7XG4gIGlmIChoYXNUYWJIYW5kbGVyKSB7XG4gICAgdGFibGVPYnNlcnZlci5saXN0ZW5lcnNUb1JlbW92ZS5hZGQoZWRpdG9yLnJlZ2lzdGVyQ29tbWFuZChLRVlfVEFCX0NPTU1BTkQsIGV2ZW50ID0+IHtcbiAgICAgIGNvbnN0IHNlbGVjdGlvbiA9ICRnZXRTZWxlY3Rpb24oKTtcbiAgICAgIGlmICghJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSB8fCAhc2VsZWN0aW9uLmlzQ29sbGFwc2VkKCkgfHwgISRpc1NlbGVjdGlvbkluVGFibGUoc2VsZWN0aW9uLCB0YWJsZU5vZGUpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHRhYmxlQ2VsbE5vZGUgPSAkZmluZENlbGxOb2RlKHNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpKTtcbiAgICAgIGlmICh0YWJsZUNlbGxOb2RlID09PSBudWxsIHx8ICF0YWJsZU5vZGUuaXMoJGZpbmRUYWJsZU5vZGUodGFibGVDZWxsTm9kZSkpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIHN0b3BFdmVudChldmVudCk7XG4gICAgICAkc2VsZWN0QWRqYWNlbnRDZWxsKHRhYmxlQ2VsbE5vZGUsIGV2ZW50LnNoaWZ0S2V5ID8gJ3ByZXZpb3VzJyA6ICduZXh0Jyk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LCBDT01NQU5EX1BSSU9SSVRZX0hJR0gpKTtcbiAgfVxuICB0YWJsZU9ic2VydmVyLmxpc3RlbmVyc1RvUmVtb3ZlLmFkZChlZGl0b3IucmVnaXN0ZXJDb21tYW5kKEZPQ1VTX0NPTU1BTkQsIHBheWxvYWQgPT4ge1xuICAgIHJldHVybiB0YWJsZU5vZGUuaXNTZWxlY3RlZCgpO1xuICB9LCBDT01NQU5EX1BSSU9SSVRZX0hJR0gpKTtcbiAgdGFibGVPYnNlcnZlci5saXN0ZW5lcnNUb1JlbW92ZS5hZGQoZWRpdG9yLnJlZ2lzdGVyQ29tbWFuZChTRUxFQ1RJT05fQ0hBTkdFX0NPTU1BTkQsICgpID0+IHtcbiAgICBjb25zdCBzZWxlY3Rpb24gPSAkZ2V0U2VsZWN0aW9uKCk7XG4gICAgY29uc3QgcHJldlNlbGVjdGlvbiA9ICRnZXRQcmV2aW91c1NlbGVjdGlvbigpO1xuICAgIGNvbnN0IG5leHRGb2N1cyA9IHRhYmxlT2JzZXJ2ZXIuZ2V0QW5kQ2xlYXJOZXh0Rm9jdXMoKTtcbiAgICBpZiAobmV4dEZvY3VzICE9PSBudWxsKSB7XG4gICAgICBjb25zdCB7XG4gICAgICAgIGZvY3VzQ2VsbFxuICAgICAgfSA9IG5leHRGb2N1cztcbiAgICAgIGlmICgkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pICYmIHNlbGVjdGlvbi50YWJsZUtleSA9PT0gdGFibGVPYnNlcnZlci50YWJsZU5vZGVLZXkpIHtcbiAgICAgICAgaWYgKGZvY3VzQ2VsbC54ID09PSB0YWJsZU9ic2VydmVyLmZvY3VzWCAmJiBmb2N1c0NlbGwueSA9PT0gdGFibGVPYnNlcnZlci5mb2N1c1kpIHtcbiAgICAgICAgICAvLyBUaGUgc2VsZWN0aW9uIGlzIGFscmVhZHkgdGhlIGNvcnJlY3QgdGFibGUgc2VsZWN0aW9uXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRhYmxlT2JzZXJ2ZXIuJHNldEZvY3VzQ2VsbEZvclNlbGVjdGlvbihmb2N1c0NlbGwpO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGZvY3VzQ2VsbCAhPT0gdGFibGVPYnNlcnZlci5hbmNob3JDZWxsICYmIHRhYmxlT2JzZXJ2ZXIuYW5jaG9yQ2VsbCAhPT0gbnVsbCAmJiB0YWJsZU9ic2VydmVyLmFuY2hvckNlbGxOb2RlS2V5ICE9PSBudWxsICYmIHRhYmxlT2JzZXJ2ZXIudGFibGVTZWxlY3Rpb24gIT09IG51bGwpIHtcbiAgICAgICAgLy8gVGhlIHNlbGVjdGlvbiBoYXMgY3Jvc3NlZCBjZWxsc1xuICAgICAgICAvLyBJZiB3ZSBoYXZlIGFuIGFuY2hvciBjZWxsIHNldCBhbmQgdGFibGVTZWxlY3Rpb24gaW5pdGlhbGl6ZWQsXG4gICAgICAgIC8vIHdlIGhhdmUgYWxsIHRoZSBuZWNlc3Nhcnkgc3RhdGUgdG8gY3JlYXRlIHRoZSBzZWxlY3Rpb24uXG4gICAgICAgIC8vIFRoZSBwcmVzZW5jZSBvZiBuZXh0Rm9jdXMgbWVhbnMgd2UncmUgZHJhZ2dpbmcsIHNvIHByb2Nlc3MgaXQuXG4gICAgICAgIC8vIFVzZSBpZ25vcmVTdGFydD10cnVlIHRvIGVuc3VyZSBpc0hpZ2hsaWdodGluZ0NlbGxzIGlzIHNldCBjb3JyZWN0bHlcbiAgICAgICAgLy8gb24gdGhlIGZpcnN0IGRyYWcgYXR0ZW1wdCwgZXNwZWNpYWxseSB3aGVuIHN3aXRjaGluZyBjb2x1bW5zLlxuICAgICAgICB0YWJsZU9ic2VydmVyLiRzZXRGb2N1c0NlbGxGb3JTZWxlY3Rpb24oZm9jdXNDZWxsLCB0cnVlKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIGNvbnN0IHNob3VsZENoZWNrU2VsZWN0aW9uID0gdGFibGVPYnNlcnZlci5nZXRBbmRDbGVhclNob3VsZENoZWNrU2VsZWN0aW9uKCk7XG4gICAgLy8gSWYgdGhleSBwcmVzc2VkIHRoZSBkb3duIGFycm93IHdpdGggdGhlIHNlbGVjdGlvbiBvdXRzaWRlIG9mIHRoZVxuICAgIC8vIHRhYmxlLCBhbmQgdGhlbiB0aGUgc2VsZWN0aW9uIGVuZHMgdXAgaW4gdGhlIHRhYmxlIGJ1dCBub3QgaW4gdGhlXG4gICAgLy8gZmlyc3QgY2VsbCwgdGhlbiBtb3ZlIHRoZSBzZWxlY3Rpb24gdG8gdGhlIGZpcnN0IGNlbGwuXG4gICAgaWYgKHNob3VsZENoZWNrU2VsZWN0aW9uICYmICRpc1JhbmdlU2VsZWN0aW9uKHByZXZTZWxlY3Rpb24pICYmICRpc1JhbmdlU2VsZWN0aW9uKHNlbGVjdGlvbikgJiYgc2VsZWN0aW9uLmlzQ29sbGFwc2VkKCkpIHtcbiAgICAgIGNvbnN0IGFuY2hvciA9IHNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpO1xuICAgICAgY29uc3QgZmlyc3RSb3cgPSB0YWJsZU5vZGUuZ2V0Rmlyc3RDaGlsZCgpO1xuICAgICAgY29uc3QgYW5jaG9yQ2VsbCA9ICRmaW5kQ2VsbE5vZGUoYW5jaG9yKTtcbiAgICAgIGlmIChhbmNob3JDZWxsICE9PSBudWxsICYmICRpc1RhYmxlUm93Tm9kZShmaXJzdFJvdykpIHtcbiAgICAgICAgY29uc3QgZmlyc3RDZWxsID0gZmlyc3RSb3cuZ2V0Rmlyc3RDaGlsZCgpO1xuICAgICAgICBpZiAoJGlzVGFibGVDZWxsTm9kZShmaXJzdENlbGwpICYmIHRhYmxlTm9kZS5pcygkZmluZE1hdGNoaW5nUGFyZW50KGFuY2hvckNlbGwsIG5vZGUgPT4gbm9kZS5pcyh0YWJsZU5vZGUpIHx8IG5vZGUuaXMoZmlyc3RDZWxsKSkpKSB7XG4gICAgICAgICAgLy8gVGhlIHNlbGVjdGlvbiBtb3ZlZCB0byB0aGUgdGFibGUsIGJ1dCBub3QgaW4gdGhlIGZpcnN0IGNlbGxcbiAgICAgICAgICBmaXJzdENlbGwuc2VsZWN0U3RhcnQoKTtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgICAgY29uc3Qge1xuICAgICAgICBhbmNob3IsXG4gICAgICAgIGZvY3VzXG4gICAgICB9ID0gc2VsZWN0aW9uO1xuICAgICAgY29uc3QgYW5jaG9yTm9kZSA9IGFuY2hvci5nZXROb2RlKCk7XG4gICAgICBjb25zdCBmb2N1c05vZGUgPSBmb2N1cy5nZXROb2RlKCk7XG4gICAgICAvLyBVc2luZyBleHBsaWNpdCBjb21wYXJpc29uIHdpdGggdGFibGUgbm9kZSB0byBlbnN1cmUgaXQncyBub3QgYSBuZXN0ZWQgdGFibGVcbiAgICAgIC8vIGFzIGluIHRoYXQgY2FzZSB3ZSdsbCBsZWF2ZSBzZWxlY3Rpb24gcmVzb2x2aW5nIHRvIHRoYXQgdGFibGVcbiAgICAgIGNvbnN0IGFuY2hvckNlbGxOb2RlID0gJGZpbmRDZWxsTm9kZShhbmNob3JOb2RlKTtcbiAgICAgIGNvbnN0IGZvY3VzQ2VsbE5vZGUgPSAkZmluZENlbGxOb2RlKGZvY3VzTm9kZSk7XG4gICAgICBjb25zdCBpc0FuY2hvckluc2lkZSA9ICEhKGFuY2hvckNlbGxOb2RlICYmIHRhYmxlTm9kZS5pcygkZmluZFRhYmxlTm9kZShhbmNob3JDZWxsTm9kZSkpKTtcbiAgICAgIGNvbnN0IGlzRm9jdXNJbnNpZGUgPSAhIShmb2N1c0NlbGxOb2RlICYmIHRhYmxlTm9kZS5pcygkZmluZFRhYmxlTm9kZShmb2N1c0NlbGxOb2RlKSkpO1xuICAgICAgY29uc3QgaXNQYXJ0aWFsbHlXaXRoaW5UYWJsZSA9IGlzQW5jaG9ySW5zaWRlICE9PSBpc0ZvY3VzSW5zaWRlO1xuICAgICAgY29uc3QgaXNXaXRoaW5UYWJsZSA9IGlzQW5jaG9ySW5zaWRlICYmIGlzRm9jdXNJbnNpZGU7XG4gICAgICBjb25zdCBpc0JhY2t3YXJkID0gc2VsZWN0aW9uLmlzQmFja3dhcmQoKTtcbiAgICAgIGlmIChpc1BhcnRpYWxseVdpdGhpblRhYmxlKSB7XG4gICAgICAgIGNvbnN0IG5ld1NlbGVjdGlvbiA9IHNlbGVjdGlvbi5jbG9uZSgpO1xuICAgICAgICBpZiAoaXNGb2N1c0luc2lkZSkge1xuICAgICAgICAgIGNvbnN0IFt0YWJsZU1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwKHRhYmxlTm9kZSwgZm9jdXNDZWxsTm9kZSwgZm9jdXNDZWxsTm9kZSk7XG4gICAgICAgICAgY29uc3QgZmlyc3RDZWxsID0gdGFibGVNYXBbMF1bMF0uY2VsbDtcbiAgICAgICAgICBjb25zdCBsYXN0Q2VsbCA9IHRhYmxlTWFwW3RhYmxlTWFwLmxlbmd0aCAtIDFdLmF0KC0xKS5jZWxsO1xuICAgICAgICAgIC8vIFdoZW4gYmFja3dhcmQsIGZvY3VzIHNob3VsZCBiZSBhdCBTVEFSVCBvZiBmaXJzdCBjZWxsICgwKVxuICAgICAgICAgIC8vIFdoZW4gZm9yd2FyZCwgZm9jdXMgc2hvdWxkIGJlIGF0IEVORCBvZiBsYXN0IGNlbGwgKGdldENoaWxkcmVuU2l6ZSlcbiAgICAgICAgICBuZXdTZWxlY3Rpb24uZm9jdXMuc2V0KGlzQmFja3dhcmQgPyBmaXJzdENlbGwuZ2V0S2V5KCkgOiBsYXN0Q2VsbC5nZXRLZXkoKSwgaXNCYWNrd2FyZCA/IDAgOiBsYXN0Q2VsbC5nZXRDaGlsZHJlblNpemUoKSwgJ2VsZW1lbnQnKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc0FuY2hvckluc2lkZSkge1xuICAgICAgICAgIGNvbnN0IFt0YWJsZU1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwKHRhYmxlTm9kZSwgYW5jaG9yQ2VsbE5vZGUsIGFuY2hvckNlbGxOb2RlKTtcbiAgICAgICAgICBjb25zdCBmaXJzdENlbGwgPSB0YWJsZU1hcFswXVswXS5jZWxsO1xuICAgICAgICAgIGNvbnN0IGxhc3RDZWxsID0gdGFibGVNYXBbdGFibGVNYXAubGVuZ3RoIC0gMV0uYXQoLTEpLmNlbGw7XG4gICAgICAgICAgLyoqXG4gICAgICAgICAgICogSWYgaXNCYWNrd2FyZCwgc2V0IHRoZSBhbmNob3IgdG8gYmUgYXQgdGhlIGVuZCBvZiB0aGUgdGFibGUgc28gdGhhdCB3aGVuIHRoZSBjdXJzb3IgbW92ZXMgb3V0c2lkZSBvZlxuICAgICAgICAgICAqIHRoZSB0YWJsZSBpbiB0aGUgYmFja3dhcmQgZGlyZWN0aW9uLCB0aGUgZW50aXJlIHRhYmxlIHdpbGwgYmUgc2VsZWN0ZWQgZnJvbSBpdHMgZW5kLlxuICAgICAgICAgICAqIE90aGVyd2lzZSwgaWYgZm9yd2FyZCwgc2V0IHRoZSBhbmNob3IgdG8gYmUgYXQgdGhlIHN0YXJ0IG9mIHRoZSB0YWJsZSBzbyB0aGF0IHdoZW4gdGhlIGZvY3VzIGlzIGRyYWdnZWRcbiAgICAgICAgICAgKiBvdXRzaWRlIHRoIGVuZCBvZiB0aGUgdGFibGUsIGl0IHdpbGwgc3RhcnQgZnJvbSB0aGUgYmVnaW5uaW5nIG9mIHRoZSB0YWJsZS5cbiAgICAgICAgICAgKi9cbiAgICAgICAgICBuZXdTZWxlY3Rpb24uYW5jaG9yLnNldChpc0JhY2t3YXJkID8gbGFzdENlbGwuZ2V0S2V5KCkgOiBmaXJzdENlbGwuZ2V0S2V5KCksIGlzQmFja3dhcmQgPyBsYXN0Q2VsbC5nZXRDaGlsZHJlblNpemUoKSA6IDAsICdlbGVtZW50Jyk7XG4gICAgICAgIH1cbiAgICAgICAgJHNldFNlbGVjdGlvbihuZXdTZWxlY3Rpb24pO1xuICAgICAgICAkYWRkSGlnaGxpZ2h0U3R5bGVUb1RhYmxlKGVkaXRvciwgdGFibGVPYnNlcnZlcik7XG4gICAgICB9IGVsc2UgaWYgKGlzV2l0aGluVGFibGUpIHtcbiAgICAgICAgLy8gSGFuZGxlIGNhc2Ugd2hlbiBzZWxlY3Rpb24gc3BhbnMgYWNyb3NzIG11bHRpcGxlIGNlbGxzIGJ1dCBzdGlsbFxuICAgICAgICAvLyBoYXMgcmFuZ2Ugc2VsZWN0aW9uLCB0aGVuIHdlIGNvbnZlcnQgaXQgaW50byB0YWJsZSBzZWxlY3Rpb25cbiAgICAgICAgaWYgKCFhbmNob3JDZWxsTm9kZS5pcyhmb2N1c0NlbGxOb2RlKSkge1xuICAgICAgICAgIHRhYmxlT2JzZXJ2ZXIuJHNldEFuY2hvckNlbGxGb3JTZWxlY3Rpb24oJGdldE9ic2VydmVyQ2VsbEZyb21DZWxsTm9kZU9yVGhyb3codGFibGVPYnNlcnZlciwgYW5jaG9yQ2VsbE5vZGUpKTtcbiAgICAgICAgICB0YWJsZU9ic2VydmVyLiRzZXRGb2N1c0NlbGxGb3JTZWxlY3Rpb24oJGdldE9ic2VydmVyQ2VsbEZyb21DZWxsTm9kZU9yVGhyb3codGFibGVPYnNlcnZlciwgZm9jdXNDZWxsTm9kZSksIHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIGNhc2Ugd2hlbiB0aGUgcG9pbnRlciB0eXBlIGlzIHRvdWNoIGFuZCB0aGUgY3VycmVudCBhbmRcbiAgICAgICAgLy8gcHJldmlvdXMgc2VsZWN0aW9uIGFyZSBjb2xsYXBzZWQsIGFuZCB0aGUgcHJldmlvdXMgYW5jaG9yIGFuZCBjdXJyZW50XG4gICAgICAgIC8vIGZvY3VzIGNlbGwgbm9kZXMgYXJlIGRpZmZlcmVudCwgdGhlbiB3ZSBjb252ZXJ0IGl0IGludG8gdGFibGUgc2VsZWN0aW9uXG4gICAgICAgIC8vIEhvd2V2ZXIsIG9ubHkgZG8gdGhpcyBpZiB0aGUgdGFibGUgb2JzZXJ2ZXIgaXMgYWN0aXZlbHkgc2VsZWN0aW5nICh1c2VyIGRyYWdnaW5nKVxuICAgICAgICAvLyB0byBwcmV2ZW50IHVud2FudGVkIHNlbGVjdGlvbnMgd2hlbiBzaW1wbHkgdGFwcGluZyBiZXR3ZWVuIGNlbGxzIG9uIG1vYmlsZVxuICAgICAgICBpZiAodGFibGVPYnNlcnZlci5wb2ludGVyVHlwZSA9PT0gJ3RvdWNoJyAmJiB0YWJsZU9ic2VydmVyLmlzU2VsZWN0aW5nICYmIHNlbGVjdGlvbi5pc0NvbGxhcHNlZCgpICYmICRpc1JhbmdlU2VsZWN0aW9uKHByZXZTZWxlY3Rpb24pICYmIHByZXZTZWxlY3Rpb24uaXNDb2xsYXBzZWQoKSkge1xuICAgICAgICAgIGNvbnN0IHByZXZBbmNob3JDZWxsTm9kZSA9ICRmaW5kQ2VsbE5vZGUocHJldlNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpKTtcbiAgICAgICAgICBpZiAocHJldkFuY2hvckNlbGxOb2RlICYmICFwcmV2QW5jaG9yQ2VsbE5vZGUuaXMoZm9jdXNDZWxsTm9kZSkpIHtcbiAgICAgICAgICAgIHRhYmxlT2JzZXJ2ZXIuJHNldEFuY2hvckNlbGxGb3JTZWxlY3Rpb24oJGdldE9ic2VydmVyQ2VsbEZyb21DZWxsTm9kZU9yVGhyb3codGFibGVPYnNlcnZlciwgcHJldkFuY2hvckNlbGxOb2RlKSk7XG4gICAgICAgICAgICB0YWJsZU9ic2VydmVyLiRzZXRGb2N1c0NlbGxGb3JTZWxlY3Rpb24oJGdldE9ic2VydmVyQ2VsbEZyb21DZWxsTm9kZU9yVGhyb3codGFibGVPYnNlcnZlciwgZm9jdXNDZWxsTm9kZSksIHRydWUpO1xuICAgICAgICAgICAgdGFibGVPYnNlcnZlci5wb2ludGVyVHlwZSA9IG51bGw7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChzZWxlY3Rpb24gJiYgJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSAmJiBzZWxlY3Rpb24uaXMocHJldlNlbGVjdGlvbikgJiYgc2VsZWN0aW9uLnRhYmxlS2V5ID09PSB0YWJsZU5vZGUuZ2V0S2V5KCkpIHtcbiAgICAgIC8vIGlmIHNlbGVjdGlvbiBnb2VzIG91dHNpZGUgb2YgdGhlIHRhYmxlIHdlIG5lZWQgdG8gY2hhbmdlIGl0IHRvIFJhbmdlIHNlbGVjdGlvblxuICAgICAgY29uc3QgZG9tU2VsZWN0aW9uID0gZ2V0RE9NU2VsZWN0aW9uKGVkaXRvcldpbmRvdyk7XG4gICAgICBpZiAoZG9tU2VsZWN0aW9uICYmIGRvbVNlbGVjdGlvbi5hbmNob3JOb2RlICYmIGRvbVNlbGVjdGlvbi5mb2N1c05vZGUpIHtcbiAgICAgICAgY29uc3QgZm9jdXNOb2RlID0gJGdldE5lYXJlc3ROb2RlRnJvbURPTU5vZGUoZG9tU2VsZWN0aW9uLmZvY3VzTm9kZSk7XG4gICAgICAgIGNvbnN0IGlzRm9jdXNPdXRzaWRlID0gZm9jdXNOb2RlICYmICF0YWJsZU5vZGUuaXNQYXJlbnRPZihmb2N1c05vZGUpO1xuICAgICAgICBjb25zdCBhbmNob3JOb2RlID0gJGdldE5lYXJlc3ROb2RlRnJvbURPTU5vZGUoZG9tU2VsZWN0aW9uLmFuY2hvck5vZGUpO1xuICAgICAgICBjb25zdCBpc0FuY2hvckluc2lkZSA9IGFuY2hvck5vZGUgJiYgdGFibGVOb2RlLmlzUGFyZW50T2YoYW5jaG9yTm9kZSk7XG4gICAgICAgIGlmIChpc0ZvY3VzT3V0c2lkZSAmJiBpc0FuY2hvckluc2lkZSAmJiBkb21TZWxlY3Rpb24ucmFuZ2VDb3VudCA+IDApIHtcbiAgICAgICAgICBjb25zdCBuZXdTZWxlY3Rpb24gPSAkY3JlYXRlUmFuZ2VTZWxlY3Rpb25Gcm9tRG9tKGRvbVNlbGVjdGlvbiwgZWRpdG9yKTtcbiAgICAgICAgICBpZiAobmV3U2VsZWN0aW9uKSB7XG4gICAgICAgICAgICBuZXdTZWxlY3Rpb24uYW5jaG9yLnNldCh0YWJsZU5vZGUuZ2V0S2V5KCksIHNlbGVjdGlvbi5pc0JhY2t3YXJkKCkgPyB0YWJsZU5vZGUuZ2V0Q2hpbGRyZW5TaXplKCkgOiAwLCAnZWxlbWVudCcpO1xuICAgICAgICAgICAgZG9tU2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgICAgICAgJHNldFNlbGVjdGlvbihuZXdTZWxlY3Rpb24pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoc2VsZWN0aW9uICYmICFzZWxlY3Rpb24uaXMocHJldlNlbGVjdGlvbikgJiYgKCRpc1RhYmxlU2VsZWN0aW9uKHNlbGVjdGlvbikgfHwgJGlzVGFibGVTZWxlY3Rpb24ocHJldlNlbGVjdGlvbikpICYmIHRhYmxlT2JzZXJ2ZXIudGFibGVTZWxlY3Rpb24gJiYgIXRhYmxlT2JzZXJ2ZXIudGFibGVTZWxlY3Rpb24uaXMocHJldlNlbGVjdGlvbikpIHtcbiAgICAgIGlmICgkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pICYmIHNlbGVjdGlvbi50YWJsZUtleSA9PT0gdGFibGVPYnNlcnZlci50YWJsZU5vZGVLZXkpIHtcbiAgICAgICAgdGFibGVPYnNlcnZlci4kdXBkYXRlVGFibGVUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pO1xuICAgICAgfSBlbHNlIGlmICghJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSAmJiAkaXNUYWJsZVNlbGVjdGlvbihwcmV2U2VsZWN0aW9uKSAmJiBwcmV2U2VsZWN0aW9uLnRhYmxlS2V5ID09PSB0YWJsZU9ic2VydmVyLnRhYmxlTm9kZUtleSkge1xuICAgICAgICB0YWJsZU9ic2VydmVyLiR1cGRhdGVUYWJsZVRhYmxlU2VsZWN0aW9uKG51bGwpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAodGFibGVPYnNlcnZlci5oYXNIaWphY2tlZFNlbGVjdGlvblN0eWxlcyAmJiAhdGFibGVOb2RlLmlzU2VsZWN0ZWQoKSkge1xuICAgICAgJHJlbW92ZUhpZ2hsaWdodFN0eWxlVG9UYWJsZShlZGl0b3IsIHRhYmxlT2JzZXJ2ZXIpO1xuICAgIH0gZWxzZSBpZiAoIXRhYmxlT2JzZXJ2ZXIuaGFzSGlqYWNrZWRTZWxlY3Rpb25TdHlsZXMgJiYgdGFibGVOb2RlLmlzU2VsZWN0ZWQoKSkge1xuICAgICAgJGFkZEhpZ2hsaWdodFN0eWxlVG9UYWJsZShlZGl0b3IsIHRhYmxlT2JzZXJ2ZXIpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH0sIENPTU1BTkRfUFJJT1JJVFlfSElHSCkpO1xuICB0YWJsZU9ic2VydmVyLmxpc3RlbmVyc1RvUmVtb3ZlLmFkZChlZGl0b3IucmVnaXN0ZXJDb21tYW5kKElOU0VSVF9QQVJBR1JBUEhfQ09NTUFORCwgKCkgPT4ge1xuICAgIGNvbnN0IHNlbGVjdGlvbiA9ICRnZXRTZWxlY3Rpb24oKTtcbiAgICBpZiAoISRpc1JhbmdlU2VsZWN0aW9uKHNlbGVjdGlvbikgfHwgIXNlbGVjdGlvbi5pc0NvbGxhcHNlZCgpIHx8ICEkaXNTZWxlY3Rpb25JblRhYmxlKHNlbGVjdGlvbiwgdGFibGVOb2RlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBlZGdlUG9zaXRpb24gPSAkZ2V0VGFibGVFZGdlQ3Vyc29yUG9zaXRpb24oZWRpdG9yLCBzZWxlY3Rpb24sIHRhYmxlTm9kZSk7XG4gICAgaWYgKGVkZ2VQb3NpdGlvbikge1xuICAgICAgJGluc2VydFBhcmFncmFwaEF0VGFibGVFZGdlKGVkZ2VQb3NpdGlvbiwgdGFibGVOb2RlKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH0sIENPTU1BTkRfUFJJT1JJVFlfSElHSCkpO1xuICByZXR1cm4gdGFibGVPYnNlcnZlcjtcbn1cbmZ1bmN0aW9uIGRldGFjaFRhYmxlT2JzZXJ2ZXJGcm9tVGFibGVFbGVtZW50KHRhYmxlRWxlbWVudCwgdGFibGVPYnNlcnZlcikge1xuICBpZiAoZ2V0VGFibGVPYnNlcnZlckZyb21UYWJsZUVsZW1lbnQodGFibGVFbGVtZW50KSA9PT0gdGFibGVPYnNlcnZlcikge1xuICAgIGRlbGV0ZSB0YWJsZUVsZW1lbnRbTEVYSUNBTF9FTEVNRU5UX0tFWV07XG4gIH1cbn1cbmZ1bmN0aW9uIGF0dGFjaFRhYmxlT2JzZXJ2ZXJUb1RhYmxlRWxlbWVudCh0YWJsZUVsZW1lbnQsIHRhYmxlT2JzZXJ2ZXIpIHtcbiAgaWYgKCEoZ2V0VGFibGVPYnNlcnZlckZyb21UYWJsZUVsZW1lbnQodGFibGVFbGVtZW50KSA9PT0gbnVsbCkpIHtcbiAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYHRhYmxlRWxlbWVudCBhbHJlYWR5IGhhcyBhbiBhdHRhY2hlZCBUYWJsZU9ic2VydmVyYCk7XG4gIH1cbiAgdGFibGVFbGVtZW50W0xFWElDQUxfRUxFTUVOVF9LRVldID0gdGFibGVPYnNlcnZlcjtcbn1cbmZ1bmN0aW9uIGdldFRhYmxlT2JzZXJ2ZXJGcm9tVGFibGVFbGVtZW50KHRhYmxlRWxlbWVudCkge1xuICByZXR1cm4gdGFibGVFbGVtZW50W0xFWElDQUxfRUxFTUVOVF9LRVldIHx8IG51bGw7XG59XG5mdW5jdGlvbiBnZXRET01DZWxsRnJvbVRhcmdldChub2RlKSB7XG4gIGxldCBjdXJyZW50Tm9kZSA9IG5vZGU7XG4gIHdoaWxlIChjdXJyZW50Tm9kZSAhPSBudWxsKSB7XG4gICAgY29uc3Qgbm9kZU5hbWUgPSBjdXJyZW50Tm9kZS5ub2RlTmFtZTtcbiAgICBpZiAobm9kZU5hbWUgPT09ICdURCcgfHwgbm9kZU5hbWUgPT09ICdUSCcpIHtcbiAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3I6IGludGVybmFsIGZpZWxkXG4gICAgICBjb25zdCBjZWxsID0gY3VycmVudE5vZGUuX2NlbGw7XG4gICAgICBpZiAoY2VsbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGNlbGw7XG4gICAgfVxuICAgIGN1cnJlbnROb2RlID0gY3VycmVudE5vZGUucGFyZW50Tm9kZTtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cbmZ1bmN0aW9uIGdldERPTUNlbGxJblRhYmxlRnJvbVRhcmdldCh0YWJsZSwgbm9kZSkge1xuICBpZiAoIXRhYmxlLmNvbnRhaW5zKG5vZGUpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgbGV0IGNlbGwgPSBudWxsO1xuICBmb3IgKGxldCBjdXJyZW50Tm9kZSA9IG5vZGU7IGN1cnJlbnROb2RlICE9IG51bGw7IGN1cnJlbnROb2RlID0gY3VycmVudE5vZGUucGFyZW50Tm9kZSkge1xuICAgIGlmIChjdXJyZW50Tm9kZSA9PT0gdGFibGUpIHtcbiAgICAgIHJldHVybiBjZWxsO1xuICAgIH1cbiAgICBjb25zdCBub2RlTmFtZSA9IGN1cnJlbnROb2RlLm5vZGVOYW1lO1xuICAgIGlmIChub2RlTmFtZSA9PT0gJ1REJyB8fCBub2RlTmFtZSA9PT0gJ1RIJykge1xuICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvcjogaW50ZXJuYWwgZmllbGRcbiAgICAgIGNlbGwgPSBjdXJyZW50Tm9kZS5fY2VsbCB8fCBudWxsO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cbmZ1bmN0aW9uIGdldFRhYmxlKHRhYmxlTm9kZSwgZG9tKSB7XG4gIGNvbnN0IHRhYmxlRWxlbWVudCA9IGdldFRhYmxlRWxlbWVudCh0YWJsZU5vZGUsIGRvbSk7XG4gIGNvbnN0IGRvbVJvd3MgPSBbXTtcbiAgY29uc3QgZ3JpZCA9IHtcbiAgICBjb2x1bW5zOiAwLFxuICAgIGRvbVJvd3MsXG4gICAgcm93czogMFxuICB9O1xuICBsZXQgY3VycmVudE5vZGUgPSB0YWJsZUVsZW1lbnQucXVlcnlTZWxlY3RvcigndHInKTtcbiAgbGV0IHggPSAwO1xuICBsZXQgeSA9IDA7XG4gIGRvbVJvd3MubGVuZ3RoID0gMDtcbiAgd2hpbGUgKGN1cnJlbnROb2RlICE9IG51bGwpIHtcbiAgICBjb25zdCBub2RlTWFtZSA9IGN1cnJlbnROb2RlLm5vZGVOYW1lO1xuICAgIGlmIChub2RlTWFtZSA9PT0gJ1REJyB8fCBub2RlTWFtZSA9PT0gJ1RIJykge1xuICAgICAgY29uc3QgZWxlbSA9IGN1cnJlbnROb2RlO1xuICAgICAgY29uc3QgY2VsbCA9IHtcbiAgICAgICAgZWxlbSxcbiAgICAgICAgaGFzQmFja2dyb3VuZENvbG9yOiBlbGVtLnN0eWxlLmJhY2tncm91bmRDb2xvciAhPT0gJycsXG4gICAgICAgIGhpZ2hsaWdodGVkOiBmYWxzZSxcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfTtcblxuICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvcjogaW50ZXJuYWwgZmllbGRcbiAgICAgIGN1cnJlbnROb2RlLl9jZWxsID0gY2VsbDtcbiAgICAgIGxldCByb3cgPSBkb21Sb3dzW3ldO1xuICAgICAgaWYgKHJvdyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJvdyA9IGRvbVJvd3NbeV0gPSBbXTtcbiAgICAgIH1cbiAgICAgIHJvd1t4XSA9IGNlbGw7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGNoaWxkID0gY3VycmVudE5vZGUuZmlyc3RDaGlsZDtcbiAgICAgIGlmIChjaGlsZCAhPSBudWxsKSB7XG4gICAgICAgIGN1cnJlbnROb2RlID0gY2hpbGQ7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBzaWJsaW5nID0gY3VycmVudE5vZGUubmV4dFNpYmxpbmc7XG4gICAgaWYgKHNpYmxpbmcgIT0gbnVsbCkge1xuICAgICAgeCsrO1xuICAgICAgY3VycmVudE5vZGUgPSBzaWJsaW5nO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IHBhcmVudCA9IGN1cnJlbnROb2RlLnBhcmVudE5vZGU7XG4gICAgaWYgKHBhcmVudCAhPSBudWxsKSB7XG4gICAgICBjb25zdCBwYXJlbnRTaWJsaW5nID0gcGFyZW50Lm5leHRTaWJsaW5nO1xuICAgICAgaWYgKHBhcmVudFNpYmxpbmcgPT0gbnVsbCkge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIHkrKztcbiAgICAgIHggPSAwO1xuICAgICAgY3VycmVudE5vZGUgPSBwYXJlbnRTaWJsaW5nO1xuICAgIH1cbiAgfVxuICBncmlkLmNvbHVtbnMgPSB4ICsgMTtcbiAgZ3JpZC5yb3dzID0geSArIDE7XG4gIHJldHVybiBncmlkO1xufVxuZnVuY3Rpb24gJHVwZGF0ZURPTUZvclNlbGVjdGlvbihlZGl0b3IsIHRhYmxlLCBzZWxlY3Rpb24pIHtcbiAgY29uc3Qgc2VsZWN0ZWRDZWxsTm9kZXMgPSBuZXcgU2V0KHNlbGVjdGlvbiA/IHNlbGVjdGlvbi5nZXROb2RlcygpIDogW10pO1xuICAkZm9yRWFjaFRhYmxlQ2VsbCh0YWJsZSwgKGNlbGwsIGxleGljYWxOb2RlKSA9PiB7XG4gICAgY29uc3QgZWxlbSA9IGNlbGwuZWxlbTtcbiAgICBpZiAoc2VsZWN0ZWRDZWxsTm9kZXMuaGFzKGxleGljYWxOb2RlKSkge1xuICAgICAgY2VsbC5oaWdobGlnaHRlZCA9IHRydWU7XG4gICAgICAkYWRkSGlnaGxpZ2h0VG9ET00oZWRpdG9yLCBjZWxsKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY2VsbC5oaWdobGlnaHRlZCA9IGZhbHNlO1xuICAgICAgJHJlbW92ZUhpZ2hsaWdodEZyb21ET00oZWRpdG9yLCBjZWxsKTtcbiAgICAgIGlmICghZWxlbS5nZXRBdHRyaWJ1dGUoJ3N0eWxlJykpIHtcbiAgICAgICAgZWxlbS5yZW1vdmVBdHRyaWJ1dGUoJ3N0eWxlJyk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn1cbmZ1bmN0aW9uICRmb3JFYWNoVGFibGVDZWxsKGdyaWQsIGNiKSB7XG4gIGNvbnN0IHtcbiAgICBkb21Sb3dzXG4gIH0gPSBncmlkO1xuICBmb3IgKGxldCB5ID0gMDsgeSA8IGRvbVJvd3MubGVuZ3RoOyB5KyspIHtcbiAgICBjb25zdCByb3cgPSBkb21Sb3dzW3ldO1xuICAgIGlmICghcm93KSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgZm9yIChsZXQgeCA9IDA7IHggPCByb3cubGVuZ3RoOyB4KyspIHtcbiAgICAgIGNvbnN0IGNlbGwgPSByb3dbeF07XG4gICAgICBpZiAoIWNlbGwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBsZXhpY2FsTm9kZSA9ICRnZXROZWFyZXN0Tm9kZUZyb21ET01Ob2RlKGNlbGwuZWxlbSk7XG4gICAgICBpZiAobGV4aWNhbE5vZGUgIT09IG51bGwpIHtcbiAgICAgICAgY2IoY2VsbCwgbGV4aWNhbE5vZGUsIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5mdW5jdGlvbiAkYWRkSGlnaGxpZ2h0U3R5bGVUb1RhYmxlKGVkaXRvciwgdGFibGVTZWxlY3Rpb24pIHtcbiAgdGFibGVTZWxlY3Rpb24uJGRpc2FibGVIaWdobGlnaHRTdHlsZSgpO1xuICAkZm9yRWFjaFRhYmxlQ2VsbCh0YWJsZVNlbGVjdGlvbi50YWJsZSwgY2VsbCA9PiB7XG4gICAgY2VsbC5oaWdobGlnaHRlZCA9IHRydWU7XG4gICAgJGFkZEhpZ2hsaWdodFRvRE9NKGVkaXRvciwgY2VsbCk7XG4gIH0pO1xufVxuZnVuY3Rpb24gJHJlbW92ZUhpZ2hsaWdodFN0eWxlVG9UYWJsZShlZGl0b3IsIHRhYmxlT2JzZXJ2ZXIpIHtcbiAgdGFibGVPYnNlcnZlci4kZW5hYmxlSGlnaGxpZ2h0U3R5bGUoKTtcbiAgJGZvckVhY2hUYWJsZUNlbGwodGFibGVPYnNlcnZlci50YWJsZSwgY2VsbCA9PiB7XG4gICAgY29uc3QgZWxlbSA9IGNlbGwuZWxlbTtcbiAgICBjZWxsLmhpZ2hsaWdodGVkID0gZmFsc2U7XG4gICAgJHJlbW92ZUhpZ2hsaWdodEZyb21ET00oZWRpdG9yLCBjZWxsKTtcbiAgICBpZiAoIWVsZW0uZ2V0QXR0cmlidXRlKCdzdHlsZScpKSB7XG4gICAgICBlbGVtLnJlbW92ZUF0dHJpYnV0ZSgnc3R5bGUnKTtcbiAgICB9XG4gIH0pO1xufVxuZnVuY3Rpb24gJHNlbGVjdEFkamFjZW50Q2VsbCh0YWJsZUNlbGxOb2RlLCBkaXJlY3Rpb24pIHtcbiAgY29uc3Qgc2libGluZ01ldGhvZCA9IGRpcmVjdGlvbiA9PT0gJ25leHQnID8gJ2dldE5leHRTaWJsaW5nJyA6ICdnZXRQcmV2aW91c1NpYmxpbmcnO1xuICBjb25zdCBjaGlsZE1ldGhvZCA9IGRpcmVjdGlvbiA9PT0gJ25leHQnID8gJ2dldEZpcnN0Q2hpbGQnIDogJ2dldExhc3RDaGlsZCc7XG4gIGNvbnN0IHNpYmxpbmcgPSB0YWJsZUNlbGxOb2RlW3NpYmxpbmdNZXRob2RdKCk7XG4gIGlmICgkaXNFbGVtZW50Tm9kZShzaWJsaW5nKSkge1xuICAgIHJldHVybiBzaWJsaW5nLnNlbGVjdEVuZCgpO1xuICB9XG4gIGNvbnN0IHBhcmVudFJvdyA9ICRmaW5kTWF0Y2hpbmdQYXJlbnQodGFibGVDZWxsTm9kZSwgJGlzVGFibGVSb3dOb2RlKTtcbiAgaWYgKCEocGFyZW50Um93ICE9PSBudWxsKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgc2VsZWN0QWRqYWNlbnRDZWxsOiBDZWxsIG5vdCBpbiB0YWJsZSByb3dgKTtcbiAgfVxuICBmb3IgKGxldCBuZXh0Um93ID0gcGFyZW50Um93W3NpYmxpbmdNZXRob2RdKCk7ICRpc1RhYmxlUm93Tm9kZShuZXh0Um93KTsgbmV4dFJvdyA9IG5leHRSb3dbc2libGluZ01ldGhvZF0oKSkge1xuICAgIGNvbnN0IGNoaWxkID0gbmV4dFJvd1tjaGlsZE1ldGhvZF0oKTtcbiAgICBpZiAoJGlzRWxlbWVudE5vZGUoY2hpbGQpKSB7XG4gICAgICByZXR1cm4gY2hpbGQuc2VsZWN0RW5kKCk7XG4gICAgfVxuICB9XG4gIGNvbnN0IHBhcmVudFRhYmxlID0gJGZpbmRNYXRjaGluZ1BhcmVudChwYXJlbnRSb3csICRpc1RhYmxlTm9kZSk7XG4gIGlmICghKHBhcmVudFRhYmxlICE9PSBudWxsKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgc2VsZWN0QWRqYWNlbnRDZWxsOiBSb3cgbm90IGluIHRhYmxlYCk7XG4gIH1cbiAgcmV0dXJuIGRpcmVjdGlvbiA9PT0gJ25leHQnID8gcGFyZW50VGFibGUuc2VsZWN0TmV4dCgpIDogcGFyZW50VGFibGUuc2VsZWN0UHJldmlvdXMoKTtcbn1cbmNvbnN0IHNlbGVjdFRhYmxlTm9kZUluRGlyZWN0aW9uID0gKHRhYmxlT2JzZXJ2ZXIsIHRhYmxlTm9kZSwgeCwgeSwgZGlyZWN0aW9uKSA9PiB7XG4gIGNvbnN0IGlzRm9yd2FyZCA9IGRpcmVjdGlvbiA9PT0gJ2ZvcndhcmQnO1xuICBzd2l0Y2ggKGRpcmVjdGlvbikge1xuICAgIGNhc2UgJ2JhY2t3YXJkJzpcbiAgICBjYXNlICdmb3J3YXJkJzpcbiAgICAgIGlmICh4ICE9PSAoaXNGb3J3YXJkID8gdGFibGVPYnNlcnZlci50YWJsZS5jb2x1bW5zIC0gMSA6IDApKSB7XG4gICAgICAgIHNlbGVjdFRhYmxlQ2VsbE5vZGUodGFibGVOb2RlLmdldENlbGxOb2RlRnJvbUNvcmRzT3JUaHJvdyh4ICsgKGlzRm9yd2FyZCA/IDEgOiAtMSksIHksIHRhYmxlT2JzZXJ2ZXIudGFibGUpLCBpc0ZvcndhcmQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHkgIT09IChpc0ZvcndhcmQgPyB0YWJsZU9ic2VydmVyLnRhYmxlLnJvd3MgLSAxIDogMCkpIHtcbiAgICAgICAgICBzZWxlY3RUYWJsZUNlbGxOb2RlKHRhYmxlTm9kZS5nZXRDZWxsTm9kZUZyb21Db3Jkc09yVGhyb3coaXNGb3J3YXJkID8gMCA6IHRhYmxlT2JzZXJ2ZXIudGFibGUuY29sdW1ucyAtIDEsIHkgKyAoaXNGb3J3YXJkID8gMSA6IC0xKSwgdGFibGVPYnNlcnZlci50YWJsZSksIGlzRm9yd2FyZCk7XG4gICAgICAgIH0gZWxzZSBpZiAoIWlzRm9yd2FyZCkge1xuICAgICAgICAgIHRhYmxlTm9kZS5zZWxlY3RQcmV2aW91cygpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRhYmxlTm9kZS5zZWxlY3ROZXh0KCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIGNhc2UgJ3VwJzpcbiAgICAgIGlmICh5ICE9PSAwKSB7XG4gICAgICAgIHNlbGVjdFRhYmxlQ2VsbE5vZGUodGFibGVOb2RlLmdldENlbGxOb2RlRnJvbUNvcmRzT3JUaHJvdyh4LCB5IC0gMSwgdGFibGVPYnNlcnZlci50YWJsZSksIGZhbHNlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRhYmxlTm9kZS5zZWxlY3RQcmV2aW91cygpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgY2FzZSAnZG93bic6XG4gICAgICBpZiAoeSAhPT0gdGFibGVPYnNlcnZlci50YWJsZS5yb3dzIC0gMSkge1xuICAgICAgICBzZWxlY3RUYWJsZUNlbGxOb2RlKHRhYmxlTm9kZS5nZXRDZWxsTm9kZUZyb21Db3Jkc09yVGhyb3coeCwgeSArIDEsIHRhYmxlT2JzZXJ2ZXIudGFibGUpLCB0cnVlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRhYmxlTm9kZS5zZWxlY3ROZXh0KCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlO1xuICB9XG59O1xuZnVuY3Rpb24gZ2V0Q29ybmVyKHJlY3QsIGNlbGxWYWx1ZSkge1xuICBsZXQgY29sTmFtZTtcbiAgbGV0IHJvd05hbWU7XG4gIGlmIChjZWxsVmFsdWUuc3RhcnRDb2x1bW4gPT09IHJlY3QubWluQ29sdW1uKSB7XG4gICAgY29sTmFtZSA9ICdtaW5Db2x1bW4nO1xuICB9IGVsc2UgaWYgKGNlbGxWYWx1ZS5zdGFydENvbHVtbiArIGNlbGxWYWx1ZS5jZWxsLl9fY29sU3BhbiAtIDEgPT09IHJlY3QubWF4Q29sdW1uKSB7XG4gICAgY29sTmFtZSA9ICdtYXhDb2x1bW4nO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGlmIChjZWxsVmFsdWUuc3RhcnRSb3cgPT09IHJlY3QubWluUm93KSB7XG4gICAgcm93TmFtZSA9ICdtaW5Sb3cnO1xuICB9IGVsc2UgaWYgKGNlbGxWYWx1ZS5zdGFydFJvdyArIGNlbGxWYWx1ZS5jZWxsLl9fcm93U3BhbiAtIDEgPT09IHJlY3QubWF4Um93KSB7XG4gICAgcm93TmFtZSA9ICdtYXhSb3cnO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIHJldHVybiBbY29sTmFtZSwgcm93TmFtZV07XG59XG5mdW5jdGlvbiBnZXRDb3JuZXJPclRocm93KHJlY3QsIGNlbGxWYWx1ZSkge1xuICBjb25zdCBjb3JuZXIgPSBnZXRDb3JuZXIocmVjdCwgY2VsbFZhbHVlKTtcbiAgaWYgKCEoY29ybmVyICE9PSBudWxsKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgZ2V0Q29ybmVyT3JUaHJvdzogY2VsbCAke2NlbGxWYWx1ZS5jZWxsLmdldEtleSgpfSBpcyBub3QgYXQgYSBjb3JuZXIgb2YgcmVjdGApO1xuICB9XG4gIHJldHVybiBjb3JuZXI7XG59XG5mdW5jdGlvbiBvcHBvc2l0ZUNvcm5lcihbY29sTmFtZSwgcm93TmFtZV0pIHtcbiAgcmV0dXJuIFtjb2xOYW1lID09PSAnbWluQ29sdW1uJyA/ICdtYXhDb2x1bW4nIDogJ21pbkNvbHVtbicsIHJvd05hbWUgPT09ICdtaW5Sb3cnID8gJ21heFJvdycgOiAnbWluUm93J107XG59XG5mdW5jdGlvbiBjZWxsQXRDb3JuZXJPclRocm93KHRhYmxlTWFwLCByZWN0LCBbY29sTmFtZSwgcm93TmFtZV0pIHtcbiAgY29uc3Qgcm93TnVtID0gcmVjdFtyb3dOYW1lXTtcbiAgY29uc3Qgcm93TWFwID0gdGFibGVNYXBbcm93TnVtXTtcbiAgaWYgKCEocm93TWFwICE9PSB1bmRlZmluZWQpKSB7XG4gICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBjZWxsQXRDb3JuZXJPclRocm93OiAke3Jvd05hbWV9ID0gJHtTdHJpbmcocm93TnVtKX0gbWlzc2luZyBpbiB0YWJsZU1hcGApO1xuICB9XG4gIGNvbnN0IGNvbE51bSA9IHJlY3RbY29sTmFtZV07XG4gIGNvbnN0IGNlbGwgPSByb3dNYXBbY29sTnVtXTtcbiAgaWYgKCEoY2VsbCAhPT0gdW5kZWZpbmVkKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgY2VsbEF0Q29ybmVyT3JUaHJvdzogJHtjb2xOYW1lfSA9ICR7U3RyaW5nKGNvbE51bSl9IG1pc3NpbmcgaW4gdGFibGVNYXBgKTtcbiAgfVxuICByZXR1cm4gY2VsbDtcbn1cbmZ1bmN0aW9uICRleHRyYWN0UmVjdENvcm5lcnModGFibGVNYXAsIGFuY2hvckNlbGxWYWx1ZSwgbmV3Rm9jdXNDZWxsVmFsdWUpIHtcbiAgLy8gV2UgYXJlIHN1cmUgdGhhdCB0aGUgZm9jdXMgbm93IGVpdGhlciBjb250cmFjdHMgb3IgZXhwYW5kcyB0aGUgcmVjdFxuICAvLyBidXQgYm90aCB0aGUgYW5jaG9yIGFuZCBmb2N1cyBtaWdodCBiZSBtb3ZlZCB0byBlbnN1cmUgYSByZWN0YW5nbGVcbiAgLy8gZ2l2ZW4gYSBwb3RlbnRpYWxseSByYWdnZWQgbWVyZ2Ugc2hhcGVcbiAgY29uc3QgcmVjdCA9ICRjb21wdXRlVGFibGVDZWxsUmVjdEJvdW5kYXJ5KHRhYmxlTWFwLCBhbmNob3JDZWxsVmFsdWUsIG5ld0ZvY3VzQ2VsbFZhbHVlKTtcbiAgY29uc3QgYW5jaG9yQ29ybmVyID0gZ2V0Q29ybmVyKHJlY3QsIGFuY2hvckNlbGxWYWx1ZSk7XG4gIGlmIChhbmNob3JDb3JuZXIpIHtcbiAgICByZXR1cm4gW2NlbGxBdENvcm5lck9yVGhyb3codGFibGVNYXAsIHJlY3QsIGFuY2hvckNvcm5lciksIGNlbGxBdENvcm5lck9yVGhyb3codGFibGVNYXAsIHJlY3QsIG9wcG9zaXRlQ29ybmVyKGFuY2hvckNvcm5lcikpXTtcbiAgfVxuICBjb25zdCBuZXdGb2N1c0Nvcm5lciA9IGdldENvcm5lcihyZWN0LCBuZXdGb2N1c0NlbGxWYWx1ZSk7XG4gIGlmIChuZXdGb2N1c0Nvcm5lcikge1xuICAgIHJldHVybiBbY2VsbEF0Q29ybmVyT3JUaHJvdyh0YWJsZU1hcCwgcmVjdCwgb3Bwb3NpdGVDb3JuZXIobmV3Rm9jdXNDb3JuZXIpKSwgY2VsbEF0Q29ybmVyT3JUaHJvdyh0YWJsZU1hcCwgcmVjdCwgbmV3Rm9jdXNDb3JuZXIpXTtcbiAgfVxuICAvLyBUT0RPIHRoaXMgZG9lc24ndCBoYXZlIHRvIGJlIGFyYml0cmFyeSwgdXNlIHRoZSBjbG9zZXN0IGNvcm5lciBpbnN0ZWFkXG4gIGNvbnN0IG5ld0FuY2hvckNvcm5lciA9IFsnbWluQ29sdW1uJywgJ21pblJvdyddO1xuICByZXR1cm4gW2NlbGxBdENvcm5lck9yVGhyb3codGFibGVNYXAsIHJlY3QsIG5ld0FuY2hvckNvcm5lciksIGNlbGxBdENvcm5lck9yVGhyb3codGFibGVNYXAsIHJlY3QsIG9wcG9zaXRlQ29ybmVyKG5ld0FuY2hvckNvcm5lcikpXTtcbn1cbmZ1bmN0aW9uICRhZGp1c3RGb2N1c0luRGlyZWN0aW9uKHRhYmxlT2JzZXJ2ZXIsIHRhYmxlTWFwLCBhbmNob3JDZWxsVmFsdWUsIGZvY3VzQ2VsbFZhbHVlLCBkaXJlY3Rpb24pIHtcbiAgY29uc3QgcmVjdCA9ICRjb21wdXRlVGFibGVDZWxsUmVjdEJvdW5kYXJ5KHRhYmxlTWFwLCBhbmNob3JDZWxsVmFsdWUsIGZvY3VzQ2VsbFZhbHVlKTtcbiAgY29uc3Qgc3BhbnMgPSAkY29tcHV0ZVRhYmxlQ2VsbFJlY3RTcGFucyh0YWJsZU1hcCwgcmVjdCk7XG4gIGNvbnN0IHtcbiAgICB0b3BTcGFuLFxuICAgIGxlZnRTcGFuLFxuICAgIGJvdHRvbVNwYW4sXG4gICAgcmlnaHRTcGFuXG4gIH0gPSBzcGFucztcbiAgY29uc3QgYW5jaG9yQ29ybmVyID0gZ2V0Q29ybmVyT3JUaHJvdyhyZWN0LCBhbmNob3JDZWxsVmFsdWUpO1xuICBjb25zdCBbZm9jdXNDb2x1bW4sIGZvY3VzUm93XSA9IG9wcG9zaXRlQ29ybmVyKGFuY2hvckNvcm5lcik7XG4gIGxldCBmQ29sID0gcmVjdFtmb2N1c0NvbHVtbl07XG4gIGxldCBmUm93ID0gcmVjdFtmb2N1c1Jvd107XG4gIGlmIChkaXJlY3Rpb24gPT09ICdmb3J3YXJkJykge1xuICAgIGZDb2wgKz0gZm9jdXNDb2x1bW4gPT09ICdtYXhDb2x1bW4nID8gMSA6IGxlZnRTcGFuO1xuICB9IGVsc2UgaWYgKGRpcmVjdGlvbiA9PT0gJ2JhY2t3YXJkJykge1xuICAgIGZDb2wgLT0gZm9jdXNDb2x1bW4gPT09ICdtaW5Db2x1bW4nID8gMSA6IHJpZ2h0U3BhbjtcbiAgfSBlbHNlIGlmIChkaXJlY3Rpb24gPT09ICdkb3duJykge1xuICAgIGZSb3cgKz0gZm9jdXNSb3cgPT09ICdtYXhSb3cnID8gMSA6IHRvcFNwYW47XG4gIH0gZWxzZSBpZiAoZGlyZWN0aW9uID09PSAndXAnKSB7XG4gICAgZlJvdyAtPSBmb2N1c1JvdyA9PT0gJ21pblJvdycgPyAxIDogYm90dG9tU3BhbjtcbiAgfVxuICBjb25zdCB0YXJnZXRSb3dNYXAgPSB0YWJsZU1hcFtmUm93XTtcbiAgaWYgKHRhcmdldFJvd01hcCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IG5ld0ZvY3VzQ2VsbFZhbHVlID0gdGFyZ2V0Um93TWFwW2ZDb2xdO1xuICBpZiAobmV3Rm9jdXNDZWxsVmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICAvLyBXZSBjYW4gYmUgY2VydGFpbiB0aGF0IGFuY2hvckNlbGxWYWx1ZSBhbmQgbmV3Rm9jdXNDZWxsVmFsdWUgYXJlXG4gIC8vIGNvbnRhaW5lZCB3aXRoaW4gdGhlIGRlc2lyZWQgc2VsZWN0aW9uLCBidXQgd2UgYXJlIG5vdCBjZXJ0YWluIGlmXG4gIC8vIHRoZXkgbmVlZCB0byBiZSBleHBhbmRlZCBvciBub3QgdG8gbWFpbnRhaW4gYSByZWN0YW5ndWxhciBzaGFwZVxuICBjb25zdCBbZmluYWxBbmNob3JDZWxsLCBmaW5hbEZvY3VzQ2VsbF0gPSAkZXh0cmFjdFJlY3RDb3JuZXJzKHRhYmxlTWFwLCBhbmNob3JDZWxsVmFsdWUsIG5ld0ZvY3VzQ2VsbFZhbHVlKTtcbiAgY29uc3QgYW5jaG9yRE9NID0gJGdldE9ic2VydmVyQ2VsbEZyb21DZWxsTm9kZU9yVGhyb3codGFibGVPYnNlcnZlciwgZmluYWxBbmNob3JDZWxsLmNlbGwpO1xuICBjb25zdCBmb2N1c0RPTSA9ICRnZXRPYnNlcnZlckNlbGxGcm9tQ2VsbE5vZGVPclRocm93KHRhYmxlT2JzZXJ2ZXIsIGZpbmFsRm9jdXNDZWxsLmNlbGwpO1xuICB0YWJsZU9ic2VydmVyLiRzZXRBbmNob3JDZWxsRm9yU2VsZWN0aW9uKGFuY2hvckRPTSk7XG4gIHRhYmxlT2JzZXJ2ZXIuJHNldEZvY3VzQ2VsbEZvclNlbGVjdGlvbihmb2N1c0RPTSwgdHJ1ZSk7XG4gIHJldHVybiB0cnVlO1xufVxuZnVuY3Rpb24gJGlzU2VsZWN0aW9uSW5UYWJsZShzZWxlY3Rpb24sIHRhYmxlTm9kZSkge1xuICBpZiAoJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSB8fCAkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pKSB7XG4gICAgLy8gVE9ETyB0aGlzIHNob3VsZCBwcm9iYWJseSByZXR1cm4gZmFsc2UgaWYgdGhlcmUncyBhbiB1bnJlbGF0ZWRcbiAgICAvLyAgICAgIHNoYWRvdyByb290IGJldHdlZW4gdGhlIG5vZGUgYW5kIHRoZSB0YWJsZSAoZS5nLiBhbm90aGVyIHRhYmxlLFxuICAgIC8vICAgICAgY29sbGFwc2libGUsIGV0Yy4pXG4gICAgY29uc3QgaXNBbmNob3JJbnNpZGUgPSB0YWJsZU5vZGUuaXNQYXJlbnRPZihzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKSk7XG4gICAgY29uc3QgaXNGb2N1c0luc2lkZSA9IHRhYmxlTm9kZS5pc1BhcmVudE9mKHNlbGVjdGlvbi5mb2N1cy5nZXROb2RlKCkpO1xuICAgIHJldHVybiBpc0FuY2hvckluc2lkZSAmJiBpc0ZvY3VzSW5zaWRlO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cbmZ1bmN0aW9uICRpc0Z1bGxUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24sIHRhYmxlTm9kZSkge1xuICBpZiAoJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgIGNvbnN0IGFuY2hvck5vZGUgPSBzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKTtcbiAgICBjb25zdCBmb2N1c05vZGUgPSBzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpO1xuICAgIGlmICh0YWJsZU5vZGUgJiYgYW5jaG9yTm9kZSAmJiBmb2N1c05vZGUpIHtcbiAgICAgIGNvbnN0IFttYXBdID0gJGNvbXB1dGVUYWJsZU1hcCh0YWJsZU5vZGUsIGFuY2hvck5vZGUsIGZvY3VzTm9kZSk7XG4gICAgICByZXR1cm4gYW5jaG9yTm9kZS5nZXRLZXkoKSA9PT0gbWFwWzBdWzBdLmNlbGwuZ2V0S2V5KCkgJiYgZm9jdXNOb2RlLmdldEtleSgpID09PSBtYXBbbWFwLmxlbmd0aCAtIDFdLmF0KC0xKS5jZWxsLmdldEtleSgpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5mdW5jdGlvbiBzZWxlY3RUYWJsZUNlbGxOb2RlKHRhYmxlQ2VsbCwgZnJvbVN0YXJ0KSB7XG4gIGlmIChmcm9tU3RhcnQpIHtcbiAgICB0YWJsZUNlbGwuc2VsZWN0U3RhcnQoKTtcbiAgfSBlbHNlIHtcbiAgICB0YWJsZUNlbGwuc2VsZWN0RW5kKCk7XG4gIH1cbn1cbmZ1bmN0aW9uICRhZGRIaWdobGlnaHRUb0RPTShlZGl0b3IsIGNlbGwpIHtcbiAgY29uc3QgZWxlbWVudCA9IGNlbGwuZWxlbTtcbiAgY29uc3QgZWRpdG9yVGhlbWVDbGFzc2VzID0gZWRpdG9yLl9jb25maWcudGhlbWU7XG4gIGNvbnN0IG5vZGUgPSAkZ2V0TmVhcmVzdE5vZGVGcm9tRE9NTm9kZShlbGVtZW50KTtcbiAgaWYgKCEkaXNUYWJsZUNlbGxOb2RlKG5vZGUpKSB7XG4gICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCB0byBmaW5kIExleGljYWxOb2RlIGZyb20gVGFibGUgQ2VsbCBET01Ob2RlYCk7XG4gIH1cbiAgYWRkQ2xhc3NOYW1lc1RvRWxlbWVudChlbGVtZW50LCBlZGl0b3JUaGVtZUNsYXNzZXMudGFibGVDZWxsU2VsZWN0ZWQpO1xufVxuZnVuY3Rpb24gJHJlbW92ZUhpZ2hsaWdodEZyb21ET00oZWRpdG9yLCBjZWxsKSB7XG4gIGNvbnN0IGVsZW1lbnQgPSBjZWxsLmVsZW07XG4gIGNvbnN0IG5vZGUgPSAkZ2V0TmVhcmVzdE5vZGVGcm9tRE9NTm9kZShlbGVtZW50KTtcbiAgaWYgKCEkaXNUYWJsZUNlbGxOb2RlKG5vZGUpKSB7XG4gICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCB0byBmaW5kIExleGljYWxOb2RlIGZyb20gVGFibGUgQ2VsbCBET01Ob2RlYCk7XG4gIH1cbiAgY29uc3QgZWRpdG9yVGhlbWVDbGFzc2VzID0gZWRpdG9yLl9jb25maWcudGhlbWU7XG4gIHJlbW92ZUNsYXNzTmFtZXNGcm9tRWxlbWVudChlbGVtZW50LCBlZGl0b3JUaGVtZUNsYXNzZXMudGFibGVDZWxsU2VsZWN0ZWQpO1xufVxuZnVuY3Rpb24gJGZpbmRDZWxsTm9kZShub2RlKSB7XG4gIGNvbnN0IGNlbGxOb2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChub2RlLCAkaXNUYWJsZUNlbGxOb2RlKTtcbiAgcmV0dXJuICRpc1RhYmxlQ2VsbE5vZGUoY2VsbE5vZGUpID8gY2VsbE5vZGUgOiBudWxsO1xufVxuZnVuY3Rpb24gJGZpbmRUYWJsZU5vZGUobm9kZSkge1xuICBjb25zdCB0YWJsZU5vZGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KG5vZGUsICRpc1RhYmxlTm9kZSk7XG4gIHJldHVybiAkaXNUYWJsZU5vZGUodGFibGVOb2RlKSA/IHRhYmxlTm9kZSA6IG51bGw7XG59XG5mdW5jdGlvbiAkZ2V0QmxvY2tQYXJlbnRJZkZpcnN0Tm9kZShub2RlKSB7XG4gIGZvciAobGV0IHByZXZOb2RlID0gbm9kZSwgY3VycmVudE5vZGUgPSBub2RlOyBjdXJyZW50Tm9kZSAhPT0gbnVsbDsgcHJldk5vZGUgPSBjdXJyZW50Tm9kZSwgY3VycmVudE5vZGUgPSBjdXJyZW50Tm9kZS5nZXRQYXJlbnQoKSkge1xuICAgIGlmICgkaXNFbGVtZW50Tm9kZShjdXJyZW50Tm9kZSkpIHtcbiAgICAgIGlmIChjdXJyZW50Tm9kZSAhPT0gcHJldk5vZGUgJiYgY3VycmVudE5vZGUuZ2V0Rmlyc3RDaGlsZCgpICE9PSBwcmV2Tm9kZSkge1xuICAgICAgICAvLyBOb3QgdGhlIGZpcnN0IGNoaWxkIG9yIHRoZSBpbml0aWFsIG5vZGVcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9IGVsc2UgaWYgKCFjdXJyZW50Tm9kZS5pc0lubGluZSgpKSB7XG4gICAgICAgIHJldHVybiBjdXJyZW50Tm9kZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5mdW5jdGlvbiAkaGFuZGxlSG9yaXpvbnRhbEFycm93S2V5UmFuZ2VTZWxlY3Rpb24oZWRpdG9yLCBldmVudCwgc2VsZWN0aW9uLCBhbHRlciwgaXNCYWNrd2FyZCwgdGFibGVOb2RlLCB0YWJsZU9ic2VydmVyKSB7XG4gIGNvbnN0IGluaXRpYWxGb2N1cyA9ICRjYXJldEZyb21Qb2ludChzZWxlY3Rpb24uZm9jdXMsIGlzQmFja3dhcmQgPyAncHJldmlvdXMnIDogJ25leHQnKTtcbiAgaWYgKCRpc0V4dGVuZGFibGVUZXh0UG9pbnRDYXJldChpbml0aWFsRm9jdXMpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGxldCBsYXN0Q2FyZXQgPSBpbml0aWFsRm9jdXM7XG4gIC8vIFRhYmxlQ2VsbE5vZGUgaXMgdGhlIG9ubHkgc2hhZG93IHJvb3Qgd2UgYXJlIGludGVyZXN0ZWQgaW4gcGllcmNpbmcgc29cbiAgLy8gd2UgZmluZCB0aGUgbGFzdCBpbnRlcm5hbCBjYXJldCBhbmQgdGhlbiBjaGVjayBpdHMgcGFyZW50XG4gIGZvciAoY29uc3QgbmV4dENhcmV0IG9mICRleHRlbmRDYXJldFRvUmFuZ2UoaW5pdGlhbEZvY3VzKS5pdGVyTm9kZUNhcmV0cygnc2hhZG93Um9vdCcpKSB7XG4gICAgaWYgKCEoJGlzU2libGluZ0NhcmV0KG5leHRDYXJldCkgJiYgJGlzRWxlbWVudE5vZGUobmV4dENhcmV0Lm9yaWdpbikpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGxhc3RDYXJldCA9IG5leHRDYXJldDtcbiAgfVxuICBjb25zdCBsYXN0Q2FyZXRQYXJlbnQgPSBsYXN0Q2FyZXQuZ2V0UGFyZW50QXRDYXJldCgpO1xuICBpZiAoISRpc1RhYmxlQ2VsbE5vZGUobGFzdENhcmV0UGFyZW50KSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCBhbmNob3JDZWxsID0gbGFzdENhcmV0UGFyZW50O1xuICBjb25zdCBmb2N1c0NhcmV0ID0gJGZpbmROZXh0VGFibGVDZWxsKCRnZXRTaWJsaW5nQ2FyZXQoYW5jaG9yQ2VsbCwgbGFzdENhcmV0LmRpcmVjdGlvbikpO1xuICBjb25zdCBhbmNob3JDZWxsVGFibGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KGFuY2hvckNlbGwsICRpc1RhYmxlTm9kZSk7XG4gIGlmICghKGFuY2hvckNlbGxUYWJsZSAmJiBhbmNob3JDZWxsVGFibGUuaXModGFibGVOb2RlKSkpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgYW5jaG9yQ2VsbERPTSA9IGVkaXRvci5nZXRFbGVtZW50QnlLZXkoYW5jaG9yQ2VsbC5nZXRLZXkoKSk7XG4gIGNvbnN0IGFuY2hvckRPTUNlbGwgPSBnZXRET01DZWxsRnJvbVRhcmdldChhbmNob3JDZWxsRE9NKTtcbiAgaWYgKCFhbmNob3JDZWxsRE9NIHx8ICFhbmNob3JET01DZWxsKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IGFuY2hvckNlbGxUYWJsZUVsZW1lbnQgPSAkZ2V0RWxlbWVudEZvclRhYmxlTm9kZShlZGl0b3IsIGFuY2hvckNlbGxUYWJsZSk7XG4gIHRhYmxlT2JzZXJ2ZXIudGFibGUgPSBhbmNob3JDZWxsVGFibGVFbGVtZW50O1xuICBpZiAoIWZvY3VzQ2FyZXQpIHtcbiAgICBpZiAoYWx0ZXIgPT09ICdleHRlbmQnKSB7XG4gICAgICAvLyBleHRlbmQgdGhlIHNlbGVjdGlvbiBmcm9tIGEgcmFuZ2UgaW5zaWRlIHRoZSBjZWxsIHRvIGEgdGFibGUgc2VsZWN0aW9uIG9mIHRoZSBjZWxsXG4gICAgICB0YWJsZU9ic2VydmVyLiRzZXRBbmNob3JDZWxsRm9yU2VsZWN0aW9uKGFuY2hvckRPTUNlbGwpO1xuICAgICAgdGFibGVPYnNlcnZlci4kc2V0Rm9jdXNDZWxsRm9yU2VsZWN0aW9uKGFuY2hvckRPTUNlbGwsIHRydWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBleGl0IHRoZSB0YWJsZVxuICAgICAgY29uc3Qgb3V0ZXJGb2N1c0NhcmV0ID0gJGdldFRhYmxlRXhpdENhcmV0KCRnZXRTaWJsaW5nQ2FyZXQoYW5jaG9yQ2VsbFRhYmxlLCBpbml0aWFsRm9jdXMuZGlyZWN0aW9uKSk7XG4gICAgICAkc2V0UG9pbnRGcm9tQ2FyZXQoc2VsZWN0aW9uLmFuY2hvciwgb3V0ZXJGb2N1c0NhcmV0KTtcbiAgICAgICRzZXRQb2ludEZyb21DYXJldChzZWxlY3Rpb24uZm9jdXMsIG91dGVyRm9jdXNDYXJldCk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGFsdGVyID09PSAnZXh0ZW5kJykge1xuICAgIGNvbnN0IGZvY3VzRE9NQ2VsbCA9IGdldERPTUNlbGxGcm9tVGFyZ2V0KGVkaXRvci5nZXRFbGVtZW50QnlLZXkoZm9jdXNDYXJldC5vcmlnaW4uZ2V0S2V5KCkpKTtcbiAgICBpZiAoIWZvY3VzRE9NQ2VsbCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICB0YWJsZU9ic2VydmVyLiRzZXRBbmNob3JDZWxsRm9yU2VsZWN0aW9uKGFuY2hvckRPTUNlbGwpO1xuICAgIHRhYmxlT2JzZXJ2ZXIuJHNldEZvY3VzQ2VsbEZvclNlbGVjdGlvbihmb2N1c0RPTUNlbGwsIHRydWUpO1xuICB9IGVsc2Uge1xuICAgIC8vIGFsdGVyID09PSAnbW92ZSdcbiAgICBjb25zdCBpbm5lckZvY3VzQ2FyZXQgPSAkbm9ybWFsaXplQ2FyZXQoZm9jdXNDYXJldCk7XG4gICAgJHNldFBvaW50RnJvbUNhcmV0KHNlbGVjdGlvbi5hbmNob3IsIGlubmVyRm9jdXNDYXJldCk7XG4gICAgJHNldFBvaW50RnJvbUNhcmV0KHNlbGVjdGlvbi5mb2N1cywgaW5uZXJGb2N1c0NhcmV0KTtcbiAgfVxuICBzdG9wRXZlbnQoZXZlbnQpO1xuICByZXR1cm4gdHJ1ZTtcbn1cbmZ1bmN0aW9uICRnZXRUYWJsZUV4aXRDYXJldChpbml0aWFsQ2FyZXQpIHtcbiAgY29uc3QgYWRqYWNlbnQgPSAkZ2V0QWRqYWNlbnRDaGlsZENhcmV0KGluaXRpYWxDYXJldCk7XG4gIHJldHVybiAkaXNDaGlsZENhcmV0KGFkamFjZW50KSA/ICRub3JtYWxpemVDYXJldChhZGphY2VudCkgOiBpbml0aWFsQ2FyZXQ7XG59XG5mdW5jdGlvbiAkZmluZE5leHRUYWJsZUNlbGwoaW5pdGlhbENhcmV0KSB7XG4gIGZvciAoY29uc3QgbmV4dENhcmV0IG9mICRleHRlbmRDYXJldFRvUmFuZ2UoaW5pdGlhbENhcmV0KS5pdGVyTm9kZUNhcmV0cygncm9vdCcpKSB7XG4gICAgY29uc3Qge1xuICAgICAgb3JpZ2luXG4gICAgfSA9IG5leHRDYXJldDtcbiAgICBpZiAoJGlzVGFibGVDZWxsTm9kZShvcmlnaW4pKSB7XG4gICAgICAvLyBub3Qgc3VyZSB3aHkgdHMgaXNuJ3QgbmFycm93aW5nIGhlcmUgKGV2ZW4gaWYgdGhlIGd1YXJkIGlzIG9uIG5leHRDYXJldC5vcmlnaW4pXG4gICAgICAvLyBidXQgcmV0dXJuaW5nIGEgbmV3IGNhcmV0IGlzIGZpbmVcbiAgICAgIGlmICgkaXNDaGlsZENhcmV0KG5leHRDYXJldCkpIHtcbiAgICAgICAgcmV0dXJuICRnZXRDaGlsZENhcmV0KG9yaWdpbiwgaW5pdGlhbENhcmV0LmRpcmVjdGlvbik7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICghJGlzVGFibGVSb3dOb2RlKG9yaWdpbikpIHtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cbmZ1bmN0aW9uICRoYW5kbGVBcnJvd0tleShlZGl0b3IsIGV2ZW50LCBkaXJlY3Rpb24sIHRhYmxlTm9kZSwgdGFibGVPYnNlcnZlcikge1xuICBpZiAoKGRpcmVjdGlvbiA9PT0gJ3VwJyB8fCBkaXJlY3Rpb24gPT09ICdkb3duJykgJiYgaXNUeXBlYWhlYWRNZW51SW5WaWV3KGVkaXRvcikpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3Qgc2VsZWN0aW9uID0gJGdldFNlbGVjdGlvbigpO1xuICBpZiAoISRpc1NlbGVjdGlvbkluVGFibGUoc2VsZWN0aW9uLCB0YWJsZU5vZGUpKSB7XG4gICAgaWYgKCRpc1JhbmdlU2VsZWN0aW9uKHNlbGVjdGlvbikpIHtcbiAgICAgIGlmIChkaXJlY3Rpb24gPT09ICdiYWNrd2FyZCcpIHtcbiAgICAgICAgaWYgKHNlbGVjdGlvbi5mb2N1cy5vZmZzZXQgPiAwKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHBhcmVudE5vZGUgPSAkZ2V0QmxvY2tQYXJlbnRJZkZpcnN0Tm9kZShzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpKTtcbiAgICAgICAgaWYgKCFwYXJlbnROb2RlKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHNpYmxpbmdOb2RlID0gcGFyZW50Tm9kZS5nZXRQcmV2aW91c1NpYmxpbmcoKTtcbiAgICAgICAgaWYgKCEkaXNUYWJsZU5vZGUoc2libGluZ05vZGUpKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHN0b3BFdmVudChldmVudCk7XG4gICAgICAgIGlmIChldmVudC5zaGlmdEtleSkge1xuICAgICAgICAgIHNlbGVjdGlvbi5mb2N1cy5zZXQoc2libGluZ05vZGUuZ2V0UGFyZW50T3JUaHJvdygpLmdldEtleSgpLCBzaWJsaW5nTm9kZS5nZXRJbmRleFdpdGhpblBhcmVudCgpLCAnZWxlbWVudCcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNpYmxpbmdOb2RlLnNlbGVjdEVuZCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5zaGlmdEtleSAmJiAoZGlyZWN0aW9uID09PSAndXAnIHx8IGRpcmVjdGlvbiA9PT0gJ2Rvd24nKSkge1xuICAgICAgICBjb25zdCBmb2N1c05vZGUgPSBzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpO1xuICAgICAgICBjb25zdCBpc1RhYmxlVW5zZWxlY3QgPSAhc2VsZWN0aW9uLmlzQ29sbGFwc2VkKCkgJiYgKGRpcmVjdGlvbiA9PT0gJ3VwJyAmJiAhc2VsZWN0aW9uLmlzQmFja3dhcmQoKSB8fCBkaXJlY3Rpb24gPT09ICdkb3duJyAmJiBzZWxlY3Rpb24uaXNCYWNrd2FyZCgpKTtcbiAgICAgICAgaWYgKGlzVGFibGVVbnNlbGVjdCkge1xuICAgICAgICAgIGxldCBmb2N1c1BhcmVudE5vZGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KGZvY3VzTm9kZSwgbiA9PiAkaXNUYWJsZU5vZGUobikpO1xuICAgICAgICAgIGlmICgkaXNUYWJsZUNlbGxOb2RlKGZvY3VzUGFyZW50Tm9kZSkpIHtcbiAgICAgICAgICAgIGZvY3VzUGFyZW50Tm9kZSA9ICRmaW5kTWF0Y2hpbmdQYXJlbnQoZm9jdXNQYXJlbnROb2RlLCAkaXNUYWJsZU5vZGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZm9jdXNQYXJlbnROb2RlICE9PSB0YWJsZU5vZGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKCFmb2N1c1BhcmVudE5vZGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qgc2libGluZyA9IGRpcmVjdGlvbiA9PT0gJ2Rvd24nID8gZm9jdXNQYXJlbnROb2RlLmdldE5leHRTaWJsaW5nKCkgOiBmb2N1c1BhcmVudE5vZGUuZ2V0UHJldmlvdXNTaWJsaW5nKCk7XG4gICAgICAgICAgaWYgKCFzaWJsaW5nKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIGxldCBuZXdPZmZzZXQgPSAwO1xuICAgICAgICAgIGlmIChkaXJlY3Rpb24gPT09ICd1cCcpIHtcbiAgICAgICAgICAgIGlmICgkaXNFbGVtZW50Tm9kZShzaWJsaW5nKSkge1xuICAgICAgICAgICAgICBuZXdPZmZzZXQgPSBzaWJsaW5nLmdldENoaWxkcmVuU2l6ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBsZXQgbmV3Rm9jdXNOb2RlID0gc2libGluZztcbiAgICAgICAgICBpZiAoZGlyZWN0aW9uID09PSAndXAnKSB7XG4gICAgICAgICAgICBpZiAoJGlzRWxlbWVudE5vZGUoc2libGluZykpIHtcbiAgICAgICAgICAgICAgY29uc3QgbGFzdENlbGwgPSBzaWJsaW5nLmdldExhc3RDaGlsZCgpO1xuICAgICAgICAgICAgICBuZXdGb2N1c05vZGUgPSBsYXN0Q2VsbCA/IGxhc3RDZWxsIDogc2libGluZztcbiAgICAgICAgICAgICAgbmV3T2Zmc2V0ID0gJGlzVGV4dE5vZGUobmV3Rm9jdXNOb2RlKSA/IG5ld0ZvY3VzTm9kZS5nZXRUZXh0Q29udGVudFNpemUoKSA6IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IG5ld1NlbGVjdGlvbiA9IHNlbGVjdGlvbi5jbG9uZSgpO1xuICAgICAgICAgIG5ld1NlbGVjdGlvbi5mb2N1cy5zZXQobmV3Rm9jdXNOb2RlLmdldEtleSgpLCBuZXdPZmZzZXQsICRpc1RleHROb2RlKG5ld0ZvY3VzTm9kZSkgPyAndGV4dCcgOiAnZWxlbWVudCcpO1xuICAgICAgICAgICRzZXRTZWxlY3Rpb24obmV3U2VsZWN0aW9uKTtcbiAgICAgICAgICBzdG9wRXZlbnQoZXZlbnQpO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKCRpc1Jvb3RPclNoYWRvd1Jvb3QoZm9jdXNOb2RlKSkge1xuICAgICAgICAgIGNvbnN0IHNlbGVjdGVkTm9kZSA9IGRpcmVjdGlvbiA9PT0gJ3VwJyA/IHNlbGVjdGlvbi5nZXROb2RlcygpW3NlbGVjdGlvbi5nZXROb2RlcygpLmxlbmd0aCAtIDFdIDogc2VsZWN0aW9uLmdldE5vZGVzKClbMF07XG4gICAgICAgICAgaWYgKHNlbGVjdGVkTm9kZSkge1xuICAgICAgICAgICAgY29uc3QgdGFibGVDZWxsTm9kZSA9ICRmaW5kUGFyZW50VGFibGVDZWxsTm9kZUluVGFibGUodGFibGVOb2RlLCBzZWxlY3RlZE5vZGUpO1xuICAgICAgICAgICAgaWYgKHRhYmxlQ2VsbE5vZGUgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgY29uc3QgZmlyc3REZXNjZW5kYW50ID0gdGFibGVOb2RlLmdldEZpcnN0RGVzY2VuZGFudCgpO1xuICAgICAgICAgICAgICBjb25zdCBsYXN0RGVzY2VuZGFudCA9IHRhYmxlTm9kZS5nZXRMYXN0RGVzY2VuZGFudCgpO1xuICAgICAgICAgICAgICBpZiAoIWZpcnN0RGVzY2VuZGFudCB8fCAhbGFzdERlc2NlbmRhbnQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY29uc3QgW2ZpcnN0Q2VsbE5vZGVdID0gJGdldE5vZGVUcmlwbGV0KGZpcnN0RGVzY2VuZGFudCk7XG4gICAgICAgICAgICAgIGNvbnN0IFtsYXN0Q2VsbE5vZGVdID0gJGdldE5vZGVUcmlwbGV0KGxhc3REZXNjZW5kYW50KTtcbiAgICAgICAgICAgICAgY29uc3QgZmlyc3RDZWxsQ29vcmRzID0gdGFibGVOb2RlLmdldENvcmRzRnJvbUNlbGxOb2RlKGZpcnN0Q2VsbE5vZGUsIHRhYmxlT2JzZXJ2ZXIudGFibGUpO1xuICAgICAgICAgICAgICBjb25zdCBsYXN0Q2VsbENvb3JkcyA9IHRhYmxlTm9kZS5nZXRDb3Jkc0Zyb21DZWxsTm9kZShsYXN0Q2VsbE5vZGUsIHRhYmxlT2JzZXJ2ZXIudGFibGUpO1xuICAgICAgICAgICAgICBjb25zdCBmaXJzdENlbGxET00gPSB0YWJsZU5vZGUuZ2V0RE9NQ2VsbEZyb21Db3Jkc09yVGhyb3coZmlyc3RDZWxsQ29vcmRzLngsIGZpcnN0Q2VsbENvb3Jkcy55LCB0YWJsZU9ic2VydmVyLnRhYmxlKTtcbiAgICAgICAgICAgICAgY29uc3QgbGFzdENlbGxET00gPSB0YWJsZU5vZGUuZ2V0RE9NQ2VsbEZyb21Db3Jkc09yVGhyb3cobGFzdENlbGxDb29yZHMueCwgbGFzdENlbGxDb29yZHMueSwgdGFibGVPYnNlcnZlci50YWJsZSk7XG4gICAgICAgICAgICAgIHRhYmxlT2JzZXJ2ZXIuJHNldEFuY2hvckNlbGxGb3JTZWxlY3Rpb24oZmlyc3RDZWxsRE9NKTtcbiAgICAgICAgICAgICAgdGFibGVPYnNlcnZlci4kc2V0Rm9jdXNDZWxsRm9yU2VsZWN0aW9uKGxhc3RDZWxsRE9NLCB0cnVlKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsZXQgZm9jdXNQYXJlbnROb2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChmb2N1c05vZGUsIG4gPT4gJGlzRWxlbWVudE5vZGUobikgJiYgIW4uaXNJbmxpbmUoKSk7XG4gICAgICAgICAgaWYgKCRpc1RhYmxlQ2VsbE5vZGUoZm9jdXNQYXJlbnROb2RlKSkge1xuICAgICAgICAgICAgZm9jdXNQYXJlbnROb2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChmb2N1c1BhcmVudE5vZGUsICRpc1RhYmxlTm9kZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICghZm9jdXNQYXJlbnROb2RlKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IHNpYmxpbmcgPSBkaXJlY3Rpb24gPT09ICdkb3duJyA/IGZvY3VzUGFyZW50Tm9kZS5nZXROZXh0U2libGluZygpIDogZm9jdXNQYXJlbnROb2RlLmdldFByZXZpb3VzU2libGluZygpO1xuICAgICAgICAgIGlmICgkaXNUYWJsZU5vZGUoc2libGluZykgJiYgdGFibGVPYnNlcnZlci50YWJsZU5vZGVLZXkgPT09IHNpYmxpbmcuZ2V0S2V5KCkpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpcnN0RGVzY2VuZGFudCA9IHNpYmxpbmcuZ2V0Rmlyc3REZXNjZW5kYW50KCk7XG4gICAgICAgICAgICBjb25zdCBsYXN0RGVzY2VuZGFudCA9IHNpYmxpbmcuZ2V0TGFzdERlc2NlbmRhbnQoKTtcbiAgICAgICAgICAgIGlmICghZmlyc3REZXNjZW5kYW50IHx8ICFsYXN0RGVzY2VuZGFudCkge1xuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBbZmlyc3RDZWxsTm9kZV0gPSAkZ2V0Tm9kZVRyaXBsZXQoZmlyc3REZXNjZW5kYW50KTtcbiAgICAgICAgICAgIGNvbnN0IFtsYXN0Q2VsbE5vZGVdID0gJGdldE5vZGVUcmlwbGV0KGxhc3REZXNjZW5kYW50KTtcbiAgICAgICAgICAgIGNvbnN0IG5ld1NlbGVjdGlvbiA9IHNlbGVjdGlvbi5jbG9uZSgpO1xuICAgICAgICAgICAgbmV3U2VsZWN0aW9uLmZvY3VzLnNldCgoZGlyZWN0aW9uID09PSAndXAnID8gZmlyc3RDZWxsTm9kZSA6IGxhc3RDZWxsTm9kZSkuZ2V0S2V5KCksIGRpcmVjdGlvbiA9PT0gJ3VwJyA/IDAgOiBsYXN0Q2VsbE5vZGUuZ2V0Q2hpbGRyZW5TaXplKCksICdlbGVtZW50Jyk7XG4gICAgICAgICAgICBzdG9wRXZlbnQoZXZlbnQpO1xuICAgICAgICAgICAgJHNldFNlbGVjdGlvbihuZXdTZWxlY3Rpb24pO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChkaXJlY3Rpb24gPT09ICdkb3duJyAmJiAkaXNTY3JvbGxhYmxlVGFibGVzQWN0aXZlKGVkaXRvcikpIHtcbiAgICAgIC8vIEVuYWJsZSBGaXJlZm94IHdvcmthcm91bmRcbiAgICAgIHRhYmxlT2JzZXJ2ZXIuc2V0U2hvdWxkQ2hlY2tTZWxlY3Rpb24oKTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGlmICgkaXNSYW5nZVNlbGVjdGlvbihzZWxlY3Rpb24pKSB7XG4gICAgaWYgKGRpcmVjdGlvbiA9PT0gJ2JhY2t3YXJkJyB8fCBkaXJlY3Rpb24gPT09ICdmb3J3YXJkJykge1xuICAgICAgY29uc3QgYWx0ZXIgPSBldmVudC5zaGlmdEtleSA/ICdleHRlbmQnIDogJ21vdmUnO1xuICAgICAgcmV0dXJuICRoYW5kbGVIb3Jpem9udGFsQXJyb3dLZXlSYW5nZVNlbGVjdGlvbihlZGl0b3IsIGV2ZW50LCBzZWxlY3Rpb24sIGFsdGVyLCBkaXJlY3Rpb24gPT09ICdiYWNrd2FyZCcsIHRhYmxlTm9kZSwgdGFibGVPYnNlcnZlcik7XG4gICAgfVxuICAgIGlmIChzZWxlY3Rpb24uaXNDb2xsYXBzZWQoKSkge1xuICAgICAgY29uc3Qge1xuICAgICAgICBhbmNob3IsXG4gICAgICAgIGZvY3VzXG4gICAgICB9ID0gc2VsZWN0aW9uO1xuICAgICAgY29uc3QgYW5jaG9yQ2VsbE5vZGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KGFuY2hvci5nZXROb2RlKCksICRpc1RhYmxlQ2VsbE5vZGUpO1xuICAgICAgY29uc3QgZm9jdXNDZWxsTm9kZSA9ICRmaW5kTWF0Y2hpbmdQYXJlbnQoZm9jdXMuZ2V0Tm9kZSgpLCAkaXNUYWJsZUNlbGxOb2RlKTtcbiAgICAgIGlmICghJGlzVGFibGVDZWxsTm9kZShhbmNob3JDZWxsTm9kZSkgfHwgIWFuY2hvckNlbGxOb2RlLmlzKGZvY3VzQ2VsbE5vZGUpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGFuY2hvckNlbGxUYWJsZSA9ICRmaW5kVGFibGVOb2RlKGFuY2hvckNlbGxOb2RlKTtcbiAgICAgIGlmIChhbmNob3JDZWxsVGFibGUgIT09IHRhYmxlTm9kZSAmJiBhbmNob3JDZWxsVGFibGUgIT0gbnVsbCkge1xuICAgICAgICBjb25zdCBhbmNob3JDZWxsVGFibGVFbGVtZW50ID0gZ2V0VGFibGVFbGVtZW50KGFuY2hvckNlbGxUYWJsZSwgZWRpdG9yLmdldEVsZW1lbnRCeUtleShhbmNob3JDZWxsVGFibGUuZ2V0S2V5KCkpKTtcbiAgICAgICAgaWYgKGFuY2hvckNlbGxUYWJsZUVsZW1lbnQgIT0gbnVsbCkge1xuICAgICAgICAgIHRhYmxlT2JzZXJ2ZXIudGFibGUgPSBnZXRUYWJsZShhbmNob3JDZWxsVGFibGUsIGFuY2hvckNlbGxUYWJsZUVsZW1lbnQpO1xuICAgICAgICAgIHJldHVybiAkaGFuZGxlQXJyb3dLZXkoZWRpdG9yLCBldmVudCwgZGlyZWN0aW9uLCBhbmNob3JDZWxsVGFibGUsIHRhYmxlT2JzZXJ2ZXIpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjb25zdCBhbmNob3JDZWxsRG9tID0gZWRpdG9yLmdldEVsZW1lbnRCeUtleShhbmNob3JDZWxsTm9kZS5fX2tleSk7XG4gICAgICBjb25zdCBhbmNob3JET00gPSBlZGl0b3IuZ2V0RWxlbWVudEJ5S2V5KGFuY2hvci5rZXkpO1xuICAgICAgaWYgKGFuY2hvckRPTSA9PSBudWxsIHx8IGFuY2hvckNlbGxEb20gPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBsZXQgZWRnZVNlbGVjdGlvblJlY3Q7XG4gICAgICBpZiAoYW5jaG9yLnR5cGUgPT09ICdlbGVtZW50Jykge1xuICAgICAgICBlZGdlU2VsZWN0aW9uUmVjdCA9IGFuY2hvckRPTS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGRvbVNlbGVjdGlvbiA9IGdldERPTVNlbGVjdGlvbihnZXRFZGl0b3JXaW5kb3coZWRpdG9yKSk7XG4gICAgICAgIGlmIChkb21TZWxlY3Rpb24gPT09IG51bGwgfHwgZG9tU2VsZWN0aW9uLnJhbmdlQ291bnQgPT09IDApIHtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcmFuZ2UgPSBkb21TZWxlY3Rpb24uZ2V0UmFuZ2VBdCgwKTtcbiAgICAgICAgZWRnZVNlbGVjdGlvblJlY3QgPSByYW5nZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGVkZ2VDaGlsZCA9IGRpcmVjdGlvbiA9PT0gJ3VwJyA/IGFuY2hvckNlbGxOb2RlLmdldEZpcnN0Q2hpbGQoKSA6IGFuY2hvckNlbGxOb2RlLmdldExhc3RDaGlsZCgpO1xuICAgICAgaWYgKGVkZ2VDaGlsZCA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGVkZ2VDaGlsZERPTSA9IGVkaXRvci5nZXRFbGVtZW50QnlLZXkoZWRnZUNoaWxkLl9fa2V5KTtcbiAgICAgIGlmIChlZGdlQ2hpbGRET00gPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBjb25zdCBlZGdlUmVjdCA9IGVkZ2VDaGlsZERPTS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGNvbnN0IGlzRXhpdGluZyA9IGRpcmVjdGlvbiA9PT0gJ3VwJyA/IGVkZ2VSZWN0LnRvcCA+IGVkZ2VTZWxlY3Rpb25SZWN0LnRvcCAtIGVkZ2VTZWxlY3Rpb25SZWN0LmhlaWdodCA6IGVkZ2VTZWxlY3Rpb25SZWN0LmJvdHRvbSArIGVkZ2VTZWxlY3Rpb25SZWN0LmhlaWdodCA+IGVkZ2VSZWN0LmJvdHRvbTtcbiAgICAgIGlmIChpc0V4aXRpbmcpIHtcbiAgICAgICAgc3RvcEV2ZW50KGV2ZW50KTtcbiAgICAgICAgY29uc3QgY29yZHMgPSB0YWJsZU5vZGUuZ2V0Q29yZHNGcm9tQ2VsbE5vZGUoYW5jaG9yQ2VsbE5vZGUsIHRhYmxlT2JzZXJ2ZXIudGFibGUpO1xuICAgICAgICBpZiAoZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgICAgICBjb25zdCBjZWxsID0gdGFibGVOb2RlLmdldERPTUNlbGxGcm9tQ29yZHNPclRocm93KGNvcmRzLngsIGNvcmRzLnksIHRhYmxlT2JzZXJ2ZXIudGFibGUpO1xuICAgICAgICAgIHRhYmxlT2JzZXJ2ZXIuJHNldEFuY2hvckNlbGxGb3JTZWxlY3Rpb24oY2VsbCk7XG4gICAgICAgICAgdGFibGVPYnNlcnZlci4kc2V0Rm9jdXNDZWxsRm9yU2VsZWN0aW9uKGNlbGwsIHRydWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBzZWxlY3RUYWJsZU5vZGVJbkRpcmVjdGlvbih0YWJsZU9ic2VydmVyLCB0YWJsZU5vZGUsIGNvcmRzLngsIGNvcmRzLnksIGRpcmVjdGlvbik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9IGVsc2UgaWYgKCRpc1RhYmxlU2VsZWN0aW9uKHNlbGVjdGlvbikpIHtcbiAgICBjb25zdCB7XG4gICAgICBhbmNob3IsXG4gICAgICBmb2N1c1xuICAgIH0gPSBzZWxlY3Rpb247XG4gICAgY29uc3QgYW5jaG9yQ2VsbE5vZGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KGFuY2hvci5nZXROb2RlKCksICRpc1RhYmxlQ2VsbE5vZGUpO1xuICAgIGNvbnN0IGZvY3VzQ2VsbE5vZGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KGZvY3VzLmdldE5vZGUoKSwgJGlzVGFibGVDZWxsTm9kZSk7XG4gICAgY29uc3QgW3RhYmxlTm9kZUZyb21TZWxlY3Rpb25dID0gc2VsZWN0aW9uLmdldE5vZGVzKCk7XG4gICAgaWYgKCEkaXNUYWJsZU5vZGUodGFibGVOb2RlRnJvbVNlbGVjdGlvbikpIHtcbiAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgJGhhbmRsZUFycm93S2V5OiBUYWJsZVNlbGVjdGlvbi5nZXROb2RlcygpWzBdIGV4cGVjdGVkIHRvIGJlIFRhYmxlTm9kZWApO1xuICAgIH1cbiAgICBjb25zdCB0YWJsZUVsZW1lbnQgPSBnZXRUYWJsZUVsZW1lbnQodGFibGVOb2RlRnJvbVNlbGVjdGlvbiwgZWRpdG9yLmdldEVsZW1lbnRCeUtleSh0YWJsZU5vZGVGcm9tU2VsZWN0aW9uLmdldEtleSgpKSk7XG4gICAgaWYgKCEkaXNUYWJsZUNlbGxOb2RlKGFuY2hvckNlbGxOb2RlKSB8fCAhJGlzVGFibGVDZWxsTm9kZShmb2N1c0NlbGxOb2RlKSB8fCAhJGlzVGFibGVOb2RlKHRhYmxlTm9kZUZyb21TZWxlY3Rpb24pIHx8IHRhYmxlRWxlbWVudCA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHRhYmxlT2JzZXJ2ZXIuJHVwZGF0ZVRhYmxlVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKTtcbiAgICBjb25zdCBncmlkID0gZ2V0VGFibGUodGFibGVOb2RlRnJvbVNlbGVjdGlvbiwgdGFibGVFbGVtZW50KTtcbiAgICBjb25zdCBjb3Jkc0FuY2hvciA9IHRhYmxlTm9kZS5nZXRDb3Jkc0Zyb21DZWxsTm9kZShhbmNob3JDZWxsTm9kZSwgZ3JpZCk7XG4gICAgY29uc3QgYW5jaG9yQ2VsbCA9IHRhYmxlTm9kZS5nZXRET01DZWxsRnJvbUNvcmRzT3JUaHJvdyhjb3Jkc0FuY2hvci54LCBjb3Jkc0FuY2hvci55LCBncmlkKTtcbiAgICB0YWJsZU9ic2VydmVyLiRzZXRBbmNob3JDZWxsRm9yU2VsZWN0aW9uKGFuY2hvckNlbGwpO1xuICAgIHN0b3BFdmVudChldmVudCk7XG4gICAgaWYgKGV2ZW50LnNoaWZ0S2V5KSB7XG4gICAgICBjb25zdCBbdGFibGVNYXAsIGFuY2hvclZhbHVlLCBmb2N1c1ZhbHVlXSA9ICRjb21wdXRlVGFibGVNYXAodGFibGVOb2RlLCBhbmNob3JDZWxsTm9kZSwgZm9jdXNDZWxsTm9kZSk7XG4gICAgICByZXR1cm4gJGFkanVzdEZvY3VzSW5EaXJlY3Rpb24odGFibGVPYnNlcnZlciwgdGFibGVNYXAsIGFuY2hvclZhbHVlLCBmb2N1c1ZhbHVlLCBkaXJlY3Rpb24pO1xuICAgIH0gZWxzZSB7XG4gICAgICBmb2N1c0NlbGxOb2RlLnNlbGVjdEVuZCgpO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5mdW5jdGlvbiBzdG9wRXZlbnQoZXZlbnQpIHtcbiAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgZXZlbnQuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG4gIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xufVxuZnVuY3Rpb24gaXNUeXBlYWhlYWRNZW51SW5WaWV3KGVkaXRvcikge1xuICAvLyBUaGVyZSBpcyBubyBpbmJ1aWx0IHdheSB0byBjaGVjayBpZiB0aGUgY29tcG9uZW50IHBpY2tlciBpcyBpbiB2aWV3XG4gIC8vIGJ1dCB3ZSBjYW4gY2hlY2sgaWYgdGhlIHJvb3QgRE9NIGVsZW1lbnQgaGFzIHRoZSBhcmlhLWNvbnRyb2xzIGF0dHJpYnV0ZSBcInR5cGVhaGVhZC1tZW51XCIuXG4gIGNvbnN0IHJvb3QgPSBlZGl0b3IuZ2V0Um9vdEVsZW1lbnQoKTtcbiAgaWYgKCFyb290KSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiByb290Lmhhc0F0dHJpYnV0ZSgnYXJpYS1jb250cm9scycpICYmIHJvb3QuZ2V0QXR0cmlidXRlKCdhcmlhLWNvbnRyb2xzJykgPT09ICd0eXBlYWhlYWQtbWVudSc7XG59XG5mdW5jdGlvbiAkaW5zZXJ0UGFyYWdyYXBoQXRUYWJsZUVkZ2UoZWRnZVBvc2l0aW9uLCB0YWJsZU5vZGUsIGNoaWxkcmVuKSB7XG4gIGNvbnN0IHBhcmFncmFwaE5vZGUgPSAkY3JlYXRlUGFyYWdyYXBoTm9kZSgpO1xuICBpZiAoZWRnZVBvc2l0aW9uID09PSAnZmlyc3QnKSB7XG4gICAgdGFibGVOb2RlLmluc2VydEJlZm9yZShwYXJhZ3JhcGhOb2RlKTtcbiAgfSBlbHNlIHtcbiAgICB0YWJsZU5vZGUuaW5zZXJ0QWZ0ZXIocGFyYWdyYXBoTm9kZSk7XG4gIH1cbiAgcGFyYWdyYXBoTm9kZS5hcHBlbmQoLi4uKGNoaWxkcmVuIHx8IFtdKSk7XG4gIHBhcmFncmFwaE5vZGUuc2VsZWN0RW5kKCk7XG59XG5mdW5jdGlvbiAkZ2V0VGFibGVFZGdlQ3Vyc29yUG9zaXRpb24oZWRpdG9yLCBzZWxlY3Rpb24sIHRhYmxlTm9kZSkge1xuICBjb25zdCB0YWJsZU5vZGVQYXJlbnQgPSB0YWJsZU5vZGUuZ2V0UGFyZW50KCk7XG4gIGlmICghdGFibGVOb2RlUGFyZW50KSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIFRPRE86IEFkZCBzdXBwb3J0IGZvciBuZXN0ZWQgdGFibGVzXG4gIGNvbnN0IGRvbVNlbGVjdGlvbiA9IGdldERPTVNlbGVjdGlvbihnZXRFZGl0b3JXaW5kb3coZWRpdG9yKSk7XG4gIGlmICghZG9tU2VsZWN0aW9uKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICBjb25zdCBkb21BbmNob3JOb2RlID0gZG9tU2VsZWN0aW9uLmFuY2hvck5vZGU7XG4gIGNvbnN0IHRhYmxlTm9kZVBhcmVudERPTSA9IGVkaXRvci5nZXRFbGVtZW50QnlLZXkodGFibGVOb2RlUGFyZW50LmdldEtleSgpKTtcbiAgY29uc3QgdGFibGVFbGVtZW50ID0gZ2V0VGFibGVFbGVtZW50KHRhYmxlTm9kZSwgZWRpdG9yLmdldEVsZW1lbnRCeUtleSh0YWJsZU5vZGUuZ2V0S2V5KCkpKTtcbiAgLy8gV2UgYXJlIG9ubHkgaW50ZXJlc3RlZCBpbiB0aGUgc2NlbmFyaW8gd2hlcmUgdGhlXG4gIC8vIG5hdGl2ZSBzZWxlY3Rpb24gYW5jaG9yIGlzOlxuICAvLyAtIGF0IG9yIGluc2lkZSB0aGUgdGFibGUncyBwYXJlbnQgRE9NXG4gIC8vIC0gYW5kIE5PVCBhdCBvciBpbnNpZGUgdGhlIHRhYmxlIERPTVxuICAvLyBJdCBtYXkgYmUgYWRqYWNlbnQgdG8gdGhlIHRhYmxlIERPTSAoZS5nLiBpbiBhIHdyYXBwZXIpXG4gIGlmICghZG9tQW5jaG9yTm9kZSB8fCAhdGFibGVOb2RlUGFyZW50RE9NIHx8ICF0YWJsZUVsZW1lbnQgfHwgIXRhYmxlTm9kZVBhcmVudERPTS5jb250YWlucyhkb21BbmNob3JOb2RlKSB8fCB0YWJsZUVsZW1lbnQuY29udGFpbnMoZG9tQW5jaG9yTm9kZSkpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGNvbnN0IGFuY2hvckNlbGxOb2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKSwgbiA9PiAkaXNUYWJsZUNlbGxOb2RlKG4pKTtcbiAgaWYgKCFhbmNob3JDZWxsTm9kZSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgcGFyZW50VGFibGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KGFuY2hvckNlbGxOb2RlLCBuID0+ICRpc1RhYmxlTm9kZShuKSk7XG4gIGlmICghJGlzVGFibGVOb2RlKHBhcmVudFRhYmxlKSB8fCAhcGFyZW50VGFibGUuaXModGFibGVOb2RlKSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgW3RhYmxlTWFwLCBjZWxsVmFsdWVdID0gJGNvbXB1dGVUYWJsZU1hcCh0YWJsZU5vZGUsIGFuY2hvckNlbGxOb2RlLCBhbmNob3JDZWxsTm9kZSk7XG4gIGNvbnN0IGZpcnN0Q2VsbCA9IHRhYmxlTWFwWzBdWzBdO1xuICBjb25zdCBsYXN0Q2VsbCA9IHRhYmxlTWFwW3RhYmxlTWFwLmxlbmd0aCAtIDFdW3RhYmxlTWFwWzBdLmxlbmd0aCAtIDFdO1xuICBjb25zdCB7XG4gICAgc3RhcnRSb3csXG4gICAgc3RhcnRDb2x1bW5cbiAgfSA9IGNlbGxWYWx1ZTtcbiAgY29uc3QgaXNBdEZpcnN0Q2VsbCA9IHN0YXJ0Um93ID09PSBmaXJzdENlbGwuc3RhcnRSb3cgJiYgc3RhcnRDb2x1bW4gPT09IGZpcnN0Q2VsbC5zdGFydENvbHVtbjtcbiAgY29uc3QgaXNBdExhc3RDZWxsID0gc3RhcnRSb3cgPT09IGxhc3RDZWxsLnN0YXJ0Um93ICYmIHN0YXJ0Q29sdW1uID09PSBsYXN0Q2VsbC5zdGFydENvbHVtbjtcbiAgaWYgKGlzQXRGaXJzdENlbGwpIHtcbiAgICByZXR1cm4gJ2ZpcnN0JztcbiAgfSBlbHNlIGlmIChpc0F0TGFzdENlbGwpIHtcbiAgICByZXR1cm4gJ2xhc3QnO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbmZ1bmN0aW9uICRnZXRPYnNlcnZlckNlbGxGcm9tQ2VsbE5vZGVPclRocm93KHRhYmxlT2JzZXJ2ZXIsIHRhYmxlQ2VsbE5vZGUpIHtcbiAgY29uc3Qge1xuICAgIHRhYmxlTm9kZVxuICB9ID0gdGFibGVPYnNlcnZlci4kbG9va3VwKCk7XG4gIGNvbnN0IGN1cnJlbnRDb3JkcyA9IHRhYmxlTm9kZS5nZXRDb3Jkc0Zyb21DZWxsTm9kZSh0YWJsZUNlbGxOb2RlLCB0YWJsZU9ic2VydmVyLnRhYmxlKTtcbiAgcmV0dXJuIHRhYmxlTm9kZS5nZXRET01DZWxsRnJvbUNvcmRzT3JUaHJvdyhjdXJyZW50Q29yZHMueCwgY3VycmVudENvcmRzLnksIHRhYmxlT2JzZXJ2ZXIudGFibGUpO1xufVxuZnVuY3Rpb24gJGdldE5lYXJlc3RUYWJsZUNlbGxJblRhYmxlRnJvbURPTU5vZGUodGFibGVOb2RlLCBzdGFydGluZ0RPTSwgZWRpdG9yU3RhdGUpIHtcbiAgcmV0dXJuICRmaW5kUGFyZW50VGFibGVDZWxsTm9kZUluVGFibGUodGFibGVOb2RlLCAkZ2V0TmVhcmVzdE5vZGVGcm9tRE9NTm9kZShzdGFydGluZ0RPTSwgZWRpdG9yU3RhdGUpKTtcbn1cblxuZnVuY3Rpb24gaXNIVE1MRGl2RWxlbWVudChlbGVtZW50KSB7XG4gIHJldHVybiBpc0hUTUxFbGVtZW50JDEoZWxlbWVudCkgJiYgZWxlbWVudC5ub2RlTmFtZSA9PT0gJ0RJVic7XG59XG5mdW5jdGlvbiB1cGRhdGVDb2xncm91cChkb20sIGNvbmZpZywgY29sQ291bnQsIGNvbFdpZHRocykge1xuICBjb25zdCBjb2xHcm91cCA9IGRvbS5xdWVyeVNlbGVjdG9yKCdjb2xncm91cCcpO1xuICBpZiAoIWNvbEdyb3VwKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IGNvbHMgPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2xDb3VudDsgaSsrKSB7XG4gICAgY29uc3QgY29sID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY29sJyk7XG4gICAgY29uc3Qgd2lkdGggPSBjb2xXaWR0aHMgJiYgY29sV2lkdGhzW2ldO1xuICAgIGlmICh3aWR0aCkge1xuICAgICAgY29sLnN0eWxlLndpZHRoID0gYCR7d2lkdGh9cHhgO1xuICAgIH1cbiAgICBjb2xzLnB1c2goY29sKTtcbiAgfVxuICBjb2xHcm91cC5yZXBsYWNlQ2hpbGRyZW4oLi4uY29scyk7XG59XG5mdW5jdGlvbiBzZXRSb3dTdHJpcGluZyhkb20sIGNvbmZpZywgcm93U3RyaXBpbmcpIHtcbiAgaWYgKHJvd1N0cmlwaW5nKSB7XG4gICAgYWRkQ2xhc3NOYW1lc1RvRWxlbWVudChkb20sIGNvbmZpZy50aGVtZS50YWJsZVJvd1N0cmlwaW5nKTtcbiAgICBkb20uc2V0QXR0cmlidXRlKCdkYXRhLWxleGljYWwtcm93LXN0cmlwaW5nJywgJ3RydWUnKTtcbiAgfSBlbHNlIHtcbiAgICByZW1vdmVDbGFzc05hbWVzRnJvbUVsZW1lbnQoZG9tLCBjb25maWcudGhlbWUudGFibGVSb3dTdHJpcGluZyk7XG4gICAgZG9tLnJlbW92ZUF0dHJpYnV0ZSgnZGF0YS1sZXhpY2FsLXJvdy1zdHJpcGluZycpO1xuICB9XG59XG5mdW5jdGlvbiBzZXRGcm96ZW5Db2x1bW5zKGRvbSwgdGFibGVFbGVtZW50LCBjb25maWcsIGZyb3plbkNvbHVtbkNvdW50KSB7XG4gIGlmIChmcm96ZW5Db2x1bW5Db3VudCA+IDApIHtcbiAgICBhZGRDbGFzc05hbWVzVG9FbGVtZW50KGRvbSwgY29uZmlnLnRoZW1lLnRhYmxlRnJvemVuQ29sdW1uKTtcbiAgICB0YWJsZUVsZW1lbnQuc2V0QXR0cmlidXRlKCdkYXRhLWxleGljYWwtZnJvemVuLWNvbHVtbicsICd0cnVlJyk7XG4gIH0gZWxzZSB7XG4gICAgcmVtb3ZlQ2xhc3NOYW1lc0Zyb21FbGVtZW50KGRvbSwgY29uZmlnLnRoZW1lLnRhYmxlRnJvemVuQ29sdW1uKTtcbiAgICB0YWJsZUVsZW1lbnQucmVtb3ZlQXR0cmlidXRlKCdkYXRhLWxleGljYWwtZnJvemVuLWNvbHVtbicpO1xuICB9XG59XG5mdW5jdGlvbiBzZXRGcm96ZW5Sb3dzKGRvbSwgdGFibGVFbGVtZW50LCBjb25maWcsIGZyb3plblJvd0NvdW50KSB7XG4gIGlmIChmcm96ZW5Sb3dDb3VudCA+IDApIHtcbiAgICBhZGRDbGFzc05hbWVzVG9FbGVtZW50KGRvbSwgY29uZmlnLnRoZW1lLnRhYmxlRnJvemVuUm93KTtcbiAgICB0YWJsZUVsZW1lbnQuc2V0QXR0cmlidXRlKCdkYXRhLWxleGljYWwtZnJvemVuLXJvdycsICd0cnVlJyk7XG4gIH0gZWxzZSB7XG4gICAgcmVtb3ZlQ2xhc3NOYW1lc0Zyb21FbGVtZW50KGRvbSwgY29uZmlnLnRoZW1lLnRhYmxlRnJvemVuUm93KTtcbiAgICB0YWJsZUVsZW1lbnQucmVtb3ZlQXR0cmlidXRlKCdkYXRhLWxleGljYWwtZnJvemVuLXJvdycpO1xuICB9XG59XG5mdW5jdGlvbiBhbGlnblRhYmxlRWxlbWVudChkb20sIGNvbmZpZywgZm9ybWF0VHlwZSkge1xuICBpZiAoIWNvbmZpZy50aGVtZS50YWJsZUFsaWdubWVudCkge1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCByZW1vdmVDbGFzc2VzID0gW107XG4gIGNvbnN0IGFkZENsYXNzZXMgPSBbXTtcbiAgZm9yIChjb25zdCBmb3JtYXQgb2YgWydjZW50ZXInLCAncmlnaHQnXSkge1xuICAgIGNvbnN0IGNsYXNzZXMgPSBjb25maWcudGhlbWUudGFibGVBbGlnbm1lbnRbZm9ybWF0XTtcbiAgICBpZiAoIWNsYXNzZXMpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICAoZm9ybWF0ID09PSBmb3JtYXRUeXBlID8gYWRkQ2xhc3NlcyA6IHJlbW92ZUNsYXNzZXMpLnB1c2goY2xhc3Nlcyk7XG4gIH1cbiAgcmVtb3ZlQ2xhc3NOYW1lc0Zyb21FbGVtZW50KGRvbSwgLi4ucmVtb3ZlQ2xhc3Nlcyk7XG4gIGFkZENsYXNzTmFtZXNUb0VsZW1lbnQoZG9tLCAuLi5hZGRDbGFzc2VzKTtcbn1cbmNvbnN0IHNjcm9sbGFibGVFZGl0b3JzID0gbmV3IFdlYWtTZXQoKTtcbmZ1bmN0aW9uICRpc1Njcm9sbGFibGVUYWJsZXNBY3RpdmUoZWRpdG9yID0gJGdldEVkaXRvcigpKSB7XG4gIHJldHVybiBzY3JvbGxhYmxlRWRpdG9ycy5oYXMoZWRpdG9yKTtcbn1cbmZ1bmN0aW9uIHNldFNjcm9sbGFibGVUYWJsZXNBY3RpdmUoZWRpdG9yLCBhY3RpdmUpIHtcbiAgaWYgKGFjdGl2ZSkge1xuICAgIGlmICghZWRpdG9yLl9jb25maWcudGhlbWUudGFibGVTY3JvbGxhYmxlV3JhcHBlcikge1xuICAgICAgY29uc29sZS53YXJuKCdUYWJsZU5vZGU6IGhhc0hvcml6b250YWxTY3JvbGwgaXMgYWN0aXZlIGJ1dCB0aGVtZS50YWJsZVNjcm9sbGFibGVXcmFwcGVyIGlzIG5vdCBkZWZpbmVkLicpO1xuICAgIH1cbiAgICBzY3JvbGxhYmxlRWRpdG9ycy5hZGQoZWRpdG9yKTtcbiAgfSBlbHNlIHtcbiAgICBzY3JvbGxhYmxlRWRpdG9ycy5kZWxldGUoZWRpdG9yKTtcbiAgfVxufVxuXG4vKiogQG5vSW5oZXJpdERvYyAqL1xuY2xhc3MgVGFibGVOb2RlIGV4dGVuZHMgRWxlbWVudE5vZGUge1xuICAvKiogQGludGVybmFsICovXG4gIF9fcm93U3RyaXBpbmc7XG4gIF9fZnJvemVuQ29sdW1uQ291bnQ7XG4gIF9fZnJvemVuUm93Q291bnQ7XG4gIF9fY29sV2lkdGhzO1xuICBzdGF0aWMgZ2V0VHlwZSgpIHtcbiAgICByZXR1cm4gJ3RhYmxlJztcbiAgfVxuICBnZXRDb2xXaWR0aHMoKSB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXMuZ2V0TGF0ZXN0KCk7XG4gICAgcmV0dXJuIHNlbGYuX19jb2xXaWR0aHM7XG4gIH1cbiAgc2V0Q29sV2lkdGhzKGNvbFdpZHRocykge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzLmdldFdyaXRhYmxlKCk7XG4gICAgLy8gTk9URTogTm9kZSBwcm9wZXJ0aWVzIHNob3VsZCBiZSBpbW11dGFibGUuIEZyZWV6ZSB0byBwcmV2ZW50IGFjY2lkZW50YWwgbXV0YXRpb24uXG4gICAgc2VsZi5fX2NvbFdpZHRocyA9IGNvbFdpZHRocyAhPT0gdW5kZWZpbmVkICYmIHRydWUgPyBPYmplY3QuZnJlZXplKGNvbFdpZHRocykgOiBjb2xXaWR0aHM7XG4gICAgcmV0dXJuIHNlbGY7XG4gIH1cbiAgc3RhdGljIGNsb25lKG5vZGUpIHtcbiAgICByZXR1cm4gbmV3IFRhYmxlTm9kZShub2RlLl9fa2V5KTtcbiAgfVxuICBhZnRlckNsb25lRnJvbShwcmV2Tm9kZSkge1xuICAgIHN1cGVyLmFmdGVyQ2xvbmVGcm9tKHByZXZOb2RlKTtcbiAgICB0aGlzLl9fY29sV2lkdGhzID0gcHJldk5vZGUuX19jb2xXaWR0aHM7XG4gICAgdGhpcy5fX3Jvd1N0cmlwaW5nID0gcHJldk5vZGUuX19yb3dTdHJpcGluZztcbiAgICB0aGlzLl9fZnJvemVuQ29sdW1uQ291bnQgPSBwcmV2Tm9kZS5fX2Zyb3plbkNvbHVtbkNvdW50O1xuICAgIHRoaXMuX19mcm96ZW5Sb3dDb3VudCA9IHByZXZOb2RlLl9fZnJvemVuUm93Q291bnQ7XG4gIH1cbiAgc3RhdGljIGltcG9ydERPTSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdGFibGU6IF9ub2RlID0+ICh7XG4gICAgICAgIGNvbnZlcnNpb246ICRjb252ZXJ0VGFibGVFbGVtZW50LFxuICAgICAgICBwcmlvcml0eTogMVxuICAgICAgfSlcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBpbXBvcnRKU09OKHNlcmlhbGl6ZWROb2RlKSB7XG4gICAgcmV0dXJuICRjcmVhdGVUYWJsZU5vZGUoKS51cGRhdGVGcm9tSlNPTihzZXJpYWxpemVkTm9kZSk7XG4gIH1cbiAgdXBkYXRlRnJvbUpTT04oc2VyaWFsaXplZE5vZGUpIHtcbiAgICByZXR1cm4gc3VwZXIudXBkYXRlRnJvbUpTT04oc2VyaWFsaXplZE5vZGUpLnNldFJvd1N0cmlwaW5nKHNlcmlhbGl6ZWROb2RlLnJvd1N0cmlwaW5nIHx8IGZhbHNlKS5zZXRGcm96ZW5Db2x1bW5zKHNlcmlhbGl6ZWROb2RlLmZyb3plbkNvbHVtbkNvdW50IHx8IDApLnNldEZyb3plblJvd3Moc2VyaWFsaXplZE5vZGUuZnJvemVuUm93Q291bnQgfHwgMCkuc2V0Q29sV2lkdGhzKHNlcmlhbGl6ZWROb2RlLmNvbFdpZHRocyk7XG4gIH1cbiAgY29uc3RydWN0b3Ioa2V5KSB7XG4gICAgc3VwZXIoa2V5KTtcbiAgICB0aGlzLl9fcm93U3RyaXBpbmcgPSBmYWxzZTtcbiAgICB0aGlzLl9fZnJvemVuQ29sdW1uQ291bnQgPSAwO1xuICAgIHRoaXMuX19mcm96ZW5Sb3dDb3VudCA9IDA7XG4gICAgdGhpcy5fX2NvbFdpZHRocyA9IHVuZGVmaW5lZDtcbiAgfVxuICBleHBvcnRKU09OKCkge1xuICAgIHJldHVybiB7XG4gICAgICAuLi5zdXBlci5leHBvcnRKU09OKCksXG4gICAgICBjb2xXaWR0aHM6IHRoaXMuZ2V0Q29sV2lkdGhzKCksXG4gICAgICBmcm96ZW5Db2x1bW5Db3VudDogdGhpcy5fX2Zyb3plbkNvbHVtbkNvdW50ID8gdGhpcy5fX2Zyb3plbkNvbHVtbkNvdW50IDogdW5kZWZpbmVkLFxuICAgICAgZnJvemVuUm93Q291bnQ6IHRoaXMuX19mcm96ZW5Sb3dDb3VudCA/IHRoaXMuX19mcm96ZW5Sb3dDb3VudCA6IHVuZGVmaW5lZCxcbiAgICAgIHJvd1N0cmlwaW5nOiB0aGlzLl9fcm93U3RyaXBpbmcgPyB0aGlzLl9fcm93U3RyaXBpbmcgOiB1bmRlZmluZWRcbiAgICB9O1xuICB9XG4gIGV4dHJhY3RXaXRoQ2hpbGQoY2hpbGQsIHNlbGVjdGlvbiwgZGVzdGluYXRpb24pIHtcbiAgICByZXR1cm4gZGVzdGluYXRpb24gPT09ICdodG1sJztcbiAgfVxuICBnZXRET01TbG90KGVsZW1lbnQpIHtcbiAgICBjb25zdCB0YWJsZUVsZW1lbnQgPSAhaXNIVE1MVGFibGVFbGVtZW50KGVsZW1lbnQpID8gZWxlbWVudC5xdWVyeVNlbGVjdG9yKCd0YWJsZScpIDogZWxlbWVudDtcbiAgICBpZiAoIWlzSFRNTFRhYmxlRWxlbWVudCh0YWJsZUVsZW1lbnQpKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYFRhYmxlTm9kZS5nZXRET01TbG90OiBjcmVhdGVET00oKSBkaWQgbm90IHJldHVybiBhIHRhYmxlYCk7XG4gICAgfVxuICAgIHJldHVybiBzdXBlci5nZXRET01TbG90KGVsZW1lbnQpLndpdGhFbGVtZW50KHRhYmxlRWxlbWVudCkud2l0aEFmdGVyKHRhYmxlRWxlbWVudC5xdWVyeVNlbGVjdG9yKCdjb2xncm91cCcpKTtcbiAgfVxuICBjcmVhdGVET00oY29uZmlnLCBlZGl0b3IpIHtcbiAgICBjb25zdCB0YWJsZUVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0YWJsZScpO1xuICAgIGlmICh0aGlzLl9fc3R5bGUpIHtcbiAgICAgIHRhYmxlRWxlbWVudC5zdHlsZS5jc3NUZXh0ID0gdGhpcy5fX3N0eWxlO1xuICAgIH1cbiAgICBjb25zdCBjb2xHcm91cCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NvbGdyb3VwJyk7XG4gICAgdGFibGVFbGVtZW50LmFwcGVuZENoaWxkKGNvbEdyb3VwKTtcbiAgICBzZXRET01Vbm1hbmFnZWQoY29sR3JvdXApO1xuICAgIGFkZENsYXNzTmFtZXNUb0VsZW1lbnQodGFibGVFbGVtZW50LCBjb25maWcudGhlbWUudGFibGUpO1xuICAgIHRoaXMudXBkYXRlVGFibGVFbGVtZW50KG51bGwsIHRhYmxlRWxlbWVudCwgY29uZmlnKTtcbiAgICBpZiAoJGlzU2Nyb2xsYWJsZVRhYmxlc0FjdGl2ZShlZGl0b3IpKSB7XG4gICAgICBjb25zdCB3cmFwcGVyRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgY29uc3QgY2xhc3NlcyA9IGNvbmZpZy50aGVtZS50YWJsZVNjcm9sbGFibGVXcmFwcGVyO1xuICAgICAgaWYgKGNsYXNzZXMpIHtcbiAgICAgICAgYWRkQ2xhc3NOYW1lc1RvRWxlbWVudCh3cmFwcGVyRWxlbWVudCwgY2xhc3Nlcyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB3cmFwcGVyRWxlbWVudC5zdHlsZS5jc3NUZXh0ID0gJ292ZXJmbG93LXg6IGF1dG87JztcbiAgICAgIH1cbiAgICAgIHdyYXBwZXJFbGVtZW50LmFwcGVuZENoaWxkKHRhYmxlRWxlbWVudCk7XG4gICAgICB0aGlzLnVwZGF0ZVRhYmxlV3JhcHBlcihudWxsLCB3cmFwcGVyRWxlbWVudCwgdGFibGVFbGVtZW50LCBjb25maWcpO1xuICAgICAgcmV0dXJuIHdyYXBwZXJFbGVtZW50O1xuICAgIH1cbiAgICByZXR1cm4gdGFibGVFbGVtZW50O1xuICB9XG4gIHVwZGF0ZVRhYmxlV3JhcHBlcihwcmV2Tm9kZSwgdGFibGVXcmFwcGVyLCB0YWJsZUVsZW1lbnQsIGNvbmZpZykge1xuICAgIGlmICh0aGlzLl9fZnJvemVuQ29sdW1uQ291bnQgIT09IChwcmV2Tm9kZSA/IHByZXZOb2RlLl9fZnJvemVuQ29sdW1uQ291bnQgOiAwKSkge1xuICAgICAgc2V0RnJvemVuQ29sdW1ucyh0YWJsZVdyYXBwZXIsIHRhYmxlRWxlbWVudCwgY29uZmlnLCB0aGlzLl9fZnJvemVuQ29sdW1uQ291bnQpO1xuICAgIH1cbiAgICBpZiAodGhpcy5fX2Zyb3plblJvd0NvdW50ICE9PSAocHJldk5vZGUgPyBwcmV2Tm9kZS5fX2Zyb3plblJvd0NvdW50IDogMCkpIHtcbiAgICAgIHNldEZyb3plblJvd3ModGFibGVXcmFwcGVyLCB0YWJsZUVsZW1lbnQsIGNvbmZpZywgdGhpcy5fX2Zyb3plblJvd0NvdW50KTtcbiAgICB9XG4gIH1cbiAgdXBkYXRlVGFibGVFbGVtZW50KHByZXZOb2RlLCB0YWJsZUVsZW1lbnQsIGNvbmZpZykge1xuICAgIGlmICh0aGlzLl9fc3R5bGUgIT09IChwcmV2Tm9kZSA/IHByZXZOb2RlLl9fc3R5bGUgOiAnJykpIHtcbiAgICAgIHRhYmxlRWxlbWVudC5zdHlsZS5jc3NUZXh0ID0gdGhpcy5fX3N0eWxlO1xuICAgIH1cbiAgICBpZiAodGhpcy5fX3Jvd1N0cmlwaW5nICE9PSAocHJldk5vZGUgPyBwcmV2Tm9kZS5fX3Jvd1N0cmlwaW5nIDogZmFsc2UpKSB7XG4gICAgICBzZXRSb3dTdHJpcGluZyh0YWJsZUVsZW1lbnQsIGNvbmZpZywgdGhpcy5fX3Jvd1N0cmlwaW5nKTtcbiAgICB9XG4gICAgdXBkYXRlQ29sZ3JvdXAodGFibGVFbGVtZW50LCBjb25maWcsIHRoaXMuZ2V0Q29sdW1uQ291bnQoKSwgdGhpcy5nZXRDb2xXaWR0aHMoKSk7XG4gICAgYWxpZ25UYWJsZUVsZW1lbnQodGFibGVFbGVtZW50LCBjb25maWcsIHRoaXMuZ2V0Rm9ybWF0VHlwZSgpKTtcbiAgfVxuICB1cGRhdGVET00ocHJldk5vZGUsIGRvbSwgY29uZmlnKSB7XG4gICAgY29uc3Qgc2xvdCA9IHRoaXMuZ2V0RE9NU2xvdChkb20pO1xuICAgIGNvbnN0IHRhYmxlRWxlbWVudCA9IHNsb3QuZWxlbWVudDtcbiAgICBpZiAoZG9tID09PSB0YWJsZUVsZW1lbnQgPT09ICRpc1Njcm9sbGFibGVUYWJsZXNBY3RpdmUoKSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChpc0hUTUxEaXZFbGVtZW50KGRvbSkpIHtcbiAgICAgIHRoaXMudXBkYXRlVGFibGVXcmFwcGVyKHByZXZOb2RlLCBkb20sIHRhYmxlRWxlbWVudCwgY29uZmlnKTtcbiAgICB9XG4gICAgdGhpcy51cGRhdGVUYWJsZUVsZW1lbnQocHJldk5vZGUsIHRhYmxlRWxlbWVudCwgY29uZmlnKTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgZXhwb3J0RE9NKGVkaXRvcikge1xuICAgIGNvbnN0IHN1cGVyRXhwb3J0ID0gc3VwZXIuZXhwb3J0RE9NKGVkaXRvcik7XG4gICAgY29uc3Qge1xuICAgICAgZWxlbWVudFxuICAgIH0gPSBzdXBlckV4cG9ydDtcbiAgICByZXR1cm4ge1xuICAgICAgYWZ0ZXI6IHRhYmxlRWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChzdXBlckV4cG9ydC5hZnRlcikge1xuICAgICAgICAgIHRhYmxlRWxlbWVudCA9IHN1cGVyRXhwb3J0LmFmdGVyKHRhYmxlRWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFpc0hUTUxUYWJsZUVsZW1lbnQodGFibGVFbGVtZW50KSAmJiBpc0hUTUxFbGVtZW50JDEodGFibGVFbGVtZW50KSkge1xuICAgICAgICAgIHRhYmxlRWxlbWVudCA9IHRhYmxlRWxlbWVudC5xdWVyeVNlbGVjdG9yKCd0YWJsZScpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghaXNIVE1MVGFibGVFbGVtZW50KHRhYmxlRWxlbWVudCkpIHtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBhbGlnblRhYmxlRWxlbWVudCh0YWJsZUVsZW1lbnQsIGVkaXRvci5fY29uZmlnLCB0aGlzLmdldEZvcm1hdFR5cGUoKSk7XG5cbiAgICAgICAgLy8gU2NhbiB0aGUgdGFibGUgbWFwIHRvIGJ1aWxkIGEgbWFwIG9mIHRhYmxlIGNlbGwga2V5IHRvIHRoZSBjb2x1bW5zIGl0IG5lZWRzXG4gICAgICAgIGNvbnN0IFt0YWJsZU1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwU2tpcENlbGxDaGVjayh0aGlzLCBudWxsLCBudWxsKTtcbiAgICAgICAgY29uc3QgY2VsbFZhbHVlcyA9IG5ldyBNYXAoKTtcbiAgICAgICAgZm9yIChjb25zdCBtYXBSb3cgb2YgdGFibGVNYXApIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IG1hcFZhbHVlIG9mIG1hcFJvdykge1xuICAgICAgICAgICAgY29uc3Qga2V5ID0gbWFwVmFsdWUuY2VsbC5nZXRLZXkoKTtcbiAgICAgICAgICAgIGlmICghY2VsbFZhbHVlcy5oYXMoa2V5KSkge1xuICAgICAgICAgICAgICBjZWxsVmFsdWVzLnNldChrZXksIHtcbiAgICAgICAgICAgICAgICBjb2xTcGFuOiBtYXBWYWx1ZS5jZWxsLmdldENvbFNwYW4oKSxcbiAgICAgICAgICAgICAgICBzdGFydENvbHVtbjogbWFwVmFsdWUuc3RhcnRDb2x1bW5cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gc2NhbiB0aGUgRE9NIHRvIGZpbmQgdGhlIHRhYmxlIGNlbGwga2V5cyB0aGF0IHdlcmUgdXNlZCBhbmQgbWFyayB0aG9zZSBjb2x1bW5zXG4gICAgICAgIGNvbnN0IGtub3duQ29sdW1ucyA9IG5ldyBTZXQoKTtcbiAgICAgICAgZm9yIChjb25zdCBjZWxsRE9NIG9mIHRhYmxlRWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsKCc6c2NvcGUgPiB0ciA+IFtkYXRhLXRlbXBvcmFyeS10YWJsZS1jZWxsLWxleGljYWwta2V5XScpKSB7XG4gICAgICAgICAgY29uc3Qga2V5ID0gY2VsbERPTS5nZXRBdHRyaWJ1dGUoJ2RhdGEtdGVtcG9yYXJ5LXRhYmxlLWNlbGwtbGV4aWNhbC1rZXknKTtcbiAgICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICBjb25zdCBjZWxsU3BhbiA9IGNlbGxWYWx1ZXMuZ2V0KGtleSk7XG4gICAgICAgICAgICBjZWxsRE9NLnJlbW92ZUF0dHJpYnV0ZSgnZGF0YS10ZW1wb3JhcnktdGFibGUtY2VsbC1sZXhpY2FsLWtleScpO1xuICAgICAgICAgICAgaWYgKGNlbGxTcGFuKSB7XG4gICAgICAgICAgICAgIGNlbGxWYWx1ZXMuZGVsZXRlKGtleSk7XG4gICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2VsbFNwYW4uY29sU3BhbjsgaSsrKSB7XG4gICAgICAgICAgICAgICAga25vd25Db2x1bW5zLmFkZChpICsgY2VsbFNwYW4uc3RhcnRDb2x1bW4pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29tcHV0ZSB0aGUgY29sZ3JvdXAgYW5kIGNvbHVtbnMgaW4gdGhlIGV4cG9ydFxuICAgICAgICBjb25zdCBjb2xHcm91cCA9IHRhYmxlRWxlbWVudC5xdWVyeVNlbGVjdG9yKCc6c2NvcGUgPiBjb2xncm91cCcpO1xuICAgICAgICBpZiAoY29sR3JvdXApIHtcbiAgICAgICAgICAvLyBPbmx5IGluY2x1ZGUgdGhlIDxjb2wgLz4gZm9yIHJvd3MgdGhhdCBhcmUgaW4gdGhlIG91dHB1dFxuICAgICAgICAgIGNvbnN0IGNvbHMgPSBBcnJheS5mcm9tKHRhYmxlRWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsKCc6c2NvcGUgPiBjb2xncm91cCA+IGNvbCcpKS5maWx0ZXIoKGRvbSwgaSkgPT4ga25vd25Db2x1bW5zLmhhcyhpKSk7XG4gICAgICAgICAgY29sR3JvdXAucmVwbGFjZUNoaWxkcmVuKC4uLmNvbHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gV3JhcCBkaXJlY3QgZGVzY2VuZGFudCByb3dzIGluIGEgdGJvZHkgZm9yIGV4cG9ydFxuICAgICAgICBjb25zdCByb3dzID0gdGFibGVFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJzpzY29wZSA+IHRyJyk7XG4gICAgICAgIGlmIChyb3dzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBjb25zdCB0Qm9keSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3Rib2R5Jyk7XG4gICAgICAgICAgZm9yIChjb25zdCByb3cgb2Ygcm93cykge1xuICAgICAgICAgICAgdEJvZHkuYXBwZW5kQ2hpbGQocm93KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGFibGVFbGVtZW50LmFwcGVuZCh0Qm9keSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRhYmxlRWxlbWVudDtcbiAgICAgIH0sXG4gICAgICBlbGVtZW50OiAhaXNIVE1MVGFibGVFbGVtZW50KGVsZW1lbnQpICYmIGlzSFRNTEVsZW1lbnQkMShlbGVtZW50KSA/IGVsZW1lbnQucXVlcnlTZWxlY3RvcigndGFibGUnKSA6IGVsZW1lbnRcbiAgICB9O1xuICB9XG4gIGNhbkJlRW1wdHkoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGlzU2hhZG93Um9vdCgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICBnZXRDb3Jkc0Zyb21DZWxsTm9kZSh0YWJsZUNlbGxOb2RlLCB0YWJsZSkge1xuICAgIGNvbnN0IHtcbiAgICAgIHJvd3MsXG4gICAgICBkb21Sb3dzXG4gICAgfSA9IHRhYmxlO1xuICAgIGZvciAobGV0IHkgPSAwOyB5IDwgcm93czsgeSsrKSB7XG4gICAgICBjb25zdCByb3cgPSBkb21Sb3dzW3ldO1xuICAgICAgaWYgKHJvdyA9PSBudWxsKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgZm9yIChsZXQgeCA9IDA7IHggPCByb3cubGVuZ3RoOyB4KyspIHtcbiAgICAgICAgY29uc3QgY2VsbCA9IHJvd1t4XTtcbiAgICAgICAgaWYgKGNlbGwgPT0gbnVsbCkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBlbGVtXG4gICAgICAgIH0gPSBjZWxsO1xuICAgICAgICBjb25zdCBjZWxsTm9kZSA9ICRnZXROZWFyZXN0VGFibGVDZWxsSW5UYWJsZUZyb21ET01Ob2RlKHRoaXMsIGVsZW0pO1xuICAgICAgICBpZiAoY2VsbE5vZGUgIT09IG51bGwgJiYgdGFibGVDZWxsTm9kZS5pcyhjZWxsTm9kZSkpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgeCxcbiAgICAgICAgICAgIHlcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignQ2VsbCBub3QgZm91bmQgaW4gdGFibGUuJyk7XG4gIH1cbiAgZ2V0RE9NQ2VsbEZyb21Db3Jkcyh4LCB5LCB0YWJsZSkge1xuICAgIGNvbnN0IHtcbiAgICAgIGRvbVJvd3NcbiAgICB9ID0gdGFibGU7XG4gICAgY29uc3Qgcm93ID0gZG9tUm93c1t5XTtcbiAgICBpZiAocm93ID09IG51bGwpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBjb25zdCBpbmRleCA9IHggPCByb3cubGVuZ3RoID8geCA6IHJvdy5sZW5ndGggLSAxO1xuICAgIGNvbnN0IGNlbGwgPSByb3dbaW5kZXhdO1xuICAgIGlmIChjZWxsID09IG51bGwpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gY2VsbDtcbiAgfVxuICBnZXRET01DZWxsRnJvbUNvcmRzT3JUaHJvdyh4LCB5LCB0YWJsZSkge1xuICAgIGNvbnN0IGNlbGwgPSB0aGlzLmdldERPTUNlbGxGcm9tQ29yZHMoeCwgeSwgdGFibGUpO1xuICAgIGlmICghY2VsbCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDZWxsIG5vdCBmb3VuZCBhdCBjb3Jkcy4nKTtcbiAgICB9XG4gICAgcmV0dXJuIGNlbGw7XG4gIH1cbiAgZ2V0Q2VsbE5vZGVGcm9tQ29yZHMoeCwgeSwgdGFibGUpIHtcbiAgICBjb25zdCBjZWxsID0gdGhpcy5nZXRET01DZWxsRnJvbUNvcmRzKHgsIHksIHRhYmxlKTtcbiAgICBpZiAoY2VsbCA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgY29uc3Qgbm9kZSA9ICRnZXROZWFyZXN0Tm9kZUZyb21ET01Ob2RlKGNlbGwuZWxlbSk7XG4gICAgaWYgKCRpc1RhYmxlQ2VsbE5vZGUobm9kZSkpIHtcbiAgICAgIHJldHVybiBub2RlO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBnZXRDZWxsTm9kZUZyb21Db3Jkc09yVGhyb3coeCwgeSwgdGFibGUpIHtcbiAgICBjb25zdCBub2RlID0gdGhpcy5nZXRDZWxsTm9kZUZyb21Db3Jkcyh4LCB5LCB0YWJsZSk7XG4gICAgaWYgKCFub2RlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vZGUgYXQgY29yZHMgbm90IFRhYmxlQ2VsbE5vZGUuJyk7XG4gICAgfVxuICAgIHJldHVybiBub2RlO1xuICB9XG4gIGdldFJvd1N0cmlwaW5nKCkge1xuICAgIHJldHVybiBCb29sZWFuKHRoaXMuZ2V0TGF0ZXN0KCkuX19yb3dTdHJpcGluZyk7XG4gIH1cbiAgc2V0Um93U3RyaXBpbmcobmV3Um93U3RyaXBpbmcpIHtcbiAgICBjb25zdCBzZWxmID0gdGhpcy5nZXRXcml0YWJsZSgpO1xuICAgIHNlbGYuX19yb3dTdHJpcGluZyA9IG5ld1Jvd1N0cmlwaW5nO1xuICAgIHJldHVybiBzZWxmO1xuICB9XG4gIHNldEZyb3plbkNvbHVtbnMoY29sdW1uQ291bnQpIHtcbiAgICBjb25zdCBzZWxmID0gdGhpcy5nZXRXcml0YWJsZSgpO1xuICAgIHNlbGYuX19mcm96ZW5Db2x1bW5Db3VudCA9IGNvbHVtbkNvdW50O1xuICAgIHJldHVybiBzZWxmO1xuICB9XG4gIGdldEZyb3plbkNvbHVtbnMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TGF0ZXN0KCkuX19mcm96ZW5Db2x1bW5Db3VudDtcbiAgfVxuICBzZXRGcm96ZW5Sb3dzKHJvd0NvdW50KSB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXMuZ2V0V3JpdGFibGUoKTtcbiAgICBzZWxmLl9fZnJvemVuUm93Q291bnQgPSByb3dDb3VudDtcbiAgICByZXR1cm4gc2VsZjtcbiAgfVxuICBnZXRGcm96ZW5Sb3dzKCkge1xuICAgIHJldHVybiB0aGlzLmdldExhdGVzdCgpLl9fZnJvemVuUm93Q291bnQ7XG4gIH1cbiAgY2FuU2VsZWN0QmVmb3JlKCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIGNhbkluZGVudCgpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgZ2V0Q29sdW1uQ291bnQoKSB7XG4gICAgY29uc3QgZmlyc3RSb3cgPSB0aGlzLmdldEZpcnN0Q2hpbGQoKTtcbiAgICBpZiAoIWZpcnN0Um93KSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgbGV0IGNvbHVtbkNvdW50ID0gMDtcbiAgICBmaXJzdFJvdy5nZXRDaGlsZHJlbigpLmZvckVhY2goY2VsbCA9PiB7XG4gICAgICBpZiAoJGlzVGFibGVDZWxsTm9kZShjZWxsKSkge1xuICAgICAgICBjb2x1bW5Db3VudCArPSBjZWxsLmdldENvbFNwYW4oKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gY29sdW1uQ291bnQ7XG4gIH1cbn1cbmZ1bmN0aW9uICRnZXRFbGVtZW50Rm9yVGFibGVOb2RlKGVkaXRvciwgdGFibGVOb2RlKSB7XG4gIGNvbnN0IHRhYmxlRWxlbWVudCA9IGVkaXRvci5nZXRFbGVtZW50QnlLZXkodGFibGVOb2RlLmdldEtleSgpKTtcbiAgaWYgKCEodGFibGVFbGVtZW50ICE9PSBudWxsKSkge1xuICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgJGdldEVsZW1lbnRGb3JUYWJsZU5vZGU6IFRhYmxlIEVsZW1lbnQgTm90IEZvdW5kYCk7XG4gIH1cbiAgcmV0dXJuIGdldFRhYmxlKHRhYmxlTm9kZSwgdGFibGVFbGVtZW50KTtcbn1cbmZ1bmN0aW9uICRjb252ZXJ0VGFibGVFbGVtZW50KGRvbU5vZGUpIHtcbiAgY29uc3QgdGFibGVOb2RlID0gJGNyZWF0ZVRhYmxlTm9kZSgpO1xuICBpZiAoZG9tTm9kZS5oYXNBdHRyaWJ1dGUoJ2RhdGEtbGV4aWNhbC1yb3ctc3RyaXBpbmcnKSkge1xuICAgIHRhYmxlTm9kZS5zZXRSb3dTdHJpcGluZyh0cnVlKTtcbiAgfVxuICBpZiAoZG9tTm9kZS5oYXNBdHRyaWJ1dGUoJ2RhdGEtbGV4aWNhbC1mcm96ZW4tY29sdW1uJykpIHtcbiAgICB0YWJsZU5vZGUuc2V0RnJvemVuQ29sdW1ucygxKTtcbiAgfVxuICBpZiAoZG9tTm9kZS5oYXNBdHRyaWJ1dGUoJ2RhdGEtbGV4aWNhbC1mcm96ZW4tcm93JykpIHtcbiAgICB0YWJsZU5vZGUuc2V0RnJvemVuUm93cygxKTtcbiAgfVxuICBjb25zdCBjb2xHcm91cCA9IGRvbU5vZGUucXVlcnlTZWxlY3RvcignOnNjb3BlID4gY29sZ3JvdXAnKTtcbiAgaWYgKGNvbEdyb3VwKSB7XG4gICAgbGV0IGNvbHVtbnMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IGNvbCBvZiBjb2xHcm91cC5xdWVyeVNlbGVjdG9yQWxsKCc6c2NvcGUgPiBjb2wnKSkge1xuICAgICAgbGV0IHdpZHRoID0gY29sLnN0eWxlLndpZHRoIHx8ICcnO1xuICAgICAgaWYgKCFQSVhFTF9WQUxVRV9SRUdfRVhQLnRlc3Qod2lkdGgpKSB7XG4gICAgICAgIC8vIEFsc28gc3VwcG9ydCBkZXByZWNhdGVkIHdpZHRoIGF0dHJpYnV0ZSBmb3IgZ29vZ2xlIGRvY3NcbiAgICAgICAgd2lkdGggPSBjb2wuZ2V0QXR0cmlidXRlKCd3aWR0aCcpIHx8ICcnO1xuICAgICAgICBpZiAoIS9eXFxkKyQvLnRlc3Qod2lkdGgpKSB7XG4gICAgICAgICAgY29sdW1ucyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29sdW1ucy5wdXNoKHBhcnNlRmxvYXQod2lkdGgpKTtcbiAgICB9XG4gICAgaWYgKGNvbHVtbnMpIHtcbiAgICAgIHRhYmxlTm9kZS5zZXRDb2xXaWR0aHMoY29sdW1ucyk7XG4gICAgfVxuICB9XG4gIHJldHVybiB7XG4gICAgYWZ0ZXI6IGNoaWxkcmVuID0+ICRkZXNjZW5kYW50c01hdGNoaW5nKGNoaWxkcmVuLCAkaXNUYWJsZVJvd05vZGUpLFxuICAgIG5vZGU6IHRhYmxlTm9kZVxuICB9O1xufVxuZnVuY3Rpb24gJGNyZWF0ZVRhYmxlTm9kZSgpIHtcbiAgcmV0dXJuICRhcHBseU5vZGVSZXBsYWNlbWVudChuZXcgVGFibGVOb2RlKCkpO1xufVxuZnVuY3Rpb24gJGlzVGFibGVOb2RlKG5vZGUpIHtcbiAgcmV0dXJuIG5vZGUgaW5zdGFuY2VvZiBUYWJsZU5vZGU7XG59XG5cbmZ1bmN0aW9uICRpbnNlcnRUYWJsZSh7XG4gIHJvd3MsXG4gIGNvbHVtbnMsXG4gIGluY2x1ZGVIZWFkZXJzXG59LCBoYXNOZXN0ZWRUYWJsZXMpIHtcbiAgY29uc3Qgc2VsZWN0aW9uID0gJGdldFNlbGVjdGlvbigpIHx8ICRnZXRQcmV2aW91c1NlbGVjdGlvbigpO1xuICBpZiAoIXNlbGVjdGlvbiB8fCAhJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIFByZXZlbnQgbmVzdGVkIHRhYmxlcyBieSBjaGVja2luZyBpZiB3ZSdyZSBhbHJlYWR5IGluc2lkZSBhIHRhYmxlXG4gIGlmICghaGFzTmVzdGVkVGFibGVzICYmICRmaW5kVGFibGVOb2RlKHNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpKSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCB0YWJsZU5vZGUgPSAkY3JlYXRlVGFibGVOb2RlV2l0aERpbWVuc2lvbnMoTnVtYmVyKHJvd3MpLCBOdW1iZXIoY29sdW1ucyksIGluY2x1ZGVIZWFkZXJzKTtcbiAgJGluc2VydE5vZGVUb05lYXJlc3RSb290KHRhYmxlTm9kZSk7XG4gIGNvbnN0IGZpcnN0RGVzY2VuZGFudCA9IHRhYmxlTm9kZS5nZXRGaXJzdERlc2NlbmRhbnQoKTtcbiAgaWYgKCRpc1RleHROb2RlKGZpcnN0RGVzY2VuZGFudCkpIHtcbiAgICBmaXJzdERlc2NlbmRhbnQuc2VsZWN0KCk7XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiAkdGFibGVDZWxsVHJhbnNmb3JtKG5vZGUpIHtcbiAgaWYgKCEkaXNUYWJsZVJvd05vZGUobm9kZS5nZXRQYXJlbnQoKSkpIHtcbiAgICAvLyBUYWJsZUNlbGxOb2RlIG11c3QgYmUgYSBjaGlsZCBvZiBUYWJsZVJvd05vZGUuXG4gICAgbm9kZS5yZW1vdmUoKTtcbiAgfSBlbHNlIGlmIChub2RlLmlzRW1wdHkoKSkge1xuICAgIC8vIFRhYmxlQ2VsbE5vZGUgc2hvdWxkIG5ldmVyIGJlIGVtcHR5XG4gICAgbm9kZS5hcHBlbmQoJGNyZWF0ZVBhcmFncmFwaE5vZGUoKSk7XG4gIH1cbn1cbmZ1bmN0aW9uICR0YWJsZVJvd1RyYW5zZm9ybShub2RlKSB7XG4gIGlmICghJGlzVGFibGVOb2RlKG5vZGUuZ2V0UGFyZW50KCkpKSB7XG4gICAgLy8gVGFibGVSb3dOb2RlIG11c3QgYmUgYSBjaGlsZCBvZiBUYWJsZU5vZGUuXG4gICAgLy8gVE9ETzogRnV0dXJlIHN1cHBvcnQgb2YgdGJvZHkvdGhlYWQvdGZvb3QgbWF5IGNoYW5nZSB0aGlzXG4gICAgbm9kZS5yZW1vdmUoKTtcbiAgfSBlbHNlIHtcbiAgICAkdW53cmFwQW5kRmlsdGVyRGVzY2VuZGFudHMobm9kZSwgJGlzVGFibGVDZWxsTm9kZSk7XG4gIH1cbn1cbmZ1bmN0aW9uICR0YWJsZVRyYW5zZm9ybShub2RlKSB7XG4gIC8vIFRhYmxlUm93Tm9kZSBpcyB0aGUgb25seSB2YWxpZCBjaGlsZCBmb3IgVGFibGVOb2RlXG4gIC8vIFRPRE86IEZ1dHVyZSBzdXBwb3J0IG9mIHRib2R5L3RoZWFkL3Rmb290L2NhcHRpb24gbWF5IGNoYW5nZSB0aGlzXG4gICR1bndyYXBBbmRGaWx0ZXJEZXNjZW5kYW50cyhub2RlLCAkaXNUYWJsZVJvd05vZGUpO1xuICBjb25zdCBbZ3JpZE1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwU2tpcENlbGxDaGVjayhub2RlLCBudWxsLCBudWxsKTtcbiAgY29uc3QgbWF4Um93TGVuZ3RoID0gZ3JpZE1hcC5yZWR1Y2UoKGN1ckxlbmd0aCwgcm93KSA9PiB7XG4gICAgcmV0dXJuIE1hdGgubWF4KGN1ckxlbmd0aCwgcm93Lmxlbmd0aCk7XG4gIH0sIDApO1xuICBjb25zdCByb3dOb2RlcyA9IG5vZGUuZ2V0Q2hpbGRyZW4oKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBncmlkTWFwLmxlbmd0aDsgKytpKSB7XG4gICAgY29uc3Qgcm93Tm9kZSA9IHJvd05vZGVzW2ldO1xuICAgIGlmICghcm93Tm9kZSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGlmICghJGlzVGFibGVSb3dOb2RlKHJvd05vZGUpKSB7XG4gICAgICBmb3JtYXREZXZFcnJvck1lc3NhZ2UoYFRhYmxlUGx1Z2luOiBFeHBlY3RpbmcgYWxsIGNoaWxkcmVuIG9mIFRhYmxlTm9kZSB0byBiZSBUYWJsZVJvd05vZGUsIGZvdW5kICR7cm93Tm9kZS5jb25zdHJ1Y3Rvci5uYW1lfSAodHlwZSAke3Jvd05vZGUuZ2V0VHlwZSgpfSlgKTtcbiAgICB9XG4gICAgY29uc3Qgcm93TGVuZ3RoID0gZ3JpZE1hcFtpXS5yZWR1Y2UoKGFjYywgY2VsbCkgPT4gY2VsbCA/IDEgKyBhY2MgOiBhY2MsIDApO1xuICAgIGlmIChyb3dMZW5ndGggPT09IG1heFJvd0xlbmd0aCkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGZvciAobGV0IGogPSByb3dMZW5ndGg7IGogPCBtYXhSb3dMZW5ndGg7ICsraikge1xuICAgICAgLy8gVE9ETzogaW5oZXJpdCBoZWFkZXIgc3RhdGUgZnJvbSBhbm90aGVyIGhlYWRlciBvciBib2R5XG4gICAgICBjb25zdCBuZXdDZWxsID0gJGNyZWF0ZVRhYmxlQ2VsbE5vZGUoKTtcbiAgICAgIG5ld0NlbGwuYXBwZW5kKCRjcmVhdGVQYXJhZ3JhcGhOb2RlKCkpO1xuICAgICAgcm93Tm9kZS5hcHBlbmQobmV3Q2VsbCk7XG4gICAgfVxuICB9XG4gIGNvbnN0IGNvbFdpZHRocyA9IG5vZGUuZ2V0Q29sV2lkdGhzKCk7XG4gIGNvbnN0IGNvbHVtbkNvdW50ID0gbm9kZS5nZXRDb2x1bW5Db3VudCgpO1xuICBpZiAoY29sV2lkdGhzICYmIGNvbFdpZHRocy5sZW5ndGggIT09IGNvbHVtbkNvdW50KSB7XG4gICAgbGV0IG5ld0NvbFdpZHRocyA9IHVuZGVmaW5lZDtcbiAgICBpZiAoY29sdW1uQ291bnQgPCBjb2xXaWR0aHMubGVuZ3RoKSB7XG4gICAgICBuZXdDb2xXaWR0aHMgPSBjb2xXaWR0aHMuc2xpY2UoMCwgY29sdW1uQ291bnQpO1xuICAgIH0gZWxzZSBpZiAoY29sV2lkdGhzLmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIFJlcGVhdCB0aGUgbGFzdCBjb2x1bW4gd2lkdGguXG4gICAgICBjb25zdCBmaWxsV2lkdGggPSBjb2xXaWR0aHNbY29sV2lkdGhzLmxlbmd0aCAtIDFdO1xuICAgICAgbmV3Q29sV2lkdGhzID0gWy4uLmNvbFdpZHRocywgLi4uQXJyYXkoY29sdW1uQ291bnQgLSBjb2xXaWR0aHMubGVuZ3RoKS5maWxsKGZpbGxXaWR0aCldO1xuICAgIH1cbiAgICBub2RlLnNldENvbFdpZHRocyhuZXdDb2xXaWR0aHMpO1xuICB9XG59XG5mdW5jdGlvbiAkdGFibGVDbGlja0NvbW1hbmQoZXZlbnQpIHtcbiAgaWYgKGV2ZW50LmRldGFpbCA8IDMgfHwgIWlzRE9NTm9kZShldmVudC50YXJnZXQpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IHN0YXJ0Tm9kZSA9ICRnZXROZWFyZXN0Tm9kZUZyb21ET01Ob2RlKGV2ZW50LnRhcmdldCk7XG4gIGlmIChzdGFydE5vZGUgPT09IG51bGwpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgYmxvY2tOb2RlID0gJGZpbmRNYXRjaGluZ1BhcmVudChzdGFydE5vZGUsIG5vZGUgPT4gJGlzRWxlbWVudE5vZGUobm9kZSkgJiYgIW5vZGUuaXNJbmxpbmUoKSk7XG4gIGlmIChibG9ja05vZGUgPT09IG51bGwpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3Qgcm9vdE5vZGUgPSBibG9ja05vZGUuZ2V0UGFyZW50KCk7XG4gIGlmICghJGlzVGFibGVDZWxsTm9kZShyb290Tm9kZSkpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgYmxvY2tOb2RlLnNlbGVjdCgwKTtcbiAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiAkdGFibGVTZWxlY3RBbGxDb21tYW5kKCkge1xuICBjb25zdCBzZWxlY3Rpb24gPSAkZ2V0U2VsZWN0aW9uKCk7XG4gIGlmICghJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIENoZWNrIGlmIHRoZSBzZWxlY3Rpb24gaXMgaW5zaWRlIGEgdGFibGVcbiAgY29uc3QgYW5jaG9yTm9kZSA9IHNlbGVjdGlvbi5hbmNob3IuZ2V0Tm9kZSgpO1xuICBjb25zdCB0YWJsZU5vZGUgPSAkZmluZFRhYmxlTm9kZShhbmNob3JOb2RlKTtcbiAgaWYgKHRhYmxlTm9kZSA9PT0gbnVsbCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIENSSVRJQ0FMOiBPbmx5IGludGVyY2VwdCBpZiB0YWJsZSBpcyB0aGUgT05MWSBjaGlsZCBvZiByb290XG4gIC8vIFRoaXMgaXMgcmVxdWlyZWQgdG8gcmVwcm9kdWNlIHRoZSBidWc6IHRhYmxlIG11c3QgYmUgdGhlIG9ubHkgY29udGVudCwgbm8gZW1wdHkgcGFyYWdyYXBoc1xuICAvLyBUaGlzIHByZXZlbnRzIGJyZWFraW5nIG90aGVyIHRlc3RzIHRoYXQgZXhwZWN0IFJhbmdlU2VsZWN0aW9uIHdoZW4gdGhlcmUncyBjb250ZW50IG91dHNpZGUgdGFibGVcbiAgY29uc3Qgcm9vdCA9ICRnZXRSb290KCk7XG4gIGlmICghcm9vdC5pcyh0YWJsZU5vZGUuZ2V0UGFyZW50KCkpIHx8IHJvb3QuZ2V0Q2hpbGRyZW5TaXplKCkgIT09IDEpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBBdCB0aGlzIHBvaW50LCB0YWJsZSBpcyB0aGUgb25seSBjaGlsZFxuICAvLyBUaGlzIGlzIHRoZSBleGFjdCBzY2VuYXJpbyBmcm9tIGlzc3VlICM4MDc0OiB0YWJsZSBpcyB0aGUgb25seSBjb250ZW50IGluIGVkaXRvclxuXG4gIC8vIEdldCB0aGUgdGFibGUgbWFwIHRvIGZpbmQgZmlyc3QgYW5kIGxhc3QgY2VsbHMgKGhhbmRsZXMgbWVyZ2VkIGNlbGxzIGNvcnJlY3RseSlcbiAgY29uc3QgW3RhYmxlTWFwXSA9ICRjb21wdXRlVGFibGVNYXBTa2lwQ2VsbENoZWNrKHRhYmxlTm9kZSwgbnVsbCwgbnVsbCk7XG4gIGlmICh0YWJsZU1hcC5sZW5ndGggPT09IDAgfHwgdGFibGVNYXBbMF0ubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gR2V0IHRoZSBmaXJzdCBjZWxsICh0b3AtbGVmdClcbiAgY29uc3QgZmlyc3RDZWxsTWFwID0gdGFibGVNYXBbMF1bMF07XG4gIGlmICghZmlyc3RDZWxsTWFwIHx8ICFmaXJzdENlbGxNYXAuY2VsbCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIEdldCB0aGUgbGFzdCBjZWxsIChib3R0b20tcmlnaHQpXG4gIGNvbnN0IGxhc3RSb3cgPSB0YWJsZU1hcFt0YWJsZU1hcC5sZW5ndGggLSAxXTtcbiAgY29uc3QgbGFzdENlbGxNYXAgPSBsYXN0Um93W2xhc3RSb3cubGVuZ3RoIC0gMV07XG4gIGlmICghbGFzdENlbGxNYXAgfHwgIWxhc3RDZWxsTWFwLmNlbGwpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBDcmVhdGUgYSBUYWJsZVNlbGVjdGlvbiB0aGF0IHNlbGVjdHMgYWxsIGNlbGxzXG4gIGNvbnN0IHRhYmxlU2VsZWN0aW9uID0gJGNyZWF0ZVRhYmxlU2VsZWN0aW9uRnJvbSh0YWJsZU5vZGUsIGZpcnN0Q2VsbE1hcC5jZWxsLCBsYXN0Q2VsbE1hcC5jZWxsKTtcbiAgJHNldFNlbGVjdGlvbih0YWJsZVNlbGVjdGlvbik7XG4gIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIFJlZ2lzdGVyIGEgdHJhbnNmb3JtIHRvIGVuc3VyZSB0aGF0IGFsbCBUYWJsZUNlbGxOb2RlIGhhdmUgYSBjb2xTcGFuIGFuZCByb3dTcGFuIG9mIDEuXG4gKiBUaGlzIHNob3VsZCBvbmx5IGJlIHJlZ2lzdGVyZWQgd2hlbiB5b3UgZG8gbm90IHdhbnQgdG8gc3VwcG9ydCBtZXJnZWQgY2VsbHMuXG4gKlxuICogQHBhcmFtIGVkaXRvciBUaGUgZWRpdG9yXG4gKiBAcmV0dXJucyBBbiB1bnJlZ2lzdGVyIGNhbGxiYWNrXG4gKi9cbmZ1bmN0aW9uIHJlZ2lzdGVyVGFibGVDZWxsVW5tZXJnZVRyYW5zZm9ybShlZGl0b3IpIHtcbiAgcmV0dXJuIGVkaXRvci5yZWdpc3Rlck5vZGVUcmFuc2Zvcm0oVGFibGVDZWxsTm9kZSwgbm9kZSA9PiB7XG4gICAgaWYgKG5vZGUuZ2V0Q29sU3BhbigpID4gMSB8fCBub2RlLmdldFJvd1NwYW4oKSA+IDEpIHtcbiAgICAgIC8vIFdoZW4gd2UgaGF2ZSByb3dTcGFuIHdlIGhhdmUgdG8gbWFwIHRoZSBlbnRpcmUgVGFibGUgdG8gdW5kZXJzdGFuZCB3aGVyZSB0aGUgbmV3IENlbGxzXG4gICAgICAvLyBmaXQgYmVzdDsgbGV0J3MgYW5hbHl6ZSBhbGwgQ2VsbHMgYXQgb25jZSB0byBzYXZlIHVzIGZyb20gZnVydGhlciB0cmFuc2Zvcm0gaXRlcmF0aW9uc1xuICAgICAgY29uc3QgWywsIGdyaWROb2RlXSA9ICRnZXROb2RlVHJpcGxldChub2RlKTtcbiAgICAgIGNvbnN0IFtncmlkTWFwXSA9ICRjb21wdXRlVGFibGVNYXAoZ3JpZE5vZGUsIG5vZGUsIG5vZGUpO1xuICAgICAgLy8gVE9ETyB0aGlzIGZ1bmN0aW9uIGV4cGVjdHMgVGFibGVzIHRvIGJlIG5vcm1hbGl6ZWQuIExvb2sgaW50byB0aGlzIG9uY2UgaXQgZXhpc3RzXG4gICAgICBjb25zdCByb3dzQ291bnQgPSBncmlkTWFwLmxlbmd0aDtcbiAgICAgIGNvbnN0IGNvbHVtbnNDb3VudCA9IGdyaWRNYXBbMF0ubGVuZ3RoO1xuICAgICAgbGV0IHJvdyA9IGdyaWROb2RlLmdldEZpcnN0Q2hpbGQoKTtcbiAgICAgIGlmICghJGlzVGFibGVSb3dOb2RlKHJvdykpIHtcbiAgICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBFeHBlY3RlZCBUYWJsZU5vZGUgZmlyc3QgY2hpbGQgdG8gYmUgYSBSb3dOb2RlYCk7XG4gICAgICB9XG4gICAgICBjb25zdCB1bm1lcmdlZCA9IFtdO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByb3dzQ291bnQ7IGkrKykge1xuICAgICAgICBpZiAoaSAhPT0gMCkge1xuICAgICAgICAgIHJvdyA9IHJvdy5nZXROZXh0U2libGluZygpO1xuICAgICAgICAgIGlmICghJGlzVGFibGVSb3dOb2RlKHJvdykpIHtcbiAgICAgICAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgVGFibGVOb2RlIGZpcnN0IGNoaWxkIHRvIGJlIGEgUm93Tm9kZWApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsZXQgbGFzdFJvd0NlbGwgPSBudWxsO1xuICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGNvbHVtbnNDb3VudDsgaisrKSB7XG4gICAgICAgICAgY29uc3QgY2VsbE1hcCA9IGdyaWRNYXBbaV1bal07XG4gICAgICAgICAgY29uc3QgY2VsbCA9IGNlbGxNYXAuY2VsbDtcbiAgICAgICAgICBpZiAoY2VsbE1hcC5zdGFydFJvdyA9PT0gaSAmJiBjZWxsTWFwLnN0YXJ0Q29sdW1uID09PSBqKSB7XG4gICAgICAgICAgICBsYXN0Um93Q2VsbCA9IGNlbGw7XG4gICAgICAgICAgICB1bm1lcmdlZC5wdXNoKGNlbGwpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoY2VsbC5nZXRDb2xTcGFuKCkgPiAxIHx8IGNlbGwuZ2V0Um93U3BhbigpID4gMSkge1xuICAgICAgICAgICAgaWYgKCEkaXNUYWJsZUNlbGxOb2RlKGNlbGwpKSB7XG4gICAgICAgICAgICAgIGZvcm1hdERldkVycm9yTWVzc2FnZShgRXhwZWN0ZWQgVGFibGVOb2RlIGNlbGwgdG8gYmUgYSBUYWJsZUNlbGxOb2RlYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBuZXdDZWxsID0gJGNyZWF0ZVRhYmxlQ2VsbE5vZGUoY2VsbC5fX2hlYWRlclN0YXRlKTtcbiAgICAgICAgICAgIGlmIChsYXN0Um93Q2VsbCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICBsYXN0Um93Q2VsbC5pbnNlcnRBZnRlcihuZXdDZWxsKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICRpbnNlcnRGaXJzdCQxKHJvdywgbmV3Q2VsbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBmb3IgKGNvbnN0IGNlbGwgb2YgdW5tZXJnZWQpIHtcbiAgICAgICAgY2VsbC5zZXRDb2xTcGFuKDEpO1xuICAgICAgICBjZWxsLnNldFJvd1NwYW4oMSk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn1cbmZ1bmN0aW9uIHJlZ2lzdGVyVGFibGVTZWxlY3Rpb25PYnNlcnZlcihlZGl0b3IsIGhhc1RhYkhhbmRsZXIgPSB0cnVlKSB7XG4gIGNvbnN0IHRhYmxlU2VsZWN0aW9ucyA9IG5ldyBNYXAoKTtcbiAgY29uc3QgaW5pdGlhbGl6ZVRhYmxlTm9kZSA9ICh0YWJsZU5vZGUsIG5vZGVLZXksIGRvbSkgPT4ge1xuICAgIGNvbnN0IHRhYmxlRWxlbWVudCA9IGdldFRhYmxlRWxlbWVudCh0YWJsZU5vZGUsIGRvbSk7XG4gICAgY29uc3QgdGFibGVTZWxlY3Rpb24gPSBhcHBseVRhYmxlSGFuZGxlcnModGFibGVOb2RlLCB0YWJsZUVsZW1lbnQsIGVkaXRvciwgaGFzVGFiSGFuZGxlcik7XG4gICAgdGFibGVTZWxlY3Rpb25zLnNldChub2RlS2V5LCBbdGFibGVTZWxlY3Rpb24sIHRhYmxlRWxlbWVudF0pO1xuICB9O1xuICBjb25zdCB1bnJlZ2lzdGVyTXV0YXRpb25MaXN0ZW5lciA9IGVkaXRvci5yZWdpc3Rlck11dGF0aW9uTGlzdGVuZXIoVGFibGVOb2RlLCBub2RlTXV0YXRpb25zID0+IHtcbiAgICBlZGl0b3IuZ2V0RWRpdG9yU3RhdGUoKS5yZWFkKCgpID0+IHtcbiAgICAgIGZvciAoY29uc3QgW25vZGVLZXksIG11dGF0aW9uXSBvZiBub2RlTXV0YXRpb25zKSB7XG4gICAgICAgIGNvbnN0IHRhYmxlU2VsZWN0aW9uID0gdGFibGVTZWxlY3Rpb25zLmdldChub2RlS2V5KTtcbiAgICAgICAgaWYgKG11dGF0aW9uID09PSAnY3JlYXRlZCcgfHwgbXV0YXRpb24gPT09ICd1cGRhdGVkJykge1xuICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgIHRhYmxlTm9kZSxcbiAgICAgICAgICAgIHRhYmxlRWxlbWVudFxuICAgICAgICAgIH0gPSAkZ2V0VGFibGVBbmRFbGVtZW50QnlLZXkobm9kZUtleSk7XG4gICAgICAgICAgaWYgKHRhYmxlU2VsZWN0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGluaXRpYWxpemVUYWJsZU5vZGUodGFibGVOb2RlLCBub2RlS2V5LCB0YWJsZUVsZW1lbnQpO1xuICAgICAgICAgIH0gZWxzZSBpZiAodGFibGVFbGVtZW50ICE9PSB0YWJsZVNlbGVjdGlvblsxXSkge1xuICAgICAgICAgICAgLy8gVGhlIHVwZGF0ZSBjcmVhdGVkIGEgbmV3IERPTSBub2RlLCBkZXN0cm95IHRoZSBleGlzdGluZyBUYWJsZU9ic2VydmVyXG4gICAgICAgICAgICB0YWJsZVNlbGVjdGlvblswXS5yZW1vdmVMaXN0ZW5lcnMoKTtcbiAgICAgICAgICAgIHRhYmxlU2VsZWN0aW9ucy5kZWxldGUobm9kZUtleSk7XG4gICAgICAgICAgICBpbml0aWFsaXplVGFibGVOb2RlKHRhYmxlTm9kZSwgbm9kZUtleSwgdGFibGVFbGVtZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAobXV0YXRpb24gPT09ICdkZXN0cm95ZWQnKSB7XG4gICAgICAgICAgaWYgKHRhYmxlU2VsZWN0aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRhYmxlU2VsZWN0aW9uWzBdLnJlbW92ZUxpc3RlbmVycygpO1xuICAgICAgICAgICAgdGFibGVTZWxlY3Rpb25zLmRlbGV0ZShub2RlS2V5KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBlZGl0b3JcbiAgICB9KTtcbiAgfSwge1xuICAgIHNraXBJbml0aWFsaXphdGlvbjogZmFsc2VcbiAgfSk7XG4gIHJldHVybiAoKSA9PiB7XG4gICAgdW5yZWdpc3Rlck11dGF0aW9uTGlzdGVuZXIoKTtcbiAgICAvLyBIb29rIG1pZ2h0IGJlIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyBzbyBjbGVhbmluZyB1cCB0YWJsZXMgbGlzdGVuZXJzIGFzIHdlbGwsXG4gICAgLy8gYXMgaXQnbGwgYmUgcmVpbml0aWFsaXplZCBkdXJpbmcgcmVjdXJyaW5nIGNhbGxcbiAgICBmb3IgKGNvbnN0IFssIFt0YWJsZVNlbGVjdGlvbl1dIG9mIHRhYmxlU2VsZWN0aW9ucykge1xuICAgICAgdGFibGVTZWxlY3Rpb24ucmVtb3ZlTGlzdGVuZXJzKCk7XG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIFJlZ2lzdGVyIHRhYmxlIGNvbW1hbmQgbGlzdGVuZXJzIGFuZCB0aGUgdGFibGUgaW50ZWdyaXR5IHRyYW5zZm9ybXMuIFRoZVxuICogdGFibGUgc2VsZWN0aW9uIG9ic2VydmVyIHNob3VsZCBiZSByZWdpc3RlcmVkIHNlcGFyYXRlbHkgYWZ0ZXIgdGhpcyB3aXRoXG4gKiB7QGxpbmsgcmVnaXN0ZXJUYWJsZVNlbGVjdGlvbk9ic2VydmVyfS5cbiAqXG4gKiBAcGFyYW0gZWRpdG9yIFRoZSBlZGl0b3JcbiAqIEByZXR1cm5zIEFuIHVucmVnaXN0ZXIgY2FsbGJhY2tcbiAqL1xuZnVuY3Rpb24gcmVnaXN0ZXJUYWJsZVBsdWdpbihlZGl0b3IsIG9wdGlvbnMpIHtcbiAgaWYgKCFlZGl0b3IuaGFzTm9kZXMoW1RhYmxlTm9kZV0pKSB7XG4gICAge1xuICAgICAgZm9ybWF0RGV2RXJyb3JNZXNzYWdlKGBUYWJsZVBsdWdpbjogVGFibGVOb2RlIGlzIG5vdCByZWdpc3RlcmVkIG9uIGVkaXRvcmApO1xuICAgIH1cbiAgfVxuICBjb25zdCB7XG4gICAgaGFzTmVzdGVkVGFibGVzID0gc2lnbmFsKGZhbHNlKSxcbiAgICBoYXNGaXROZXN0ZWRUYWJsZXMgPSBzaWduYWwoZmFsc2UpXG4gIH0gPSBvcHRpb25zID8/IHt9O1xuICByZXR1cm4gbWVyZ2VSZWdpc3RlcihlZGl0b3IucmVnaXN0ZXJDb21tYW5kKElOU0VSVF9UQUJMRV9DT01NQU5ELCBwYXlsb2FkID0+IHtcbiAgICByZXR1cm4gJGluc2VydFRhYmxlKHBheWxvYWQsIGhhc05lc3RlZFRhYmxlcy5wZWVrKCkpO1xuICB9LCBDT01NQU5EX1BSSU9SSVRZX0VESVRPUiksIGVkaXRvci5yZWdpc3RlckNvbW1hbmQoU0VMRUNUSU9OX0lOU0VSVF9DTElQQk9BUkRfTk9ERVNfQ09NTUFORCwgKHBheWxvYWQsIGRpc3BhdGNoRWRpdG9yKSA9PiB7XG4gICAgaWYgKGVkaXRvciAhPT0gZGlzcGF0Y2hFZGl0b3IpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuICR0YWJsZVNlbGVjdGlvbkluc2VydENsaXBib2FyZE5vZGVzQ29tbWFuZChwYXlsb2FkLCBoYXNOZXN0ZWRUYWJsZXMsIGhhc0ZpdE5lc3RlZFRhYmxlcyk7XG4gIH0sIENPTU1BTkRfUFJJT1JJVFlfRURJVE9SKSwgZWRpdG9yLnJlZ2lzdGVyQ29tbWFuZChTRUxFQ1RfQUxMX0NPTU1BTkQsICR0YWJsZVNlbGVjdEFsbENvbW1hbmQsIENPTU1BTkRfUFJJT1JJVFlfTE9XKSwgZWRpdG9yLnJlZ2lzdGVyQ29tbWFuZChDTElDS19DT01NQU5ELCAkdGFibGVDbGlja0NvbW1hbmQsIENPTU1BTkRfUFJJT1JJVFlfRURJVE9SKSwgZWRpdG9yLnJlZ2lzdGVyTm9kZVRyYW5zZm9ybShUYWJsZU5vZGUsICR0YWJsZVRyYW5zZm9ybSksIGVkaXRvci5yZWdpc3Rlck5vZGVUcmFuc2Zvcm0oVGFibGVSb3dOb2RlLCAkdGFibGVSb3dUcmFuc2Zvcm0pLCBlZGl0b3IucmVnaXN0ZXJOb2RlVHJhbnNmb3JtKFRhYmxlQ2VsbE5vZGUsICR0YWJsZUNlbGxUcmFuc2Zvcm0pKTtcbn1cbmZ1bmN0aW9uICR0YWJsZVNlbGVjdGlvbkluc2VydENsaXBib2FyZE5vZGVzQ29tbWFuZChzZWxlY3Rpb25QYXlsb2FkLCBoYXNOZXN0ZWRUYWJsZXMsIGhhc0ZpdE5lc3RlZFRhYmxlcykge1xuICBjb25zdCB7XG4gICAgbm9kZXMsXG4gICAgc2VsZWN0aW9uXG4gIH0gPSBzZWxlY3Rpb25QYXlsb2FkO1xuICBjb25zdCBoYXNUYWJsZXMgPSBub2Rlcy5zb21lKG4gPT4gJGlzVGFibGVOb2RlKG4pIHx8ICRkZnMobikuc29tZShkID0+ICRpc1RhYmxlTm9kZShkLm5vZGUpKSk7XG4gIGlmICghaGFzVGFibGVzKSB7XG4gICAgLy8gTm90IHBhc3RpbmcgYSB0YWJsZSAtIG5vIHNwZWNpYWwgaGFuZGxpbmcgcmVxdWlyZWQuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IGlzVGFibGVTZWxlY3Rpb24gPSAkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pO1xuICBjb25zdCBpc1JhbmdlU2VsZWN0aW9uID0gJGlzUmFuZ2VTZWxlY3Rpb24oc2VsZWN0aW9uKTtcbiAgY29uc3QgaXNTZWxlY3Rpb25JbnNpZGVPZkdyaWQgPSBpc1JhbmdlU2VsZWN0aW9uICYmICRmaW5kTWF0Y2hpbmdQYXJlbnQoc2VsZWN0aW9uLmFuY2hvci5nZXROb2RlKCksIG4gPT4gJGlzVGFibGVDZWxsTm9kZShuKSkgIT09IG51bGwgJiYgJGZpbmRNYXRjaGluZ1BhcmVudChzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpLCBuID0+ICRpc1RhYmxlQ2VsbE5vZGUobikpICE9PSBudWxsIHx8IGlzVGFibGVTZWxlY3Rpb247XG4gIGlmICghaXNTZWxlY3Rpb25JbnNpZGVPZkdyaWQpIHtcbiAgICAvLyBOb3QgcGFzdGluZyBpbiBhIGdyaWQgLSBubyBzcGVjaWFsIGhhbmRsaW5nIHJlcXVpcmVkLlxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIFdoZW4gcGFzdGluZyBqdXN0IGEgdGFibGUsIGZsYXR0ZW4gdGhlIHRhYmxlIG9uIHRoZSBkZXN0aW5hdGlvbiB0YWJsZSwgZXZlbiB3aGVuIG5lc3RlZCB0YWJsZXMgYXJlIGFsbG93ZWQuXG4gIGlmIChub2Rlcy5sZW5ndGggPT09IDEgJiYgJGlzVGFibGVOb2RlKG5vZGVzWzBdKSkge1xuICAgIHJldHVybiAkaW5zZXJ0VGFibGVJbnRvR3JpZChub2Rlc1swXSwgc2VsZWN0aW9uKTtcbiAgfVxuXG4gIC8vIFdoZW4gcGFzdGluZyBtdWx0aXBsZSBub2RlcyAoaW5jbHVkaW5nIHRhYmxlcykgaW50byBhIGNlbGwsIHVwZGF0ZSB0aGUgdGFibGUgdG8gZml0LlxuICBpZiAoaXNSYW5nZVNlbGVjdGlvbiAmJiBoYXNOZXN0ZWRUYWJsZXMucGVlaygpKSB7XG4gICAgcmV0dXJuICRpbnNlcnRUYWJsZU5vZGVzSW50b0NlbGxzKG5vZGVzLCBzZWxlY3Rpb24sIGhhc0ZpdE5lc3RlZFRhYmxlcy5wZWVrKCkpO1xuICB9XG5cbiAgLy8gSWYgd2UgcmVhY2hlZCB0aGlzIHBvaW50LCB0aGVyZSdzIGEgdGFibGUgaW4gdGhlIHNlbGVjdGlvbiBhbmQgbmVzdGVkIHRhYmxlcyBhcmUgbm90IGFsbG93ZWQgLSByZWplY3QgdGhlIHBhc3RlLlxuICByZXR1cm4gdHJ1ZTtcbn1cbmZ1bmN0aW9uICRpbnNlcnRUYWJsZUludG9HcmlkKHRhYmxlTm9kZSwgc2VsZWN0aW9uKSB7XG4gIGNvbnN0IGFuY2hvckFuZEZvY3VzID0gc2VsZWN0aW9uLmdldFN0YXJ0RW5kUG9pbnRzKCk7XG4gIGNvbnN0IGlzVGFibGVTZWxlY3Rpb24gPSAkaXNUYWJsZVNlbGVjdGlvbihzZWxlY3Rpb24pO1xuICBpZiAoYW5jaG9yQW5kRm9jdXMgPT09IG51bGwpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgW2FuY2hvciwgZm9jdXNdID0gYW5jaG9yQW5kRm9jdXM7XG4gIGNvbnN0IFthbmNob3JDZWxsTm9kZSwgYW5jaG9yUm93Tm9kZSwgZ3JpZE5vZGVdID0gJGdldE5vZGVUcmlwbGV0KGFuY2hvcik7XG4gIGNvbnN0IGZvY3VzQ2VsbE5vZGUgPSAkZmluZE1hdGNoaW5nUGFyZW50KGZvY3VzLmdldE5vZGUoKSwgbiA9PiAkaXNUYWJsZUNlbGxOb2RlKG4pKTtcbiAgaWYgKCEkaXNUYWJsZUNlbGxOb2RlKGFuY2hvckNlbGxOb2RlKSB8fCAhJGlzVGFibGVDZWxsTm9kZShmb2N1c0NlbGxOb2RlKSB8fCAhJGlzVGFibGVSb3dOb2RlKGFuY2hvclJvd05vZGUpIHx8ICEkaXNUYWJsZU5vZGUoZ3JpZE5vZGUpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IFtpbml0aWFsR3JpZE1hcCwgYW5jaG9yQ2VsbE1hcCwgZm9jdXNDZWxsTWFwXSA9ICRjb21wdXRlVGFibGVNYXAoZ3JpZE5vZGUsIGFuY2hvckNlbGxOb2RlLCBmb2N1c0NlbGxOb2RlKTtcbiAgY29uc3QgW3RlbXBsYXRlR3JpZE1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwU2tpcENlbGxDaGVjayh0YWJsZU5vZGUsIG51bGwsIG51bGwpO1xuICBjb25zdCBpbml0aWFsUm93Q291bnQgPSBpbml0aWFsR3JpZE1hcC5sZW5ndGg7XG4gIGNvbnN0IGluaXRpYWxDb2xDb3VudCA9IGluaXRpYWxSb3dDb3VudCA+IDAgPyBpbml0aWFsR3JpZE1hcFswXS5sZW5ndGggOiAwO1xuXG4gIC8vIElmIHdlIGhhdmUgYSByYW5nZSBzZWxlY3Rpb24sIHdlJ2xsIGZpdCB0aGUgdGVtcGxhdGUgZ3JpZCBpbnRvIHRoZVxuICAvLyB0YWJsZSwgZ3Jvd2luZyB0aGUgdGFibGUgaWYgbmVjZXNzYXJ5LlxuICBsZXQgc3RhcnRSb3cgPSBhbmNob3JDZWxsTWFwLnN0YXJ0Um93O1xuICBsZXQgc3RhcnRDb2wgPSBhbmNob3JDZWxsTWFwLnN0YXJ0Q29sdW1uO1xuICBsZXQgYWZmZWN0ZWRSb3dDb3VudCA9IHRlbXBsYXRlR3JpZE1hcC5sZW5ndGg7XG4gIGxldCBhZmZlY3RlZENvbENvdW50ID0gYWZmZWN0ZWRSb3dDb3VudCA+IDAgPyB0ZW1wbGF0ZUdyaWRNYXBbMF0ubGVuZ3RoIDogMDtcbiAgaWYgKGlzVGFibGVTZWxlY3Rpb24pIHtcbiAgICAvLyBJZiB3ZSBoYXZlIGEgdGFibGUgc2VsZWN0aW9uLCB3ZSdsbCBvbmx5IG1vZGlmeSB0aGUgY2VsbHMgd2l0aGluXG4gICAgLy8gdGhlIHNlbGVjdGlvbiBib3VuZGFyeS5cbiAgICBjb25zdCBzZWxlY3Rpb25Cb3VuZGFyeSA9ICRjb21wdXRlVGFibGVDZWxsUmVjdEJvdW5kYXJ5KGluaXRpYWxHcmlkTWFwLCBhbmNob3JDZWxsTWFwLCBmb2N1c0NlbGxNYXApO1xuICAgIGNvbnN0IHNlbGVjdGlvblJvd0NvdW50ID0gc2VsZWN0aW9uQm91bmRhcnkubWF4Um93IC0gc2VsZWN0aW9uQm91bmRhcnkubWluUm93ICsgMTtcbiAgICBjb25zdCBzZWxlY3Rpb25Db2xDb3VudCA9IHNlbGVjdGlvbkJvdW5kYXJ5Lm1heENvbHVtbiAtIHNlbGVjdGlvbkJvdW5kYXJ5Lm1pbkNvbHVtbiArIDE7XG4gICAgc3RhcnRSb3cgPSBzZWxlY3Rpb25Cb3VuZGFyeS5taW5Sb3c7XG4gICAgc3RhcnRDb2wgPSBzZWxlY3Rpb25Cb3VuZGFyeS5taW5Db2x1bW47XG4gICAgYWZmZWN0ZWRSb3dDb3VudCA9IE1hdGgubWluKGFmZmVjdGVkUm93Q291bnQsIHNlbGVjdGlvblJvd0NvdW50KTtcbiAgICBhZmZlY3RlZENvbENvdW50ID0gTWF0aC5taW4oYWZmZWN0ZWRDb2xDb3VudCwgc2VsZWN0aW9uQ29sQ291bnQpO1xuICB9XG5cbiAgLy8gU3RlcCAxOiBVbm1lcmdlIGFsbCBtZXJnZWQgY2VsbHMgd2l0aGluIHRoZSBhZmZlY3RlZCBhcmVhXG4gIGxldCBkaWRQZXJmb3JtTWVyZ2VPcGVyYXRpb25zID0gZmFsc2U7XG4gIGNvbnN0IGxhc3RSb3dGb3JVbm1lcmdlID0gTWF0aC5taW4oaW5pdGlhbFJvd0NvdW50LCBzdGFydFJvdyArIGFmZmVjdGVkUm93Q291bnQpIC0gMTtcbiAgY29uc3QgbGFzdENvbEZvclVubWVyZ2UgPSBNYXRoLm1pbihpbml0aWFsQ29sQ291bnQsIHN0YXJ0Q29sICsgYWZmZWN0ZWRDb2xDb3VudCkgLSAxO1xuICBjb25zdCB1bm1lcmdlZEtleXMgPSBuZXcgU2V0KCk7XG4gIGZvciAobGV0IHJvdyA9IHN0YXJ0Um93OyByb3cgPD0gbGFzdFJvd0ZvclVubWVyZ2U7IHJvdysrKSB7XG4gICAgZm9yIChsZXQgY29sID0gc3RhcnRDb2w7IGNvbCA8PSBsYXN0Q29sRm9yVW5tZXJnZTsgY29sKyspIHtcbiAgICAgIGNvbnN0IGNlbGxNYXAgPSBpbml0aWFsR3JpZE1hcFtyb3ddW2NvbF07XG4gICAgICBpZiAodW5tZXJnZWRLZXlzLmhhcyhjZWxsTWFwLmNlbGwuZ2V0S2V5KCkpKSB7XG4gICAgICAgIGNvbnRpbnVlOyAvLyBjZWxsIHdhcyBhIG1lcmdlZCBjZWxsIHRoYXQgd2FzIGFscmVhZHkgaGFuZGxlZFxuICAgICAgfVxuICAgICAgaWYgKGNlbGxNYXAuY2VsbC5fX3Jvd1NwYW4gPT09IDEgJiYgY2VsbE1hcC5jZWxsLl9fY29sU3BhbiA9PT0gMSkge1xuICAgICAgICBjb250aW51ZTsgLy8gY2VsbCBpcyBub3QgYSBtZXJnZWQgY2VsbFxuICAgICAgfVxuICAgICAgJHVubWVyZ2VDZWxsTm9kZShjZWxsTWFwLmNlbGwpO1xuICAgICAgdW5tZXJnZWRLZXlzLmFkZChjZWxsTWFwLmNlbGwuZ2V0S2V5KCkpO1xuICAgICAgZGlkUGVyZm9ybU1lcmdlT3BlcmF0aW9ucyA9IHRydWU7XG4gICAgfVxuICB9XG4gIGxldCBbaW50ZXJpbUdyaWRNYXBdID0gJGNvbXB1dGVUYWJsZU1hcFNraXBDZWxsQ2hlY2soZ3JpZE5vZGUuZ2V0V3JpdGFibGUoKSwgbnVsbCwgbnVsbCk7XG5cbiAgLy8gU3RlcCAyOiBFeHBhbmQgY3VycmVudCB0YWJsZSAoaWYgbmVlZGVkKVxuICBjb25zdCByb3dzVG9JbnNlcnQgPSBhZmZlY3RlZFJvd0NvdW50IC0gaW5pdGlhbFJvd0NvdW50ICsgc3RhcnRSb3c7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcm93c1RvSW5zZXJ0OyBpKyspIHtcbiAgICBjb25zdCBjZWxsTWFwID0gaW50ZXJpbUdyaWRNYXBbaW5pdGlhbFJvd0NvdW50IC0gMV1bMF07XG4gICAgJGluc2VydFRhYmxlUm93QXROb2RlKGNlbGxNYXAuY2VsbCk7XG4gIH1cbiAgY29uc3QgY29sc1RvSW5zZXJ0ID0gYWZmZWN0ZWRDb2xDb3VudCAtIGluaXRpYWxDb2xDb3VudCArIHN0YXJ0Q29sO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbHNUb0luc2VydDsgaSsrKSB7XG4gICAgY29uc3QgY2VsbE1hcCA9IGludGVyaW1HcmlkTWFwWzBdW2luaXRpYWxDb2xDb3VudCAtIDFdO1xuICAgICRpbnNlcnRUYWJsZUNvbHVtbkF0Tm9kZShjZWxsTWFwLmNlbGwsIHRydWUsIGZhbHNlKTtcbiAgfVxuICBbaW50ZXJpbUdyaWRNYXBdID0gJGNvbXB1dGVUYWJsZU1hcFNraXBDZWxsQ2hlY2soZ3JpZE5vZGUuZ2V0V3JpdGFibGUoKSwgbnVsbCwgbnVsbCk7XG5cbiAgLy8gU3RlcCAzOiBNZXJnZSBjZWxscyBhbmQgc2V0IGNlbGwgY29udGVudCwgdG8gbWF0Y2ggdGVtcGxhdGUgZ3JpZFxuICBmb3IgKGxldCByb3cgPSBzdGFydFJvdzsgcm93IDwgc3RhcnRSb3cgKyBhZmZlY3RlZFJvd0NvdW50OyByb3crKykge1xuICAgIGZvciAobGV0IGNvbCA9IHN0YXJ0Q29sOyBjb2wgPCBzdGFydENvbCArIGFmZmVjdGVkQ29sQ291bnQ7IGNvbCsrKSB7XG4gICAgICBjb25zdCB0ZW1wbGF0ZVJvdyA9IHJvdyAtIHN0YXJ0Um93O1xuICAgICAgY29uc3QgdGVtcGxhdGVDb2wgPSBjb2wgLSBzdGFydENvbDtcbiAgICAgIGNvbnN0IHRlbXBsYXRlQ2VsbE1hcCA9IHRlbXBsYXRlR3JpZE1hcFt0ZW1wbGF0ZVJvd11bdGVtcGxhdGVDb2xdO1xuICAgICAgaWYgKHRlbXBsYXRlQ2VsbE1hcC5zdGFydFJvdyAhPT0gdGVtcGxhdGVSb3cgfHwgdGVtcGxhdGVDZWxsTWFwLnN0YXJ0Q29sdW1uICE9PSB0ZW1wbGF0ZUNvbCkge1xuICAgICAgICBjb250aW51ZTsgLy8gY2VsbCBpcyBhIG1lcmdlZCBjZWxsIHRoYXQgd2FzIGFscmVhZHkgaGFuZGxlZFxuICAgICAgfVxuICAgICAgY29uc3QgdGVtcGxhdGVDZWxsID0gdGVtcGxhdGVDZWxsTWFwLmNlbGw7XG4gICAgICBpZiAodGVtcGxhdGVDZWxsLl9fcm93U3BhbiAhPT0gMSB8fCB0ZW1wbGF0ZUNlbGwuX19jb2xTcGFuICE9PSAxKSB7XG4gICAgICAgIGNvbnN0IGNlbGxzVG9NZXJnZSA9IFtdO1xuICAgICAgICBjb25zdCBsYXN0Um93Rm9yTWVyZ2UgPSBNYXRoLm1pbihyb3cgKyB0ZW1wbGF0ZUNlbGwuX19yb3dTcGFuLCBzdGFydFJvdyArIGFmZmVjdGVkUm93Q291bnQpIC0gMTtcbiAgICAgICAgY29uc3QgbGFzdENvbEZvck1lcmdlID0gTWF0aC5taW4oY29sICsgdGVtcGxhdGVDZWxsLl9fY29sU3Bhbiwgc3RhcnRDb2wgKyBhZmZlY3RlZENvbENvdW50KSAtIDE7XG4gICAgICAgIGZvciAobGV0IHIgPSByb3c7IHIgPD0gbGFzdFJvd0Zvck1lcmdlOyByKyspIHtcbiAgICAgICAgICBmb3IgKGxldCBjID0gY29sOyBjIDw9IGxhc3RDb2xGb3JNZXJnZTsgYysrKSB7XG4gICAgICAgICAgICBjb25zdCBjZWxsTWFwID0gaW50ZXJpbUdyaWRNYXBbcl1bY107XG4gICAgICAgICAgICBjZWxsc1RvTWVyZ2UucHVzaChjZWxsTWFwLmNlbGwpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAkbWVyZ2VDZWxscyhjZWxsc1RvTWVyZ2UpO1xuICAgICAgICBkaWRQZXJmb3JtTWVyZ2VPcGVyYXRpb25zID0gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgY2VsbFxuICAgICAgfSA9IGludGVyaW1HcmlkTWFwW3Jvd11bY29sXTtcbiAgICAgIGNvbnN0IGJhY2tncm91bmRDb2xvciA9IHRlbXBsYXRlQ2VsbC5nZXRCYWNrZ3JvdW5kQ29sb3IoKTtcbiAgICAgIGlmIChiYWNrZ3JvdW5kQ29sb3IgIT09IG51bGwgJiYgYmFja2dyb3VuZENvbG9yICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY2VsbC5zZXRCYWNrZ3JvdW5kQ29sb3IoYmFja2dyb3VuZENvbG9yKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IG9yaWdpbmFsQ2hpbGRyZW4gPSBjZWxsLmdldENoaWxkcmVuKCk7XG4gICAgICB0ZW1wbGF0ZUNlbGwuZ2V0Q2hpbGRyZW4oKS5mb3JFYWNoKGNoaWxkID0+IHtcbiAgICAgICAgaWYgKCRpc1RleHROb2RlKGNoaWxkKSkge1xuICAgICAgICAgIGNvbnN0IHBhcmFncmFwaE5vZGUgPSAkY3JlYXRlUGFyYWdyYXBoTm9kZSgpO1xuICAgICAgICAgIHBhcmFncmFwaE5vZGUuYXBwZW5kKGNoaWxkKTtcbiAgICAgICAgICBjZWxsLmFwcGVuZChjaGlsZCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY2VsbC5hcHBlbmQoY2hpbGQpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIG9yaWdpbmFsQ2hpbGRyZW4uZm9yRWFjaChuID0+IG4ucmVtb3ZlKCkpO1xuICAgIH1cbiAgfVxuICBpZiAoaXNUYWJsZVNlbGVjdGlvbiAmJiBkaWRQZXJmb3JtTWVyZ2VPcGVyYXRpb25zKSB7XG4gICAgLy8gcmVzZXQgdGhlIHRhYmxlIHNlbGVjdGlvbiBpbiBjYXNlIHRoZSBhbmNob3Igb3IgZm9jdXMgY2VsbCB3YXNcbiAgICAvLyByZW1vdmVkIHZpYSBtZXJnZSBvcGVyYXRpb25zXG4gICAgY29uc3QgW2ZpbmFsR3JpZE1hcF0gPSAkY29tcHV0ZVRhYmxlTWFwU2tpcENlbGxDaGVjayhncmlkTm9kZS5nZXRXcml0YWJsZSgpLCBudWxsLCBudWxsKTtcbiAgICBjb25zdCBuZXdBbmNob3JDZWxsTWFwID0gZmluYWxHcmlkTWFwW2FuY2hvckNlbGxNYXAuc3RhcnRSb3ddW2FuY2hvckNlbGxNYXAuc3RhcnRDb2x1bW5dO1xuICAgIG5ld0FuY2hvckNlbGxNYXAuY2VsbC5zZWxlY3RFbmQoKTtcbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn1cblxuLy8gSW5zZXJ0cyB0aGUgZ2l2ZW4gbm9kZXMgKHdoaWNoIHdpbGwgaW5jbHVkZSBUYWJsZU5vZGVzKSBpbnRvIHRoZSB0YWJsZSBhdCB0aGUgZ2l2ZW4gc2VsZWN0aW9uLlxuZnVuY3Rpb24gJGluc2VydFRhYmxlTm9kZXNJbnRvQ2VsbHMobm9kZXMsIHNlbGVjdGlvbiwgaGFzRml0TmVzdGVkVGFibGVzKSB7XG4gIC8vIEN1cnJlbnRseSBvbmx5IHN1cHBvcnQgcGFzdGluZyBpbnRvIGEgc2luZ2xlIGNlbGwuIEluIG90aGVyIGNhc2VzIHdlIHJlamVjdCB0aGUgaW5zZXJ0aW9uLlxuICBjb25zdCBpc011bHRpQ2VsbFRhYmxlU2VsZWN0aW9uID0gJGlzVGFibGVTZWxlY3Rpb24oc2VsZWN0aW9uKSAmJiAhc2VsZWN0aW9uLmZvY3VzLmdldE5vZGUoKS5pcyhzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKSk7XG4gIGNvbnN0IGlzTXVsdGlDZWxsUmFuZ2VTZWxlY3Rpb24gPSAkaXNSYW5nZVNlbGVjdGlvbihzZWxlY3Rpb24pICYmICRpc1RhYmxlQ2VsbE5vZGUoc2VsZWN0aW9uLmFuY2hvci5nZXROb2RlKCkpICYmICFzZWxlY3Rpb24uYW5jaG9yLmdldE5vZGUoKS5pcyhzZWxlY3Rpb24uZm9jdXMuZ2V0Tm9kZSgpKTtcbiAgaWYgKGlzTXVsdGlDZWxsVGFibGVTZWxlY3Rpb24gfHwgaXNNdWx0aUNlbGxSYW5nZVNlbGVjdGlvbikge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIGlmICghaGFzRml0TmVzdGVkVGFibGVzKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IGZvY3VzTm9kZSA9IHNlbGVjdGlvbi5mb2N1cy5nZXROb2RlKCk7XG4gIGNvbnN0IHBhcmVudENlbGwgPSAkZmluZE1hdGNoaW5nUGFyZW50KGZvY3VzTm9kZSwgJGlzVGFibGVDZWxsTm9kZSk7XG4gIGlmICghcGFyZW50Q2VsbCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCBjZWxsV2lkdGggPSAkZ2V0Q2VsbFdpZHRoKHBhcmVudENlbGwpO1xuICBpZiAoY2VsbFdpZHRoID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgYm9yZGVyQm94SW5zZXRzID0gJGNhbGN1bGF0ZUNlbGxJbnNldHMocGFyZW50Q2VsbCk7XG4gIGNvbnN0IHRhYmxlcyA9IG5vZGVzLmZpbHRlcigkaXNUYWJsZU5vZGUpO1xuICBmb3IgKGNvbnN0IHRhYmxlIG9mIHRhYmxlcykge1xuICAgIC8vIE5vdGU6IGhlcmUgd2UgYXNzdW1lIHRoZSBpbnNldCBpcyBjb25zaXN0ZW50IGZvciBjZWxscyBhdCBhbGwgbmVzdGluZyBsZXZlbHMuXG4gICAgJHJlc2l6ZVRhYmxlVG9GaXRDZWxsKHRhYmxlLCBjZWxsV2lkdGgsIGJvcmRlckJveEluc2V0cyk7XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKipcbiAqIFJldHVybiB0aGUgd2lkdGggb2YgYSBzcGVjaWZpYyBjZWxsLCB1c2luZyB0aGUgdGFibGUtbGV2ZWwgY29sV2lkdGhzLlxuICovXG5mdW5jdGlvbiAkZ2V0Q2VsbFdpZHRoKGNlbGwpIHtcbiAgY29uc3QgZGVzdGluYXRpb25UYWJsZU5vZGUgPSAkZ2V0VGFibGVOb2RlRnJvbUxleGljYWxOb2RlT3JUaHJvdyhjZWxsKTtcbiAgY29uc3QgY2VsbFJlY3QgPSAkZ2V0VGFibGVDZWxsTm9kZVJlY3QoY2VsbCk7XG4gIGNvbnN0IGNvbFdpZHRocyA9IGRlc3RpbmF0aW9uVGFibGVOb2RlLmdldENvbFdpZHRocygpO1xuICBpZiAoIWNlbGxSZWN0IHx8ICFjb2xXaWR0aHMpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGNvbnN0IHtcbiAgICBjb2x1bW5JbmRleCxcbiAgICBjb2xTcGFuXG4gIH0gPSBjZWxsUmVjdDtcbiAgbGV0IHRvdGFsV2lkdGggPSAwO1xuICBmb3IgKGxldCBpID0gY29sdW1uSW5kZXg7IGkgPCBjb2x1bW5JbmRleCArIGNvbFNwYW47IGkrKykge1xuICAgIHRvdGFsV2lkdGggKz0gY29sV2lkdGhzW2ldO1xuICB9XG4gIHJldHVybiB0b3RhbFdpZHRoO1xufVxuXG4vKipcbiAqIFJldHVybnMgaG9yaXpvbnRhbCBpbnNldHMgb2YgdGhlIGdpdmVuIGNlbGwgKHBhZGRpbmcgKyBib3JkZXIpLlxuICovXG5mdW5jdGlvbiAkY2FsY3VsYXRlQ2VsbEluc2V0cyhjZWxsKSB7XG4gIGNvbnN0IGNlbGxET00gPSAkZ2V0RWRpdG9yKCkuZ2V0RWxlbWVudEJ5S2V5KGNlbGwuZ2V0S2V5KCkpO1xuICBpZiAoY2VsbERPTSA9PT0gbnVsbCkge1xuICAgIHJldHVybiAwO1xuICB9XG4gIGNvbnN0IGNvbXB1dGVkU3R5bGUgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShjZWxsRE9NKTtcbiAgY29uc3QgcGFkZGluZ0xlZnQgPSBjb21wdXRlZFN0eWxlLmdldFByb3BlcnR5VmFsdWUoJ3BhZGRpbmctbGVmdCcpIHx8ICcwcHgnO1xuICBjb25zdCBwYWRkaW5nUmlnaHQgPSBjb21wdXRlZFN0eWxlLmdldFByb3BlcnR5VmFsdWUoJ3BhZGRpbmctcmlnaHQnKSB8fCAnMHB4JztcbiAgY29uc3QgYm9yZGVyTGVmdFdpZHRoID0gY29tcHV0ZWRTdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKCdib3JkZXItbGVmdC13aWR0aCcpIHx8ICcwcHgnO1xuICBjb25zdCBib3JkZXJSaWdodFdpZHRoID0gY29tcHV0ZWRTdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKCdwYWRkaW5nLXJpZ2h0LXdpZHRoJykgfHwgJzBweCc7XG4gIGlmICghUElYRUxfVkFMVUVfUkVHX0VYUC50ZXN0KHBhZGRpbmdMZWZ0KSB8fCAhUElYRUxfVkFMVUVfUkVHX0VYUC50ZXN0KHBhZGRpbmdSaWdodCkgfHwgIVBJWEVMX1ZBTFVFX1JFR19FWFAudGVzdChib3JkZXJMZWZ0V2lkdGgpIHx8ICFQSVhFTF9WQUxVRV9SRUdfRVhQLnRlc3QoYm9yZGVyUmlnaHRXaWR0aCkpIHtcbiAgICByZXR1cm4gMDtcbiAgfVxuICBjb25zdCBwYWRkaW5nTGVmdFB4ID0gcGFyc2VGbG9hdChwYWRkaW5nTGVmdCk7XG4gIGNvbnN0IHBhZGRpbmdSaWdodFB4ID0gcGFyc2VGbG9hdChwYWRkaW5nUmlnaHQpO1xuICBjb25zdCBib3JkZXJMZWZ0V2lkdGhQeCA9IHBhcnNlRmxvYXQoYm9yZGVyTGVmdFdpZHRoKTtcbiAgY29uc3QgYm9yZGVyUmlnaHRXaWR0aFB4ID0gcGFyc2VGbG9hdChib3JkZXJSaWdodFdpZHRoKTtcbiAgcmV0dXJuIHBhZGRpbmdMZWZ0UHggKyBwYWRkaW5nUmlnaHRQeCArIGJvcmRlckxlZnRXaWR0aFB4ICsgYm9yZGVyUmlnaHRXaWR0aFB4O1xufVxuZnVuY3Rpb24gJGdldFRvdGFsVGFibGVXaWR0aChjb2xXaWR0aHMpIHtcbiAgcmV0dXJuIGNvbFdpZHRocy5yZWR1Y2UoKGN1cldpZHRoLCB3aWR0aCkgPT4gY3VyV2lkdGggKyB3aWR0aCwgMCk7XG59XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgcmVzaXplcyB0YWJsZSBjZWxscyB0byBmaXQgYSBnaXZlbiB3aWR0aC5cbiAqXG4gKiBAcGFyYW0gbm9kZSB0aGUgdGFibGUgbm9kZSB0byByZXNpemUuIFRoZSB0YWJsZSBtdXN0IGhhdmUgY29sV2lkdGhzIHRvIGJlIHJlc2l6ZWQuXG4gKiBAcGFyYW0gcGFyZW50Q2VsbFdpZHRoIHRoZSB3aWR0aCBvZiB0aGUgcGFyZW50IGNlbGxcbiAqIEBwYXJhbSBib3JkZXJCb3hJbnNldHMgdGhlIGluc2V0cyBvZiB0aGUgcGFyZW50IGNlbGwgKHBhZGRpbmcgKyBib3JkZXIpXG4gKi9cbmZ1bmN0aW9uICRyZXNpemVUYWJsZVRvRml0Q2VsbChub2RlLCBwYXJlbnRDZWxsV2lkdGgsIGJvcmRlckJveEluc2V0cykge1xuICBjb25zdCBvbGRDb2xXaWR0aHMgPSBub2RlLmdldENvbFdpZHRocygpO1xuICBpZiAoIW9sZENvbFdpZHRocykge1xuICAgIHJldHVybiBub2RlO1xuICB9XG4gIGNvbnN0IHVzYWJsZVdpZHRoID0gcGFyZW50Q2VsbFdpZHRoIC0gYm9yZGVyQm94SW5zZXRzO1xuICBjb25zdCB0YWJsZVdpZHRoID0gJGdldFRvdGFsVGFibGVXaWR0aChvbGRDb2xXaWR0aHMpO1xuICBpZiAodGFibGVXaWR0aCA8PSB1c2FibGVXaWR0aCkge1xuICAgIHJldHVybiBub2RlO1xuICB9XG4gIGNvbnN0IHByb3BvcnRpb25hbFdpZHRoID0gdXNhYmxlV2lkdGggLyB0YWJsZVdpZHRoO1xuICBub2RlLnNldENvbFdpZHRocyhvbGRDb2xXaWR0aHMubWFwKHdpZHRoID0+IHdpZHRoICogcHJvcG9ydGlvbmFsV2lkdGgpKTtcbiAgY29uc3Qgcm93Q2hpbGRyZW4gPSBub2RlLmdldENoaWxkcmVuKCkuZmlsdGVyKCRpc1RhYmxlUm93Tm9kZSk7XG4gIGZvciAoY29uc3Qgcm93Q2hpbGQgb2Ygcm93Q2hpbGRyZW4pIHtcbiAgICBjb25zdCBjZWxsQ2hpbGRyZW4gPSByb3dDaGlsZC5nZXRDaGlsZHJlbigpLmZpbHRlcigkaXNUYWJsZUNlbGxOb2RlKTtcbiAgICBmb3IgKGNvbnN0IGNlbGxDaGlsZCBvZiBjZWxsQ2hpbGRyZW4pIHtcbiAgICAgIGNvbnN0IGNlbGxXaWR0aCA9ICRnZXRDZWxsV2lkdGgoY2VsbENoaWxkKTtcbiAgICAgIGlmIChjZWxsV2lkdGggPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgdGFibGUgb2YgY2VsbENoaWxkLmdldENoaWxkcmVuKCkuZmlsdGVyKCRpc1RhYmxlTm9kZSkpIHtcbiAgICAgICAgJHJlc2l6ZVRhYmxlVG9GaXRDZWxsKHRhYmxlLCBjZWxsV2lkdGgsIGJvcmRlckJveEluc2V0cyk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQ29weXJpZ2h0IChjKSBNZXRhIFBsYXRmb3JtcywgSW5jLiBhbmQgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKi9cblxuLyoqXG4gKiBDb25maWd1cmVzIHtAbGluayBUYWJsZU5vZGV9LCB7QGxpbmsgVGFibGVSb3dOb2RlfSwge0BsaW5rIFRhYmxlQ2VsbE5vZGV9IGFuZFxuICogcmVnaXN0ZXJzIHRhYmxlIGJlaGF2aW9ycyAoc2VlIHtAbGluayBUYWJsZUNvbmZpZ30pXG4gKi9cbmNvbnN0IFRhYmxlRXh0ZW5zaW9uID0gZGVmaW5lRXh0ZW5zaW9uKHtcbiAgYnVpbGQoZWRpdG9yLCBjb25maWcsIHN0YXRlKSB7XG4gICAgcmV0dXJuIG5hbWVkU2lnbmFscyhjb25maWcpO1xuICB9LFxuICBjb25maWc6IHNhZmVDYXN0KHtcbiAgICBoYXNDZWxsQmFja2dyb3VuZENvbG9yOiB0cnVlLFxuICAgIGhhc0NlbGxNZXJnZTogdHJ1ZSxcbiAgICBoYXNGaXROZXN0ZWRUYWJsZXM6IGZhbHNlLFxuICAgIGhhc0hvcml6b250YWxTY3JvbGw6IHRydWUsXG4gICAgaGFzTmVzdGVkVGFibGVzOiBmYWxzZSxcbiAgICBoYXNUYWJIYW5kbGVyOiB0cnVlXG4gIH0pLFxuICBuYW1lOiAnQGxleGljYWwvdGFibGUvVGFibGUnLFxuICBub2RlczogKCkgPT4gW1RhYmxlTm9kZSwgVGFibGVSb3dOb2RlLCBUYWJsZUNlbGxOb2RlXSxcbiAgcmVnaXN0ZXIoZWRpdG9yLCBjb25maWcsIHN0YXRlKSB7XG4gICAgY29uc3Qgc3RvcmVzID0gc3RhdGUuZ2V0T3V0cHV0KCk7XG4gICAgcmV0dXJuIG1lcmdlUmVnaXN0ZXIoZWZmZWN0KCgpID0+IHtcbiAgICAgIGNvbnN0IGhhc0hvcml6b250YWxTY3JvbGwgPSBzdG9yZXMuaGFzSG9yaXpvbnRhbFNjcm9sbC52YWx1ZTtcbiAgICAgIGNvbnN0IGhhZEhvcml6b250YWxTY3JvbGwgPSAkaXNTY3JvbGxhYmxlVGFibGVzQWN0aXZlKGVkaXRvcik7XG4gICAgICBpZiAoaGFkSG9yaXpvbnRhbFNjcm9sbCAhPT0gaGFzSG9yaXpvbnRhbFNjcm9sbCkge1xuICAgICAgICBzZXRTY3JvbGxhYmxlVGFibGVzQWN0aXZlKGVkaXRvciwgaGFzSG9yaXpvbnRhbFNjcm9sbCk7XG4gICAgICAgIC8vIFJlZ2lzdGVyaW5nIHRoZSB0cmFuc2Zvcm0gaGFzIHRoZSBzaWRlLWVmZmVjdCBvZiBtYXJraW5nIGFsbCBleGlzdGluZ1xuICAgICAgICAvLyBUYWJsZU5vZGVzIGFzIGRpcnR5LiBUaGUgaGFuZGxlciBpcyBpbW1lZGlhdGVseSB1bnJlZ2lzdGVyZWQuXG4gICAgICAgIGVkaXRvci5yZWdpc3Rlck5vZGVUcmFuc2Zvcm0oVGFibGVOb2RlLCAoKSA9PiB7fSkoKTtcbiAgICAgIH1cbiAgICB9KSwgcmVnaXN0ZXJUYWJsZVBsdWdpbihlZGl0b3IsIHN0b3JlcyksIGVmZmVjdCgoKSA9PiByZWdpc3RlclRhYmxlU2VsZWN0aW9uT2JzZXJ2ZXIoZWRpdG9yLCBzdG9yZXMuaGFzVGFiSGFuZGxlci52YWx1ZSkpLCBlZmZlY3QoKCkgPT4gc3RvcmVzLmhhc0NlbGxNZXJnZS52YWx1ZSA/IHVuZGVmaW5lZCA6IHJlZ2lzdGVyVGFibGVDZWxsVW5tZXJnZVRyYW5zZm9ybShlZGl0b3IpKSwgZWZmZWN0KCgpID0+IHN0b3Jlcy5oYXNDZWxsQmFja2dyb3VuZENvbG9yLnZhbHVlID8gdW5kZWZpbmVkIDogZWRpdG9yLnJlZ2lzdGVyTm9kZVRyYW5zZm9ybShUYWJsZUNlbGxOb2RlLCBub2RlID0+IHtcbiAgICAgIGlmIChub2RlLmdldEJhY2tncm91bmRDb2xvcigpICE9PSBudWxsKSB7XG4gICAgICAgIG5vZGUuc2V0QmFja2dyb3VuZENvbG9yKG51bGwpO1xuICAgICAgfVxuICAgIH0pKSk7XG4gIH1cbn0pO1xuXG5leHBvcnQgeyAkY29tcHV0ZVRhYmxlTWFwLCAkY29tcHV0ZVRhYmxlTWFwU2tpcENlbGxDaGVjaywgJGNyZWF0ZVRhYmxlQ2VsbE5vZGUsICRjcmVhdGVUYWJsZU5vZGUsICRjcmVhdGVUYWJsZU5vZGVXaXRoRGltZW5zaW9ucywgJGNyZWF0ZVRhYmxlUm93Tm9kZSwgJGNyZWF0ZVRhYmxlU2VsZWN0aW9uLCAkY3JlYXRlVGFibGVTZWxlY3Rpb25Gcm9tLCAkZGVsZXRlVGFibGVDb2x1bW4sICRkZWxldGVUYWJsZUNvbHVtbkF0U2VsZWN0aW9uLCAkZGVsZXRlVGFibGVDb2x1bW5fX0VYUEVSSU1FTlRBTCwgJGRlbGV0ZVRhYmxlUm93QXRTZWxlY3Rpb24sICRkZWxldGVUYWJsZVJvd19fRVhQRVJJTUVOVEFMLCAkZmluZENlbGxOb2RlLCAkZmluZFRhYmxlTm9kZSwgJGdldEVsZW1lbnRGb3JUYWJsZU5vZGUsICRnZXROb2RlVHJpcGxldCwgJGdldFRhYmxlQW5kRWxlbWVudEJ5S2V5LCAkZ2V0VGFibGVDZWxsTm9kZUZyb21MZXhpY2FsTm9kZSwgJGdldFRhYmxlQ2VsbE5vZGVSZWN0LCAkZ2V0VGFibGVDb2x1bW5JbmRleEZyb21UYWJsZUNlbGxOb2RlLCAkZ2V0VGFibGVOb2RlRnJvbUxleGljYWxOb2RlT3JUaHJvdywgJGdldFRhYmxlUm93SW5kZXhGcm9tVGFibGVDZWxsTm9kZSwgJGdldFRhYmxlUm93Tm9kZUZyb21UYWJsZUNlbGxOb2RlT3JUaHJvdywgJGluc2VydFRhYmxlQ29sdW1uLCAkaW5zZXJ0VGFibGVDb2x1bW5BdFNlbGVjdGlvbiwgJGluc2VydFRhYmxlQ29sdW1uX19FWFBFUklNRU5UQUwsICRpbnNlcnRUYWJsZVJvdywgJGluc2VydFRhYmxlUm93QXRTZWxlY3Rpb24sICRpbnNlcnRUYWJsZVJvd19fRVhQRVJJTUVOVEFMLCAkaXNTY3JvbGxhYmxlVGFibGVzQWN0aXZlLCAkaXNTaW1wbGVUYWJsZSwgJGlzVGFibGVDZWxsTm9kZSwgJGlzVGFibGVOb2RlLCAkaXNUYWJsZVJvd05vZGUsICRpc1RhYmxlU2VsZWN0aW9uLCAkbWVyZ2VDZWxscywgJG1vdmVUYWJsZUNvbHVtbiwgJHJlbW92ZVRhYmxlUm93QXRJbmRleCwgJHVubWVyZ2VDZWxsLCBJTlNFUlRfVEFCTEVfQ09NTUFORCwgVGFibGVDZWxsSGVhZGVyU3RhdGVzLCBUYWJsZUNlbGxOb2RlLCBUYWJsZUV4dGVuc2lvbiwgVGFibGVOb2RlLCBUYWJsZU9ic2VydmVyLCBUYWJsZVJvd05vZGUsIGFwcGx5VGFibGVIYW5kbGVycywgZ2V0RE9NQ2VsbEZyb21UYXJnZXQsIGdldFRhYmxlRWxlbWVudCwgZ2V0VGFibGVPYnNlcnZlckZyb21UYWJsZUVsZW1lbnQsIHJlZ2lzdGVyVGFibGVDZWxsVW5tZXJnZVRyYW5zZm9ybSwgcmVnaXN0ZXJUYWJsZVBsdWdpbiwgcmVnaXN0ZXJUYWJsZVNlbGVjdGlvbk9ic2VydmVyLCBzZXRTY3JvbGxhYmxlVGFibGVzQWN0aXZlIH07XG4iXSwibmFtZXMiOltdLCJpZ25vcmVMaXN0IjpbMF0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///(rsc)/./node_modules/.pnpm/@lexical+table@0.41.0/node_modules/@lexical/table/LexicalTable.dev.mjs\n");
/***/ })
};
;