@excalidraw/excalidraw 0.17.2 → 0.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2507,7 +2507,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
2507
2507
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2508
2508
 
2509
2509
  "use strict";
2510
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"ExcalidrawContainerContext\": () => (/* binding */ ExcalidrawContainerContext),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ \"useApp\": () => (/* binding */ useApp),\n/* harmony export */ \"useAppProps\": () => (/* binding */ useAppProps),\n/* harmony export */ \"useDevice\": () => (/* binding */ useDevice),\n/* harmony export */ \"useExcalidrawActionManager\": () => (/* binding */ useExcalidrawActionManager),\n/* harmony export */ \"useExcalidrawAppState\": () => (/* binding */ useExcalidrawAppState),\n/* harmony export */ \"useExcalidrawContainer\": () => (/* binding */ useExcalidrawContainer),\n/* harmony export */ \"useExcalidrawElements\": () => (/* binding */ useExcalidrawElements),\n/* harmony export */ \"useExcalidrawSetAppState\": () => (/* binding */ useExcalidrawSetAppState)\n/* harmony export */ });\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react/jsx-runtime */ \"react/jsx-runtime\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ \"react\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-dom */ \"react-dom\");\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! roughjs/bin/rough */ \"../../../node_modules/roughjs/bin/rough.js\");\n/* harmony import */ var clsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! clsx */ \"../../../node_modules/clsx/dist/clsx.m.js\");\n/* harmony import */ var nanoid__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(/*! nanoid */ \"../../../node_modules/nanoid/index.browser.js\");\n/* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../actions */ \"../../actions/index.ts\");\n/* harmony import */ var _actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../actions/actionHistory */ \"../../actions/actionHistory.tsx\");\n/* harmony import */ var _actions_manager__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../actions/manager */ \"../../actions/manager.tsx\");\n/* harmony import */ var _actions_register__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../actions/register */ \"../../actions/register.ts\");\n/* harmony import */ var _analytics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../analytics */ \"../../analytics.ts\");\n/* harmony import */ var _appState__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../appState */ \"../../appState.ts\");\n/* harmony import */ var _clipboard__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../clipboard */ \"../../clipboard.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\n/* harmony import */ var _data__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../data */ \"../../data/index.ts\");\n/* harmony import */ var _data_library__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../data/library */ \"../../data/library.ts\");\n/* harmony import */ var _data_restore__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../data/restore */ \"../../data/restore.ts\");\n/* harmony import */ var _element__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../element */ \"../../element/index.ts\");\n/* harmony import */ var _element_binding__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../element/binding */ \"../../element/binding.ts\");\n/* harmony import */ var _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../element/linearElementEditor */ \"../../element/linearElementEditor.ts\");\n/* harmony import */ var _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../element/mutateElement */ \"../../element/mutateElement.ts\");\n/* harmony import */ var _element_newElement__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../element/newElement */ \"../../element/newElement.ts\");\n/* harmony import */ var _element_typeChecks__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../element/typeChecks */ \"../../element/typeChecks.ts\");\n/* harmony import */ var _gesture__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../gesture */ \"../../gesture.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../groups */ \"../../groups.ts\");\n/* harmony import */ var _history__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../history */ \"../../history.ts\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../i18n */ \"../../i18n.ts\");\n/* harmony import */ var _keys__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ../keys */ \"../../keys.ts\");\n/* harmony import */ var _element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ../element/sizeHelpers */ \"../../element/sizeHelpers.ts\");\n/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ../math */ \"../../math.ts\");\n/* harmony import */ var _scene__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ../scene */ \"../../scene/index.ts\");\n/* harmony import */ var _scene_Scene__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ../scene/Scene */ \"../../scene/Scene.ts\");\n/* harmony import */ var _scene_zoom__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ../scene/zoom */ \"../../scene/zoom.ts\");\n/* harmony import */ var _shapes__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ../shapes */ \"../../shapes.tsx\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _element_embeddable__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ../element/embeddable */ \"../../element/embeddable.ts\");\n/* harmony import */ var _ContextMenu__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ./ContextMenu */ \"../../components/ContextMenu.tsx\");\n/* harmony import */ var _LayerUI__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./LayerUI */ \"../../components/LayerUI.tsx\");\n/* harmony import */ var _Toast__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./Toast */ \"../../components/Toast.tsx\");\n/* harmony import */ var _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ../actions/actionToggleViewMode */ \"../../actions/actionToggleViewMode.tsx\");\n/* harmony import */ var _data_blob__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ../data/blob */ \"../../data/blob.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ../element/image */ \"../../element/image.ts\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! lodash.throttle */ \"../../../node_modules/lodash.throttle/index.js\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default = /*#__PURE__*/__webpack_require__.n(lodash_throttle__WEBPACK_IMPORTED_MODULE_41__);\n/* harmony import */ var _data_filesystem__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! ../data/filesystem */ \"../../data/filesystem.ts\");\n/* harmony import */ var _element_textElement__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ../element/textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _element_collision__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ../element/collision */ \"../../element/collision.ts\");\n/* harmony import */ var _element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! ../element/Hyperlink */ \"../../element/Hyperlink.tsx\");\n/* harmony import */ var _data_url__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! ../data/url */ \"../../data/url.ts\");\n/* harmony import */ var _element_transformHandles__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! ../element/transformHandles */ \"../../element/transformHandles.ts\");\n/* harmony import */ var _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! ../actions/actionElementLock */ \"../../actions/actionElementLock.ts\");\n/* harmony import */ var _scene_Fonts__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! ../scene/Fonts */ \"../../scene/Fonts.ts\");\n/* harmony import */ var _frame__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! ../frame */ \"../../frame.ts\");\n/* harmony import */ var _scene_selection__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! ../scene/selection */ \"../../scene/selection.ts\");\n/* harmony import */ var _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! ../actions/actionClipboard */ \"../../actions/actionClipboard.tsx\");\n/* harmony import */ var _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! ../actions/actionFrame */ \"../../actions/actionFrame.ts\");\n/* harmony import */ var _actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ../actions/actionCanvas */ \"../../actions/actionCanvas.tsx\");\n/* harmony import */ var _jotai__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ../jotai */ \"../../jotai.ts\");\n/* harmony import */ var _ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! ./ActiveConfirmDialog */ \"../../components/ActiveConfirmDialog.tsx\");\n/* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ../errors */ \"../../errors.ts\");\n/* harmony import */ var _snapping__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(/*! ../snapping */ \"../../snapping.ts\");\n/* harmony import */ var _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(/*! ../actions/actionBoundText */ \"../../actions/actionBoundText.tsx\");\n/* harmony import */ var _BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(/*! ./BraveMeasureTextError */ \"../../components/BraveMeasureTextError.tsx\");\n/* harmony import */ var _EyeDropper__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(/*! ./EyeDropper */ \"../../components/EyeDropper.tsx\");\n/* harmony import */ var _data_transform__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(/*! ../data/transform */ \"../../data/transform.ts\");\n/* harmony import */ var _Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(/*! ./Sidebar/Sidebar */ \"../../components/Sidebar/Sidebar.tsx\");\n/* harmony import */ var _canvases__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(/*! ./canvases */ \"../../components/canvases/index.tsx\");\n/* harmony import */ var _scene_Renderer__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(/*! ../scene/Renderer */ \"../../scene/Renderer.ts\");\n/* harmony import */ var _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(/*! ../scene/ShapeCache */ \"../../scene/ShapeCache.ts\");\n/* harmony import */ var _MermaidToExcalidraw__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(/*! ./MermaidToExcalidraw */ \"../../components/MermaidToExcalidraw.tsx\");\n/* harmony import */ var _LaserTool_LaserTool__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(/*! ./LaserTool/LaserTool */ \"../../components/LaserTool/LaserTool.tsx\");\n/* harmony import */ var _LaserTool_LaserPathManager__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(/*! ./LaserTool/LaserPathManager */ \"../../components/LaserTool/LaserPathManager.ts\");\n/* harmony import */ var _cursor__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(/*! ../cursor */ \"../../cursor.ts\");\n/* harmony import */ var _emitter__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(/*! ../emitter */ \"../../emitter.ts\");\nvar __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {\n function adopt(value) {\n return value instanceof P ? value : new P(function (resolve) {\n resolve(value);\n });\n }\n\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) {\n try {\n step(generator.next(value));\n } catch (e) {\n reject(e);\n }\n }\n\n function rejected(value) {\n try {\n step(generator[\"throw\"](value));\n } catch (e) {\n reject(e);\n }\n }\n\n function step(result) {\n result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n }\n\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst AppContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst AppPropsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst deviceContextInitialValue = {\n viewport: {\n isMobile: false,\n isLandscape: false\n },\n editor: {\n isMobile: false,\n canFitSidebar: false\n },\n isTouchScreen: false\n};\nconst DeviceContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(deviceContextInitialValue);\nDeviceContext.displayName = \"DeviceContext\";\nconst ExcalidrawContainerContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext({\n container: null,\n id: null\n});\nExcalidrawContainerContext.displayName = \"ExcalidrawContainerContext\";\nconst ExcalidrawElementsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext([]);\nExcalidrawElementsContext.displayName = \"ExcalidrawElementsContext\";\nconst ExcalidrawAppStateContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n width: 0,\n height: 0,\n offsetLeft: 0,\n offsetTop: 0\n}));\nExcalidrawAppStateContext.displayName = \"ExcalidrawAppStateContext\";\nconst ExcalidrawSetAppStateContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(() => {\n console.warn(\"unitialized ExcalidrawSetAppStateContext context!\");\n});\nExcalidrawSetAppStateContext.displayName = \"ExcalidrawSetAppStateContext\";\nconst ExcalidrawActionManagerContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nExcalidrawActionManagerContext.displayName = \"ExcalidrawActionManagerContext\";\nconst useApp = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(AppContext);\nconst useAppProps = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(AppPropsContext);\nconst useDevice = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(DeviceContext);\nconst useExcalidrawContainer = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawContainerContext);\nconst useExcalidrawElements = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawElementsContext);\nconst useExcalidrawAppState = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawAppStateContext);\nconst useExcalidrawSetAppState = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawSetAppStateContext);\nconst useExcalidrawActionManager = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawActionManagerContext);\nconst supportsResizeObserver = typeof window !== \"undefined\" && \"ResizeObserver\" in window;\nlet didTapTwice = false;\nlet tappedTwiceTimer = 0;\nlet isHoldingSpace = false;\nlet isPanning = false;\nlet isDraggingScrollBar = false;\nlet currentScrollBars = {\n horizontal: null,\n vertical: null\n};\nlet touchTimeout = 0;\nlet invalidateContextMenu = false;\n/**\n * Map of youtube embed video states\n */\n\nconst YOUTUBE_VIDEO_STATES = new Map();\nlet IS_PLAIN_PASTE = false;\nlet IS_PLAIN_PASTE_TIMER = 0;\nlet PLAIN_PASTE_TOAST_SHOWN = false;\nlet lastPointerUp = null;\nconst gesture = {\n pointers: new Map(),\n lastCenter: null,\n initialDistance: null,\n initialScale: null\n};\n\nclass App extends (react__WEBPACK_IMPORTED_MODULE_1___default().Component) {\n constructor(props) {\n super(props);\n this.interactiveCanvas = null;\n this.unmounted = false;\n this.device = deviceContextInitialValue;\n this.excalidrawContainerRef = react__WEBPACK_IMPORTED_MODULE_1___default().createRef();\n this.files = {};\n this.imageCache = new Map();\n this.iFrameRefs = new Map();\n this.lastPointerDownEvent = null;\n this.lastPointerUpEvent = null;\n this.lastViewportPosition = {\n x: 0,\n y: 0\n };\n this.laserPathManager = new _LaserTool_LaserPathManager__WEBPACK_IMPORTED_MODULE_69__.LaserPathManager(this);\n this.onChangeEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_71__.Emitter();\n this.onPointerDownEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_71__.Emitter();\n this.onPointerUpEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_71__.Emitter();\n\n this.updateEmbeddables = () => {\n const embeddableElements = new Map();\n let updated = false;\n this.scene.getNonDeletedElements().filter(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(element)) {\n embeddableElements.set(element.id, true);\n\n if (element.validated == null) {\n updated = true;\n const validated = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(element.link, this.props.validateEmbeddable);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n validated\n }, false);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element);\n }\n }\n\n return false;\n });\n\n if (updated) {\n this.scene.informMutation();\n } // GC\n\n\n this.iFrameRefs.forEach((ref, id) => {\n if (!embeddableElements.has(id)) {\n this.iFrameRefs.delete(id);\n }\n });\n };\n\n this.getFrameNameDOMId = frameElement => {\n return `${this.id}-frame-name-${frameElement.id}`;\n };\n\n this.frameNameBoundsCache = {\n get: frameElement => {\n let bounds = this.frameNameBoundsCache._cache.get(frameElement.id);\n\n if (!bounds || bounds.zoom !== this.state.zoom.value || bounds.versionNonce !== frameElement.versionNonce) {\n const frameNameDiv = document.getElementById(this.getFrameNameDOMId(frameElement));\n\n if (frameNameDiv) {\n const box = frameNameDiv.getBoundingClientRect();\n const boxSceneTopLeft = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: box.x,\n clientY: box.y\n }, this.state);\n const boxSceneBottomRight = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: box.right,\n clientY: box.bottom\n }, this.state);\n bounds = {\n x: boxSceneTopLeft.x,\n y: boxSceneTopLeft.y,\n width: boxSceneBottomRight.x - boxSceneTopLeft.x,\n height: boxSceneBottomRight.y - boxSceneTopLeft.y,\n angle: 0,\n zoom: this.state.zoom.value,\n versionNonce: frameElement.versionNonce\n };\n\n this.frameNameBoundsCache._cache.set(frameElement.id, bounds);\n\n return bounds;\n }\n\n return null;\n }\n\n return bounds;\n },\n\n /**\n * @private\n */\n _cache: new Map()\n };\n\n this.renderFrameNames = () => {\n if (!this.state.frameRendering.enabled || !this.state.frameRendering.name) {\n return null;\n }\n\n const isDarkTheme = this.state.theme === \"dark\";\n return this.scene.getNonDeletedFrames().map((f, index) => {\n if (!(0,_element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__.isElementInViewport)(f, this.canvas.width / window.devicePixelRatio, this.canvas.height / window.devicePixelRatio, {\n offsetLeft: this.state.offsetLeft,\n offsetTop: this.state.offsetTop,\n scrollX: this.state.scrollX,\n scrollY: this.state.scrollY,\n zoom: this.state.zoom\n })) {\n // if frame not visible, don't render its name\n return null;\n }\n\n const {\n x: x1,\n y: y1\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: f.x,\n sceneY: f.y\n }, this.state);\n const FRAME_NAME_EDIT_PADDING = 6;\n\n const reset = () => {\n var _a;\n\n if (((_a = f.name) === null || _a === void 0 ? void 0 : _a.trim()) === \"\") {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(f, {\n name: null\n });\n }\n\n this.setState({\n editingFrame: null\n });\n };\n\n let frameNameJSX;\n\n if (f.id === this.state.editingFrame) {\n const frameNameInEdit = f.name == null ? `Frame ${index + 1}` : f.name;\n frameNameJSX = (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"input\", {\n autoFocus: true,\n value: frameNameInEdit,\n onChange: e => {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(f, {\n name: e.target.value\n });\n },\n onBlur: () => reset(),\n onKeyDown: event => {\n // for some inexplicable reason, `onBlur` triggered on ESC\n // does not reset `state.editingFrame` despite being called,\n // and we need to reset it here as well\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ESCAPE || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ENTER) {\n reset();\n }\n },\n style: {\n background: this.state.viewBackgroundColor,\n filter: isDarkTheme ? _constants__WEBPACK_IMPORTED_MODULE_12__.THEME_FILTER : \"none\",\n zIndex: 2,\n border: \"none\",\n display: \"block\",\n padding: `${FRAME_NAME_EDIT_PADDING}px`,\n borderRadius: 4,\n boxShadow: \"inset 0 0 0 1px var(--color-primary)\",\n fontFamily: \"Assistant\",\n fontSize: \"14px\",\n transform: `translate(-${FRAME_NAME_EDIT_PADDING}px, ${FRAME_NAME_EDIT_PADDING}px)`,\n color: \"var(--color-gray-80)\",\n overflow: \"hidden\",\n maxWidth: `${document.body.clientWidth - x1 - FRAME_NAME_EDIT_PADDING}px`\n },\n size: frameNameInEdit.length + 1 || 1,\n dir: \"auto\",\n autoComplete: \"off\",\n autoCapitalize: \"off\",\n autoCorrect: \"off\"\n });\n } else {\n frameNameJSX = f.name == null || f.name.trim() === \"\" ? `Frame ${index + 1}` : f.name.trim();\n }\n\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n id: this.getFrameNameDOMId(f),\n style: {\n position: \"absolute\",\n // Positioning from bottom so that we don't to either\n // calculate text height or adjust using transform (which)\n // messes up input position when editing the frame name.\n // This makes the positioning deterministic and we can calculate\n // the same position when rendering to canvas / svg.\n bottom: `${this.state.height + _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameOffsetY - y1 + this.state.offsetTop}px`,\n left: `${x1 - this.state.offsetLeft}px`,\n zIndex: 2,\n fontSize: _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameFontSize,\n color: isDarkTheme ? _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameColorDarkTheme : _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameColorLightTheme,\n lineHeight: _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameLineHeight,\n width: \"max-content\",\n maxWidth: `${f.width}px`,\n overflow: f.id === this.state.editingFrame ? \"visible\" : \"hidden\",\n whiteSpace: \"nowrap\",\n textOverflow: \"ellipsis\",\n cursor: _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE,\n pointerEvents: this.state.viewModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled\n },\n onPointerDown: event => this.handleCanvasPointerDown(event),\n onWheel: event => this.handleWheel(event),\n onContextMenu: this.handleCanvasContextMenu,\n onDoubleClick: () => {\n this.setState({\n editingFrame: f.id\n });\n }\n }, {\n children: frameNameJSX\n }), f.id);\n });\n };\n\n this.focusContainer = () => {\n var _a;\n\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.focus();\n };\n\n this.getSceneElementsIncludingDeleted = () => {\n return this.scene.getElementsIncludingDeleted();\n };\n\n this.getSceneElements = () => {\n return this.scene.getNonDeletedElements();\n };\n\n this.onInsertElements = elements => {\n this.addElementsFromPasteOrLibrary({\n elements,\n position: \"center\",\n files: null\n });\n };\n\n this.onExportImage = (type, elements, opts) => __awaiter(this, void 0, void 0, function* () {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"export\", type, \"ui\");\n const fileHandle = yield (0,_data__WEBPACK_IMPORTED_MODULE_13__.exportCanvas)(type, elements, this.state, this.files, {\n exportBackground: this.state.exportBackground,\n name: this.state.name,\n viewBackgroundColor: this.state.viewBackgroundColor,\n exportingFrame: opts.exportingFrame\n }).catch(_utils__WEBPACK_IMPORTED_MODULE_33__.muteFSAbortError).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: error.message\n });\n });\n\n if (this.state.exportEmbedScene && fileHandle && (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isImageFileHandle)(fileHandle)) {\n this.setState({\n fileHandle\n });\n }\n });\n\n this.openEyeDropper = ({\n type\n }) => {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_EyeDropper__WEBPACK_IMPORTED_MODULE_61__.activeEyeDropperAtom, {\n swapPreviewOnAlt: true,\n colorPickerType: type === \"stroke\" ? \"elementStroke\" : \"elementBackground\",\n onSelect: (color, event) => {\n const shouldUpdateStrokeColor = type === \"background\" && event.altKey || type === \"stroke\" && !event.altKey;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (!selectedElements.length || this.state.activeTool.type !== \"selection\") {\n if (shouldUpdateStrokeColor) {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemStrokeColor: color\n }),\n commitToHistory: true\n });\n } else {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemBackgroundColor: color\n }),\n commitToHistory: true\n });\n }\n } else {\n this.updateScene({\n elements: this.scene.getElementsIncludingDeleted().map(el => {\n if (this.state.selectedElementIds[el.id]) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(el, {\n [shouldUpdateStrokeColor ? \"strokeColor\" : \"backgroundColor\"]: color\n });\n }\n\n return el;\n })\n });\n }\n },\n keepOpenOnAlt: false\n });\n };\n\n this.syncActionResult = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(actionResult => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n\n if (this.unmounted || actionResult === false) {\n return;\n }\n\n let editingElement = null;\n\n if (actionResult.elements) {\n actionResult.elements.forEach(element => {\n var _a;\n\n if (((_a = this.state.editingElement) === null || _a === void 0 ? void 0 : _a.id) === element.id && this.state.editingElement !== element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n editingElement = element;\n }\n });\n this.scene.replaceAllElements(actionResult.elements);\n\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n }\n\n if (actionResult.files) {\n this.files = actionResult.replaceFiles ? actionResult.files : Object.assign(Object.assign({}, this.files), actionResult.files);\n this.addNewImagesToImageCache();\n }\n\n if (actionResult.appState || editingElement || this.state.contextMenu) {\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n\n let viewModeEnabled = ((_a = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _a === void 0 ? void 0 : _a.viewModeEnabled) || false;\n let zenModeEnabled = ((_b = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _b === void 0 ? void 0 : _b.zenModeEnabled) || false;\n let gridSize = ((_c = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _c === void 0 ? void 0 : _c.gridSize) || null;\n const theme = ((_d = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _d === void 0 ? void 0 : _d.theme) || this.props.theme || _constants__WEBPACK_IMPORTED_MODULE_12__.THEME.LIGHT;\n let name = (_f = (_e = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : this.state.name;\n const errorMessage = (_h = (_g = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _g === void 0 ? void 0 : _g.errorMessage) !== null && _h !== void 0 ? _h : this.state.errorMessage;\n\n if (typeof this.props.viewModeEnabled !== \"undefined\") {\n viewModeEnabled = this.props.viewModeEnabled;\n }\n\n if (typeof this.props.zenModeEnabled !== \"undefined\") {\n zenModeEnabled = this.props.zenModeEnabled;\n }\n\n if (typeof this.props.gridModeEnabled !== \"undefined\") {\n gridSize = this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null;\n }\n\n if (typeof this.props.name !== \"undefined\") {\n name = this.props.name;\n }\n\n editingElement = editingElement || ((_j = actionResult.appState) === null || _j === void 0 ? void 0 : _j.editingElement) || null;\n\n if (editingElement === null || editingElement === void 0 ? void 0 : editingElement.isDeleted) {\n editingElement = null;\n }\n\n this.setState(state => {\n // using Object.assign instead of spread to fool TS 4.2.2+ into\n // regarding the resulting type as not containing undefined\n // (which the following expression will never contain)\n return Object.assign(actionResult.appState || {}, {\n // NOTE this will prevent opening context menu using an action\n // or programmatically from the host, so it will need to be\n // rewritten later\n contextMenu: null,\n editingElement,\n viewModeEnabled,\n zenModeEnabled,\n gridSize,\n theme,\n name,\n errorMessage\n });\n }, () => {\n if (actionResult.syncHistory) {\n this.history.setCurrentState(this.state, this.scene.getElementsIncludingDeleted());\n }\n });\n }\n }); // Lifecycle\n\n this.onBlur = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isHoldingSpace = false;\n this.setState({\n isBindingEnabled: true\n });\n });\n\n this.onUnload = () => {\n this.onBlur();\n };\n\n this.disableEvent = event => {\n event.preventDefault();\n };\n\n this.resetHistory = () => {\n this.history.clear();\n };\n /**\n * Resets scene & history.\n * ! Do not use to clear scene user action !\n */\n\n\n this.resetScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(opts => {\n this.scene.replaceAllElements([]);\n this.setState(state => Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n isLoading: (opts === null || opts === void 0 ? void 0 : opts.resetLoadingState) ? false : state.isLoading,\n theme: this.state.theme\n }));\n this.resetHistory();\n });\n\n this.initializeScene = () => __awaiter(this, void 0, void 0, function* () {\n var _a;\n\n if (\"launchQueue\" in window && \"LaunchParams\" in window) {\n window.launchQueue.setConsumer(launchParams => __awaiter(this, void 0, void 0, function* () {\n if (!launchParams.files.length) {\n return;\n }\n\n const fileHandle = launchParams.files[0];\n const blob = yield fileHandle.getFile();\n this.loadFileToCanvas(new File([blob], blob.name || \"\", {\n type: blob.type\n }), fileHandle);\n }));\n }\n\n if (this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (!this.state.isLoading) {\n this.setState({\n isLoading: true\n });\n }\n\n let initialData = null;\n\n try {\n initialData = (yield this.props.initialData) || null;\n\n if (initialData === null || initialData === void 0 ? void 0 : initialData.libraryItems) {\n this.library.updateLibrary({\n libraryItems: initialData.libraryItems,\n merge: true\n }).catch(error => {\n console.error(error);\n });\n }\n } catch (error) {\n console.error(error);\n initialData = {\n appState: {\n errorMessage: error.message || \"Encountered an error during importing or restoring scene data\"\n }\n };\n }\n\n const scene = (0,_data_restore__WEBPACK_IMPORTED_MODULE_15__.restore)(initialData, null, null, {\n repairBindings: true\n });\n scene.appState = Object.assign(Object.assign({}, scene.appState), {\n theme: this.props.theme || scene.appState.theme,\n // we're falling back to current (pre-init) state when deciding\n // whether to open the library, to handle a case where we\n // update the state outside of initialData (e.g. when loading the app\n // with a library install link, which should auto-open the library)\n openSidebar: ((_a = scene.appState) === null || _a === void 0 ? void 0 : _a.openSidebar) || this.state.openSidebar,\n activeTool: scene.appState.activeTool.type === \"image\" ? Object.assign(Object.assign({}, scene.appState.activeTool), {\n type: \"selection\"\n }) : scene.appState.activeTool,\n isLoading: false,\n toast: this.state.toast\n });\n\n if (initialData === null || initialData === void 0 ? void 0 : initialData.scrollToContent) {\n scene.appState = Object.assign(Object.assign({}, scene.appState), (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(scene.elements, Object.assign(Object.assign({}, scene.appState), {\n width: this.state.width,\n height: this.state.height,\n offsetTop: this.state.offsetTop,\n offsetLeft: this.state.offsetLeft\n })));\n } // FontFaceSet loadingdone event we listen on may not always fire\n // (looking at you Safari), so on init we manually load fonts for current\n // text elements on canvas, and rerender them once done. This also\n // seems faster even in browsers that do fire the loadingdone event.\n\n\n this.fonts.loadFontsForElements(scene.elements);\n this.resetHistory();\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n commitToHistory: true\n }));\n });\n\n this.isMobileBreakpoint = (width, height) => {\n return width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_PORTRAIT || height < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_HEIGHT_LANDSCAPE && width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_LANDSCAPE;\n };\n\n this.refreshViewportBreakpoints = () => {\n const container = this.excalidrawContainerRef.current;\n\n if (!container) {\n return;\n }\n\n const {\n clientWidth: viewportWidth,\n clientHeight: viewportHeight\n } = document.body;\n const prevViewportState = this.device.viewport;\n const nextViewportState = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(prevViewportState, {\n isLandscape: viewportWidth > viewportHeight,\n isMobile: this.isMobileBreakpoint(viewportWidth, viewportHeight)\n });\n\n if (prevViewportState !== nextViewportState) {\n this.device = Object.assign(Object.assign({}, this.device), {\n viewport: nextViewportState\n });\n return true;\n }\n\n return false;\n };\n\n this.refreshEditorBreakpoints = () => {\n const container = this.excalidrawContainerRef.current;\n\n if (!container) {\n return;\n }\n\n const {\n width: editorWidth,\n height: editorHeight\n } = container.getBoundingClientRect();\n const sidebarBreakpoint = this.props.UIOptions.dockedSidebarBreakpoint != null ? this.props.UIOptions.dockedSidebarBreakpoint : _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_RIGHT_SIDEBAR_MIN_WIDTH;\n const prevEditorState = this.device.editor;\n const nextEditorState = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(prevEditorState, {\n isMobile: this.isMobileBreakpoint(editorWidth, editorHeight),\n canFitSidebar: editorWidth > sidebarBreakpoint\n });\n\n if (prevEditorState !== nextEditorState) {\n this.device = Object.assign(Object.assign({}, this.device), {\n editor: nextEditorState\n });\n return true;\n }\n\n return false;\n };\n\n this.onResize = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n this.scene.getElementsIncludingDeleted().forEach(element => _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element));\n this.refreshViewportBreakpoints();\n this.updateDOMRect();\n\n if (!supportsResizeObserver) {\n this.refreshEditorBreakpoints();\n }\n\n this.setState({});\n });\n\n this.renderInteractiveSceneCallback = ({\n atLeastOneVisibleElement,\n scrollBars,\n elements\n }) => {\n if (scrollBars) {\n currentScrollBars = scrollBars;\n }\n\n const scrolledOutside = // hide when editing text\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? false : !atLeastOneVisibleElement && elements.length > 0;\n\n if (this.state.scrolledOutside !== scrolledOutside) {\n this.setState({\n scrolledOutside\n });\n }\n\n this.scheduleImageRefresh();\n };\n\n this.onScroll = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n const {\n offsetTop,\n offsetLeft\n } = this.getCanvasOffsets();\n this.setState(state => {\n if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {\n return null;\n }\n\n return {\n offsetTop,\n offsetLeft\n };\n });\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.SCROLL_TIMEOUT); // Copy/paste\n\n this.onCut = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, \"keyboard\", event);\n event.preventDefault();\n event.stopPropagation();\n });\n this.onCopy = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, \"keyboard\", event);\n event.preventDefault();\n event.stopPropagation();\n });\n\n this.onTouchStart = event => {\n // fix for Apple Pencil Scribble\n // On Android, preventing the event would disable contextMenu on tap-hold\n if (!_constants__WEBPACK_IMPORTED_MODULE_12__.isAndroid) {\n event.preventDefault();\n }\n\n if (!didTapTwice) {\n didTapTwice = true;\n clearTimeout(tappedTwiceTimer);\n tappedTwiceTimer = window.setTimeout(App.resetTapTwice, _constants__WEBPACK_IMPORTED_MODULE_12__.TAP_TWICE_TIMEOUT);\n return;\n } // insert text only if we tapped twice with a single finger\n // event.touches.length === 1 will also prevent inserting text when user's zooming\n\n\n if (didTapTwice && event.touches.length === 1) {\n const touch = event.touches[0]; // @ts-ignore\n\n this.handleCanvasDoubleClick({\n clientX: touch.clientX,\n clientY: touch.clientY\n });\n didTapTwice = false;\n clearTimeout(tappedTwiceTimer);\n }\n\n if (_constants__WEBPACK_IMPORTED_MODULE_12__.isAndroid) {\n event.preventDefault();\n }\n\n if (event.touches.length === 2) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n };\n\n this.onTouchEnd = event => {\n this.resetContextMenuTimer();\n\n if (event.touches.length > 0) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n } else {\n gesture.pointers.clear();\n }\n };\n\n this.pasteFromClipboard = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => __awaiter(this, void 0, void 0, function* () {\n var _b, _c, _d;\n\n const isPlainPaste = !!IS_PLAIN_PASTE; // #686\n\n const target = document.activeElement;\n const isExcalidrawActive = (_b = this.excalidrawContainerRef.current) === null || _b === void 0 ? void 0 : _b.contains(target);\n\n if (event && !isExcalidrawActive) {\n return;\n }\n\n const elementUnderCursor = document.elementFromPoint(this.lastViewportPosition.x, this.lastViewportPosition.y);\n\n if (event && (!(elementUnderCursor instanceof HTMLCanvasElement) || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(target))) {\n return;\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state); // must be called in the same frame (thus before any awaits) as the paste\n // event else some browsers (FF...) will clear the clipboardData\n // (something something security)\n\n let file = (_c = event === null || event === void 0 ? void 0 : event.clipboardData) === null || _c === void 0 ? void 0 : _c.files[0];\n const data = yield (0,_clipboard__WEBPACK_IMPORTED_MODULE_11__.parseClipboard)(event, isPlainPaste);\n\n if (!file && !isPlainPaste) {\n if (data.mixedContent) {\n return this.addElementsFromMixedContentPaste(data.mixedContent, {\n isPlainPaste,\n sceneX,\n sceneY\n });\n } else if (data.text) {\n const string = data.text.trim();\n\n if (string.startsWith(\"<svg\") && string.endsWith(\"</svg>\")) {\n // ignore SVG validation/normalization which will be done during image\n // initialization\n file = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(string);\n }\n }\n } // prefer spreadsheet data over image file (MS Office/Libre Office)\n\n\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(file) && !data.spreadsheet) {\n if (!this.isToolSupported(\"image\")) {\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageToolNotSupported\")\n });\n return;\n }\n\n const imageElement = this.createImageElement({\n sceneX,\n sceneY\n });\n this.insertImageElement(imageElement, file);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n });\n return;\n }\n\n if (this.props.onPaste) {\n try {\n if ((yield this.props.onPaste(data, event)) === false) {\n return;\n }\n } catch (error) {\n console.error(error);\n }\n }\n\n if (data.errorMessage) {\n this.setState({\n errorMessage: data.errorMessage\n });\n } else if (data.spreadsheet && !isPlainPaste) {\n this.setState({\n pasteDialog: {\n data: data.spreadsheet,\n shown: true\n }\n });\n } else if (data.elements) {\n const elements = data.programmaticAPI ? (0,_data_transform__WEBPACK_IMPORTED_MODULE_62__.convertToExcalidrawElements)(data.elements) : data.elements; // TODO remove formatting from elements if isPlainPaste\n\n this.addElementsFromPasteOrLibrary({\n elements,\n files: data.files || null,\n position: \"cursor\",\n retainSeed: isPlainPaste\n });\n } else if (data.text) {\n const maybeUrl = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.extractSrc)(data.text);\n\n if (!isPlainPaste && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(maybeUrl, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(maybeUrl) || ((_d = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(maybeUrl)) === null || _d === void 0 ? void 0 : _d.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(maybeUrl)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n\n return;\n }\n\n this.addTextFromPaste(data.text, isPlainPaste);\n }\n\n this.setActiveTool({\n type: \"selection\"\n });\n event === null || event === void 0 ? void 0 : event.preventDefault();\n }));\n\n this.addElementsFromPasteOrLibrary = opts => {\n const elements = (0,_data_restore__WEBPACK_IMPORTED_MODULE_15__.restoreElements)(opts.elements, null, undefined);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(elements);\n const elementsCenterX = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minX, maxX) / 2;\n const elementsCenterY = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minY, maxY) / 2;\n const clientX = typeof opts.position === \"object\" ? opts.position.clientX : opts.position === \"cursor\" ? this.lastViewportPosition.x : this.state.width / 2 + this.state.offsetLeft;\n const clientY = typeof opts.position === \"object\" ? opts.position.clientY : opts.position === \"cursor\" ? this.lastViewportPosition.y : this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const dx = x - elementsCenterX;\n const dy = y - elementsCenterY;\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(dx, dy, this.state.gridSize);\n const newElements = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.duplicateElements)(elements.map(element => {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n x: element.x + gridX - minX,\n y: element.y + gridY - minY\n });\n }), {\n randomizeSeed: !opts.retainSeed\n });\n const nextElements = [...this.scene.getElementsIncludingDeleted(), ...newElements];\n this.scene.replaceAllElements(nextElements);\n newElements.forEach(newElement => {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(newElement) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(newElement)) {\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerElement)(newElement);\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.redrawTextBoundingBox)(newElement, container);\n }\n });\n\n if (opts.files) {\n this.files = Object.assign(Object.assign({}, this.files), opts.files);\n }\n\n this.history.resumeRecording();\n const nextElementsToSelect = (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.excludeElementsInFramesFromSelection)(newElements);\n this.setState(Object.assign(Object.assign(Object.assign({}, this.state), {\n // keep sidebar (presumably the library) open if it's docked and\n // can fit.\n //\n // Note, we should close the sidebar only if we're dropping items\n // from library, not when pasting from clipboard. Alas.\n openSidebar: this.state.openSidebar && this.device.editor.canFitSidebar && _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.get(_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_63__.isSidebarDockedAtom) ? this.state.openSidebar : null\n }), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: null,\n selectedElementIds: nextElementsToSelect.reduce((acc, element) => {\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(element)) {\n acc[element.id] = true;\n }\n\n return acc;\n }, {})\n }, this.scene.getNonDeletedElements(), this.state, this)), () => {\n if (opts.files) {\n this.addNewImagesToImageCache();\n }\n });\n this.setActiveTool({\n type: \"selection\"\n });\n\n if (opts.fitToContent) {\n this.scrollToContent(newElements, {\n fitToContent: true\n });\n }\n };\n\n this.setAppState = (state, callback) => {\n this.setState(state, callback);\n };\n\n this.removePointer = event => {\n if (touchTimeout) {\n this.resetContextMenuTimer();\n }\n\n gesture.pointers.delete(event.pointerId);\n };\n\n this.toggleLock = (source = \"ui\") => {\n if (!this.state.activeTool.locked) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", \"toggleLock\", `${source} (${this.device.editor.isMobile ? \"mobile\" : \"desktop\"})`);\n }\n\n this.setState(prevState => {\n return {\n activeTool: Object.assign(Object.assign(Object.assign({}, prevState.activeTool), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, prevState.activeTool.locked ? {\n type: \"selection\"\n } : prevState.activeTool)), {\n locked: !prevState.activeTool.locked\n })\n };\n });\n };\n\n this.updateFrameRendering = opts => {\n this.setState(prevState => {\n var _a, _b, _c, _d;\n\n const next = typeof opts === \"function\" ? opts(prevState.frameRendering) : opts;\n return {\n frameRendering: {\n enabled: (_a = next === null || next === void 0 ? void 0 : next.enabled) !== null && _a !== void 0 ? _a : prevState.frameRendering.enabled,\n clip: (_b = next === null || next === void 0 ? void 0 : next.clip) !== null && _b !== void 0 ? _b : prevState.frameRendering.clip,\n name: (_c = next === null || next === void 0 ? void 0 : next.name) !== null && _c !== void 0 ? _c : prevState.frameRendering.name,\n outline: (_d = next === null || next === void 0 ? void 0 : next.outline) !== null && _d !== void 0 ? _d : prevState.frameRendering.outline\n }\n };\n });\n };\n\n this.togglePenMode = force => {\n this.setState(prevState => {\n return {\n penMode: force !== null && force !== void 0 ? force : !prevState.penMode,\n penDetected: true\n };\n });\n };\n\n this.onHandToolToggle = () => {\n this.actionManager.executeAction(_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.actionToggleHandTool);\n };\n /**\n * Zooms on canvas viewport center\n */\n\n\n this.zoomCanvas = (\n /** decimal fraction between 0.1 (10% zoom) and 30 (3000% zoom) */\n value) => {\n this.setState(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.state.width / 2 + this.state.offsetLeft,\n viewportY: this.state.height / 2 + this.state.offsetTop,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(value)\n }, this.state)));\n };\n\n this.cancelInProgresAnimation = null;\n\n this.scrollToContent = (target = this.scene.getNonDeletedElements(), opts) => {\n var _a, _b;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this); // convert provided target into ExcalidrawElement[] if necessary\n\n const targetElements = Array.isArray(target) ? target : [target];\n let zoom = this.state.zoom;\n let scrollX = this.state.scrollX;\n let scrollY = this.state.scrollY;\n\n if ((opts === null || opts === void 0 ? void 0 : opts.fitToContent) || (opts === null || opts === void 0 ? void 0 : opts.fitToViewport)) {\n const {\n appState\n } = (0,_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.zoomToFit)({\n targetElements,\n appState: this.state,\n fitToViewport: !!(opts === null || opts === void 0 ? void 0 : opts.fitToViewport),\n viewportZoomFactor: opts === null || opts === void 0 ? void 0 : opts.viewportZoomFactor\n });\n zoom = appState.zoom;\n scrollX = appState.scrollX;\n scrollY = appState.scrollY;\n } else {\n // compute only the viewport location, without any zoom adjustment\n const scroll = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(targetElements, this.state);\n scrollX = scroll.scrollX;\n scrollY = scroll.scrollY;\n } // when animating, we use RequestAnimationFrame to prevent the animation\n // from slowing down other processes\n\n\n if (opts === null || opts === void 0 ? void 0 : opts.animate) {\n const origScrollX = this.state.scrollX;\n const origScrollY = this.state.scrollY;\n const origZoom = this.state.zoom.value;\n const cancel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeToValuesRAF)({\n fromValues: {\n scrollX: origScrollX,\n scrollY: origScrollY,\n zoom: origZoom\n },\n toValues: {\n scrollX,\n scrollY,\n zoom: zoom.value\n },\n interpolateValue: (from, to, progress, key) => {\n // for zoom, use different easing\n if (key === \"zoom\") {\n return from * Math.pow(to / from, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeOut)(progress));\n } // handle using default\n\n\n return undefined;\n },\n onStep: ({\n scrollX,\n scrollY,\n zoom\n }) => {\n this.setState({\n scrollX,\n scrollY,\n zoom: {\n value: zoom\n }\n });\n },\n onStart: () => {\n this.setState({\n shouldCacheIgnoreZoom: true\n });\n },\n onEnd: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n onCancel: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n duration: (_b = opts === null || opts === void 0 ? void 0 : opts.duration) !== null && _b !== void 0 ? _b : 500\n });\n\n this.cancelInProgresAnimation = () => {\n cancel();\n this.cancelInProgresAnimation = null;\n };\n } else {\n this.setState({\n scrollX,\n scrollY,\n zoom\n });\n }\n };\n /** use when changing scrollX/scrollY/zoom based on user interaction */\n\n\n this.translateCanvas = state => {\n var _a;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this);\n this.setState(state);\n };\n\n this.setToast = toast => {\n this.setState({\n toast\n });\n };\n\n this.restoreFileFromShare = () => __awaiter(this, void 0, void 0, function* () {\n try {\n const webShareTargetCache = yield caches.open(\"web-share-target\");\n const response = yield webShareTargetCache.match(\"shared-file\");\n\n if (response) {\n const blob = yield response.blob();\n const file = new File([blob], blob.name || \"\", {\n type: blob.type\n });\n this.loadFileToCanvas(file, null);\n yield webShareTargetCache.delete(\"shared-file\");\n window.history.replaceState(null, _constants__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, window.location.pathname);\n }\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n });\n /** adds supplied files to existing files in the appState */\n\n\n this.addFiles = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(files => {\n const filesMap = files.reduce((acc, fileData) => {\n acc.set(fileData.id, fileData);\n return acc;\n }, new Map());\n this.files = Object.assign(Object.assign({}, this.files), Object.fromEntries(filesMap));\n this.scene.getNonDeletedElements().forEach(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && filesMap.has(element.fileId)) {\n this.imageCache.delete(element.fileId);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element);\n }\n });\n this.scene.informMutation();\n this.addNewImagesToImageCache();\n });\n this.updateScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(sceneData => {\n if (sceneData.commitToHistory) {\n this.history.resumeRecording();\n }\n\n if (sceneData.appState) {\n this.setState(sceneData.appState);\n }\n\n if (sceneData.elements) {\n this.scene.replaceAllElements(sceneData.elements);\n }\n\n if (sceneData.collaborators) {\n this.setState({\n collaborators: sceneData.collaborators\n });\n }\n });\n\n this.onSceneUpdated = () => {\n this.setState({});\n };\n /**\n * @returns whether the menu was toggled on or off\n */\n\n\n this.toggleSidebar = ({\n name,\n tab,\n force\n }) => {\n var _a;\n\n let nextName;\n\n if (force === undefined) {\n nextName = ((_a = this.state.openSidebar) === null || _a === void 0 ? void 0 : _a.name) === name ? null : name;\n } else {\n nextName = force ? name : null;\n }\n\n this.setState({\n openSidebar: nextName ? {\n name: nextName,\n tab\n } : null\n });\n return !!nextName;\n };\n\n this.updateCurrentCursorPosition = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n this.lastViewportPosition.x = event.clientX;\n this.lastViewportPosition.y = event.clientY;\n }); // Input handling\n\n this.onKeyDown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // normalize `event.key` when CapsLock is pressed #2372\n if (\"Proxy\" in window && (!event.shiftKey && /^[A-Z]$/.test(event.key) || event.shiftKey && /^[a-z]$/.test(event.key))) {\n event = new Proxy(event, {\n get(ev, prop) {\n const value = ev[prop];\n\n if (typeof value === \"function\") {\n // fix for Proxies hijacking `this`\n return value.bind(ev);\n }\n\n return prop === \"key\" ? // CapsLock inverts capitalization based on ShiftKey, so invert\n // it back\n event.shiftKey ? ev.key.toUpperCase() : ev.key.toLowerCase() : value;\n }\n\n });\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.V) {\n IS_PLAIN_PASTE = event.shiftKey;\n clearTimeout(IS_PLAIN_PASTE_TIMER); // reset (100ms to be safe that we it runs after the ensuing\n // paste event). Though, technically unnecessary to reset since we\n // (re)set the flag before each paste event.\n\n IS_PLAIN_PASTE_TIMER = window.setTimeout(() => {\n IS_PLAIN_PASTE = false;\n }, 100);\n } // prevent browser zoom in input fields\n\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n if (event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.MINUS || event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.EQUAL) {\n event.preventDefault();\n return;\n }\n } // bail if\n\n\n if ( // inside an input\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target) && // unless pressing escape (finalize action)\n event.key !== _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ESCAPE || // or unless using arrows (to move between buttons)\n (0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key) && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isInputLike)(event.target)) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.QUESTION_MARK) {\n this.setState({\n openDialog: \"help\"\n });\n return;\n } else if (event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.E && event.shiftKey && event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n event.preventDefault();\n this.setState({\n openDialog: \"imageExport\"\n });\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_UP || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n let offset = (event.shiftKey ? this.state.width : this.state.height) / this.state.zoom.value;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n offset = -offset;\n }\n\n if (event.shiftKey) {\n this.translateCanvas(state => ({\n scrollX: state.scrollX + offset\n }));\n } else {\n this.translateCanvas(state => ({\n scrollY: state.scrollY + offset\n }));\n }\n }\n\n if (this.actionManager.handleKeyDown(event)) {\n return;\n }\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: false\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const step = this.state.gridSize && (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize) || (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_SHIFT_TRANSLATE_AMOUNT : _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT);\n let offsetX = 0;\n let offsetY = 0;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_LEFT) {\n offsetX = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_RIGHT) {\n offsetX = step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_UP) {\n offsetY = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_DOWN) {\n offsetY = step;\n }\n\n const selectedElements = this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n });\n selectedElements.forEach(element => {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: element.x + offsetX,\n y: element.y + offsetY\n });\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element, {\n simultaneouslyUpdated: selectedElements\n });\n });\n this.maybeSuggestBindingForAll(selectedElements);\n event.preventDefault();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ENTER) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n const selectedElement = selectedElements[0];\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElement)) {\n if (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElement, this.scene)\n });\n }\n }\n } else if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isValidTextContainer)(selectedElement)) {\n let container;\n\n if (!(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement)) {\n container = selectedElement;\n }\n\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(selectedElement, this.state);\n const sceneX = midPoint.x;\n const sceneY = midPoint.y;\n this.startTextEditing({\n sceneX,\n sceneY,\n container\n });\n event.preventDefault();\n return;\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(selectedElement)) {\n this.setState({\n editingFrame: selectedElement.id\n });\n }\n }\n } else if (!event.ctrlKey && !event.altKey && !event.metaKey && this.state.draggingElement === null) {\n const shape = (0,_shapes__WEBPACK_IMPORTED_MODULE_32__.findShapeByKey)(event.key);\n\n if (shape) {\n if (this.state.activeTool.type !== shape) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", shape, `keyboard (${this.device.editor.isMobile ? \"mobile\" : \"desktop\"})`);\n }\n\n this.setActiveTool({\n type: shape\n });\n event.stopPropagation();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.Q) {\n this.toggleLock(\"keyboard\");\n event.stopPropagation();\n }\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE && gesture.pointers.size === 0) {\n isHoldingSpace = true;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n event.preventDefault();\n }\n\n if ((event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (this.state.activeTool.type === \"selection\" && !selectedElements.length) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && ((0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(this.state.activeTool.type) || selectedElements.some(element => (0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(element.type)))) {\n this.setState({\n openPopup: \"elementBackground\"\n });\n event.stopPropagation();\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) {\n this.setState({\n openPopup: \"elementStroke\"\n });\n event.stopPropagation();\n }\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.K && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if (this.state.activeTool.type === \"laser\") {\n this.setActiveTool({\n type: \"selection\"\n });\n } else {\n this.setActiveTool({\n type: \"laser\"\n });\n }\n\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.BACKSPACE || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.DELETE)) {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__.activeConfirmDialogAtom, \"clearCanvas\");\n } // eye dropper\n // -----------------------------------------------------------------------\n\n\n const lowerCased = event.key.toLocaleLowerCase();\n const isPickingStroke = lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S && event.shiftKey;\n const isPickingBackground = event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.I || lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && event.shiftKey;\n\n if (isPickingStroke || isPickingBackground) {\n this.openEyeDropper({\n type: isPickingStroke ? \"stroke\" : \"background\"\n });\n } // -----------------------------------------------------------------------\n\n });\n this.onWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // prevent browser pinch zoom on DOM elements\n if (!(event.target instanceof HTMLCanvasElement) && event.ctrlKey) {\n event.preventDefault();\n }\n });\n this.onKeyUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE) {\n if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (this.state.activeTool.type === \"selection\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n isHoldingSpace = false;\n }\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: true\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements)(selectedElements) : (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(selectedElements);\n this.setState({\n suggestedBindings: []\n });\n }\n }); // We purposely widen the `tool` type so this helper can be called with\n // any tool without having to type check it\n\n this.isToolSupported = tool => {\n var _a;\n\n return ((_a = this.props.UIOptions.tools) === null || _a === void 0 ? void 0 : _a[tool]) !== false;\n };\n\n this.setActiveTool = tool => {\n var _a;\n\n if (!this.isToolSupported(tool.type)) {\n console.warn(`\"${tool.type}\" tool is disabled via \"UIOptions.canvasActions.tools.${tool.type}\"`);\n return;\n }\n\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, tool);\n\n if (nextActiveTool.type === \"hand\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (!isHoldingSpace) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_33__.isToolIcon)(document.activeElement)) {\n this.focusContainer();\n }\n\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElementType)(nextActiveTool.type)) {\n this.setState({\n suggestedBindings: []\n });\n }\n\n if (nextActiveTool.type === \"image\") {\n this.onImageAction({\n insertOnCanvasDirectly: (_a = tool.type === \"image\" && tool.insertOnCanvasDirectly) !== null && _a !== void 0 ? _a : false\n });\n }\n\n this.setState(prevState => {\n const commonResets = {\n snapLines: prevState.snapLines.length ? [] : prevState.snapLines,\n originSnapOffset: null,\n activeEmbeddable: null\n };\n\n if (nextActiveTool.type !== \"selection\") {\n return Object.assign(Object.assign(Object.assign({}, prevState), {\n activeTool: nextActiveTool,\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n selectedGroupIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n editingGroupId: null,\n multiElement: null\n }), commonResets);\n }\n\n return Object.assign(Object.assign(Object.assign({}, prevState), {\n activeTool: nextActiveTool\n }), commonResets);\n });\n };\n\n this.setOpenDialog = dialogType => {\n this.setState({\n openDialog: dialogType\n });\n };\n\n this.setCursor = cursor => {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, cursor);\n };\n\n this.resetCursor = () => {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n };\n /**\n * returns whether user is making a gesture with >= 2 fingers (points)\n * on o touch screen (not on a trackpad). Currently only relates to Darwin\n * (iOS/iPadOS,MacOS), but may work on other devices in the future if\n * GestureEvent is standardized.\n */\n\n\n this.isTouchScreenMultiTouchGesture = () => {\n // we don't want to deselect when using trackpad, and multi-point gestures\n // only work on touch screens, so checking for >= pointers means we're on a\n // touchscreen\n return gesture.pointers.size >= 2;\n }; // fires only on Safari\n\n\n this.onGestureStart = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // we only want to deselect on touch screens because user may have selected\n // elements by mistake while zooming\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n\n gesture.initialScale = this.state.zoom.value;\n }); // fires only on Safari\n\n this.onGestureChange = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // onGestureChange only has zoom factor but not the center.\n // If we're on iPad or iPhone, then we recognize multi-touch and will\n // zoom in at the right location in the touchmove handler\n // (handleCanvasPointerMove).\n //\n // On Macbook trackpad, we don't have those events so will zoom in at the\n // current location instead.\n //\n // As such, bail from this handler on touch devices.\n\n if (this.isTouchScreenMultiTouchGesture()) {\n return;\n }\n\n const initialScale = gesture.initialScale;\n\n if (initialScale) {\n this.setState(state => Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * event.scale)\n }, state)));\n }\n }); // fires only on Safari\n\n this.onGestureEnd = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // reselect elements only on touch screens (see onGestureStart)\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n }\n\n gesture.initialScale = null;\n });\n\n this.startTextEditing = ({\n sceneX,\n sceneY,\n insertAtParentCenter = true,\n container\n }) => {\n var _a, _b;\n\n let shouldBindToContainer = false;\n let parentCenterPosition = insertAtParentCenter && this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n\n if (container && parentCenterPosition) {\n const boundTextElementToContainer = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(container);\n\n if (!boundTextElementToContainer) {\n shouldBindToContainer = true;\n }\n }\n\n let existingTextElement = null;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElements[0])) {\n existingTextElement = selectedElements[0];\n } else if (container) {\n existingTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(selectedElements[0]);\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n\n const fontFamily = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.fontFamily) || this.state.currentItemFontFamily;\n const lineHeight = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.lineHeight) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(fontFamily);\n const fontSize = this.state.currentItemFontSize;\n\n if (!existingTextElement && shouldBindToContainer && container && !(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isArrowElement)(container)) {\n const fontString = {\n fontSize,\n fontFamily\n };\n const minWidth = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineWidth)((0,_utils__WEBPACK_IMPORTED_MODULE_33__.getFontString)(fontString), lineHeight);\n const minHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineHeight)(fontSize, lineHeight);\n const newHeight = Math.max(container.height, minHeight);\n const newWidth = Math.max(container.width, minWidth);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n height: newHeight,\n width: newWidth\n });\n sceneX = container.x + newWidth / 2;\n sceneY = container.y + newHeight / 2;\n\n if (parentCenterPosition) {\n parentCenterPosition = this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n }\n }\n\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: sceneX,\n y: sceneY\n });\n const element = existingTextElement ? existingTextElement : (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)({\n x: parentCenterPosition ? parentCenterPosition.elementCenterX : sceneX,\n y: parentCenterPosition ? parentCenterPosition.elementCenterY : sceneY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text: \"\",\n fontSize,\n fontFamily,\n textAlign: parentCenterPosition ? \"center\" : this.state.currentItemTextAlign,\n verticalAlign: parentCenterPosition ? _constants__WEBPACK_IMPORTED_MODULE_12__.VERTICAL_ALIGN.MIDDLE : _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n containerId: shouldBindToContainer ? container === null || container === void 0 ? void 0 : container.id : undefined,\n groupIds: (_a = container === null || container === void 0 ? void 0 : container.groupIds) !== null && _a !== void 0 ? _a : [],\n lineHeight,\n angle: (_b = container === null || container === void 0 ? void 0 : container.angle) !== null && _b !== void 0 ? _b : 0,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n\n if (!existingTextElement && shouldBindToContainer && container) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n boundElements: (container.boundElements || []).concat({\n type: \"text\",\n id: element.id\n })\n });\n }\n\n this.setState({\n editingElement: element\n });\n\n if (!existingTextElement) {\n if (container && shouldBindToContainer) {\n const containerIndex = this.scene.getElementIndex(container.id);\n this.scene.insertElementAtIndex(element, containerIndex + 1);\n } else {\n this.scene.addNewElement(element);\n }\n }\n\n this.setState({\n editingElement: element\n });\n this.handleTextWysiwyg(element, {\n isExistingElement: !!existingTextElement\n });\n };\n\n this.handleCanvasDoubleClick = event => {\n // case: double-clicking with arrow/line tool selected would both create\n // text and enter multiElement mode\n if (this.state.multiElement) {\n return;\n } // we should only be able to double click when mode is selection\n\n\n if (this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0])) {\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id)) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElements[0], this.scene)\n });\n return;\n } else if (this.state.editingLinearElement && this.state.editingLinearElement.elementId === selectedElements[0].id) {\n return;\n }\n }\n\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n let {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedGroupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIds)(this.state);\n\n if (selectedGroupIds.length > 0) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n const selectedGroupId = hitElement && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIdForElement)(hitElement, this.state.selectedGroupIds);\n\n if (selectedGroupId) {\n this.setState(prevState => Object.assign(Object.assign({}, prevState), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: selectedGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)));\n return;\n }\n }\n\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.viewModeEnabled) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) {\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"active\"\n }\n });\n return;\n }\n\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if (container) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(container) || !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTransparent)(container.backgroundColor) || (0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY])) {\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, this.state);\n sceneX = midPoint.x;\n sceneY = midPoint.y;\n }\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n }\n };\n\n this.getElementLinkAtPosition = (scenePointer, hitElement) => {\n // Reversing so we traverse the elements in decreasing order\n // of z-index\n const elements = this.scene.getNonDeletedElements().slice().reverse();\n let hitElementIndex = Infinity;\n return elements.find((element, index) => {\n if (hitElement && element.id === hitElement.id) {\n hitElementIndex = index;\n }\n\n return element.link && index <= hitElementIndex && (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(element, this.state, [scenePointer.x, scenePointer.y], this.device.editor.isMobile);\n });\n };\n\n this.redirectToLink = (event, isTouchScreen) => {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDownEvent.clientX, this.lastPointerDownEvent.clientY, this.lastPointerUpEvent.clientX, this.lastPointerUpEvent.clientY);\n\n if (!this.hitLinkElement || // For touch screen allow dragging threshold else strict check\n isTouchScreen && draggedDistance > _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD || !isTouchScreen && draggedDistance !== 0) {\n return;\n }\n\n const lastPointerDownCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerDownEvent, this.state);\n const lastPointerDownHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerDownCoords.x, lastPointerDownCoords.y], this.device.editor.isMobile);\n const lastPointerUpCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerUpEvent, this.state);\n const lastPointerUpHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerUpCoords.x, lastPointerUpCoords.y], this.device.editor.isMobile);\n\n if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {\n let url = this.hitLinkElement.link;\n\n if (url) {\n url = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(url);\n let customEvent;\n\n if (this.props.onLinkOpen) {\n customEvent = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.wrapEvent)(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.EXCALIDRAW_LINK, event.nativeEvent);\n this.props.onLinkOpen(Object.assign(Object.assign({}, this.hitLinkElement), {\n link: url\n }), customEvent);\n }\n\n if (!(customEvent === null || customEvent === void 0 ? void 0 : customEvent.defaultPrevented)) {\n const target = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.isLocalLink)(url) ? \"_self\" : \"_blank\";\n const newWindow = window.open(undefined, target); // https://mathiasbynens.github.io/rel-noopener/\n\n if (newWindow) {\n newWindow.opener = null;\n newWindow.location = url;\n }\n }\n }\n }\n };\n\n this.getTopLayerFrameAtSceneCoords = sceneCoords => {\n const frames = this.scene.getNonDeletedFrames().filter(frame => (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)(sceneCoords, frame));\n return frames.length ? frames[frames.length - 1] : null;\n };\n\n this.handleCanvasPointerMove = event => {\n var _a, _b;\n\n this.savePointer(event.clientX, event.clientY, this.state.cursorButton);\n\n if (gesture.pointers.has(event.pointerId)) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n }\n\n const initialScale = gesture.initialScale;\n\n if (gesture.pointers.size === 2 && gesture.lastCenter && initialScale && gesture.initialDistance) {\n const center = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n const deltaX = center.x - gesture.lastCenter.x;\n const deltaY = center.y - gesture.lastCenter.y;\n gesture.lastCenter = center;\n const distance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n const scaleFactor = this.state.activeTool.type === \"freedraw\" && this.state.penMode ? 1 : distance / gesture.initialDistance;\n const nextZoom = scaleFactor ? (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * scaleFactor) : this.state.zoom.value;\n this.setState(state => {\n const zoomState = (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: center.x,\n viewportY: center.y,\n nextZoom\n }, state);\n this.translateCanvas({\n zoom: zoomState.zoom,\n scrollX: zoomState.scrollX + deltaX / nextZoom,\n scrollY: zoomState.scrollY + deltaY / nextZoom,\n shouldCacheIgnoreZoom: true\n });\n });\n this.resetShouldCacheIgnoreZoomDebounced();\n } else {\n gesture.lastCenter = gesture.initialDistance = gesture.initialScale = null;\n }\n\n if (isHoldingSpace || isPanning || isDraggingScrollBar || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state)) {\n return;\n }\n\n const isPointerOverScrollBars = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop);\n const isOverScrollBar = isPointerOverScrollBars.isOverEither;\n\n if (!this.state.draggingElement && !this.state.multiElement) {\n if (isOverScrollBar) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const {\n x: scenePointerX,\n y: scenePointerY\n } = scenePointer;\n\n if (!this.state.draggingElement && (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.isActiveToolNonLinearSnappable)(this.state.activeTool.type)) {\n const {\n originOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.getSnapLinesAtPointer)(this.scene.getNonDeletedElements(), this.state, {\n x: scenePointerX,\n y: scenePointerY\n }, event);\n this.setState({\n snapLines,\n originSnapOffset: originOffset\n });\n } else if (!this.state.draggingElement) {\n this.setState({\n snapLines: []\n });\n }\n\n if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerMove(event, scenePointerX, scenePointerY, this.state);\n\n if (editingLinearElement && editingLinearElement !== this.state.editingLinearElement) {\n // Since we are reading from previous state which is not possible with\n // automatic batching in React 18 hence using flush sync to synchronously\n // update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n this.setState({\n editingLinearElement\n });\n });\n }\n\n if ((editingLinearElement === null || editingLinearElement === void 0 ? void 0 : editingLinearElement.lastUncommittedPoint) != null) {\n this.maybeSuggestBindingAtCursor(scenePointer);\n } else {\n // causes stack overflow if not sync\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n this.setState({\n suggestedBindings: []\n });\n });\n }\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElementType)(this.state.activeTool.type)) {\n // Hovering with a selected tool or creating new linear element via click\n // and point\n const {\n draggingElement\n } = this.state;\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [scenePointer], this.state.startBoundElement);\n } else {\n this.maybeSuggestBindingAtCursor(scenePointer);\n }\n }\n\n if (this.state.multiElement) {\n const {\n multiElement\n } = this.state;\n const {\n x: rx,\n y: ry\n } = multiElement;\n const {\n points,\n lastCommittedPoint\n } = multiElement;\n const lastPoint = points[points.length - 1];\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n\n if (lastPoint === lastCommittedPoint) {\n // if we haven't yet created a temp point and we're beyond commit-zone\n // threshold, add a point\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(scenePointerX - rx, scenePointerY - ry, lastPoint[0], lastPoint[1]) >= _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: [...points, [scenePointerX - rx, scenePointerY - ry]]\n });\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER); // in this branch, we're inside the commit zone, and no uncommitted\n // point exists. Thus do nothing (don't add/remove points).\n }\n } else if (points.length > 2 && lastCommittedPoint && (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(scenePointerX - rx, scenePointerY - ry, lastCommittedPoint[0], lastCommittedPoint[1]) < _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: points.slice(0, -1)\n });\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(scenePointerX, scenePointerY, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const [lastCommittedX, lastCommittedY] = (_a = multiElement === null || multiElement === void 0 ? void 0 : multiElement.lastCommittedPoint) !== null && _a !== void 0 ? _a : [0, 0];\n let dxFromLastCommitted = gridX - rx - lastCommittedX;\n let dyFromLastCommitted = gridY - ry - lastCommittedY;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event)) {\n ({\n width: dxFromLastCommitted,\n height: dyFromLastCommitted\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)( // actual coordinate of the last committed point\n lastCommittedX + rx, lastCommittedY + ry, // cursor-grid coordinate\n gridX, gridY));\n }\n\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.isPathALoop)(points, this.state.zoom.value)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } // update last uncommitted point\n\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: [...points.slice(0, -1), [lastCommittedX + dxFromLastCommitted, lastCommittedY + dyFromLastCommitted]]\n });\n }\n\n return;\n }\n\n const hasDeselectedButton = Boolean(event.buttons);\n\n if (hasDeselectedButton || this.state.activeTool.type !== \"selection\" && this.state.activeTool.type !== \"text\" && this.state.activeTool.type !== \"eraser\") {\n return;\n }\n\n const elements = this.scene.getNonDeletedElements();\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && !isOverScrollBar && !this.state.editingLinearElement) {\n const elementWithTransformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getElementWithTransformHandleType)(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType);\n\n if (elementWithTransformHandleType && elementWithTransformHandleType.transformHandleType) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCursorForResizingElement)(elementWithTransformHandleType));\n return;\n }\n } else if (selectedElements.length > 1 && !isOverScrollBar) {\n const transformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getTransformHandleTypeFromCoords)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType);\n\n if (transformHandleType) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCursorForResizingElement)({\n transformHandleType\n }));\n return;\n }\n }\n\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n this.hitLinkElement = this.getElementLinkAtPosition(scenePointer, hitElement);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n return;\n }\n\n if (this.hitLinkElement && !this.state.selectedElementIds[this.hitLinkElement.id]) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.showHyperlinkTooltip)(this.hitLinkElement, this.state);\n } else {\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.hideHyperlinkToolip)();\n\n if (hitElement && (hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) && this.state.selectedElementIds[hitElement.id] && !this.state.contextMenu && !this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: \"info\"\n });\n } else if (this.state.activeTool.type === \"text\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(hitElement) ? _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.TEXT : _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.CROSSHAIR);\n } else if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (isOverScrollBar) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n } else if (this.state.selectedLinearElement) {\n this.handleHoverSelectedLinearElement(this.state.selectedLinearElement, scenePointerX, scenePointerY);\n } else if ( // if using cmd/ctrl, we're not dragging\n !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((hitElement || this.isHittingCommonBoundingBoxOfSelectedElements(scenePointer, selectedElements)) && !(hitElement === null || hitElement === void 0 ? void 0 : hitElement.locked)) {\n if (hitElement && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, event, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"hover\"\n }\n });\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n\n if (((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"hover\") {\n this.setState({\n activeEmbeddable: null\n });\n }\n }\n }\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n };\n\n this.handleEraser = (event, pointerDownState, scenePointer) => {\n const updateElementIds = elements => {\n elements.forEach(element => {\n if (element.locked) {\n return;\n }\n\n idsToUpdate.push(element.id);\n\n if (event.altKey) {\n if (pointerDownState.elementIdsToErase[element.id] && pointerDownState.elementIdsToErase[element.id].erase) {\n pointerDownState.elementIdsToErase[element.id].erase = false;\n }\n } else if (!pointerDownState.elementIdsToErase[element.id]) {\n pointerDownState.elementIdsToErase[element.id] = {\n erase: true,\n opacity: element.opacity\n };\n }\n });\n };\n\n const idsToUpdate = [];\n const distance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y, scenePointer.x, scenePointer.y);\n const threshold = 10 / this.state.zoom.value;\n const point = Object.assign({}, pointerDownState.lastCoords);\n let samplingInterval = 0;\n\n while (samplingInterval <= distance) {\n const hitElements = this.getElementsAtPosition(point.x, point.y);\n updateElementIds(hitElements); // Exit since we reached current point\n\n if (samplingInterval === distance) {\n break;\n } // Calculate next point in the line at a distance of sampling interval\n\n\n samplingInterval = Math.min(samplingInterval + threshold, distance);\n const distanceRatio = samplingInterval / distance;\n const nextX = (1 - distanceRatio) * point.x + distanceRatio * scenePointer.x;\n const nextY = (1 - distanceRatio) * point.y + distanceRatio * scenePointer.y;\n point.x = nextX;\n point.y = nextY;\n }\n\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n const id = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && idsToUpdate.includes(ele.containerId) ? ele.containerId : ele.id;\n\n if (idsToUpdate.includes(id)) {\n if (event.altKey) {\n if (pointerDownState.elementIdsToErase[id] && pointerDownState.elementIdsToErase[id].erase === false) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[id].opacity\n });\n }\n } else {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_READY_TO_ERASE_OPACITY\n });\n }\n }\n\n return ele;\n });\n this.scene.replaceAllElements(elements);\n pointerDownState.lastCoords.x = scenePointer.x;\n pointerDownState.lastCoords.y = scenePointer.y;\n }; // set touch moving for mobile context menu\n\n\n this.handleTouchMove = event => {\n invalidateContextMenu = true;\n };\n\n this.handleCanvasPointerDown = event => {\n var _a, _b; // since contextMenu options are potentially evaluated on each render,\n // and an contextMenu action may depend on selection state, we must\n // close the contextMenu before we update the selection on pointerDown\n // (e.g. resetting selection)\n\n\n if (this.state.contextMenu) {\n this.setState({\n contextMenu: null\n });\n }\n\n if (this.state.snapLines) {\n this.setAppState({\n snapLines: []\n });\n }\n\n this.updateGestureOnPointerDown(event); // if dragging element is freedraw and another pointerdown event occurs\n // a second finger is on the screen\n // discard the freedraw element if it is very short because it is likely\n // just a spike, otherwise finalize the freedraw element when the second\n // finger is lifted\n\n if (event.pointerType === \"touch\" && this.state.draggingElement && this.state.draggingElement.type === \"freedraw\") {\n const element = this.state.draggingElement;\n this.updateScene(Object.assign(Object.assign({}, element.points.length < 10 ? {\n elements: this.scene.getElementsIncludingDeleted().filter(el => el.id !== element.id)\n } : {}), {\n appState: {\n draggingElement: null,\n editingElement: null,\n startBoundElement: null,\n suggestedBindings: [],\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.keys(this.state.selectedElementIds).filter(key => key !== element.id).reduce((obj, key) => {\n obj[key] = this.state.selectedElementIds[key];\n return obj;\n }, {}), this.state)\n }\n }));\n return;\n } // remove any active selection when we start to interact with canvas\n // (mainly, we care about removing selection outside the component which\n // would prevent our copy handling otherwise)\n\n\n const selection = document.getSelection();\n\n if (selection === null || selection === void 0 ? void 0 : selection.anchorNode) {\n selection.removeAllRanges();\n }\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices(event);\n this.maybeCleanupAfterMissingPointerUp(event); //fires only once, if pen is detected, penMode is enabled\n //the user can disable this by toggling the penMode button\n\n if (!this.state.penDetected && event.pointerType === \"pen\") {\n this.setState(prevState => {\n return {\n penMode: true,\n penDetected: true\n };\n });\n }\n\n if (!this.device.isTouchScreen && [\"pen\", \"touch\"].includes(event.pointerType)) {\n this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(this.device, {\n isTouchScreen: true\n });\n }\n\n if (isPanning) {\n return;\n }\n\n this.lastPointerDownEvent = event; // we must exit before we set `cursorButton` state and `savePointer`\n // else it will send pointer state & laser pointer events in collab when\n // panning\n\n if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) {\n return;\n }\n\n this.setState({\n lastPointerDownWith: event.pointerType,\n cursorButton: \"down\"\n });\n this.savePointer(event.clientX, event.clientY, \"down\"); // only handle left mouse button or touch\n\n if (event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.TOUCH) {\n return;\n } // don't select while panning\n\n\n if (gesture.pointers.size > 1) {\n return;\n } // State for the duration of a pointer interaction, which starts with a\n // pointerDown event, ends with a pointerUp event (or another pointerDown)\n\n\n const pointerDownState = this.initialPointerDownState(event);\n this.setState({\n selectedElementsAreBeingDragged: false\n });\n\n if (this.handleDraggingScrollBar(event, pointerDownState)) {\n return;\n }\n\n this.clearSelectionIfNotUsingSelection();\n this.updateBindingEnabledOnPointerMove(event);\n\n if (this.handleSelectionOnPointerDown(event, pointerDownState)) {\n return;\n }\n\n const allowOnPointerDown = !this.state.penMode || event.pointerType !== \"touch\" || this.state.activeTool.type === \"selection\" || this.state.activeTool.type === \"text\" || this.state.activeTool.type === \"image\";\n\n if (!allowOnPointerDown) {\n return;\n }\n\n if (this.state.activeTool.type === \"text\") {\n this.handleTextOnPointerDown(event, pointerDownState);\n return;\n } else if (this.state.activeTool.type === \"arrow\" || this.state.activeTool.type === \"line\") {\n this.handleLinearElementOnPointerDown(event, this.state.activeTool.type, pointerDownState);\n } else if (this.state.activeTool.type === \"image\") {\n // reset image preview on pointerdown\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.CROSSHAIR); // retrieve the latest element as the state may be stale\n\n const pendingImageElement = this.state.pendingImageElementId && this.scene.getElement(this.state.pendingImageElementId);\n\n if (!pendingImageElement) {\n return;\n }\n\n this.setState({\n draggingElement: pendingImageElement,\n editingElement: pendingImageElement,\n pendingImageElementId: null,\n multiElement: null\n });\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const frame = this.getTopLayerFrameAtSceneCoords({\n x,\n y\n });\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(pendingImageElement, {\n x,\n y,\n frameId: frame ? frame.id : null\n });\n } else if (this.state.activeTool.type === \"freedraw\") {\n this.handleFreeDrawElementOnPointerDown(event, this.state.activeTool.type, pointerDownState);\n } else if (this.state.activeTool.type === \"custom\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n } else if (this.state.activeTool.type === \"frame\") {\n this.createFrameElementOnPointerDown(pointerDownState);\n } else if (this.state.activeTool.type === \"laser\") {\n this.laserPathManager.startPath(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y);\n } else if (this.state.activeTool.type !== \"eraser\" && this.state.activeTool.type !== \"hand\") {\n this.createGenericElementOnPointerDown(this.state.activeTool.type, pointerDownState);\n }\n\n (_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.onPointerDown) === null || _b === void 0 ? void 0 : _b.call(_a, this.state.activeTool, pointerDownState);\n this.onPointerDownEmitter.trigger(this.state.activeTool, pointerDownState, event);\n const onPointerMove = this.onPointerMoveFromPointerDownHandler(pointerDownState);\n const onPointerUp = this.onPointerUpFromPointerDownHandler(pointerDownState);\n const onKeyDown = this.onKeyDownFromPointerDownHandler(pointerDownState);\n const onKeyUp = this.onKeyUpFromPointerDownHandler(pointerDownState);\n lastPointerUp = onPointerUp;\n\n if (!this.state.viewModeEnabled || this.state.activeTool.type === \"laser\") {\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, onKeyDown);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, onKeyUp);\n pointerDownState.eventListeners.onMove = onPointerMove;\n pointerDownState.eventListeners.onUp = onPointerUp;\n pointerDownState.eventListeners.onKeyUp = onKeyUp;\n pointerDownState.eventListeners.onKeyDown = onKeyDown;\n }\n };\n\n this.handleCanvasPointerUp = event => {\n var _a, _b;\n\n this.removePointer(event);\n this.lastPointerUpEvent = event;\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: event.clientX,\n clientY: event.clientY\n }, this.state);\n const clicklength = event.timeStamp - ((_b = (_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a.timeStamp) !== null && _b !== void 0 ? _b : 0);\n\n if (this.device.editor.isMobile && clicklength < 300) {\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, event, scenePointer.x, scenePointer.y)) {\n this.handleEmbeddableCenterClick(hitElement);\n return;\n }\n }\n\n if (this.device.isTouchScreen) {\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n this.hitLinkElement = this.getElementLinkAtPosition(scenePointer, hitElement);\n }\n\n if (this.hitLinkElement && !this.state.selectedElementIds[this.hitLinkElement.id]) {\n if (clicklength < 300 && this.hitLinkElement.type === \"embeddable\" && !(0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLinkIcon)(this.hitLinkElement, this.state, [scenePointer.x, scenePointer.y])) {\n this.handleEmbeddableCenterClick(this.hitLinkElement);\n } else {\n this.redirectToLink(event, this.device.isTouchScreen);\n }\n } else if (this.state.viewModeEnabled) {\n this.setState({\n activeEmbeddable: null,\n selectedElementIds: {}\n });\n }\n };\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices = event => {\n // deal with opening context menu on touch devices\n if (event.pointerType === \"touch\") {\n invalidateContextMenu = false;\n\n if (touchTimeout) {\n // If there's already a touchTimeout, this means that there's another\n // touch down and we are doing another touch, so we shouldn't open the\n // context menu.\n invalidateContextMenu = true;\n } else {\n // open the context menu with the first touch's clientX and clientY\n // if the touch is not moving\n touchTimeout = window.setTimeout(() => {\n touchTimeout = 0;\n\n if (!invalidateContextMenu) {\n this.handleCanvasContextMenu(event);\n }\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.TOUCH_CTX_MENU_TIMEOUT);\n }\n }\n };\n\n this.resetContextMenuTimer = () => {\n clearTimeout(touchTimeout);\n touchTimeout = 0;\n invalidateContextMenu = false;\n }; // Returns whether the event is a panning\n\n\n this.handleCanvasPanUsingWheelOrSpaceDrag = event => {\n if (!(gesture.pointers.size <= 1 && (event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.WHEEL || event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && isHoldingSpace || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state) || this.state.viewModeEnabled)) || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement)) {\n return false;\n }\n\n isPanning = true;\n event.preventDefault();\n let nextPastePrevented = false;\n const isLinux = /Linux/.test(window.navigator.platform);\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRABBING);\n let {\n clientX: lastX,\n clientY: lastY\n } = event;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const deltaX = lastX - event.clientX;\n const deltaY = lastY - event.clientY;\n lastX = event.clientX;\n lastY = event.clientY;\n /*\n * Prevent paste event if we move while middle clicking on Linux.\n * See issue #1383.\n */\n\n if (isLinux && !nextPastePrevented && (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1)) {\n nextPastePrevented = true;\n /* Prevent the next paste event */\n\n const preventNextPaste = event => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n event.stopPropagation();\n };\n /*\n * Reenable next paste in case of disabled middle click paste for\n * any reason:\n * - right click paste\n * - empty clipboard\n */\n\n\n const enableNextPaste = () => {\n setTimeout(() => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }, 100);\n };\n\n document.body.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }\n\n this.translateCanvas({\n scrollX: this.state.scrollX - deltaX / this.state.zoom.value,\n scrollY: this.state.scrollY - deltaY / this.state.zoom.value\n });\n });\n const teardown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(lastPointerUp = () => {\n lastPointerUp = null;\n isPanning = false;\n\n if (!isHoldingSpace) {\n if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n this.setState({\n cursorButton: \"up\"\n });\n this.savePointer(event.clientX, event.clientY, \"up\");\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, teardown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, teardown);\n onPointerMove.flush();\n });\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, teardown);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove, {\n passive: true\n });\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, teardown);\n return true;\n };\n\n this.clearSelectionIfNotUsingSelection = () => {\n if (this.state.activeTool.type !== \"selection\") {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n };\n /**\n * @returns whether the pointer event has been completely handled\n */\n\n\n this.handleSelectionOnPointerDown = (event, pointerDownState) => {\n var _a;\n\n if (this.state.activeTool.type === \"selection\") {\n const elements = this.scene.getNonDeletedElements();\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && !this.state.editingLinearElement) {\n const elementWithTransformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getElementWithTransformHandleType)(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);\n\n if (elementWithTransformHandleType != null) {\n this.setState({\n resizingElement: elementWithTransformHandleType.element\n });\n pointerDownState.resize.handleType = elementWithTransformHandleType.transformHandleType;\n }\n } else if (selectedElements.length > 1) {\n pointerDownState.resize.handleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getTransformHandleTypeFromCoords)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);\n }\n\n if (pointerDownState.resize.handleType) {\n pointerDownState.resize.isResizing = true;\n pointerDownState.resize.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getResizeOffsetXY)(pointerDownState.resize.handleType, selectedElements, pointerDownState.origin.x, pointerDownState.origin.y));\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0]) && selectedElements[0].points.length === 2) {\n pointerDownState.resize.arrowDirection = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getResizeArrowDirection)(pointerDownState.resize.handleType, selectedElements[0]);\n }\n } else {\n if (this.state.selectedLinearElement) {\n const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;\n const ret = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerDown(event, this.state, this.history, pointerDownState.origin, linearElementEditor);\n\n if (ret.hitElement) {\n pointerDownState.hit.element = ret.hitElement;\n }\n\n if (ret.linearElementEditor) {\n this.setState({\n selectedLinearElement: ret.linearElementEditor\n });\n\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: ret.linearElementEditor\n });\n }\n }\n\n if (ret.didAddPoint) {\n return true;\n }\n } // hitElement may already be set above, so check first\n\n\n pointerDownState.hit.element = (_a = pointerDownState.hit.element) !== null && _a !== void 0 ? _a : this.getElementAtPosition(pointerDownState.origin.x, pointerDownState.origin.y);\n\n if (pointerDownState.hit.element) {\n // Early return if pointer is hitting link icon\n const hitLinkElement = this.getElementLinkAtPosition({\n x: pointerDownState.origin.x,\n y: pointerDownState.origin.y\n }, pointerDownState.hit.element);\n\n if (hitLinkElement) {\n return false;\n }\n } // For overlapped elements one position may hit\n // multiple elements\n\n\n pointerDownState.hit.allHitElements = this.getElementsAtPosition(pointerDownState.origin.x, pointerDownState.origin.y);\n const hitElement = pointerDownState.hit.element;\n const someHitElementIsSelected = pointerDownState.hit.allHitElements.some(element => this.isASelectedElement(element));\n\n if ((hitElement === null || !someHitElementIsSelected) && !event.shiftKey && !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) {\n this.clearSelection(hitElement);\n }\n\n if (this.state.editingLinearElement) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [this.state.editingLinearElement.elementId]: true\n }, this.state)\n }); // If we click on something\n } else if (hitElement != null) {\n // on CMD/CTRL, drill down to hit element regardless of groups etc.\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if (!this.state.selectedElementIds[hitElement.id]) {\n pointerDownState.hit.wasAddedToSelection = true;\n }\n\n this.setState(prevState => Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.editGroupForSelectedElement)(prevState, hitElement)), {\n previousSelectedElementIds: this.state.selectedElementIds\n })); // mark as not completely handled so as to allow dragging etc.\n\n return false;\n } // deselect if item is selected\n // if shift is not clicked, this will always return true\n // otherwise, it will trigger selection based on current\n // state of the box\n\n\n if (!this.state.selectedElementIds[hitElement.id]) {\n // if we are currently editing a group, exiting editing mode and deselect the group.\n if (this.state.editingGroupId && !(0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, this.state.editingGroupId)) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n } // Add hit element to selection. At this point if we're not holding\n // SHIFT the previously selected element(s) were deselected above\n // (make sure you use setState updater to use latest state)\n // With shift-selection, we want to make sure that frames and their containing\n // elements are not selected at the same time.\n\n\n if (!someHitElementIsSelected && !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) {\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n });\n const previouslySelectedElements = [];\n Object.keys(prevState.selectedElementIds).forEach(id => {\n const element = this.scene.getElement(id);\n element && previouslySelectedElements.push(element);\n }); // if hitElement is frame, deselect all of its elements if they are selected\n\n if (hitElement.type === \"frame\") {\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getFrameChildren)(previouslySelectedElements, hitElement.id).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n } else if (hitElement.frameId) {\n // if hitElement is in a frame and its frame has been selected\n // disable selection for the given element\n if (nextSelectedElementIds[hitElement.frameId]) {\n delete nextSelectedElementIds[hitElement.id];\n }\n } else {\n // hitElement is neither a frame nor an element in a frame\n // but since hitElement could be in a group with some frames\n // this means selecting hitElement will have the frames selected as well\n // because we want to keep the invariant:\n // - frames and their elements are not selected at the same time\n // we deselect elements in those frames that were previously selected\n const groupIds = hitElement.groupIds;\n const framesInGroups = new Set(groupIds.flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).filter(element => element.type === \"frame\").map(frame => frame.id));\n\n if (framesInGroups.size > 0) {\n previouslySelectedElements.forEach(element => {\n if (element.frameId && framesInGroups.has(element.frameId)) {\n // deselect element and groups containing the element\n delete nextSelectedElementIds[element.id];\n element.groupIds.flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n }\n });\n }\n }\n\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n showHyperlinkPopup: hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) ? \"info\" : false\n });\n });\n pointerDownState.hit.wasAddedToSelection = true;\n }\n }\n }\n\n this.setState({\n previousSelectedElementIds: this.state.selectedElementIds\n });\n }\n }\n\n return false;\n };\n\n this.handleTextOnPointerDown = (event, pointerDownState) => {\n // if we're currently still editing text, clicking outside\n // should only finalize it, not create another (irrespective\n // of state.activeTool.locked)\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement)) {\n return;\n }\n\n let sceneX = pointerDownState.origin.x;\n let sceneY = pointerDownState.origin.y;\n const element = this.getElementAtPosition(sceneX, sceneY, {\n includeBoundTextElement: true\n }); // FIXME\n\n let container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(element)) {\n container = element;\n sceneX = element.x + element.width / 2;\n sceneY = element.y + element.height / 2;\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n\n if (!this.state.activeTool.locked) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n };\n\n this.handleFreeDrawElementOnPointerDown = (event, elementType, pointerDownState) => {\n // Begin a mark capture. This does not have to update state yet.\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, null);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFreeDrawElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: null,\n simulatePressure: event.pressure === 0.5,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n const pressures = element.simulatePressure ? element.pressures : [...element.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [[0, 0]],\n pressures\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }; //create rectangle element with youtube top left on nearest grid point width / hight 640/360\n\n\n this.insertEmbeddableElement = ({\n sceneX,\n sceneY,\n link\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(link);\n\n if (!embedLink) {\n return;\n }\n\n if (embedLink.warning) {\n this.setToast({\n message: embedLink.warning,\n closable: true\n });\n }\n\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)({\n type: \"embeddable\",\n x: gridX,\n y: gridY,\n strokeColor: \"transparent\",\n backgroundColor: \"transparent\",\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n roundness: this.getCurrentItemRoundness(\"embeddable\"),\n opacity: this.state.currentItemOpacity,\n locked: false,\n width: embedLink.aspectRatio.w,\n height: embedLink.aspectRatio.h,\n link,\n validated: null\n });\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), element]);\n return element;\n };\n\n this.createImageElement = ({\n sceneX,\n sceneY,\n addToFrameUnderCursor = true\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const topLayerFrame = addToFrameUnderCursor ? this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n }) : null;\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newImageElement)({\n type: \"image\",\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n roundness: null,\n opacity: this.state.currentItemOpacity,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n return element;\n };\n\n this.handleLinearElementOnPointerDown = (event, elementType, pointerDownState) => {\n if (this.state.multiElement) {\n const {\n multiElement\n } = this.state; // finalize if completing a loop\n\n if (multiElement.type === \"line\" && (0,_math__WEBPACK_IMPORTED_MODULE_28__.isPathALoop)(multiElement.points, this.state.zoom.value)) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n lastCommittedPoint: multiElement.points[multiElement.points.length - 1]\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n const {\n x: rx,\n y: ry,\n lastCommittedPoint\n } = multiElement; // clicking inside commit zone → finalize arrow\n\n if (multiElement.points.length > 1 && lastCommittedPoint && (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerDownState.origin.x - rx, pointerDownState.origin.y - ry, lastCommittedPoint[0], lastCommittedPoint[1]) < _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [multiElement.id]: true\n }), prevState)\n })); // clicking outside commit zone → update reference for last committed\n // point\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n lastCommittedPoint: multiElement.points[multiElement.points.length - 1]\n });\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.\n If so, we want it to be null for start and \"arrow\" for end. If the linear item is not\n an arrow, we want it to be null for both. Otherwise, we want it to use the\n values from appState. */\n\n const {\n currentItemStartArrowhead,\n currentItemEndArrowhead\n } = this.state;\n const [startArrowhead, endArrowhead] = elementType === \"arrow\" ? [currentItemStartArrowhead, currentItemEndArrowhead] : [null, null];\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newLinearElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.state.currentItemRoundness === \"round\" ? {\n type: _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null,\n startArrowhead,\n endArrowhead,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [...element.points, [0, 0]]\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }\n };\n\n this.createGenericElementOnPointerDown = (elementType, pointerDownState) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const baseElementAttributes = {\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.getCurrentItemRoundness(elementType),\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n };\n let element;\n\n if (elementType === \"embeddable\") {\n element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)(Object.assign({\n type: \"embeddable\",\n validated: null\n }, baseElementAttributes));\n } else {\n element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newElement)(Object.assign({\n type: elementType\n }, baseElementAttributes));\n }\n\n if (element.type === \"selection\") {\n this.setState({\n selectionElement: element,\n draggingElement: element\n });\n } else {\n this.scene.addNewElement(element);\n this.setState({\n multiElement: null,\n draggingElement: element,\n editingElement: element\n });\n }\n };\n\n this.createFrameElementOnPointerDown = pointerDownState => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const frame = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFrameElement)(Object.assign({\n x: gridX,\n y: gridY,\n opacity: this.state.currentItemOpacity,\n locked: false\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE));\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), frame]);\n this.setState({\n multiElement: null,\n draggingElement: frame,\n editingElement: frame\n });\n };\n\n this.restoreReadyToEraseElements = pointerDownState => {\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n if (pointerDownState.elementIdsToErase[ele.id] && pointerDownState.elementIdsToErase[ele.id].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.id].opacity\n });\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && pointerDownState.elementIdsToErase[ele.containerId] && pointerDownState.elementIdsToErase[ele.containerId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.containerId].opacity\n });\n } else if (ele.frameId && pointerDownState.elementIdsToErase[ele.frameId] && pointerDownState.elementIdsToErase[ele.frameId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.frameId].opacity\n });\n }\n\n return ele;\n });\n this.scene.replaceAllElements(elements);\n };\n\n this.eraseElements = pointerDownState => {\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n if (pointerDownState.elementIdsToErase[ele.id] && pointerDownState.elementIdsToErase[ele.id].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && pointerDownState.elementIdsToErase[ele.containerId] && pointerDownState.elementIdsToErase[ele.containerId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n } else if (ele.frameId && pointerDownState.elementIdsToErase[ele.frameId] && pointerDownState.elementIdsToErase[ele.frameId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n }\n\n return ele;\n });\n this.history.resumeRecording();\n this.scene.replaceAllElements(elements);\n };\n\n this.initializeImage = ({\n imageFile,\n imageElement: _imageElement,\n showCursorImagePreview = false\n }) => __awaiter(this, void 0, void 0, function* () {\n var _e, _f, _g, _h; // at this point this should be guaranteed image file, but we do this check\n // to satisfy TS down the line\n\n\n if (!(0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(imageFile)) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.unsupportedFileType\"));\n }\n\n const mimeType = imageFile.type;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, \"wait\");\n\n if (mimeType === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n try {\n imageFile = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.normalizeSVG)(yield imageFile.text()), imageFile.name);\n } catch (error) {\n console.warn(error);\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.svgImageInsertError\"));\n }\n } // generate image id (by default the file digest) before any\n // resizing/compression takes place to keep it more portable\n\n\n const fileId = yield ((_f = (_e = this.props).generateIdForFile) === null || _f === void 0 ? void 0 : _f.call(_e, imageFile)) || (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.generateIdFromFile)(imageFile);\n\n if (!fileId) {\n console.warn(\"Couldn't generate file id or the supplied `generateIdForFile` didn't resolve to one.\");\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\"));\n }\n\n const existingFileData = this.files[fileId];\n\n if (!(existingFileData === null || existingFileData === void 0 ? void 0 : existingFileData.dataURL)) {\n try {\n imageFile = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT\n });\n } catch (error) {\n console.error(\"error trying to resing image file on insertion\", error);\n }\n\n if (imageFile.size > _constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.fileTooBig\", {\n maxSize: `${Math.trunc(_constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES / 1024 / 1024)}MB`\n }));\n }\n }\n\n if (showCursorImagePreview) {\n const dataURL = (_g = this.files[fileId]) === null || _g === void 0 ? void 0 : _g.dataURL; // optimization so that we don't unnecessarily resize the original\n // full-size file for cursor preview\n // (it's much faster to convert the resized dataURL to File)\n\n const resizedFile = dataURL && (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.dataURLToFile)(dataURL);\n this.setImagePreviewCursor(resizedFile || imageFile);\n }\n\n const dataURL = ((_h = this.files[fileId]) === null || _h === void 0 ? void 0 : _h.dataURL) || (yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imageFile));\n const imageElement = (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(_imageElement, {\n fileId\n }, false);\n return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {\n var _j;\n\n try {\n this.files = Object.assign(Object.assign({}, this.files), {\n [fileId]: {\n mimeType,\n id: fileId,\n dataURL,\n created: Date.now(),\n lastRetrieved: Date.now()\n }\n });\n const cachedImageData = this.imageCache.get(fileId);\n\n if (!cachedImageData) {\n this.addNewImagesToImageCache();\n yield this.updateImageCache([imageElement]);\n }\n\n if ((cachedImageData === null || cachedImageData === void 0 ? void 0 : cachedImageData.image) instanceof Promise) {\n yield cachedImageData.image;\n }\n\n if (this.state.pendingImageElementId !== imageElement.id && ((_j = this.state.draggingElement) === null || _j === void 0 ? void 0 : _j.id) !== imageElement.id) {\n this.initializeImageDimensions(imageElement, true);\n }\n\n resolve(imageElement);\n } catch (error) {\n console.error(error);\n reject(new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\")));\n } finally {\n if (!showCursorImagePreview) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n }\n }\n }));\n });\n /**\n * inserts image into elements array and rerenders\n */\n\n\n this.insertImageElement = (imageElement, imageFile, showCursorImagePreview) => __awaiter(this, void 0, void 0, function* () {\n // we should be handling all cases upstream, but in case we forget to handle\n // a future case, let's throw here\n if (!this.isToolSupported(\"image\")) {\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageToolNotSupported\")\n });\n return;\n }\n\n this.scene.addNewElement(imageElement);\n\n try {\n return yield this.initializeImage({\n imageFile,\n imageElement,\n showCursorImagePreview\n });\n } catch (error) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n isDeleted: true\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n this.setState({\n errorMessage: error.message || (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\")\n });\n return null;\n }\n });\n\n this.setImagePreviewCursor = imageFile => __awaiter(this, void 0, void 0, function* () {\n // mustn't be larger than 128 px\n // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Basic_User_Interface/Using_URL_values_for_the_cursor_property\n const cursorImageSizePx = 96;\n const imagePreview = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: cursorImageSizePx\n });\n let previewDataURL = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imagePreview); // SVG cannot be resized via `resizeImageFile` so we resize by rendering to\n // a small canvas\n\n if (imageFile.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n const img = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.loadHTMLImageElement)(previewDataURL);\n let height = Math.min(img.height, cursorImageSizePx);\n let width = height * (img.width / img.height);\n\n if (width > cursorImageSizePx) {\n width = cursorImageSizePx;\n height = width * (img.height / img.width);\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.height = height;\n canvas.width = width;\n const context = canvas.getContext(\"2d\");\n context.drawImage(img, 0, 0, width, height);\n previewDataURL = canvas.toDataURL(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg);\n }\n\n if (this.state.pendingImageElementId) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, `url(${previewDataURL}) 4 4, auto`);\n }\n });\n\n this.onImageAction = ({\n insertOnCanvasDirectly\n }) => __awaiter(this, void 0, void 0, function* () {\n try {\n const clientX = this.state.width / 2 + this.state.offsetLeft;\n const clientY = this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const imageFile = yield (0,_data_filesystem__WEBPACK_IMPORTED_MODULE_42__.fileOpen)({\n description: \"Image\",\n extensions: Object.keys(_constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_MIME_TYPES)\n });\n const imageElement = this.createImageElement({\n sceneX: x,\n sceneY: y,\n addToFrameUnderCursor: false\n });\n\n if (insertOnCanvasDirectly) {\n this.insertImageElement(imageElement, imageFile);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } else {\n this.setState({\n pendingImageElementId: imageElement.id\n }, () => {\n this.insertImageElement(imageElement, imageFile,\n /* showCursorImagePreview */\n true);\n });\n }\n } catch (error) {\n if (error.name !== \"AbortError\") {\n console.error(error);\n } else {\n console.warn(error);\n }\n\n this.setState({\n pendingImageElementId: null,\n editingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n }\n });\n\n this.initializeImageDimensions = (imageElement, forceNaturalSize = false) => {\n var _a;\n\n const image = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(imageElement) && ((_a = this.imageCache.get(imageElement.fileId)) === null || _a === void 0 ? void 0 : _a.image);\n\n if (!image || image instanceof Promise) {\n if (imageElement.width < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value && imageElement.height < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value) {\n const placeholderSize = 100 / this.state.zoom.value;\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n x: imageElement.x - placeholderSize / 2,\n y: imageElement.y - placeholderSize / 2,\n width: placeholderSize,\n height: placeholderSize\n });\n }\n\n return;\n }\n\n if (forceNaturalSize || // if user-created bounding box is below threshold, assume the\n // intention was to click instead of drag, and use the image's\n // intrinsic size\n imageElement.width < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value && imageElement.height < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value) {\n const minHeight = Math.max(this.state.height - 120, 160); // max 65% of canvas height, clamped to <300px, vh - 120px>\n\n const maxHeight = Math.min(minHeight, Math.floor(this.state.height * 0.5) / this.state.zoom.value);\n const height = Math.min(image.naturalHeight, maxHeight);\n const width = height * (image.naturalWidth / image.naturalHeight); // add current imageElement width/height to account for previous centering\n // of the placeholder image\n\n const x = imageElement.x + imageElement.width / 2 - width / 2;\n const y = imageElement.y + imageElement.height / 2 - height / 2;\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n x,\n y,\n width,\n height\n });\n }\n };\n /** updates image cache, refreshing updated elements and/or setting status\n to error for images that fail during <img> element creation */\n\n\n this.updateImageCache = (elements, files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const {\n updatedFiles,\n erroredFiles\n } = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.updateImageCache)({\n imageCache: this.imageCache,\n fileIds: elements.map(element => element.fileId),\n files\n });\n\n if (updatedFiles.size || erroredFiles.size) {\n for (const element of elements) {\n if (updatedFiles.has(element.fileId)) {\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element);\n }\n }\n }\n\n if (erroredFiles.size) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().map(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && erroredFiles.has(element.fileId)) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n status: \"error\"\n });\n }\n\n return element;\n }));\n }\n\n return {\n updatedFiles,\n erroredFiles\n };\n });\n /** adds new images to imageCache and re-renders if needed */\n\n\n this.addNewImagesToImageCache = (imageElements = (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.getInitializedImageElements)(this.scene.getNonDeletedElements()), files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const uncachedImageElements = imageElements.filter(element => !element.isDeleted && !this.imageCache.has(element.fileId));\n\n if (uncachedImageElements.length) {\n const {\n updatedFiles\n } = yield this.updateImageCache(uncachedImageElements, files);\n\n if (updatedFiles.size) {\n this.scene.informMutation();\n }\n }\n });\n /** generally you should use `addNewImagesToImageCache()` directly if you need\n * to render new images. This is just a failsafe */\n\n\n this.scheduleImageRefresh = lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default()(() => {\n this.addNewImagesToImageCache();\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_RENDER_TIMEOUT);\n\n this.updateBindingEnabledOnPointerMove = event => {\n const shouldEnableBinding = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.shouldEnableBindingForPointerEvent)(event);\n\n if (this.state.isBindingEnabled !== shouldEnableBinding) {\n this.setState({\n isBindingEnabled: shouldEnableBinding\n });\n }\n };\n\n this.maybeSuggestBindingAtCursor = pointerCoords => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerCoords, this.scene);\n this.setState({\n suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : []\n });\n };\n\n this.maybeSuggestBindingsForLinearElementAtCoords = (linearElement,\n /** scene coords */\n pointerCoords, // During line creation the start binding hasn't been written yet\n // into `linearElement`\n oppositeBindingBoundElement) => {\n if (!pointerCoords.length) {\n return;\n }\n\n const suggestedBindings = pointerCoords.reduce((acc, coords) => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(coords, this.scene);\n\n if (hoveredBindableElement != null && !(0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isLinearElementSimpleAndAlreadyBound)(linearElement, oppositeBindingBoundElement === null || oppositeBindingBoundElement === void 0 ? void 0 : oppositeBindingBoundElement.id, hoveredBindableElement)) {\n acc.push(hoveredBindableElement);\n }\n\n return acc;\n }, []);\n this.setState({\n suggestedBindings\n });\n };\n\n this.handleInteractiveCanvasRef = canvas => {\n var _a, _b, _c; // canvas is null when unmounting\n\n\n if (canvas !== null) {\n this.interactiveCanvas = canvas; // -----------------------------------------------------------------------\n // NOTE wheel, touchstart, touchend events must be registered outside\n // of react because react binds them them passively (so we can't prevent\n // default on them)\n\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd); // -----------------------------------------------------------------------\n } else {\n (_a = this.interactiveCanvas) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n (_b = this.interactiveCanvas) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n (_c = this.interactiveCanvas) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd);\n }\n };\n\n this.handleAppOnDrop = event => __awaiter(this, void 0, void 0, function* () {\n var _k, _l, _m, _o; // must be retrieved first, in the same frame\n\n\n const {\n file,\n fileHandle\n } = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getFileFromEvent)(event);\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n try {\n // if image tool not supported, don't show an error here and let it fall\n // through so we still support importing scene data from images. If no\n // scene data encoded, we'll show an error then\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(file) && this.isToolSupported(\"image\")) {\n // first attempt to decode scene from the image if it's embedded\n // ---------------------------------------------------------------------\n if ((file === null || file === void 0 ? void 0 : file.type) === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.png || (file === null || file === void 0 ? void 0 : file.type) === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n try {\n const scene = yield (0,_data__WEBPACK_IMPORTED_MODULE_13__.loadFromBlob)(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n appState: Object.assign(Object.assign({}, scene.appState || this.state), {\n isLoading: false\n }),\n replaceFiles: true,\n commitToHistory: true\n }));\n return;\n } catch (error) {\n if (error.name !== \"EncodingError\") {\n throw error;\n }\n }\n } // if no scene is embedded or we fail for whatever reason, fall back\n // to importing as regular image\n // ---------------------------------------------------------------------\n\n\n const imageElement = this.createImageElement({\n sceneX,\n sceneY\n });\n this.insertImageElement(imageElement, file);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n });\n return;\n }\n } catch (error) {\n return this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n\n const libraryJSON = event.dataTransfer.getData(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib);\n\n if (libraryJSON && typeof libraryJSON === \"string\") {\n try {\n const libraryItems = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.parseLibraryJSON)(libraryJSON);\n this.addElementsFromPasteOrLibrary({\n elements: (0,_data_library__WEBPACK_IMPORTED_MODULE_14__.distributeLibraryItemsOnSquareGrid)(libraryItems),\n position: event,\n files: null\n });\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n\n return;\n }\n\n if (file) {\n // atetmpt to parse an excalidraw/excalidrawlib file\n yield this.loadFileToCanvas(file, fileHandle);\n }\n\n if ((_l = (_k = event.dataTransfer) === null || _k === void 0 ? void 0 : _k.types) === null || _l === void 0 ? void 0 : _l.includes(\"text/plain\")) {\n const text = (_m = event.dataTransfer) === null || _m === void 0 ? void 0 : _m.getData(\"text\");\n\n if (text && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(text, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(text) || ((_o = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(text)) === null || _o === void 0 ? void 0 : _o.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(text)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n }\n }\n });\n\n this.loadFileToCanvas = (file, fileHandle) => __awaiter(this, void 0, void 0, function* () {\n file = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.normalizeFile)(file);\n\n try {\n const ret = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.loadSceneOrLibraryFromBlob)(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);\n\n if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidraw) {\n this.setState({\n isLoading: true\n });\n this.syncActionResult(Object.assign(Object.assign({}, ret.data), {\n appState: Object.assign(Object.assign({}, ret.data.appState || this.state), {\n isLoading: false\n }),\n replaceFiles: true,\n commitToHistory: true\n }));\n } else if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib) {\n yield this.library.updateLibrary({\n libraryItems: file,\n merge: true,\n openLibraryMenu: true\n }).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.importLibraryError\")\n });\n });\n }\n } catch (error) {\n if (error instanceof _errors__WEBPACK_IMPORTED_MODULE_57__.ImageSceneDataError && error.code === \"IMAGE_NOT_CONTAINS_SCENE_DATA\" && !this.isToolSupported(\"image\")) {\n this.setState({\n isLoading: false,\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageToolNotSupported\")\n });\n return;\n }\n\n this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n });\n\n this.handleCanvasContextMenu = event => {\n event.preventDefault();\n\n if ((\"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"touch\" || \"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"pen\" && // always allow if user uses a pen secondary button\n event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.SECONDARY) && this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const element = this.getElementAtPosition(x, y, {\n preferSelected: true,\n includeLockedElements: true\n });\n const selectedElements = this.scene.getSelectedElements(this.state);\n const isHittignCommonBoundBox = this.isHittingCommonBoundingBoxOfSelectedElements({\n x,\n y\n }, selectedElements);\n const type = element || isHittignCommonBoundBox ? \"element\" : \"canvas\";\n const container = this.excalidrawContainerRef.current;\n const {\n top: offsetTop,\n left: offsetLeft\n } = container.getBoundingClientRect();\n const left = event.clientX - offsetLeft;\n const top = event.clientY - offsetTop;\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"contextMenu\", \"openContextMenu\", type);\n this.setState(Object.assign(Object.assign({}, element && !this.state.selectedElementIds[element.id] ? Object.assign(Object.assign(Object.assign({}, this.state), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: this.state.editingGroupId,\n selectedElementIds: {\n [element.id]: true\n }\n }, this.scene.getNonDeletedElements(), this.state, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(element) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(element, this.scene) : null\n }) : this.state), {\n showHyperlinkPopup: false\n }), () => {\n this.setState({\n contextMenu: {\n top,\n left,\n items: this.getContextMenuItems(type)\n }\n });\n });\n };\n\n this.maybeDragNewGenericElement = (pointerDownState, event) => {\n var _a, _b, _c, _d, _e;\n\n const draggingElement = this.state.draggingElement;\n const pointerCoords = pointerDownState.lastCoords;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"selection\" && this.state.activeTool.type !== \"eraser\") {\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.origin.x, pointerDownState.origin.y, pointerCoords.x, pointerCoords.y, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.x, pointerCoords.x), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.y, pointerCoords.y), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event));\n } else {\n let [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const image = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(draggingElement) && ((_a = this.imageCache.get(draggingElement.fileId)) === null || _a === void 0 ? void 0 : _a.image);\n const aspectRatio = image && !(image instanceof Promise) ? image.width / image.height : null;\n this.maybeCacheReferenceSnapPoints(event, [draggingElement]);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.snapNewElement)(draggingElement, this.state, event, {\n x: pointerDownState.originInGrid.x + ((_c = (_b = this.state.originSnapOffset) === null || _b === void 0 ? void 0 : _b.x) !== null && _c !== void 0 ? _c : 0),\n y: pointerDownState.originInGrid.y + ((_e = (_d = this.state.originSnapOffset) === null || _d === void 0 ? void 0 : _d.y) !== null && _e !== void 0 ? _e : 0)\n }, {\n x: gridX - pointerDownState.originInGrid.x,\n y: gridY - pointerDownState.originInGrid.y\n });\n gridX += snapOffset.x;\n gridY += snapOffset.y;\n this.setState({\n snapLines\n });\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.originInGrid.x, pointerDownState.originInGrid.y, gridX, gridY, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.x, gridX), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.y, gridY), (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), aspectRatio, this.state.originSnapOffset);\n this.maybeSuggestBindingForAll([draggingElement]); // highlight elements that are to be added to frames on frames creation\n\n if (this.state.activeTool.type === \"frame\") {\n this.setState({\n elementsToHighlight: (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), draggingElement, this.state)\n });\n }\n }\n };\n\n this.maybeHandleResize = (pointerDownState, event) => {\n const selectedElements = this.scene.getSelectedElements(this.state);\n const selectedFrames = selectedElements.filter(element => element.type === \"frame\");\n const transformHandleType = pointerDownState.resize.handleType;\n\n if (selectedFrames.length > 0 && transformHandleType === \"rotation\") {\n return false;\n }\n\n this.setState({\n // TODO: rename this state field to \"isScaling\" to distinguish\n // it from the generic \"isResizing\" which includes scaling and\n // rotating\n isResizing: transformHandleType && transformHandleType !== \"rotation\",\n isRotating: transformHandleType === \"rotation\",\n activeEmbeddable: null\n });\n const pointerCoords = pointerDownState.lastCoords;\n let [resizeX, resizeY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x - pointerDownState.resize.offset.x, pointerCoords.y - pointerDownState.resize.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const frameElementsOffsetsMap = new Map();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getFrameChildren)(this.scene.getNonDeletedElements(), frame.id);\n elementsInFrame.forEach(element => {\n frameElementsOffsetsMap.set(frame.id + element.id, {\n x: element.x - frame.x,\n y: element.y - frame.y\n });\n });\n }); // check needed for avoiding flickering when a key gets pressed\n // during dragging\n\n if (!this.state.selectedElementsAreBeingDragged) {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const dragOffset = {\n x: gridX - pointerDownState.originInGrid.x,\n y: gridY - pointerDownState.originInGrid.y\n };\n const originalElements = [...pointerDownState.originalElements.values()];\n this.maybeCacheReferenceSnapPoints(event, selectedElements);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.snapResizingElements)(selectedElements, (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(originalElements, this.state), this.state, event, dragOffset, transformHandleType);\n resizeX += snapOffset.x;\n resizeY += snapOffset.y;\n this.setState({\n snapLines\n });\n }\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.transformElements)(pointerDownState, transformHandleType, selectedElements, pointerDownState.resize.arrowDirection, (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(selectedElements[0]) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y, this.state)) {\n this.maybeSuggestBindingForAll(selectedElements);\n const elementsToHighlight = new Set();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getFrameChildren)(this.scene.getNonDeletedElements(), frame.id); // keep elements' positions relative to their frames on frames resizing\n\n if (transformHandleType) {\n if (transformHandleType.includes(\"w\")) {\n elementsInFrame.forEach(element => {\n var _a, _b;\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: frame.x + (((_a = frameElementsOffsetsMap.get(frame.id + element.id)) === null || _a === void 0 ? void 0 : _a.x) || 0),\n y: frame.y + (((_b = frameElementsOffsetsMap.get(frame.id + element.id)) === null || _b === void 0 ? void 0 : _b.y) || 0)\n });\n });\n }\n\n if (transformHandleType.includes(\"n\")) {\n elementsInFrame.forEach(element => {\n var _a, _b;\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: frame.x + (((_a = frameElementsOffsetsMap.get(frame.id + element.id)) === null || _a === void 0 ? void 0 : _a.x) || 0),\n y: frame.y + (((_b = frameElementsOffsetsMap.get(frame.id + element.id)) === null || _b === void 0 ? void 0 : _b.y) || 0)\n });\n });\n }\n }\n\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), frame, this.state).forEach(element => elementsToHighlight.add(element));\n });\n this.setState({\n elementsToHighlight: [...elementsToHighlight]\n });\n return true;\n }\n\n return false;\n };\n\n this.getContextMenuItems = type => {\n const options = [];\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsPng, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsSvg); // canvas contextMenu\n // -------------------------------------------------------------------------\n\n if (type === \"canvas\") {\n if (this.state.viewModeEnabled) {\n return [...options, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleGridMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n }\n\n return [_actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsPng, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsSvg, _actions__WEBPACK_IMPORTED_MODULE_5__.copyText, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSelectAll, _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_48__.actionUnlockAllElements, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleGridMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleObjectsSnapMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n } // element contextMenu\n // -------------------------------------------------------------------------\n\n\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.copyText);\n\n if (this.state.viewModeEnabled) {\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, ...options];\n }\n\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionSelectAllElementsInFrame, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionRemoveAllElementsFromFrame, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, ...options, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyStyles, _actions__WEBPACK_IMPORTED_MODULE_5__.actionPasteStyles, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionGroup, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUnbindText, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBindText, _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_59__.actionWrapTextInContainer, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUngroup, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionAddToLibrary, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendBackward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringForward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendToBack, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringToFront, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipHorizontal, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipVertical, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleLinearEditor, _actions__WEBPACK_IMPORTED_MODULE_5__.actionLink, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDuplicateSelection, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleElementLock, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDeleteSelected];\n };\n\n this.handleWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault();\n\n if (isPanning) {\n return;\n }\n\n const {\n deltaX,\n deltaY\n } = event; // note that event.ctrlKey is necessary to handle pinch zooming\n\n if (event.metaKey || event.ctrlKey) {\n const sign = Math.sign(deltaY);\n const MAX_STEP = _constants__WEBPACK_IMPORTED_MODULE_12__.ZOOM_STEP * 100;\n const absDelta = Math.abs(deltaY);\n let delta = deltaY;\n\n if (absDelta > MAX_STEP) {\n delta = MAX_STEP * sign;\n }\n\n let newZoom = this.state.zoom.value - delta / 100; // increase zoom steps the more zoomed-in we are (applies to >100% only)\n\n newZoom += Math.log10(Math.max(1, this.state.zoom.value)) * -sign * // reduced amplification for small deltas (small movements on a trackpad)\n Math.min(1, absDelta / 20);\n this.translateCanvas(state => Object.assign(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(newZoom)\n }, state)), {\n shouldCacheIgnoreZoom: true\n }));\n this.resetShouldCacheIgnoreZoomDebounced();\n return;\n } // scroll horizontally when shift pressed\n\n\n if (event.shiftKey) {\n this.translateCanvas(({\n zoom,\n scrollX\n }) => ({\n // on Mac, shift+wheel tends to result in deltaX\n scrollX: scrollX - (deltaY || deltaX) / zoom.value\n }));\n return;\n }\n\n this.translateCanvas(({\n zoom,\n scrollX,\n scrollY\n }) => ({\n scrollX: scrollX - deltaX / zoom.value,\n scrollY: scrollY - deltaY / zoom.value\n }));\n });\n\n this.savePointer = (x, y, button) => {\n var _a, _b;\n\n if (!x || !y) {\n return;\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: x,\n clientY: y\n }, this.state);\n\n if (isNaN(sceneX) || isNaN(sceneY)) {// sometimes the pointer goes off screen\n }\n\n const pointer = {\n x: sceneX,\n y: sceneY,\n tool: this.state.activeTool.type === \"laser\" ? \"laser\" : \"pointer\"\n };\n (_b = (_a = this.props).onPointerUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, {\n pointer,\n button,\n pointersMap: gesture.pointers\n });\n };\n\n this.resetShouldCacheIgnoreZoomDebounced = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n if (!this.unmounted) {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n }\n }, 300);\n\n this.updateDOMRect = cb => {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n width,\n height,\n left: offsetLeft,\n top: offsetTop\n } = excalidrawContainer.getBoundingClientRect();\n const {\n width: currentWidth,\n height: currentHeight,\n offsetTop: currentOffsetTop,\n offsetLeft: currentOffsetLeft\n } = this.state;\n\n if (width === currentWidth && height === currentHeight && offsetLeft === currentOffsetLeft && offsetTop === currentOffsetTop) {\n if (cb) {\n cb();\n }\n\n return;\n }\n\n this.setState({\n width,\n height,\n offsetLeft,\n offsetTop\n }, () => {\n cb && cb();\n });\n }\n };\n\n this.refresh = () => {\n this.setState(Object.assign({}, this.getCanvasOffsets()));\n };\n\n const defaultAppState = (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)();\n const {\n excalidrawAPI,\n viewModeEnabled = false,\n zenModeEnabled = false,\n gridModeEnabled = false,\n objectsSnapModeEnabled = false,\n theme = defaultAppState.theme,\n name = defaultAppState.name\n } = props;\n this.state = Object.assign(Object.assign(Object.assign(Object.assign({}, defaultAppState), {\n theme,\n isLoading: true\n }), this.getCanvasOffsets()), {\n viewModeEnabled,\n zenModeEnabled,\n objectsSnapModeEnabled,\n gridSize: gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null,\n name,\n width: window.innerWidth,\n height: window.innerHeight\n });\n this.id = (0,nanoid__WEBPACK_IMPORTED_MODULE_72__.nanoid)();\n this.library = new _data_library__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this);\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_30__[\"default\"]();\n this.canvas = document.createElement(\"canvas\");\n this.rc = roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_3__[\"default\"].canvas(this.canvas);\n this.renderer = new _scene_Renderer__WEBPACK_IMPORTED_MODULE_65__.Renderer(this.scene);\n\n if (excalidrawAPI) {\n const api = {\n updateScene: this.updateScene,\n updateLibrary: this.library.updateLibrary,\n addFiles: this.addFiles,\n resetScene: this.resetScene,\n getSceneElementsIncludingDeleted: this.getSceneElementsIncludingDeleted,\n history: {\n clear: this.resetHistory\n },\n scrollToContent: this.scrollToContent,\n getSceneElements: this.getSceneElements,\n getAppState: () => this.state,\n getFiles: () => this.files,\n refresh: this.refresh,\n setToast: this.setToast,\n id: this.id,\n setActiveTool: this.setActiveTool,\n setCursor: this.setCursor,\n resetCursor: this.resetCursor,\n updateFrameRendering: this.updateFrameRendering,\n toggleSidebar: this.toggleSidebar,\n onChange: cb => this.onChangeEmitter.on(cb),\n onPointerDown: cb => this.onPointerDownEmitter.on(cb),\n onPointerUp: cb => this.onPointerUpEmitter.on(cb)\n };\n\n if (typeof excalidrawAPI === \"function\") {\n excalidrawAPI(api);\n } else {\n console.error(\"excalidrawAPI should be a function!\");\n }\n }\n\n this.excalidrawContainerValue = {\n container: this.excalidrawContainerRef.current,\n id: this.id\n };\n this.fonts = new _scene_Fonts__WEBPACK_IMPORTED_MODULE_49__.Fonts({\n scene: this.scene,\n onSceneUpdated: this.onSceneUpdated\n });\n this.history = new _history__WEBPACK_IMPORTED_MODULE_24__[\"default\"]();\n this.actionManager = new _actions_manager__WEBPACK_IMPORTED_MODULE_7__.ActionManager(this.syncActionResult, () => this.state, () => this.scene.getElementsIncludingDeleted(), this);\n this.actionManager.registerAll(_actions_register__WEBPACK_IMPORTED_MODULE_8__.actions);\n this.actionManager.registerAction((0,_actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__.createUndoAction)(this.history));\n this.actionManager.registerAction((0,_actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__.createRedoAction)(this.history));\n }\n\n onWindowMessage(event) {\n if (event.origin !== \"https://player.vimeo.com\" && event.origin !== \"https://www.youtube.com\") {\n return;\n }\n\n let data = null;\n\n try {\n data = JSON.parse(event.data);\n } catch (e) {}\n\n if (!data) {\n return;\n }\n\n switch (event.origin) {\n case \"https://player.vimeo.com\":\n //Allowing for multiple instances of Excalidraw running in the window\n if (data.method === \"paused\") {\n let source = null;\n const iframes = document.body.querySelectorAll(\"iframe.excalidraw__embeddable\");\n\n if (!iframes) {\n break;\n }\n\n for (const iframe of iframes) {\n if (iframe.contentWindow === event.source) {\n source = iframe.contentWindow;\n }\n }\n\n source === null || source === void 0 ? void 0 : source.postMessage(JSON.stringify({\n method: data.value ? \"play\" : \"pause\",\n value: true\n }), \"*\");\n }\n\n break;\n\n case \"https://www.youtube.com\":\n if (data.event === \"infoDelivery\" && data.info && data.id && typeof data.info.playerState === \"number\") {\n const id = data.id;\n const playerState = data.info.playerState;\n\n if (Object.values(_constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES).includes(playerState)) {\n YOUTUBE_VIDEO_STATES.set(id, playerState);\n }\n }\n\n break;\n }\n }\n\n updateEmbeddableRef(id, ref) {\n if (ref) {\n this.iFrameRefs.set(id, ref);\n }\n }\n\n getHTMLIFrameElement(id) {\n return this.iFrameRefs.get(id);\n }\n\n handleEmbeddableCenterClick(element) {\n var _a, _b, _c, _d;\n\n if (((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) === element && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"active\") {\n return;\n } // The delay serves two purposes\n // 1. To prevent first click propagating to iframe on mobile,\n // else the click will immediately start and stop the video\n // 2. If the user double clicks the frame center to activate it\n // without the delay youtube will immediately open the video\n // in fullscreen mode\n\n\n setTimeout(() => {\n this.setState({\n activeEmbeddable: {\n element,\n state: \"active\"\n },\n selectedElementIds: {\n [element.id]: true\n },\n draggingElement: null,\n selectionElement: null\n });\n }, 100);\n const iframe = this.getHTMLIFrameElement(element.id);\n\n if (!(iframe === null || iframe === void 0 ? void 0 : iframe.contentWindow)) {\n return;\n }\n\n if (iframe.src.includes(\"youtube\")) {\n const state = YOUTUBE_VIDEO_STATES.get(element.id);\n\n if (!state) {\n YOUTUBE_VIDEO_STATES.set(element.id, _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.UNSTARTED);\n iframe.contentWindow.postMessage(JSON.stringify({\n event: \"listening\",\n id: element.id\n }), \"*\");\n }\n\n switch (state) {\n case _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.PLAYING:\n case _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.BUFFERING:\n (_c = iframe.contentWindow) === null || _c === void 0 ? void 0 : _c.postMessage(JSON.stringify({\n event: \"command\",\n func: \"pauseVideo\",\n args: \"\"\n }), \"*\");\n break;\n\n default:\n (_d = iframe.contentWindow) === null || _d === void 0 ? void 0 : _d.postMessage(JSON.stringify({\n event: \"command\",\n func: \"playVideo\",\n args: \"\"\n }), \"*\");\n }\n }\n\n if (iframe.src.includes(\"player.vimeo.com\")) {\n iframe.contentWindow.postMessage(JSON.stringify({\n method: \"paused\" //video play/pause in onWindowMessage handler\n\n }), \"*\");\n }\n }\n\n isEmbeddableCenter(el, event, sceneX, sceneY) {\n var _a, _b;\n\n return el && !event.altKey && !event.shiftKey && !event.metaKey && !event.ctrlKey && (((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) !== el || ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"hover\" || !this.state.activeEmbeddable) && sceneX >= el.x + el.width / 3 && sceneX <= el.x + 2 * el.width / 3 && sceneY >= el.y + el.height / 3 && sceneY <= el.y + 2 * el.height / 3;\n }\n\n renderEmbeddables() {\n const scale = this.state.zoom.value;\n const normalizedWidth = this.state.width;\n const normalizedHeight = this.state.height;\n const embeddableElements = this.scene.getNonDeletedElements().filter(el => (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(el) && !!el.validated);\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {\n children: embeddableElements.map(el => {\n var _a, _b, _c, _d, _e, _f, _g, _h;\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: el.x,\n sceneY: el.y\n }, this.state);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)((0,_data_url__WEBPACK_IMPORTED_MODULE_46__.toValidURL)(el.link || \"\"));\n const isVisible = (0,_element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__.isElementInViewport)(el, normalizedWidth, normalizedHeight, this.state);\n const isActive = ((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) === el && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"active\";\n const isHovered = ((_c = this.state.activeEmbeddable) === null || _c === void 0 ? void 0 : _c.element) === el && ((_d = this.state.activeEmbeddable) === null || _d === void 0 ? void 0 : _d.state) === \"hover\";\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: (0,clsx__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\"excalidraw__embeddable-container\", {\n \"is-hovered\": isHovered\n }),\n style: {\n transform: isVisible ? `translate(${x - this.state.offsetLeft}px, ${y - this.state.offsetTop}px) scale(${scale})` : \"none\",\n display: isVisible ? \"block\" : \"none\",\n opacity: el.opacity / 100,\n [\"--embeddable-radius\"]: `${(0,_math__WEBPACK_IMPORTED_MODULE_28__.getCornerRadius)(Math.min(el.width, el.height), el)}px`\n }\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(\"div\", Object.assign({\n //this is a hack that addresses isse with embedded excalidraw.com embeddable\n //https://github.com/excalidraw/excalidraw/pull/6691#issuecomment-1607383938\n\n /*ref={(ref) => {\n if (!this.excalidrawContainerRef.current) {\n return;\n }\n const container = this.excalidrawContainerRef.current;\n const sh = container.scrollHeight;\n const ch = container.clientHeight;\n if (sh !== ch) {\n container.style.height = `${sh}px`;\n setTimeout(() => {\n container.style.height = `100%`;\n });\n }\n }}*/\n className: \"excalidraw__embeddable-container__inner\",\n style: {\n width: isVisible ? `${el.width}px` : 0,\n height: isVisible ? `${el.height}px` : 0,\n transform: isVisible ? `rotate(${el.angle}rad)` : \"none\",\n pointerEvents: isActive ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled\n }\n }, {\n children: [isHovered && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: \"excalidraw__embeddable-hint\"\n }, {\n children: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"buttons.embeddableInteractionButton\")\n })), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: \"excalidraw__embeddable__outer\",\n style: {\n padding: `${el.strokeWidth}px`\n }\n }, {\n children: (_g = (_f = (_e = this.props).renderEmbeddable) === null || _f === void 0 ? void 0 : _f.call(_e, el, this.state)) !== null && _g !== void 0 ? _g : (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"iframe\", {\n ref: ref => this.updateEmbeddableRef(el.id, ref),\n className: \"excalidraw__embeddable\",\n srcDoc: (embedLink === null || embedLink === void 0 ? void 0 : embedLink.type) === \"document\" ? embedLink.srcdoc(this.state.theme) : undefined,\n src: (embedLink === null || embedLink === void 0 ? void 0 : embedLink.type) !== \"document\" ? (_h = embedLink === null || embedLink === void 0 ? void 0 : embedLink.link) !== null && _h !== void 0 ? _h : \"\" : undefined,\n // https://stackoverflow.com/q/18470015\n scrolling: \"no\",\n referrerPolicy: \"no-referrer-when-downgrade\",\n title: \"Excalidraw Embedded Content\",\n allow: \"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\",\n allowFullScreen: true,\n sandbox: \"allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads\"\n })\n }))]\n }))\n }), el.id);\n })\n });\n }\n\n render() {\n var _a, _b, _c;\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n const {\n renderTopRightUI,\n renderCustomStats\n } = this.props;\n const versionNonce = this.scene.getVersionNonce();\n const {\n canvasElements,\n visibleElements\n } = this.renderer.getRenderableElements({\n versionNonce,\n zoom: this.state.zoom,\n offsetLeft: this.state.offsetLeft,\n offsetTop: this.state.offsetTop,\n scrollX: this.state.scrollX,\n scrollY: this.state.scrollY,\n height: this.state.height,\n width: this.state.width,\n editingElement: this.state.editingElement,\n pendingImageElementId: this.state.pendingImageElementId\n });\n const shouldBlockPointerEvents = !(this.state.editingElement && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(this.state.editingElement)) && (this.state.selectionElement || this.state.draggingElement || this.state.resizingElement || this.state.activeTool.type === \"laser\" && // technically we can just test on this once we make it more safe\n this.state.cursorButton === \"down\" || this.state.editingElement && !(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement));\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: (0,clsx__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\"excalidraw excalidraw-container\", {\n \"excalidraw--view-mode\": this.state.viewModeEnabled,\n \"excalidraw--mobile\": this.device.editor.isMobile\n }),\n style: {\n [\"--ui-pointerEvents\"]: shouldBlockPointerEvents ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled\n },\n ref: this.excalidrawContainerRef,\n onDrop: this.handleAppOnDrop,\n tabIndex: 0,\n onKeyDown: this.props.handleKeyboardGlobally ? undefined : this.onKeyDown\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AppContext.Provider, Object.assign({\n value: this\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AppPropsContext.Provider, Object.assign({\n value: this.props\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawContainerContext.Provider, Object.assign({\n value: this.excalidrawContainerValue\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(DeviceContext.Provider, Object.assign({\n value: this.device\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawSetAppStateContext.Provider, Object.assign({\n value: this.setAppState\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawAppStateContext.Provider, Object.assign({\n value: this.state\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(ExcalidrawElementsContext.Provider, Object.assign({\n value: this.scene.getNonDeletedElements()\n }, {\n children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(ExcalidrawActionManagerContext.Provider, Object.assign({\n value: this.actionManager\n }, {\n children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_LayerUI__WEBPACK_IMPORTED_MODULE_36__[\"default\"], Object.assign({\n canvas: this.canvas,\n appState: this.state,\n files: this.files,\n setAppState: this.setAppState,\n actionManager: this.actionManager,\n elements: this.scene.getNonDeletedElements(),\n onLockToggle: this.toggleLock,\n onPenModeToggle: this.togglePenMode,\n onHandToolToggle: this.onHandToolToggle,\n langCode: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.getLanguage)().code,\n renderTopRightUI: renderTopRightUI,\n renderCustomStats: renderCustomStats,\n showExitZenModeBtn: typeof ((_a = this.props) === null || _a === void 0 ? void 0 : _a.zenModeEnabled) === \"undefined\" && this.state.zenModeEnabled,\n UIOptions: this.props.UIOptions,\n onExportImage: this.onExportImage,\n renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === \"selection\" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,\n app: this,\n isCollaborating: this.props.isCollaborating\n }, {\n children: [this.props.children, this.state.openDialog === \"mermaid\" && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_MermaidToExcalidraw__WEBPACK_IMPORTED_MODULE_67__[\"default\"], {})]\n })), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-textEditorContainer\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-contextMenuContainer\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-eye-dropper-container\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_LaserTool_LaserTool__WEBPACK_IMPORTED_MODULE_68__.LaserToolOverlay, {\n manager: this.laserPathManager\n }), selectedElements.length === 1 && !this.state.contextMenu && this.state.showHyperlinkPopup && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.Hyperlink, {\n element: selectedElements[0],\n setAppState: this.setAppState,\n onLinkOpen: this.props.onLinkOpen,\n setToast: this.setToast\n }, selectedElements[0].id), this.state.toast !== null && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_Toast__WEBPACK_IMPORTED_MODULE_37__.Toast, {\n message: this.state.toast.message,\n onClose: () => this.setToast(null),\n duration: this.state.toast.duration,\n closable: this.state.toast.closable\n }), this.state.contextMenu && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_ContextMenu__WEBPACK_IMPORTED_MODULE_35__.ContextMenu, {\n items: this.state.contextMenu.items,\n top: this.state.contextMenu.top,\n left: this.state.contextMenu.left,\n actionManager: this.actionManager,\n onClose: callback => {\n this.setState({\n contextMenu: null\n }, () => {\n this.focusContainer();\n callback === null || callback === void 0 ? void 0 : callback();\n });\n }\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_64__.StaticCanvas, {\n canvas: this.canvas,\n rc: this.rc,\n elements: canvasElements,\n visibleElements: visibleElements,\n versionNonce: versionNonce,\n selectionNonce: (_b = this.state.selectionElement) === null || _b === void 0 ? void 0 : _b.versionNonce,\n scale: window.devicePixelRatio,\n appState: this.state,\n renderConfig: {\n imageCache: this.imageCache,\n isExporting: false,\n renderGrid: true\n }\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_64__.InteractiveCanvas, {\n containerRef: this.excalidrawContainerRef,\n canvas: this.interactiveCanvas,\n elements: canvasElements,\n visibleElements: visibleElements,\n selectedElements: selectedElements,\n versionNonce: versionNonce,\n selectionNonce: (_c = this.state.selectionElement) === null || _c === void 0 ? void 0 : _c.versionNonce,\n scale: window.devicePixelRatio,\n appState: this.state,\n renderInteractiveSceneCallback: this.renderInteractiveSceneCallback,\n handleCanvasRef: this.handleInteractiveCanvasRef,\n onContextMenu: this.handleCanvasContextMenu,\n onPointerMove: this.handleCanvasPointerMove,\n onPointerUp: this.handleCanvasPointerUp,\n onPointerCancel: this.removePointer,\n onTouchMove: this.handleTouchMove,\n onPointerDown: this.handleCanvasPointerDown,\n onDoubleClick: this.handleCanvasDoubleClick\n }), this.renderFrameNames()]\n })), this.renderEmbeddables()]\n }))\n }))\n }))\n }))\n }))\n }))\n }))\n }));\n }\n\n componentDidMount() {\n var _a;\n\n return __awaiter(this, void 0, void 0, function* () {\n this.unmounted = false;\n this.excalidrawContainerValue.container = this.excalidrawContainerRef.current;\n\n if (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n const setState = this.setState.bind(this);\n Object.defineProperties(window.h, {\n state: {\n configurable: true,\n get: () => {\n return this.state;\n }\n },\n setState: {\n configurable: true,\n value: (...args) => {\n return this.setState(...args);\n }\n },\n app: {\n configurable: true,\n value: this\n },\n history: {\n configurable: true,\n value: this.history\n }\n });\n }\n\n this.scene.addCallback(this.onSceneUpdated);\n this.addEventListeners();\n\n if (this.props.autoFocus && this.excalidrawContainerRef.current) {\n this.focusContainer();\n }\n\n if ( // bounding rects don't work in tests so updating\n // the state on init would result in making the test enviro run\n // in mobile breakpoint (0 width/height), making everything fail\n !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTestEnv)()) {\n this.refreshViewportBreakpoints();\n this.refreshEditorBreakpoints();\n }\n\n if (supportsResizeObserver && this.excalidrawContainerRef.current) {\n this.resizeObserver = new ResizeObserver(() => {\n this.refreshEditorBreakpoints();\n this.updateDOMRect();\n });\n (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(this.excalidrawContainerRef.current);\n }\n\n const searchParams = new URLSearchParams(window.location.search.slice(1));\n\n if (searchParams.has(\"web-share-target\")) {\n // Obtain a file that was shared via the Web Share Target API.\n this.restoreFileFromShare();\n } else {\n this.updateDOMRect(this.initializeScene);\n } // note that this check seems to always pass in localhost\n\n\n if ((0,_constants__WEBPACK_IMPORTED_MODULE_12__.isBrave)() && !(0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isMeasureTextSupported)()) {\n this.setState({\n errorMessage: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_60__[\"default\"], {})\n });\n }\n });\n }\n\n componentWillUnmount() {\n var _a;\n\n this.renderer.destroy();\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_30__[\"default\"]();\n this.renderer = new _scene_Renderer__WEBPACK_IMPORTED_MODULE_65__.Renderer(this.scene);\n this.files = {};\n this.imageCache.clear();\n (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();\n this.unmounted = true;\n this.removeEventListeners();\n this.scene.destroy();\n this.library.destroy();\n this.laserPathManager.destroy();\n this.onChangeEmitter.destroy();\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache.destroy();\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.destroy();\n clearTimeout(touchTimeout);\n _scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected.clearCache();\n _groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements.clearCache();\n touchTimeout = 0;\n }\n\n removeEventListeners() {\n var _a, _b, _c, _d;\n\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel);\n (_b = this.nearestScrollableContainer) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MESSAGE, this.onWindowMessage, false);\n }\n\n addEventListeners() {\n var _a, _b, _c, _d, _e;\n\n this.removeEventListeners();\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MESSAGE, this.onWindowMessage, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer); // #3553\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel, {\n passive: false\n });\n\n if (this.props.handleKeyboardGlobally) {\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp, {\n passive: true\n });\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition); // rerender text elements on font load to fix #637 && #1553\n\n (_c = (_b = document.fonts) === null || _b === void 0 ? void 0 : _b.addEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, \"loadingdone\", event => {\n const loadedFontFaces = event.fontfaces;\n this.fonts.onFontsLoaded(loadedFontFaces);\n }); // Safari-only desktop pinch zoom\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n\n if (this.props.detectScroll) {\n this.nearestScrollableContainer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getNearestScrollableContainer)(this.excalidrawContainerRef.current);\n this.nearestScrollableContainer.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n }\n\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_e = this.excalidrawContainerRef.current) === null || _e === void 0 ? void 0 : _e.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n }\n\n componentDidUpdate(prevProps, prevState) {\n var _a, _b, _c, _d, _e, _f;\n\n this.updateEmbeddables();\n\n if (!this.state.showWelcomeScreen && !this.scene.getElementsIncludingDeleted().length) {\n this.setState({\n showWelcomeScreen: true\n });\n }\n\n if (prevProps.UIOptions.dockedSidebarBreakpoint !== this.props.UIOptions.dockedSidebarBreakpoint) {\n this.refreshEditorBreakpoints();\n }\n\n if (prevState.scrollX !== this.state.scrollX || prevState.scrollY !== this.state.scrollY) {\n (_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.onScrollChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.state.scrollX, this.state.scrollY);\n }\n\n if (Object.keys(this.state.selectedElementIds).length && (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n\n if (this.state.activeTool.type === \"eraser\" && prevState.theme !== this.state.theme) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setEraserCursor)(this.interactiveCanvas, this.state.theme);\n } // Hide hyperlink popup if shown when element type is not selection\n\n\n if (prevState.activeTool.type === \"selection\" && this.state.activeTool.type !== \"selection\" && this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: false\n });\n }\n\n if (prevProps.langCode !== this.props.langCode) {\n this.updateLanguage();\n }\n\n if (prevProps.viewModeEnabled !== this.props.viewModeEnabled) {\n this.setState({\n viewModeEnabled: !!this.props.viewModeEnabled\n });\n }\n\n if (prevState.viewModeEnabled !== this.state.viewModeEnabled) {\n this.addEventListeners();\n this.deselectElements();\n }\n\n if (prevProps.zenModeEnabled !== this.props.zenModeEnabled) {\n this.setState({\n zenModeEnabled: !!this.props.zenModeEnabled\n });\n }\n\n if (prevProps.theme !== this.props.theme && this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {\n this.setState({\n gridSize: this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null\n });\n }\n\n if (this.props.name && prevProps.name !== this.props.name) {\n this.setState({\n name: this.props.name\n });\n }\n\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.classList.toggle(\"theme--dark\", this.state.theme === \"dark\");\n\n if (this.state.editingLinearElement && !this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {\n // defer so that the commitToHistory flag isn't reset via current update\n setTimeout(() => {\n // execute only if the condition still holds when the deferred callback\n // executes (it can be scheduled multiple times depending on how\n // many times the component renders)\n this.state.editingLinearElement && this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } // failsafe in case the state is being updated in incorrect order resulting\n // in the editingElement being now a deleted element\n\n\n if ((_d = this.state.editingElement) === null || _d === void 0 ? void 0 : _d.isDeleted) {\n this.setState({\n editingElement: null\n });\n }\n\n if (this.state.selectedLinearElement && !this.state.selectedElementIds[this.state.selectedLinearElement.elementId]) {\n // To make sure `selectedLinearElement` is in sync with `selectedElementIds`, however this shouldn't be needed once\n // we have a single API to update `selectedElementIds`\n this.setState({\n selectedLinearElement: null\n });\n }\n\n const {\n multiElement\n } = prevState;\n\n if (prevState.activeTool !== this.state.activeTool && multiElement != null && (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(multiElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(multiElement, this.state, this.scene, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)(_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1)));\n }\n\n this.history.record(this.state, this.scene.getElementsIncludingDeleted()); // Do not notify consumers if we're still loading the scene. Among other\n // potential issues, this fixes a case where the tab isn't focused during\n // init, which would trigger onChange with empty elements, which would then\n // override whatever is in localStorage currently.\n\n if (!this.state.isLoading) {\n (_f = (_e = this.props).onChange) === null || _f === void 0 ? void 0 : _f.call(_e, this.scene.getElementsIncludingDeleted(), this.state, this.files);\n this.onChangeEmitter.trigger(this.scene.getElementsIncludingDeleted(), this.state, this.files);\n }\n }\n\n static resetTapTwice() {\n didTapTwice = false;\n } // TODO rewrite this to paste both text & images at the same time if\n // pasted data contains both\n\n\n addElementsFromMixedContentPaste(mixedContent, {\n isPlainPaste,\n sceneX,\n sceneY\n }) {\n return __awaiter(this, void 0, void 0, function* () {\n if (!isPlainPaste && mixedContent.some(node => node.type === \"imageUrl\") && this.isToolSupported(\"image\")) {\n const imageURLs = mixedContent.filter(node => node.type === \"imageUrl\").map(node => node.value);\n const responses = yield Promise.all(imageURLs.map(url => __awaiter(this, void 0, void 0, function* () {\n try {\n return {\n file: yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.ImageURLToFile)(url)\n };\n } catch (error) {\n return {\n errorMessage: error.message\n };\n }\n })));\n let y = sceneY;\n let firstImageYOffsetDone = false;\n const nextSelectedIds = {};\n\n for (const response of responses) {\n if (response.file) {\n const imageElement = this.createImageElement({\n sceneX,\n sceneY: y\n });\n const initializedImageElement = yield this.insertImageElement(imageElement, response.file);\n\n if (initializedImageElement) {\n // vertically center first image in the batch\n if (!firstImageYOffsetDone) {\n firstImageYOffsetDone = true;\n y -= initializedImageElement.height / 2;\n } // hack to reset the `y` coord because we vertically center during\n // insertImageElement\n\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(initializedImageElement, {\n y\n }, false);\n y = imageElement.y + imageElement.height + 25;\n nextSelectedIds[imageElement.id] = true;\n }\n }\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedIds, this.state)\n });\n const error = responses.find(response => !!response.errorMessage);\n\n if (error && error.errorMessage) {\n this.setState({\n errorMessage: error.errorMessage\n });\n }\n } else {\n const textNodes = mixedContent.filter(node => node.type === \"text\");\n\n if (textNodes.length) {\n this.addTextFromPaste(textNodes.map(node => node.value).join(\"\\n\\n\"), isPlainPaste);\n }\n }\n });\n }\n\n addTextFromPaste(text, isPlainPaste = false) {\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state);\n const textElementProps = {\n x,\n y,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roundness: null,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text,\n fontSize: this.state.currentItemFontSize,\n fontFamily: this.state.currentItemFontFamily,\n textAlign: this.state.currentItemTextAlign,\n verticalAlign: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n locked: false\n };\n const LINE_GAP = 10;\n let currentY = y;\n const lines = isPlainPaste ? [text] : text.split(\"\\n\");\n const textElements = lines.reduce((acc, line, idx) => {\n var _a;\n\n const text = line.trim();\n const lineHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(textElementProps.fontFamily);\n\n if (text.length) {\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x,\n y: currentY\n });\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)(Object.assign(Object.assign({}, textElementProps), {\n x,\n y: currentY,\n text,\n lineHeight,\n frameId: topLayerFrame ? topLayerFrame.id : null\n }));\n acc.push(element);\n currentY += element.height + LINE_GAP;\n } else {\n const prevLine = (_a = lines[idx - 1]) === null || _a === void 0 ? void 0 : _a.trim(); // add paragraph only if previous line was not empty, IOW don't add\n // more than one empty line\n\n if (prevLine) {\n currentY += (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getLineHeightInPx)(textElementProps.fontSize, lineHeight) + LINE_GAP;\n }\n }\n\n return acc;\n }, []);\n\n if (textElements.length === 0) {\n return;\n }\n\n const frameId = textElements[0].frameId;\n\n if (frameId) {\n this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));\n } else {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), ...textElements]);\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.fromEntries(textElements.map(el => [el.id, true])), this.state)\n });\n\n if (!isPlainPaste && textElements.length > 1 && PLAIN_PASTE_TOAST_SHOWN === false && !this.device.editor.isMobile) {\n this.setToast({\n message: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"toast.pasteAsSingleElement\", {\n shortcut: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getShortcutKey)(\"CtrlOrCmd+Shift+V\")\n }),\n duration: 5000\n });\n PLAIN_PASTE_TOAST_SHOWN = true;\n }\n\n this.history.resumeRecording();\n }\n\n handleTextWysiwyg(element, {\n isExistingElement = false\n }) {\n const updateElement = (text, originalText, isDeleted) => {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted().map(_element => {\n if (_element.id === element.id && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(_element)) {\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.updateTextElement)(_element, {\n text,\n isDeleted,\n originalText\n });\n }\n\n return _element;\n })]);\n };\n\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.textWysiwyg)({\n id: element.id,\n canvas: this.canvas,\n getViewportCoords: (x, y) => {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: x,\n sceneY: y\n }, this.state);\n return [viewportX - this.state.offsetLeft, viewportY - this.state.offsetTop];\n },\n onChange: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(text => {\n updateElement(text, text, false);\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element);\n }\n }),\n onSubmit: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(({\n text,\n viaKeyboard,\n originalText\n }) => {\n const isDeleted = !text.trim();\n updateElement(text, originalText, isDeleted); // select the created text element only if submitting via keyboard\n // (when submitting via click it should act as signal to deselect)\n\n if (!isDeleted && viaKeyboard) {\n const elementIdToSelect = element.containerId ? element.containerId : element.id;\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [elementIdToSelect]: true\n }), prevState)\n }));\n }\n\n if (isDeleted) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDeletion)(this.scene.getNonDeletedElements(), [element]);\n }\n\n if (!isDeleted || isExistingElement) {\n this.history.resumeRecording();\n }\n\n this.setState({\n draggingElement: null,\n editingElement: null\n });\n\n if (this.state.activeTool.locked) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n this.focusContainer();\n }),\n element,\n excalidrawContainer: this.excalidrawContainerRef.current,\n app: this\n }); // deselect all other elements when inserting text\n\n this.deselectElements(); // do an initial update to re-initialize element position since we were\n // modifying element's x/y for sake of editor (case: syncing to remote)\n\n updateElement(element.text, element.originalText, false);\n }\n\n deselectElements() {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n getTextElementAtPosition(x, y) {\n const element = this.getElementAtPosition(x, y, {\n includeBoundTextElement: true\n });\n\n if (element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && !element.isDeleted) {\n return element;\n }\n\n return null;\n }\n\n getElementAtPosition(x, y, opts) {\n const allHitElements = this.getElementsAtPosition(x, y, opts === null || opts === void 0 ? void 0 : opts.includeBoundTextElement, opts === null || opts === void 0 ? void 0 : opts.includeLockedElements);\n\n if (allHitElements.length > 1) {\n if (opts === null || opts === void 0 ? void 0 : opts.preferSelected) {\n for (let index = allHitElements.length - 1; index > -1; index--) {\n if (this.state.selectedElementIds[allHitElements[index].id]) {\n return allHitElements[index];\n }\n }\n }\n\n const elementWithHighestZIndex = allHitElements[allHitElements.length - 1]; // If we're hitting element with highest z-index only on its bounding box\n // while also hitting other element figure, the latter should be considered.\n\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(elementWithHighestZIndex, this.state, this.frameNameBoundsCache, x, y) ? allHitElements[allHitElements.length - 2] : elementWithHighestZIndex;\n }\n\n if (allHitElements.length === 1) {\n return allHitElements[0];\n }\n\n return null;\n }\n\n getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {\n const elements = includeBoundTextElement && includeLockedElements ? this.scene.getNonDeletedElements() : this.scene.getNonDeletedElements().filter(element => (includeLockedElements || !element.locked) && (includeBoundTextElement || !((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && element.containerId)));\n return (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsAtPosition)(elements, element => (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(element, this.state, this.frameNameBoundsCache, x, y)).filter(element => {\n // hitting a frame's element from outside the frame is not considered a hit\n const containingFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(element);\n return containingFrame && this.state.frameRendering.enabled && this.state.frameRendering.clip ? (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)({\n x,\n y\n }, containingFrame) : true;\n });\n }\n\n handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {\n const element = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getElement(linearElementEditor.elementId);\n const boundTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(element);\n\n if (!element) {\n return;\n }\n\n if (this.state.selectedLinearElement) {\n let hoverPointIndex = -1;\n let segmentMidPointHoveredCoords = null;\n\n if ((0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(element, this.state, this.frameNameBoundsCache, [scenePointerX, scenePointerY])) {\n hoverPointIndex = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointIndexUnderCursor(element, this.state.zoom, scenePointerX, scenePointerY);\n segmentMidPointHoveredCoords = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, {\n x: scenePointerX,\n y: scenePointerY\n }, this.state);\n\n if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n } else if ((0,_element_transformHandles__WEBPACK_IMPORTED_MODULE_47__.shouldShowBoundingBox)([element], this.state) && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n } else if (boundTextElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(boundTextElement, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n\n if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n hoverPointIndex\n })\n });\n }\n\n if (!_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.arePointsEqual(this.state.selectedLinearElement.segmentMidPointHoveredCoords, segmentMidPointHoveredCoords)) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n segmentMidPointHoveredCoords\n })\n });\n }\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n\n maybeCleanupAfterMissingPointerUp(event) {\n if (lastPointerUp !== null) {\n // Unfortunately, sometimes we don't get a pointerup after a pointerdown,\n // this can happen when a contextual menu or alert is triggered. In order to avoid\n // being in a weird state, we clean up on the next pointerdown\n lastPointerUp(event);\n }\n }\n\n updateGestureOnPointerDown(event) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n\n if (gesture.pointers.size === 2) {\n gesture.lastCenter = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n gesture.initialScale = this.state.zoom.value;\n gesture.initialDistance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n }\n }\n\n initialPointerDownState(event) {\n const origin = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedElements = this.scene.getSelectedElements(this.state);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return {\n origin,\n withCmdOrCtrl: event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD],\n originInGrid: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(origin.x, origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize)),\n scrollbars: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop),\n // we need to duplicate because we'll be updating this state\n lastCoords: Object.assign({}, origin),\n originalElements: this.scene.getNonDeletedElements().reduce((acc, element) => {\n acc.set(element.id, (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.deepCopyElement)(element));\n return acc;\n }, new Map()),\n resize: {\n handleType: false,\n isResizing: false,\n offset: {\n x: 0,\n y: 0\n },\n arrowDirection: \"origin\",\n center: {\n x: (maxX + minX) / 2,\n y: (maxY + minY) / 2\n }\n },\n hit: {\n element: null,\n allHitElements: [],\n wasAddedToSelection: false,\n hasBeenDuplicated: false,\n hasHitCommonBoundingBoxOfSelectedElements: this.isHittingCommonBoundingBoxOfSelectedElements(origin, selectedElements)\n },\n drag: {\n hasOccurred: false,\n offset: null\n },\n eventListeners: {\n onMove: null,\n onUp: null,\n onKeyUp: null,\n onKeyDown: null\n },\n boxSelection: {\n hasOccurred: false\n },\n elementIdsToErase: {}\n };\n } // Returns whether the event is a dragging a scrollbar\n\n\n handleDraggingScrollBar(event, pointerDownState) {\n if (!(pointerDownState.scrollbars.isOverEither && !this.state.multiElement)) {\n return false;\n }\n\n isDraggingScrollBar = true;\n pointerDownState.lastCoords.x = event.clientX;\n pointerDownState.lastCoords.y = event.clientY;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n this.handlePointerMoveOverScrollbars(event, pointerDownState);\n });\n const onPointerUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isDraggingScrollBar = false;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n lastPointerUp = null;\n this.setState({\n cursorButton: \"up\"\n });\n this.savePointer(event.clientX, event.clientY, \"up\");\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n onPointerMove.flush();\n });\n lastPointerUp = onPointerUp;\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n return true;\n }\n\n isASelectedElement(hitElement) {\n return hitElement != null && this.state.selectedElementIds[hitElement.id];\n }\n\n isHittingCommonBoundingBoxOfSelectedElements(point, selectedElements) {\n if (selectedElements.length < 2) {\n return false;\n } // How many pixels off the shape boundary we still consider a hit\n\n\n const threshold = 10 / this.state.zoom.value;\n const [x1, y1, x2, y2] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return point.x > x1 - threshold && point.x < x2 + threshold && point.y > y1 - threshold && point.y < y2 + threshold;\n }\n\n getCurrentItemRoundness(elementType) {\n return this.state.currentItemRoundness === \"round\" ? {\n type: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isUsingAdaptiveRadius)(elementType) ? _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.ADAPTIVE_RADIUS : _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null;\n }\n\n maybeCacheReferenceSnapPoints(event, selectedElements, recomputeAnyways = false) {\n if ((0,_snapping__WEBPACK_IMPORTED_MODULE_58__.isSnappingEnabled)({\n event,\n appState: this.state,\n selectedElements\n }) && (recomputeAnyways || !_snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.getReferenceSnapPoints())) {\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.setReferenceSnapPoints((0,_snapping__WEBPACK_IMPORTED_MODULE_58__.getReferenceSnapPoints)(this.scene.getNonDeletedElements(), selectedElements, this.state));\n }\n }\n\n maybeCacheVisibleGaps(event, selectedElements, recomputeAnyways = false) {\n if ((0,_snapping__WEBPACK_IMPORTED_MODULE_58__.isSnappingEnabled)({\n event,\n appState: this.state,\n selectedElements\n }) && (recomputeAnyways || !_snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.getVisibleGaps())) {\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.setVisibleGaps((0,_snapping__WEBPACK_IMPORTED_MODULE_58__.getVisibleGaps)(this.scene.getNonDeletedElements(), selectedElements, this.state));\n }\n }\n\n onKeyDownFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onKeyUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // Prevents focus from escaping excalidraw tab\n event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ALT && event.preventDefault();\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onPointerMoveFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n var _a, _b; // We need to initialize dragOffsetXY only after we've updated\n // `state.selectedElementIds` on pointerDown. Doing it here in pointerMove\n // event handler should hopefully ensure we're already working with\n // the updated state.\n\n\n if (pointerDownState.drag.offset === null) {\n pointerDownState.drag.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getDragOffsetXY)(this.scene.getSelectedElements(this.state), pointerDownState.origin.x, pointerDownState.origin.y));\n }\n\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n if (this.handlePointerMoveOverScrollbars(event, pointerDownState)) {\n return;\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.handleEraser(event, pointerDownState, pointerCoords);\n return;\n }\n\n if (this.state.activeTool.type === \"laser\") {\n this.laserPathManager.addPointToPath(pointerCoords.x, pointerCoords.y);\n }\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize); // for arrows/lines, don't start dragging until a given threshold\n // to ensure we don't create a 2-point arrow by mistake when\n // user clicks mouse in a way that it moves a tiny bit (thus\n // triggering pointermove)\n\n if (!pointerDownState.drag.hasOccurred && (this.state.activeTool.type === \"arrow\" || this.state.activeTool.type === \"line\")) {\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerCoords.x, pointerCoords.y, pointerDownState.origin.x, pointerDownState.origin.y) < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD) {\n return;\n }\n }\n\n if (pointerDownState.resize.isResizing) {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return true;\n }\n }\n\n if (this.state.selectedLinearElement) {\n const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;\n\n if (_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.shouldAddMidpoint(this.state.selectedLinearElement, pointerCoords, this.state)) {\n const ret = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.addMidpoint(this.state.selectedLinearElement, pointerCoords, this.state, !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]);\n\n if (!ret) {\n return;\n } // Since we are reading from previous state which is not possible with\n // automatic batching in React 18 hence using flush sync to synchronously\n // update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.\n\n\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n if (this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n pointerDownState: ret.pointerDownState,\n selectedPointsIndices: ret.selectedPointsIndices\n })\n });\n }\n\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: Object.assign(Object.assign({}, this.state.editingLinearElement), {\n pointerDownState: ret.pointerDownState,\n selectedPointsIndices: ret.selectedPointsIndices\n })\n });\n }\n });\n return;\n } else if (linearElementEditor.pointerDownState.segmentMidpoint.value !== null && !linearElementEditor.pointerDownState.segmentMidpoint.added) {\n return;\n }\n\n const didDrag = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointDragging(event, this.state, pointerCoords.x, pointerCoords.y, (element, pointsSceneCoords) => {\n this.maybeSuggestBindingsForLinearElementAtCoords(element, pointsSceneCoords);\n }, linearElementEditor);\n\n if (didDrag) {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n pointerDownState.drag.hasOccurred = true;\n\n if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {\n this.setState({\n editingLinearElement: Object.assign(Object.assign({}, this.state.editingLinearElement), {\n isDragging: true\n })\n });\n }\n\n if (!this.state.selectedLinearElement.isDragging) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n isDragging: true\n })\n });\n }\n\n return;\n }\n }\n\n const hasHitASelectedElement = pointerDownState.hit.allHitElements.some(element => this.isASelectedElement(element));\n const isSelectingPointsInLineEditor = this.state.editingLinearElement && event.shiftKey && this.state.editingLinearElement.elementId === ((_a = pointerDownState.hit.element) === null || _a === void 0 ? void 0 : _a.id);\n\n if ((hasHitASelectedElement || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) && !isSelectingPointsInLineEditor) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.every(element => element.locked)) {\n return;\n }\n\n const selectedElementsHasAFrame = selectedElements.find(e => (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(e));\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(pointerCoords);\n this.setState({\n frameToHighlight: topLayerFrame && !selectedElementsHasAFrame ? topLayerFrame : null\n }); // Marking that click was used for dragging to check\n // if elements should be deselected on pointerup\n\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n }); // prevent dragging even if we're no longer holding cmd/ctrl otherwise\n // it would have weird results (stuff jumping all over the screen)\n // Checking for editingElement to avoid jump while editing on mobile #6503\n\n if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl && !this.state.editingElement && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) !== \"active\") {\n const dragOffset = {\n x: pointerCoords.x - pointerDownState.origin.x,\n y: pointerCoords.y - pointerDownState.origin.y\n };\n const originalElements = [...pointerDownState.originalElements.values()]; // We only drag in one direction if shift is pressed\n\n const lockDirection = event.shiftKey;\n\n if (lockDirection) {\n const distanceX = Math.abs(dragOffset.x);\n const distanceY = Math.abs(dragOffset.y);\n const lockX = lockDirection && distanceX < distanceY;\n const lockY = lockDirection && distanceX > distanceY;\n\n if (lockX) {\n dragOffset.x = 0;\n }\n\n if (lockY) {\n dragOffset.y = 0;\n }\n } // Snap cache *must* be synchronously popuplated before initial drag,\n // otherwise the first drag even will not snap, causing a jump before\n // it snaps to its position if previously snapped already.\n\n\n this.maybeCacheVisibleGaps(event, selectedElements);\n this.maybeCacheReferenceSnapPoints(event, selectedElements);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.snapDraggedElements)((0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(originalElements, this.state), dragOffset, this.state, event);\n this.setState({\n snapLines\n }); // when we're editing the name of a frame, we want the user to be\n // able to select and interact with the text input\n\n !this.state.editingFrame && (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragSelectedElements)(pointerDownState, selectedElements, dragOffset, this.state, this.scene, snapOffset, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n this.maybeSuggestBindingForAll(selectedElements); // We duplicate the selected element if alt is pressed on pointer move\n\n if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {\n // Move the currently selected elements to the top of the z index stack, and\n // put the duplicates where the selected elements used to be.\n // (the origin point where the dragging started)\n pointerDownState.hit.hasBeenDuplicated = true;\n const nextElements = [];\n const elementsToAppend = [];\n const groupIdMap = new Map();\n const oldIdToDuplicatedId = new Map();\n const hitElement = pointerDownState.hit.element;\n const selectedElementIds = new Set(this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n }).map(element => element.id));\n const elements = this.scene.getElementsIncludingDeleted();\n\n for (const element of elements) {\n if (selectedElementIds.has(element.id) || // case: the state.selectedElementIds might not have been\n // updated yet by the time this mousemove event is fired\n element.id === (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && pointerDownState.hit.wasAddedToSelection) {\n const duplicatedElement = (0,_element__WEBPACK_IMPORTED_MODULE_16__.duplicateElement)(this.state.editingGroupId, groupIdMap, element);\n const origElement = pointerDownState.originalElements.get(element.id);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(duplicatedElement, {\n x: origElement.x,\n y: origElement.y\n }); // put duplicated element to pointerDownState.originalElements\n // so that we can snap to the duplicated element without releasing\n\n pointerDownState.originalElements.set(duplicatedElement.id, duplicatedElement);\n nextElements.push(duplicatedElement);\n elementsToAppend.push(element);\n oldIdToDuplicatedId.set(element.id, duplicatedElement.id);\n } else {\n nextElements.push(element);\n }\n }\n\n const nextSceneElements = [...nextElements, ...elementsToAppend];\n (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.bindTextToShapeAfterDuplication)(nextElements, elementsToAppend, oldIdToDuplicatedId);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, \"duplicatesServeAsOld\");\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.bindElementsToFramesAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);\n this.scene.replaceAllElements(nextSceneElements);\n this.maybeCacheVisibleGaps(event, selectedElements, true);\n this.maybeCacheReferenceSnapPoints(event, selectedElements, true);\n }\n\n return;\n }\n } // It is very important to read this.state within each move event,\n // otherwise we would read a stale one!\n\n\n const draggingElement = this.state.draggingElement;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"freedraw\") {\n const points = draggingElement.points;\n const dx = pointerCoords.x - draggingElement.x;\n const dy = pointerCoords.y - draggingElement.y;\n const lastPoint = points.length > 0 && points[points.length - 1];\n const discardPoint = lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;\n\n if (!discardPoint) {\n const pressures = draggingElement.simulatePressure ? draggingElement.pressures : [...draggingElement.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures\n });\n }\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n });\n const points = draggingElement.points;\n let dx = gridX - draggingElement.x;\n let dy = gridY - draggingElement.y;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event) && points.length === 2) {\n ({\n width: dx,\n height: dy\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)(draggingElement.x, draggingElement.y, pointerCoords.x, pointerCoords.y));\n }\n\n if (points.length === 1) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]]\n });\n } else if (points.length === 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points.slice(0, -1), [dx, dy]]\n });\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n // When creating a linear element by dragging\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [pointerCoords], this.state.startBoundElement);\n }\n } else {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n this.maybeDragNewGenericElement(pointerDownState, event);\n }\n\n if (this.state.activeTool.type === \"selection\") {\n pointerDownState.boxSelection.hasOccurred = true;\n const elements = this.scene.getNonDeletedElements(); // box-select line editor points\n\n if (this.state.editingLinearElement) {\n _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handleBoxSelection(event, this.state, this.setState.bind(this)); // regular box-select\n } else {\n let shouldReuseSelection = true;\n\n if (!event.shiftKey && (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(elements, this.state)) {\n if (pointerDownState.withCmdOrCtrl && pointerDownState.hit.element) {\n this.setState(prevState => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)(Object.assign(Object.assign({}, prevState), {\n selectedElementIds: {\n [pointerDownState.hit.element.id]: true\n }\n }), this.scene.getNonDeletedElements(), prevState, this));\n } else {\n shouldReuseSelection = false;\n }\n }\n\n const elementsWithinSelection = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsWithinSelection)(elements, draggingElement);\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, shouldReuseSelection && prevState.selectedElementIds), elementsWithinSelection.reduce((acc, element) => {\n acc[element.id] = true;\n return acc;\n }, {}));\n\n if (pointerDownState.hit.element) {\n // if using ctrl/cmd, select the hitElement only if we\n // haven't box-selected anything else\n if (!elementsWithinSelection.length) {\n nextSelectedElementIds[pointerDownState.hit.element.id] = true;\n } else {\n delete nextSelectedElementIds[pointerDownState.hit.element.id];\n }\n }\n\n prevState = !shouldReuseSelection ? Object.assign(Object.assign({}, prevState), {\n selectedGroupIds: {},\n editingGroupId: null\n }) : prevState;\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // select linear element only when we haven't box-selected anything else\n selectedLinearElement: elementsWithinSelection.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(elementsWithinSelection[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(elementsWithinSelection[0], this.scene) : null,\n showHyperlinkPopup: elementsWithinSelection.length === 1 && (elementsWithinSelection[0].link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(elementsWithinSelection[0])) ? \"info\" : false\n });\n });\n }\n }\n });\n } // Returns whether the pointer move happened over either scrollbar\n\n\n handlePointerMoveOverScrollbars(event, pointerDownState) {\n if (pointerDownState.scrollbars.isOverHorizontal) {\n const x = event.clientX;\n const dx = x - pointerDownState.lastCoords.x;\n this.translateCanvas({\n scrollX: this.state.scrollX - dx / this.state.zoom.value\n });\n pointerDownState.lastCoords.x = x;\n return true;\n }\n\n if (pointerDownState.scrollbars.isOverVertical) {\n const y = event.clientY;\n const dy = y - pointerDownState.lastCoords.y;\n this.translateCanvas({\n scrollY: this.state.scrollY - dy / this.state.zoom.value\n });\n pointerDownState.lastCoords.y = y;\n return true;\n }\n\n return false;\n }\n\n onPointerUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(childEvent => {\n var _a, _b, _c, _d, _e, _f;\n\n if (pointerDownState.eventListeners.onMove) {\n pointerDownState.eventListeners.onMove.flush();\n }\n\n const {\n draggingElement,\n resizingElement,\n multiElement,\n activeTool,\n isResizing,\n isRotating\n } = this.state;\n this.setState({\n isResizing: false,\n isRotating: false,\n resizingElement: null,\n selectionElement: null,\n frameToHighlight: null,\n elementsToHighlight: null,\n cursorButton: \"up\",\n // text elements are reset on finalize, and resetting on pointerup\n // may cause issues with double taps\n editingElement: multiElement || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? this.state.editingElement : null,\n snapLines: [],\n originSnapOffset: null\n });\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.setReferenceSnapPoints(null);\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.setVisibleGaps(null);\n this.savePointer(childEvent.clientX, childEvent.clientY, \"up\");\n this.setState({\n selectedElementsAreBeingDragged: false\n }); // Handle end of dragging a point of a linear element, might close a loop\n // and sets binding element\n\n if (this.state.editingLinearElement) {\n if (!pointerDownState.boxSelection.hasOccurred && ((_b = (_a = pointerDownState.hit) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.id) !== this.state.editingLinearElement.elementId) {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n } else {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state);\n\n if (editingLinearElement !== this.state.editingLinearElement) {\n this.setState({\n editingLinearElement,\n suggestedBindings: []\n });\n }\n }\n } else if (this.state.selectedLinearElement) {\n if (((_d = (_c = pointerDownState.hit) === null || _c === void 0 ? void 0 : _c.element) === null || _d === void 0 ? void 0 : _d.id) !== this.state.selectedLinearElement.elementId) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement to null if there is more than one element selected since we don't want to show linear element handles\n\n if (selectedELements.length > 1) {\n this.setState({\n selectedLinearElement: null\n });\n }\n } else {\n const linearElementEditor = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state);\n const {\n startBindingElement,\n endBindingElement\n } = linearElementEditor;\n const element = this.scene.getElement(linearElementEditor.elementId);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindLinearElement)(element, startBindingElement, endBindingElement);\n }\n\n if (linearElementEditor !== this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, linearElementEditor), {\n selectedPointsIndices: null\n }),\n suggestedBindings: []\n });\n }\n }\n }\n\n lastPointerUp = null;\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, pointerDownState.eventListeners.onMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, pointerDownState.eventListeners.onUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, pointerDownState.eventListeners.onKeyDown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, pointerDownState.eventListeners.onKeyUp);\n\n if (this.state.pendingImageElementId) {\n this.setState({\n pendingImageElementId: null\n });\n }\n\n this.onPointerUpEmitter.trigger(this.state.activeTool, pointerDownState, childEvent);\n\n if ((draggingElement === null || draggingElement === void 0 ? void 0 : draggingElement.type) === \"freedraw\") {\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n const points = draggingElement.points;\n let dx = pointerCoords.x - draggingElement.x;\n let dy = pointerCoords.y - draggingElement.y; // Allows dots to avoid being flagged as infinitely small\n\n if (dx === points[0][0] && dy === points[0][1]) {\n dy += 0.0001;\n dx += 0.0001;\n }\n\n const pressures = draggingElement.simulatePressure ? [] : [...draggingElement.pressures, childEvent.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures,\n lastCommittedPoint: [dx, dy]\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement)) {\n const imageElement = draggingElement;\n\n try {\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } catch (error) {\n console.error(error);\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== imageElement.id));\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n }\n\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n if (draggingElement.points.length > 1) {\n this.history.resumeRecording();\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n\n if (!pointerDownState.drag.hasOccurred && draggingElement && !multiElement) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...draggingElement.points, [pointerCoords.x - draggingElement.x, pointerCoords.y - draggingElement.y]]\n });\n this.setState({\n multiElement: draggingElement,\n editingElement: this.state.draggingElement\n });\n } else if (pointerDownState.drag.hasOccurred && !multiElement) {\n if ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(draggingElement, this.state, this.scene, pointerCoords);\n }\n\n this.setState({\n suggestedBindings: [],\n startBoundElement: null\n });\n\n if (!activeTool.locked) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n this.setState(prevState => ({\n draggingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n }),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(draggingElement, this.scene)\n }));\n } else {\n this.setState(prevState => ({\n draggingElement: null\n }));\n }\n }\n\n return;\n }\n\n if (activeTool.type !== \"selection\" && draggingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(draggingElement)) {\n // remove invisible element which was added in onPointerDown\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== draggingElement.id));\n this.setState({\n draggingElement: null\n });\n return;\n }\n\n if (draggingElement) {\n if (pointerDownState.drag.hasOccurred) {\n const sceneCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state); // when editing the points of a linear element, we check if the\n // linear element still is in the frame afterwards\n // if not, the linear element will be removed from its frame (if any)\n\n if (this.state.selectedLinearElement && this.state.selectedLinearElement.isDragging) {\n const linearElement = this.scene.getElement(this.state.selectedLinearElement.elementId);\n\n if (linearElement === null || linearElement === void 0 ? void 0 : linearElement.frameId) {\n const frame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(linearElement);\n\n if (frame && linearElement) {\n if (!(0,_frame__WEBPACK_IMPORTED_MODULE_50__.elementOverlapsWithFrame)(linearElement, frame)) {\n // remove the linear element from all groups\n // before removing it from the frame as well\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(linearElement, {\n groupIds: []\n });\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.removeElementsFromFrame)(this.scene.getElementsIncludingDeleted(), [linearElement], this.state));\n }\n }\n }\n } else {\n // update the relationships between selected elements and frames\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(sceneCoords);\n const selectedElements = this.scene.getSelectedElements(this.state);\n let nextElements = this.scene.getElementsIncludingDeleted();\n\n const updateGroupIdsAfterEditingGroup = elements => {\n if (elements.length > 0) {\n for (const element of elements) {\n const index = element.groupIds.indexOf(this.state.editingGroupId);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: element.groupIds.slice(0, index)\n }, false);\n }\n\n nextElements.forEach(element => {\n if (element.groupIds.length && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(nextElements, element.groupIds[element.groupIds.length - 1]).length < 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: []\n }, false);\n }\n });\n this.setState({\n editingGroupId: null\n });\n }\n };\n\n if (topLayerFrame && !this.state.selectedElementIds[topLayerFrame.id]) {\n const elementsToAdd = selectedElements.filter(element => element.frameId !== topLayerFrame.id && (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n\n if (this.state.editingGroupId) {\n updateGroupIdsAfterEditingGroup(elementsToAdd);\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(nextElements, elementsToAdd, topLayerFrame);\n } else if (!topLayerFrame) {\n if (this.state.editingGroupId) {\n const elementsToRemove = selectedElements.filter(element => element.frameId && !(0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n updateGroupIdsAfterEditingGroup(elementsToRemove);\n }\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(nextElements, this.state, this);\n this.scene.replaceAllElements(nextElements);\n }\n }\n\n if (draggingElement.type === \"frame\") {\n const elementsInsideFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInNewFrame)(this.scene.getElementsIncludingDeleted(), draggingElement);\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(this.scene.getElementsIncludingDeleted(), elementsInsideFrame, draggingElement));\n }\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getNormalizedDimensions)(draggingElement));\n }\n\n if (resizingElement) {\n this.history.resumeRecording();\n }\n\n if (resizingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(resizingElement)) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== resizingElement.id));\n } // handle frame membership for resizing frames and/or selected elements\n\n\n if (pointerDownState.resize.isResizing) {\n let nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(this.scene.getElementsIncludingDeleted(), this.state, this);\n const selectedFrames = this.scene.getSelectedElements(this.state).filter(element => element.type === \"frame\");\n\n for (const frame of selectedFrames) {\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.replaceAllElementsInFrame)(nextElements, (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getElementsIncludingDeleted(), frame, this.state), frame, this.state);\n }\n\n this.scene.replaceAllElements(nextElements);\n } // Code below handles selection when element(s) weren't\n // drag or added to selection on pointer down phase.\n\n\n const hitElement = pointerDownState.hit.element;\n\n if (((_e = this.state.selectedLinearElement) === null || _e === void 0 ? void 0 : _e.elementId) !== (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement)) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement when no other element selected except\n // the one we've hit\n\n if (selectedELements.length === 1) {\n this.setState({\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene)\n });\n }\n }\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDownEvent.clientX, this.lastPointerDownEvent.clientY, this.lastPointerUpEvent.clientX, this.lastPointerUpEvent.clientY);\n\n if (draggedDistance === 0) {\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastPointerUpEvent.clientX,\n clientY: this.lastPointerUpEvent.clientY\n }, this.state);\n const hitElements = this.getElementsAtPosition(scenePointer.x, scenePointer.y);\n hitElements.forEach(hitElement => pointerDownState.elementIdsToErase[hitElement.id] = {\n erase: true,\n opacity: hitElement.opacity\n });\n }\n\n this.eraseElements(pointerDownState);\n return;\n } else if (Object.keys(pointerDownState.elementIdsToErase).length) {\n this.restoreReadyToEraseElements(pointerDownState);\n }\n\n if (hitElement && !pointerDownState.drag.hasOccurred && !pointerDownState.hit.wasAddedToSelection && ( // if we're editing a line, pointerup shouldn't switch selection if\n // box selected\n !this.state.editingLinearElement || !pointerDownState.boxSelection.hasOccurred)) {\n // when inside line editor, shift selects points instead\n if (childEvent.shiftKey && !this.state.editingLinearElement) {\n if (this.state.selectedElementIds[hitElement.id]) {\n if ((0,_groups__WEBPACK_IMPORTED_MODULE_23__.isSelectedViaGroup)(this.state, hitElement)) {\n this.setState(_prevState => {\n const nextSelectedElementIds = Object.assign({}, _prevState.selectedElementIds); // We want to unselect all groups hitElement is part of\n // as well as all elements that are part of the groups\n // hitElement is part of\n\n for (const groupedElement of hitElement.groupIds.flatMap(groupId => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), groupId))) {\n delete nextSelectedElementIds[groupedElement.id];\n }\n\n return {\n selectedGroupIds: Object.assign(Object.assign({}, _prevState.selectedElementIds), hitElement.groupIds.map(gId => ({\n [gId]: false\n })).reduce((prev, acc) => Object.assign(Object.assign({}, prev), acc), {})),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, _prevState)\n };\n }); // if not gragging a linear element point (outside editor)\n } else if (!((_f = this.state.selectedLinearElement) === null || _f === void 0 ? void 0 : _f.isDragging)) {\n // remove element from selection while\n // keeping prev elements selected\n this.setState(prevState => {\n const newSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete newSelectedElementIds[hitElement.id];\n const newSelectedElements = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(this.scene.getNonDeletedElements(), {\n selectedElementIds: newSelectedElementIds\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: newSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // set selectedLinearElement only if thats the only element selected\n selectedLinearElement: newSelectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(newSelectedElements[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(newSelectedElements[0], this.scene) : prevState.selectedLinearElement\n });\n });\n }\n } else if (hitElement.frameId && this.state.selectedElementIds[hitElement.frameId]) {\n // when hitElement is part of a selected frame, deselect the frame\n // to avoid frame and containing elements selected simultaneously\n this.setState(prevState => {\n var _a, _b;\n\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n }); // deselect the frame\n\n delete nextSelectedElementIds[hitElement.frameId]; // deselect groups containing the frame\n\n ((_b = (_a = this.scene.getElement(hitElement.frameId)) === null || _a === void 0 ? void 0 : _a.groupIds) !== null && _b !== void 0 ? _b : []).flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n showHyperlinkPopup: hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) ? \"info\" : false\n });\n });\n } else {\n // add element to selection while keeping prev elements selected\n this.setState(_prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, _prevState.selectedElementIds), {\n [hitElement.id]: true\n }), _prevState)\n }));\n }\n } else {\n this.setState(prevState => {\n var _a;\n\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement) && // Don't set `selectedLinearElement` if its same as the hitElement, this is mainly to prevent resetting the `hoverPointIndex` to -1.\n // Future we should update the API to take care of setting the correct `hoverPointIndex` when initialized\n ((_a = prevState.selectedLinearElement) === null || _a === void 0 ? void 0 : _a.elementId) !== hitElement.id ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene) : prevState.selectedLinearElement\n });\n });\n }\n }\n\n if (!pointerDownState.drag.hasOccurred && !this.state.isResizing && (hitElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(hitElement, this.state, this.frameNameBoundsCache, pointerDownState.origin.x, pointerDownState.origin.y) || !hitElement && pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements)) {\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: null\n });\n } else {\n // Deselect selected elements\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\" && draggingElement && draggingElement.type !== \"selection\") {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n showHyperlinkPopup: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(draggingElement) && !draggingElement.link ? \"editor\" : prevState.showHyperlinkPopup\n }));\n }\n\n if (activeTool.type !== \"selection\" || (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(this.scene.getNonDeletedElements(), this.state)) {\n this.history.resumeRecording();\n }\n\n if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {\n ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? _element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements : _element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(this.scene.getSelectedElements(this.state));\n }\n\n if (activeTool.type === \"laser\") {\n this.laserPathManager.endPath();\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n this.setState({\n draggingElement: null,\n suggestedBindings: [],\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n } else {\n this.setState({\n draggingElement: null,\n suggestedBindings: []\n });\n }\n\n if (hitElement && this.lastPointerUpEvent && this.lastPointerDownEvent && this.lastPointerUpEvent.timeStamp - this.lastPointerDownEvent.timeStamp < 300 && gesture.pointers.size <= 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, this.lastPointerUpEvent, pointerDownState.origin.x, pointerDownState.origin.y)) {\n this.handleEmbeddableCenterClick(hitElement);\n }\n });\n }\n\n maybeSuggestBindingForAll(selectedElements) {\n if (selectedElements.length > 50) {\n return;\n }\n\n const suggestedBindings = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getEligibleElementsForBinding)(selectedElements);\n this.setState({\n suggestedBindings\n });\n }\n\n clearSelection(hitElement) {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n activeEmbeddable: null,\n selectedGroupIds: {},\n // Continue editing the same group if the user selected a different\n // element from it\n editingGroupId: prevState.editingGroupId && hitElement != null && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, prevState.editingGroupId) ? prevState.editingGroupId : null\n }));\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null,\n previousSelectedElementIds: this.state.selectedElementIds\n });\n }\n\n getTextWysiwygSnappedToCenterPosition(x, y, appState, container) {\n if (container) {\n let elementCenterX = container.x + container.width / 2;\n let elementCenterY = container.y + container.height / 2;\n const elementCenter = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, appState);\n\n if (elementCenter) {\n elementCenterX = elementCenter.x;\n elementCenterY = elementCenter.y;\n }\n\n const distanceToCenter = Math.hypot(x - elementCenterX, y - elementCenterY);\n const isSnappedToCenter = distanceToCenter < _constants__WEBPACK_IMPORTED_MODULE_12__.TEXT_TO_CENTER_SNAP_THRESHOLD;\n\n if (isSnappedToCenter) {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: elementCenterX,\n sceneY: elementCenterY\n }, appState);\n return {\n viewportX,\n viewportY,\n elementCenterX,\n elementCenterY\n };\n }\n }\n }\n\n getCanvasOffsets() {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n left,\n top\n } = excalidrawContainer.getBoundingClientRect();\n return {\n offsetLeft: left,\n offsetTop: top\n };\n }\n\n return {\n offsetLeft: 0,\n offsetTop: 0\n };\n }\n\n updateLanguage() {\n return __awaiter(this, void 0, void 0, function* () {\n const currentLang = _i18n__WEBPACK_IMPORTED_MODULE_25__.languages.find(lang => lang.code === this.props.langCode) || _i18n__WEBPACK_IMPORTED_MODULE_25__.defaultLang;\n yield (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.setLanguage)(currentLang);\n this.setAppState({});\n });\n }\n\n}\n\nApp.defaultProps = {\n // needed for tests to pass since we directly render App in many tests\n UIOptions: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_UI_OPTIONS\n};\n\nif (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n window.h = window.h || {};\n Object.defineProperties(window.h, {\n elements: {\n configurable: true,\n\n get() {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.getElementsIncludingDeleted();\n },\n\n set(elements) {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.replaceAllElements(elements);\n }\n\n }\n });\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUFZLG1EQUFXO0FBQ3ZCLHlCQUF5QjtBQUN6QixLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGFBQWEsMkRBQWtCO0FBQy9COztBQUVBLElBQUksYUFBb0IsS0FBSyxpREFBUSxJQUFJLGFBQW9CO0FBQzdEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDs7QUFFQSxpRUFBZSxHQUFHIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2NvbXBvbmVudHMvQXBwLnRzeD82N2FlIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX2F3YWl0ZXIgPSB0aGlzICYmIHRoaXMuX19hd2FpdGVyIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcbiAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkge1xuICAgICAgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7XG4gICAgfVxuXG4gICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xuICB9KTtcbn07XG5cbmltcG9ydCB7IGpzeCBhcyBfanN4LCBqc3hzIGFzIF9qc3hzLCBGcmFnbWVudCBhcyBfRnJhZ21lbnQgfSBmcm9tIFwicmVhY3QvanN4LXJ1bnRpbWVcIjtcbmltcG9ydCBSZWFjdCwgeyB1c2VDb250ZXh0IH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBmbHVzaFN5bmMgfSBmcm9tIFwicmVhY3QtZG9tXCI7XG5pbXBvcnQgcm91Z2ggZnJvbSBcInJvdWdoanMvYmluL3JvdWdoXCI7XG5pbXBvcnQgY2xzeCBmcm9tIFwiY2xzeFwiO1xuaW1wb3J0IHsgbmFub2lkIH0gZnJvbSBcIm5hbm9pZFwiO1xuaW1wb3J0IHsgYWN0aW9uQWRkVG9MaWJyYXJ5LCBhY3Rpb25CcmluZ0ZvcndhcmQsIGFjdGlvbkJyaW5nVG9Gcm9udCwgYWN0aW9uQ29weSwgYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcsIGNvcHlUZXh0LCBhY3Rpb25Db3B5U3R5bGVzLCBhY3Rpb25DdXQsIGFjdGlvbkRlbGV0ZVNlbGVjdGVkLCBhY3Rpb25EdXBsaWNhdGVTZWxlY3Rpb24sIGFjdGlvbkZpbmFsaXplLCBhY3Rpb25GbGlwSG9yaXpvbnRhbCwgYWN0aW9uRmxpcFZlcnRpY2FsLCBhY3Rpb25Hcm91cCwgYWN0aW9uUGFzdGVTdHlsZXMsIGFjdGlvblNlbGVjdEFsbCwgYWN0aW9uU2VuZEJhY2t3YXJkLCBhY3Rpb25TZW5kVG9CYWNrLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHMsIGFjdGlvblRvZ2dsZVplbk1vZGUsIGFjdGlvblVuYmluZFRleHQsIGFjdGlvbkJpbmRUZXh0LCBhY3Rpb25Vbmdyb3VwLCBhY3Rpb25MaW5rLCBhY3Rpb25Ub2dnbGVFbGVtZW50TG9jaywgYWN0aW9uVG9nZ2xlTGluZWFyRWRpdG9yLCBhY3Rpb25Ub2dnbGVPYmplY3RzU25hcE1vZGUgfSBmcm9tIFwiLi4vYWN0aW9uc1wiO1xuaW1wb3J0IHsgY3JlYXRlUmVkb0FjdGlvbiwgY3JlYXRlVW5kb0FjdGlvbiB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkhpc3RvcnlcIjtcbmltcG9ydCB7IEFjdGlvbk1hbmFnZXIgfSBmcm9tIFwiLi4vYWN0aW9ucy9tYW5hZ2VyXCI7XG5pbXBvcnQgeyBhY3Rpb25zIH0gZnJvbSBcIi4uL2FjdGlvbnMvcmVnaXN0ZXJcIjtcbmltcG9ydCB7IHRyYWNrRXZlbnQgfSBmcm9tIFwiLi4vYW5hbHl0aWNzXCI7XG5pbXBvcnQgeyBnZXREZWZhdWx0QXBwU3RhdGUsIGlzRXJhc2VyQWN0aXZlLCBpc0hhbmRUb29sQWN0aXZlIH0gZnJvbSBcIi4uL2FwcFN0YXRlXCI7XG5pbXBvcnQgeyBwYXJzZUNsaXBib2FyZCB9IGZyb20gXCIuLi9jbGlwYm9hcmRcIjtcbmltcG9ydCB7IEFQUF9OQU1FLCBDVVJTT1JfVFlQRSwgREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hULCBERUZBVUxUX1VJX09QVElPTlMsIERFRkFVTFRfVkVSVElDQUxfQUxJR04sIERSQUdHSU5HX1RIUkVTSE9MRCwgRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZLCBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQsIEVMRU1FTlRfVFJBTlNMQVRFX0FNT1VOVCwgRU5WLCBFVkVOVCwgRlJBTUVfU1RZTEUsIEdSSURfU0laRSwgSU1BR0VfTUlNRV9UWVBFUywgSU1BR0VfUkVOREVSX1RJTUVPVVQsIGlzQW5kcm9pZCwgaXNCcmF2ZSwgTElORV9DT05GSVJNX1RIUkVTSE9MRCwgTUFYX0FMTE9XRURfRklMRV9CWVRFUywgTUlNRV9UWVBFUywgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9QT1JUUkFJVCwgTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEgsIFBPSU5URVJfQlVUVE9OLCBST1VORE5FU1MsIFNDUk9MTF9USU1FT1VULCBUQVBfVFdJQ0VfVElNRU9VVCwgVEVYVF9UT19DRU5URVJfU05BUF9USFJFU0hPTEQsIFRIRU1FLCBUSEVNRV9GSUxURVIsIFRPVUNIX0NUWF9NRU5VX1RJTUVPVVQsIFZFUlRJQ0FMX0FMSUdOLCBZT1VUVUJFX1NUQVRFUywgWk9PTV9TVEVQLCBQT0lOVEVSX0VWRU5UUyB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGV4cG9ydENhbnZhcywgbG9hZEZyb21CbG9iIH0gZnJvbSBcIi4uL2RhdGFcIjtcbmltcG9ydCBMaWJyYXJ5LCB7IGRpc3RyaWJ1dGVMaWJyYXJ5SXRlbXNPblNxdWFyZUdyaWQgfSBmcm9tIFwiLi4vZGF0YS9saWJyYXJ5XCI7XG5pbXBvcnQgeyByZXN0b3JlLCByZXN0b3JlRWxlbWVudHMgfSBmcm9tIFwiLi4vZGF0YS9yZXN0b3JlXCI7XG5pbXBvcnQgeyBkcmFnTmV3RWxlbWVudCwgZHJhZ1NlbGVjdGVkRWxlbWVudHMsIGR1cGxpY2F0ZUVsZW1lbnQsIGdldENvbW1vbkJvdW5kcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50LCBnZXREcmFnT2Zmc2V0WFksIGdldEVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSwgZ2V0Tm9ybWFsaXplZERpbWVuc2lvbnMsIGdldFJlc2l6ZUFycm93RGlyZWN0aW9uLCBnZXRSZXNpemVPZmZzZXRYWSwgZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplLCBnZXRUcmFuc2Zvcm1IYW5kbGVUeXBlRnJvbUNvb3JkcywgaGl0VGVzdCwgaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50LCBpc0ludmlzaWJseVNtYWxsRWxlbWVudCwgaXNOb25EZWxldGVkRWxlbWVudCwgaXNUZXh0RWxlbWVudCwgbmV3RWxlbWVudCwgbmV3TGluZWFyRWxlbWVudCwgbmV3VGV4dEVsZW1lbnQsIG5ld0ltYWdlRWxlbWVudCwgdGV4dFd5c2l3eWcsIHRyYW5zZm9ybUVsZW1lbnRzLCB1cGRhdGVUZXh0RWxlbWVudCwgcmVkcmF3VGV4dEJvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnRcIjtcbmltcG9ydCB7IGJpbmRPclVuYmluZExpbmVhckVsZW1lbnQsIGJpbmRPclVuYmluZFNlbGVjdGVkRWxlbWVudHMsIGZpeEJpbmRpbmdzQWZ0ZXJEZWxldGlvbiwgZml4QmluZGluZ3NBZnRlckR1cGxpY2F0aW9uLCBnZXRFbGlnaWJsZUVsZW1lbnRzRm9yQmluZGluZywgZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nLCBpc0JpbmRpbmdFbmFibGVkLCBpc0xpbmVhckVsZW1lbnRTaW1wbGVBbmRBbHJlYWR5Qm91bmQsIG1heWJlQmluZExpbmVhckVsZW1lbnQsIHNob3VsZEVuYWJsZUJpbmRpbmdGb3JQb2ludGVyRXZlbnQsIHVuYmluZExpbmVhckVsZW1lbnRzLCB1cGRhdGVCb3VuZEVsZW1lbnRzIH0gZnJvbSBcIi4uL2VsZW1lbnQvYmluZGluZ1wiO1xuaW1wb3J0IHsgTGluZWFyRWxlbWVudEVkaXRvciB9IGZyb20gXCIuLi9lbGVtZW50L2xpbmVhckVsZW1lbnRFZGl0b3JcIjtcbmltcG9ydCB7IG11dGF0ZUVsZW1lbnQsIG5ld0VsZW1lbnRXaXRoIH0gZnJvbSBcIi4uL2VsZW1lbnQvbXV0YXRlRWxlbWVudFwiO1xuaW1wb3J0IHsgZGVlcENvcHlFbGVtZW50LCBkdXBsaWNhdGVFbGVtZW50cywgbmV3RnJhbWVFbGVtZW50LCBuZXdGcmVlRHJhd0VsZW1lbnQsIG5ld0VtYmVkZGFibGVFbGVtZW50IH0gZnJvbSBcIi4uL2VsZW1lbnQvbmV3RWxlbWVudFwiO1xuaW1wb3J0IHsgaGFzQm91bmRUZXh0RWxlbWVudCwgaXNBcnJvd0VsZW1lbnQsIGlzQmluZGluZ0VsZW1lbnQsIGlzQmluZGluZ0VsZW1lbnRUeXBlLCBpc0JvdW5kVG9Db250YWluZXIsIGlzRnJhbWVFbGVtZW50LCBpc0ltYWdlRWxlbWVudCwgaXNFbWJlZGRhYmxlRWxlbWVudCwgaXNJbml0aWFsaXplZEltYWdlRWxlbWVudCwgaXNMaW5lYXJFbGVtZW50LCBpc0xpbmVhckVsZW1lbnRUeXBlLCBpc1VzaW5nQWRhcHRpdmVSYWRpdXMgfSBmcm9tIFwiLi4vZWxlbWVudC90eXBlQ2hlY2tzXCI7XG5pbXBvcnQgeyBnZXRDZW50ZXIsIGdldERpc3RhbmNlIH0gZnJvbSBcIi4uL2dlc3R1cmVcIjtcbmltcG9ydCB7IGVkaXRHcm91cEZvclNlbGVjdGVkRWxlbWVudCwgZ2V0RWxlbWVudHNJbkdyb3VwLCBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50LCBnZXRTZWxlY3RlZEdyb3VwSWRzLCBpc0VsZW1lbnRJbkdyb3VwLCBpc1NlbGVjdGVkVmlhR3JvdXAsIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMgfSBmcm9tIFwiLi4vZ3JvdXBzXCI7XG5pbXBvcnQgSGlzdG9yeSBmcm9tIFwiLi4vaGlzdG9yeVwiO1xuaW1wb3J0IHsgZGVmYXVsdExhbmcsIGdldExhbmd1YWdlLCBsYW5ndWFnZXMsIHNldExhbmd1YWdlLCB0IH0gZnJvbSBcIi4uL2kxOG5cIjtcbmltcG9ydCB7IENPREVTLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyLCBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvLCBzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZSwgaXNBcnJvd0tleSwgS0VZUyB9IGZyb20gXCIuLi9rZXlzXCI7XG5pbXBvcnQgeyBpc0VsZW1lbnRJblZpZXdwb3J0IH0gZnJvbSBcIi4uL2VsZW1lbnQvc2l6ZUhlbHBlcnNcIjtcbmltcG9ydCB7IGRpc3RhbmNlMmQsIGdldENvcm5lclJhZGl1cywgZ2V0R3JpZFBvaW50LCBpc1BhdGhBTG9vcCB9IGZyb20gXCIuLi9tYXRoXCI7XG5pbXBvcnQgeyBjYWxjdWxhdGVTY3JvbGxDZW50ZXIsIGdldEVsZW1lbnRzQXRQb3NpdGlvbiwgZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24sIGdldE5vcm1hbGl6ZWRab29tLCBnZXRTZWxlY3RlZEVsZW1lbnRzLCBoYXNCYWNrZ3JvdW5kLCBpc092ZXJTY3JvbGxCYXJzLCBpc1NvbWVFbGVtZW50U2VsZWN0ZWQgfSBmcm9tIFwiLi4vc2NlbmVcIjtcbmltcG9ydCBTY2VuZSBmcm9tIFwiLi4vc2NlbmUvU2NlbmVcIjtcbmltcG9ydCB7IGdldFN0YXRlRm9yWm9vbSB9IGZyb20gXCIuLi9zY2VuZS96b29tXCI7XG5pbXBvcnQgeyBmaW5kU2hhcGVCeUtleSB9IGZyb20gXCIuLi9zaGFwZXNcIjtcbmltcG9ydCB7IGRlYm91bmNlLCBkaXN0YW5jZSwgZ2V0Rm9udFN0cmluZywgZ2V0TmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIsIGlzSW5wdXRMaWtlLCBpc1Rvb2xJY29uLCBpc1dyaXRhYmxlRWxlbWVudCwgc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzLCB0dXBsZVRvQ29vcnMsIHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcywgd2l0aEJhdGNoZWRVcGRhdGVzLCB3cmFwRXZlbnQsIHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZCwgdXBkYXRlT2JqZWN0LCB1cGRhdGVBY3RpdmVUb29sLCBnZXRTaG9ydGN1dEtleSwgaXNUcmFuc3BhcmVudCwgZWFzZVRvVmFsdWVzUkFGLCBtdXRlRlNBYm9ydEVycm9yLCBpc1Rlc3RFbnYsIGVhc2VPdXQgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IsIGV4dHJhY3RTcmMsIGdldEVtYmVkTGluayB9IGZyb20gXCIuLi9lbGVtZW50L2VtYmVkZGFibGVcIjtcbmltcG9ydCB7IENvbnRleHRNZW51LCBDT05URVhUX01FTlVfU0VQQVJBVE9SIH0gZnJvbSBcIi4vQ29udGV4dE1lbnVcIjtcbmltcG9ydCBMYXllclVJIGZyb20gXCIuL0xheWVyVUlcIjtcbmltcG9ydCB7IFRvYXN0IH0gZnJvbSBcIi4vVG9hc3RcIjtcbmltcG9ydCB7IGFjdGlvblRvZ2dsZVZpZXdNb2RlIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uVG9nZ2xlVmlld01vZGVcIjtcbmltcG9ydCB7IGRhdGFVUkxUb0ZpbGUsIGdlbmVyYXRlSWRGcm9tRmlsZSwgZ2V0RGF0YVVSTCwgZ2V0RmlsZUZyb21FdmVudCwgSW1hZ2VVUkxUb0ZpbGUsIGlzSW1hZ2VGaWxlSGFuZGxlLCBpc1N1cHBvcnRlZEltYWdlRmlsZSwgbG9hZFNjZW5lT3JMaWJyYXJ5RnJvbUJsb2IsIG5vcm1hbGl6ZUZpbGUsIHBhcnNlTGlicmFyeUpTT04sIHJlc2l6ZUltYWdlRmlsZSwgU1ZHU3RyaW5nVG9GaWxlIH0gZnJvbSBcIi4uL2RhdGEvYmxvYlwiO1xuaW1wb3J0IHsgZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzLCBsb2FkSFRNTEltYWdlRWxlbWVudCwgbm9ybWFsaXplU1ZHLCB1cGRhdGVJbWFnZUNhY2hlIGFzIF91cGRhdGVJbWFnZUNhY2hlIH0gZnJvbSBcIi4uL2VsZW1lbnQvaW1hZ2VcIjtcbmltcG9ydCB0aHJvdHRsZSBmcm9tIFwibG9kYXNoLnRocm90dGxlXCI7XG5pbXBvcnQgeyBmaWxlT3BlbiB9IGZyb20gXCIuLi9kYXRhL2ZpbGVzeXN0ZW1cIjtcbmltcG9ydCB7IGJpbmRUZXh0VG9TaGFwZUFmdGVyRHVwbGljYXRpb24sIGdldEFwcHJveE1pbkxpbmVIZWlnaHQsIGdldEFwcHJveE1pbkxpbmVXaWR0aCwgZ2V0Qm91bmRUZXh0RWxlbWVudCwgZ2V0Q29udGFpbmVyQ2VudGVyLCBnZXRDb250YWluZXJFbGVtZW50LCBnZXREZWZhdWx0TGluZUhlaWdodCwgZ2V0TGluZUhlaWdodEluUHgsIGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24sIGlzTWVhc3VyZVRleHRTdXBwb3J0ZWQsIGlzVmFsaWRUZXh0Q29udGFpbmVyIH0gZnJvbSBcIi4uL2VsZW1lbnQvdGV4dEVsZW1lbnRcIjtcbmltcG9ydCB7IGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnQvY29sbGlzaW9uXCI7XG5pbXBvcnQgeyBzaG93SHlwZXJsaW5rVG9vbHRpcCwgaGlkZUh5cGVybGlua1Rvb2xpcCwgSHlwZXJsaW5rLCBpc1BvaW50SGl0dGluZ0xpbmssIGlzUG9pbnRIaXR0aW5nTGlua0ljb24gfSBmcm9tIFwiLi4vZWxlbWVudC9IeXBlcmxpbmtcIjtcbmltcG9ydCB7IGlzTG9jYWxMaW5rLCBub3JtYWxpemVMaW5rLCB0b1ZhbGlkVVJMIH0gZnJvbSBcIi4uL2RhdGEvdXJsXCI7XG5pbXBvcnQgeyBzaG91bGRTaG93Qm91bmRpbmdCb3ggfSBmcm9tIFwiLi4vZWxlbWVudC90cmFuc2Zvcm1IYW5kbGVzXCI7XG5pbXBvcnQgeyBhY3Rpb25VbmxvY2tBbGxFbGVtZW50cyB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkVsZW1lbnRMb2NrXCI7XG5pbXBvcnQgeyBGb250cyB9IGZyb20gXCIuLi9zY2VuZS9Gb250c1wiO1xuaW1wb3J0IHsgZ2V0RnJhbWVDaGlsZHJlbiwgaXNDdXJzb3JJbkZyYW1lLCBiaW5kRWxlbWVudHNUb0ZyYW1lc0FmdGVyRHVwbGljYXRpb24sIGFkZEVsZW1lbnRzVG9GcmFtZSwgcmVwbGFjZUFsbEVsZW1lbnRzSW5GcmFtZSwgcmVtb3ZlRWxlbWVudHNGcm9tRnJhbWUsIGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lLCBnZXRFbGVtZW50c0luTmV3RnJhbWUsIGdldENvbnRhaW5pbmdGcmFtZSwgZWxlbWVudE92ZXJsYXBzV2l0aEZyYW1lLCB1cGRhdGVGcmFtZU1lbWJlcnNoaXBPZlNlbGVjdGVkRWxlbWVudHMsIGlzRWxlbWVudEluRnJhbWUgfSBmcm9tIFwiLi4vZnJhbWVcIjtcbmltcG9ydCB7IGV4Y2x1ZGVFbGVtZW50c0luRnJhbWVzRnJvbVNlbGVjdGlvbiwgbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMgfSBmcm9tIFwiLi4vc2NlbmUvc2VsZWN0aW9uXCI7XG5pbXBvcnQgeyBhY3Rpb25QYXN0ZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkNsaXBib2FyZFwiO1xuaW1wb3J0IHsgYWN0aW9uUmVtb3ZlQWxsRWxlbWVudHNGcm9tRnJhbWUsIGFjdGlvblNlbGVjdEFsbEVsZW1lbnRzSW5GcmFtZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkZyYW1lXCI7XG5pbXBvcnQgeyBhY3Rpb25Ub2dnbGVIYW5kVG9vbCwgem9vbVRvRml0IH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uQ2FudmFzXCI7XG5pbXBvcnQgeyBqb3RhaVN0b3JlIH0gZnJvbSBcIi4uL2pvdGFpXCI7XG5pbXBvcnQgeyBhY3RpdmVDb25maXJtRGlhbG9nQXRvbSB9IGZyb20gXCIuL0FjdGl2ZUNvbmZpcm1EaWFsb2dcIjtcbmltcG9ydCB7IEltYWdlU2NlbmVEYXRhRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBnZXRTbmFwTGluZXNBdFBvaW50ZXIsIHNuYXBEcmFnZ2VkRWxlbWVudHMsIGlzQWN0aXZlVG9vbE5vbkxpbmVhclNuYXBwYWJsZSwgc25hcE5ld0VsZW1lbnQsIHNuYXBSZXNpemluZ0VsZW1lbnRzLCBpc1NuYXBwaW5nRW5hYmxlZCwgZ2V0VmlzaWJsZUdhcHMsIGdldFJlZmVyZW5jZVNuYXBQb2ludHMsIFNuYXBDYWNoZSB9IGZyb20gXCIuLi9zbmFwcGluZ1wiO1xuaW1wb3J0IHsgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkJvdW5kVGV4dFwiO1xuaW1wb3J0IEJyYXZlTWVhc3VyZVRleHRFcnJvciBmcm9tIFwiLi9CcmF2ZU1lYXN1cmVUZXh0RXJyb3JcIjtcbmltcG9ydCB7IGFjdGl2ZUV5ZURyb3BwZXJBdG9tIH0gZnJvbSBcIi4vRXllRHJvcHBlclwiO1xuaW1wb3J0IHsgY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzIH0gZnJvbSBcIi4uL2RhdGEvdHJhbnNmb3JtXCI7XG5pbXBvcnQgeyBpc1NpZGViYXJEb2NrZWRBdG9tIH0gZnJvbSBcIi4vU2lkZWJhci9TaWRlYmFyXCI7XG5pbXBvcnQgeyBTdGF0aWNDYW52YXMsIEludGVyYWN0aXZlQ2FudmFzIH0gZnJvbSBcIi4vY2FudmFzZXNcIjtcbmltcG9ydCB7IFJlbmRlcmVyIH0gZnJvbSBcIi4uL3NjZW5lL1JlbmRlcmVyXCI7XG5pbXBvcnQgeyBTaGFwZUNhY2hlIH0gZnJvbSBcIi4uL3NjZW5lL1NoYXBlQ2FjaGVcIjtcbmltcG9ydCBNZXJtYWlkVG9FeGNhbGlkcmF3IGZyb20gXCIuL01lcm1haWRUb0V4Y2FsaWRyYXdcIjtcbmltcG9ydCB7IExhc2VyVG9vbE92ZXJsYXkgfSBmcm9tIFwiLi9MYXNlclRvb2wvTGFzZXJUb29sXCI7XG5pbXBvcnQgeyBMYXNlclBhdGhNYW5hZ2VyIH0gZnJvbSBcIi4vTGFzZXJUb29sL0xhc2VyUGF0aE1hbmFnZXJcIjtcbmltcG9ydCB7IHNldEVyYXNlckN1cnNvciwgc2V0Q3Vyc29yLCByZXNldEN1cnNvciwgc2V0Q3Vyc29yRm9yU2hhcGUgfSBmcm9tIFwiLi4vY3Vyc29yXCI7XG5pbXBvcnQgeyBFbWl0dGVyIH0gZnJvbSBcIi4uL2VtaXR0ZXJcIjtcbmNvbnN0IEFwcENvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuY29uc3QgQXBwUHJvcHNDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChudWxsKTtcbmNvbnN0IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWUgPSB7XG4gIHZpZXdwb3J0OiB7XG4gICAgaXNNb2JpbGU6IGZhbHNlLFxuICAgIGlzTGFuZHNjYXBlOiBmYWxzZVxuICB9LFxuICBlZGl0b3I6IHtcbiAgICBpc01vYmlsZTogZmFsc2UsXG4gICAgY2FuRml0U2lkZWJhcjogZmFsc2VcbiAgfSxcbiAgaXNUb3VjaFNjcmVlbjogZmFsc2Vcbn07XG5jb25zdCBEZXZpY2VDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChkZXZpY2VDb250ZXh0SW5pdGlhbFZhbHVlKTtcbkRldmljZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkRldmljZUNvbnRleHRcIjtcbmV4cG9ydCBjb25zdCBFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoe1xuICBjb250YWluZXI6IG51bGwsXG4gIGlkOiBudWxsXG59KTtcbkV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoW10pO1xuRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXREZWZhdWx0QXBwU3RhdGUoKSksIHtcbiAgd2lkdGg6IDAsXG4gIGhlaWdodDogMCxcbiAgb2Zmc2V0TGVmdDogMCxcbiAgb2Zmc2V0VG9wOiAwXG59KSk7XG5FeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dCgoKSA9PiB7XG4gIGNvbnNvbGUud2FybihcInVuaXRpYWxpemVkIEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQgY29udGV4dCFcIik7XG59KTtcbkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQobnVsbCk7XG5FeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dFwiO1xuZXhwb3J0IGNvbnN0IHVzZUFwcCA9ICgpID0+IHVzZUNvbnRleHQoQXBwQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlQXBwUHJvcHMgPSAoKSA9PiB1c2VDb250ZXh0KEFwcFByb3BzQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRGV2aWNlID0gKCkgPT4gdXNlQ29udGV4dChEZXZpY2VDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3Q29udGFpbmVyID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0VsZW1lbnRzID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3QXBwU3RhdGUgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdTZXRBcHBTdGF0ZSA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXIgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCk7XG5jb25zdCBzdXBwb3J0c1Jlc2l6ZU9ic2VydmVyID0gdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiAmJiBcIlJlc2l6ZU9ic2VydmVyXCIgaW4gd2luZG93O1xubGV0IGRpZFRhcFR3aWNlID0gZmFsc2U7XG5sZXQgdGFwcGVkVHdpY2VUaW1lciA9IDA7XG5sZXQgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbmxldCBpc1Bhbm5pbmcgPSBmYWxzZTtcbmxldCBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gZmFsc2U7XG5sZXQgY3VycmVudFNjcm9sbEJhcnMgPSB7XG4gIGhvcml6b250YWw6IG51bGwsXG4gIHZlcnRpY2FsOiBudWxsXG59O1xubGV0IHRvdWNoVGltZW91dCA9IDA7XG5sZXQgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG4vKipcbiAqIE1hcCBvZiB5b3V0dWJlIGVtYmVkIHZpZGVvIHN0YXRlc1xuICovXG5cbmNvbnN0IFlPVVRVQkVfVklERU9fU1RBVEVTID0gbmV3IE1hcCgpO1xubGV0IElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG5sZXQgSVNfUExBSU5fUEFTVEVfVElNRVIgPSAwO1xubGV0IFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gZmFsc2U7XG5sZXQgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG5jb25zdCBnZXN0dXJlID0ge1xuICBwb2ludGVyczogbmV3IE1hcCgpLFxuICBsYXN0Q2VudGVyOiBudWxsLFxuICBpbml0aWFsRGlzdGFuY2U6IG51bGwsXG4gIGluaXRpYWxTY2FsZTogbnVsbFxufTtcblxuY2xhc3MgQXBwIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyA9IG51bGw7XG4gICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICB0aGlzLmRldmljZSA9IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWU7XG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmID0gUmVhY3QuY3JlYXRlUmVmKCk7XG4gICAgdGhpcy5maWxlcyA9IHt9O1xuICAgIHRoaXMuaW1hZ2VDYWNoZSA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmlGcmFtZVJlZnMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCA9IG51bGw7XG4gICAgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQgPSBudWxsO1xuICAgIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24gPSB7XG4gICAgICB4OiAwLFxuICAgICAgeTogMFxuICAgIH07XG4gICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyID0gbmV3IExhc2VyUGF0aE1hbmFnZXIodGhpcyk7XG4gICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyVXBFbWl0dGVyID0gbmV3IEVtaXR0ZXIoKTtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBlbWJlZGRhYmxlRWxlbWVudHMgPSBuZXcgTWFwKCk7XG4gICAgICBsZXQgdXBkYXRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgZW1iZWRkYWJsZUVsZW1lbnRzLnNldChlbGVtZW50LmlkLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50LnZhbGlkYXRlZCA9PSBudWxsKSB7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlZCA9IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IoZWxlbWVudC5saW5rLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSk7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgdmFsaWRhdGVkXG4gICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWQpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgfSAvLyBHQ1xuXG5cbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5mb3JFYWNoKChyZWYsIGlkKSA9PiB7XG4gICAgICAgIGlmICghZW1iZWRkYWJsZUVsZW1lbnRzLmhhcyhpZCkpIHtcbiAgICAgICAgICB0aGlzLmlGcmFtZVJlZnMuZGVsZXRlKGlkKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQgPSBmcmFtZUVsZW1lbnQgPT4ge1xuICAgICAgcmV0dXJuIGAke3RoaXMuaWR9LWZyYW1lLW5hbWUtJHtmcmFtZUVsZW1lbnQuaWR9YDtcbiAgICB9O1xuXG4gICAgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSA9IHtcbiAgICAgIGdldDogZnJhbWVFbGVtZW50ID0+IHtcbiAgICAgICAgbGV0IGJvdW5kcyA9IHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLmdldChmcmFtZUVsZW1lbnQuaWQpO1xuXG4gICAgICAgIGlmICghYm91bmRzIHx8IGJvdW5kcy56b29tICE9PSB0aGlzLnN0YXRlLnpvb20udmFsdWUgfHwgYm91bmRzLnZlcnNpb25Ob25jZSAhPT0gZnJhbWVFbGVtZW50LnZlcnNpb25Ob25jZSkge1xuICAgICAgICAgIGNvbnN0IGZyYW1lTmFtZURpdiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQoZnJhbWVFbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoZnJhbWVOYW1lRGl2KSB7XG4gICAgICAgICAgICBjb25zdCBib3ggPSBmcmFtZU5hbWVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBjb25zdCBib3hTY2VuZVRvcExlZnQgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgICBjbGllbnRYOiBib3gueCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LnlcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3QgYm94U2NlbmVCb3R0b21SaWdodCA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICAgIGNsaWVudFg6IGJveC5yaWdodCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LmJvdHRvbVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBib3VuZHMgPSB7XG4gICAgICAgICAgICAgIHg6IGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICB5OiBib3hTY2VuZVRvcExlZnQueSxcbiAgICAgICAgICAgICAgd2lkdGg6IGJveFNjZW5lQm90dG9tUmlnaHQueCAtIGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICBoZWlnaHQ6IGJveFNjZW5lQm90dG9tUmlnaHQueSAtIGJveFNjZW5lVG9wTGVmdC55LFxuICAgICAgICAgICAgICBhbmdsZTogMCxcbiAgICAgICAgICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLnZhbHVlLFxuICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IGZyYW1lRWxlbWVudC52ZXJzaW9uTm9uY2VcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLnNldChmcmFtZUVsZW1lbnQuaWQsIGJvdW5kcyk7XG5cbiAgICAgICAgICAgIHJldHVybiBib3VuZHM7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYm91bmRzO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICovXG4gICAgICBfY2FjaGU6IG5ldyBNYXAoKVxuICAgIH07XG5cbiAgICB0aGlzLnJlbmRlckZyYW1lTmFtZXMgPSAoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCB8fCAhdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc0RhcmtUaGVtZSA9IHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiO1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLm1hcCgoZiwgaW5kZXgpID0+IHtcbiAgICAgICAgaWYgKCFpc0VsZW1lbnRJblZpZXdwb3J0KGYsIHRoaXMuY2FudmFzLndpZHRoIC8gd2luZG93LmRldmljZVBpeGVsUmF0aW8sIHRoaXMuY2FudmFzLmhlaWdodCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLCB7XG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb21cbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAvLyBpZiBmcmFtZSBub3QgdmlzaWJsZSwgZG9uJ3QgcmVuZGVyIGl0cyBuYW1lXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogeDEsXG4gICAgICAgICAgeTogeTFcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBmLngsXG4gICAgICAgICAgc2NlbmVZOiBmLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IEZSQU1FX05BTUVfRURJVF9QQURESU5HID0gNjtcblxuICAgICAgICBjb25zdCByZXNldCA9ICgpID0+IHtcbiAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICBpZiAoKChfYSA9IGYubmFtZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRyaW0oKSkgPT09IFwiXCIpIHtcbiAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZiwge1xuICAgICAgICAgICAgICBuYW1lOiBudWxsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIGxldCBmcmFtZU5hbWVKU1g7XG5cbiAgICAgICAgaWYgKGYuaWQgPT09IHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lKSB7XG4gICAgICAgICAgY29uc3QgZnJhbWVOYW1lSW5FZGl0ID0gZi5uYW1lID09IG51bGwgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZTtcbiAgICAgICAgICBmcmFtZU5hbWVKU1ggPSBfanN4KFwiaW5wdXRcIiwge1xuICAgICAgICAgICAgYXV0b0ZvY3VzOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IGZyYW1lTmFtZUluRWRpdCxcbiAgICAgICAgICAgIG9uQ2hhbmdlOiBlID0+IHtcbiAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChmLCB7XG4gICAgICAgICAgICAgICAgbmFtZTogZS50YXJnZXQudmFsdWVcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25CbHVyOiAoKSA9PiByZXNldCgpLFxuICAgICAgICAgICAgb25LZXlEb3duOiBldmVudCA9PiB7XG4gICAgICAgICAgICAgIC8vIGZvciBzb21lIGluZXhwbGljYWJsZSByZWFzb24sIGBvbkJsdXJgIHRyaWdnZXJlZCBvbiBFU0NcbiAgICAgICAgICAgICAgLy8gZG9lcyBub3QgcmVzZXQgYHN0YXRlLmVkaXRpbmdGcmFtZWAgZGVzcGl0ZSBiZWluZyBjYWxsZWQsXG4gICAgICAgICAgICAgIC8vIGFuZCB3ZSBuZWVkIHRvIHJlc2V0IGl0IGhlcmUgYXMgd2VsbFxuICAgICAgICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkVTQ0FQRSB8fCBldmVudC5rZXkgPT09IEtFWVMuRU5URVIpIHtcbiAgICAgICAgICAgICAgICByZXNldCgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgYmFja2dyb3VuZDogdGhpcy5zdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yLFxuICAgICAgICAgICAgICBmaWx0ZXI6IGlzRGFya1RoZW1lID8gVEhFTUVfRklMVEVSIDogXCJub25lXCIsXG4gICAgICAgICAgICAgIHpJbmRleDogMixcbiAgICAgICAgICAgICAgYm9yZGVyOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgZGlzcGxheTogXCJibG9ja1wiLFxuICAgICAgICAgICAgICBwYWRkaW5nOiBgJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weGAsXG4gICAgICAgICAgICAgIGJvcmRlclJhZGl1czogNCxcbiAgICAgICAgICAgICAgYm94U2hhZG93OiBcImluc2V0IDAgMCAwIDFweCB2YXIoLS1jb2xvci1wcmltYXJ5KVwiLFxuICAgICAgICAgICAgICBmb250RmFtaWx5OiBcIkFzc2lzdGFudFwiLFxuICAgICAgICAgICAgICBmb250U2l6ZTogXCIxNHB4XCIsXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogYHRyYW5zbGF0ZSgtJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weCwgJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weClgLFxuICAgICAgICAgICAgICBjb2xvcjogXCJ2YXIoLS1jb2xvci1ncmF5LTgwKVwiLFxuICAgICAgICAgICAgICBvdmVyZmxvdzogXCJoaWRkZW5cIixcbiAgICAgICAgICAgICAgbWF4V2lkdGg6IGAke2RvY3VtZW50LmJvZHkuY2xpZW50V2lkdGggLSB4MSAtIEZSQU1FX05BTUVfRURJVF9QQURESU5HfXB4YFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNpemU6IGZyYW1lTmFtZUluRWRpdC5sZW5ndGggKyAxIHx8IDEsXG4gICAgICAgICAgICBkaXI6IFwiYXV0b1wiLFxuICAgICAgICAgICAgYXV0b0NvbXBsZXRlOiBcIm9mZlwiLFxuICAgICAgICAgICAgYXV0b0NhcGl0YWxpemU6IFwib2ZmXCIsXG4gICAgICAgICAgICBhdXRvQ29ycmVjdDogXCJvZmZcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IGYubmFtZSA9PSBudWxsIHx8IGYubmFtZS50cmltKCkgPT09IFwiXCIgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZS50cmltKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBpZDogdGhpcy5nZXRGcmFtZU5hbWVET01JZChmKSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgcG9zaXRpb246IFwiYWJzb2x1dGVcIixcbiAgICAgICAgICAgIC8vIFBvc2l0aW9uaW5nIGZyb20gYm90dG9tIHNvIHRoYXQgd2UgZG9uJ3QgdG8gZWl0aGVyXG4gICAgICAgICAgICAvLyBjYWxjdWxhdGUgdGV4dCBoZWlnaHQgb3IgYWRqdXN0IHVzaW5nIHRyYW5zZm9ybSAod2hpY2gpXG4gICAgICAgICAgICAvLyBtZXNzZXMgdXAgaW5wdXQgcG9zaXRpb24gd2hlbiBlZGl0aW5nIHRoZSBmcmFtZSBuYW1lLlxuICAgICAgICAgICAgLy8gVGhpcyBtYWtlcyB0aGUgcG9zaXRpb25pbmcgZGV0ZXJtaW5pc3RpYyBhbmQgd2UgY2FuIGNhbGN1bGF0ZVxuICAgICAgICAgICAgLy8gdGhlIHNhbWUgcG9zaXRpb24gd2hlbiByZW5kZXJpbmcgdG8gY2FudmFzIC8gc3ZnLlxuICAgICAgICAgICAgYm90dG9tOiBgJHt0aGlzLnN0YXRlLmhlaWdodCArIEZSQU1FX1NUWUxFLm5hbWVPZmZzZXRZIC0geTEgKyB0aGlzLnN0YXRlLm9mZnNldFRvcH1weGAsXG4gICAgICAgICAgICBsZWZ0OiBgJHt4MSAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdH1weGAsXG4gICAgICAgICAgICB6SW5kZXg6IDIsXG4gICAgICAgICAgICBmb250U2l6ZTogRlJBTUVfU1RZTEUubmFtZUZvbnRTaXplLFxuICAgICAgICAgICAgY29sb3I6IGlzRGFya1RoZW1lID8gRlJBTUVfU1RZTEUubmFtZUNvbG9yRGFya1RoZW1lIDogRlJBTUVfU1RZTEUubmFtZUNvbG9yTGlnaHRUaGVtZSxcbiAgICAgICAgICAgIGxpbmVIZWlnaHQ6IEZSQU1FX1NUWUxFLm5hbWVMaW5lSGVpZ2h0LFxuICAgICAgICAgICAgd2lkdGg6IFwibWF4LWNvbnRlbnRcIixcbiAgICAgICAgICAgIG1heFdpZHRoOiBgJHtmLndpZHRofXB4YCxcbiAgICAgICAgICAgIG92ZXJmbG93OiBmLmlkID09PSB0aGlzLnN0YXRlLmVkaXRpbmdGcmFtZSA/IFwidmlzaWJsZVwiIDogXCJoaWRkZW5cIixcbiAgICAgICAgICAgIHdoaXRlU3BhY2U6IFwibm93cmFwXCIsXG4gICAgICAgICAgICB0ZXh0T3ZlcmZsb3c6IFwiZWxsaXBzaXNcIixcbiAgICAgICAgICAgIGN1cnNvcjogQ1VSU09SX1RZUEUuTU9WRSxcbiAgICAgICAgICAgIHBvaW50ZXJFdmVudHM6IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkID8gUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5lbmFibGVkXG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblBvaW50ZXJEb3duOiBldmVudCA9PiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJEb3duKGV2ZW50KSxcbiAgICAgICAgICBvbldoZWVsOiBldmVudCA9PiB0aGlzLmhhbmRsZVdoZWVsKGV2ZW50KSxcbiAgICAgICAgICBvbkNvbnRleHRNZW51OiB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51LFxuICAgICAgICAgIG9uRG91YmxlQ2xpY2s6ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nRnJhbWU6IGYuaWRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBmcmFtZU5hbWVKU1hcbiAgICAgICAgfSksIGYuaWQpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZm9jdXNDb250YWluZXIgPSAoKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZm9jdXMoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5nZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCA9ICgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuICAgIH07XG5cbiAgICB0aGlzLmdldFNjZW5lRWxlbWVudHMgPSAoKSA9PiB7XG4gICAgICByZXR1cm4gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5vbkluc2VydEVsZW1lbnRzID0gZWxlbWVudHMgPT4ge1xuICAgICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSh7XG4gICAgICAgIGVsZW1lbnRzLFxuICAgICAgICBwb3NpdGlvbjogXCJjZW50ZXJcIixcbiAgICAgICAgZmlsZXM6IG51bGxcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLm9uRXhwb3J0SW1hZ2UgPSAodHlwZSwgZWxlbWVudHMsIG9wdHMpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRyYWNrRXZlbnQoXCJleHBvcnRcIiwgdHlwZSwgXCJ1aVwiKTtcbiAgICAgIGNvbnN0IGZpbGVIYW5kbGUgPSB5aWVsZCBleHBvcnRDYW52YXModHlwZSwgZWxlbWVudHMsIHRoaXMuc3RhdGUsIHRoaXMuZmlsZXMsIHtcbiAgICAgICAgZXhwb3J0QmFja2dyb3VuZDogdGhpcy5zdGF0ZS5leHBvcnRCYWNrZ3JvdW5kLFxuICAgICAgICBuYW1lOiB0aGlzLnN0YXRlLm5hbWUsXG4gICAgICAgIHZpZXdCYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUudmlld0JhY2tncm91bmRDb2xvcixcbiAgICAgICAgZXhwb3J0aW5nRnJhbWU6IG9wdHMuZXhwb3J0aW5nRnJhbWVcbiAgICAgIH0pLmNhdGNoKG11dGVGU0Fib3J0RXJyb3IpLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5leHBvcnRFbWJlZFNjZW5lICYmIGZpbGVIYW5kbGUgJiYgaXNJbWFnZUZpbGVIYW5kbGUoZmlsZUhhbmRsZSkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZmlsZUhhbmRsZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub3BlbkV5ZURyb3BwZXIgPSAoe1xuICAgICAgdHlwZVxuICAgIH0pID0+IHtcbiAgICAgIGpvdGFpU3RvcmUuc2V0KGFjdGl2ZUV5ZURyb3BwZXJBdG9tLCB7XG4gICAgICAgIHN3YXBQcmV2aWV3T25BbHQ6IHRydWUsXG4gICAgICAgIGNvbG9yUGlja2VyVHlwZTogdHlwZSA9PT0gXCJzdHJva2VcIiA/IFwiZWxlbWVudFN0cm9rZVwiIDogXCJlbGVtZW50QmFja2dyb3VuZFwiLFxuICAgICAgICBvblNlbGVjdDogKGNvbG9yLCBldmVudCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHNob3VsZFVwZGF0ZVN0cm9rZUNvbG9yID0gdHlwZSA9PT0gXCJiYWNrZ3JvdW5kXCIgJiYgZXZlbnQuYWx0S2V5IHx8IHR5cGUgPT09IFwic3Ryb2tlXCIgJiYgIWV2ZW50LmFsdEtleTtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgICAgaWYgKCFzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICAgICAgaWYgKHNob3VsZFVwZGF0ZVN0cm9rZUNvbG9yKSB7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCh7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGN1cnJlbnRJdGVtU3Ryb2tlQ29sb3I6IGNvbG9yXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KHtcbiAgICAgICAgICAgICAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAgICAgICAgICAgY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3I6IGNvbG9yXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVNjZW5lKHtcbiAgICAgICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbZWwuaWRdKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWwsIHtcbiAgICAgICAgICAgICAgICAgICAgW3Nob3VsZFVwZGF0ZVN0cm9rZUNvbG9yID8gXCJzdHJva2VDb2xvclwiIDogXCJiYWNrZ3JvdW5kQ29sb3JcIl06IGNvbG9yXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gZWw7XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGtlZXBPcGVuT25BbHQ6IGZhbHNlXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0ID0gd2l0aEJhdGNoZWRVcGRhdGVzKGFjdGlvblJlc3VsdCA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZiwgX2csIF9oLCBfajtcblxuICAgICAgaWYgKHRoaXMudW5tb3VudGVkIHx8IGFjdGlvblJlc3VsdCA9PT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsZXQgZWRpdGluZ0VsZW1lbnQgPSBudWxsO1xuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmVsZW1lbnRzKSB7XG4gICAgICAgIGFjdGlvblJlc3VsdC5lbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgIGlmICgoKF9hID0gdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmlkKSA9PT0gZWxlbWVudC5pZCAmJiB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICE9PSBlbGVtZW50ICYmIGlzTm9uRGVsZXRlZEVsZW1lbnQoZWxlbWVudCkpIHtcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50ID0gZWxlbWVudDtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhhY3Rpb25SZXN1bHQuZWxlbWVudHMpO1xuXG4gICAgICAgIGlmIChhY3Rpb25SZXN1bHQuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3Rpb25SZXN1bHQuZmlsZXMpIHtcbiAgICAgICAgdGhpcy5maWxlcyA9IGFjdGlvblJlc3VsdC5yZXBsYWNlRmlsZXMgPyBhY3Rpb25SZXN1bHQuZmlsZXMgOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZmlsZXMpLCBhY3Rpb25SZXN1bHQuZmlsZXMpO1xuICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmFwcFN0YXRlIHx8IGVkaXRpbmdFbGVtZW50IHx8IHRoaXMuc3RhdGUuY29udGV4dE1lbnUpIHtcbiAgICAgICAgaWYgKGFjdGlvblJlc3VsdC5jb21taXRUb0hpc3RvcnkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdmlld01vZGVFbmFibGVkID0gKChfYSA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnZpZXdNb2RlRW5hYmxlZCkgfHwgZmFsc2U7XG4gICAgICAgIGxldCB6ZW5Nb2RlRW5hYmxlZCA9ICgoX2IgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi56ZW5Nb2RlRW5hYmxlZCkgfHwgZmFsc2U7XG4gICAgICAgIGxldCBncmlkU2l6ZSA9ICgoX2MgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5ncmlkU2l6ZSkgfHwgbnVsbDtcbiAgICAgICAgY29uc3QgdGhlbWUgPSAoKF9kID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QudGhlbWUpIHx8IHRoaXMucHJvcHMudGhlbWUgfHwgVEhFTUUuTElHSFQ7XG4gICAgICAgIGxldCBuYW1lID0gKF9mID0gKF9lID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2UubmFtZSkgIT09IG51bGwgJiYgX2YgIT09IHZvaWQgMCA/IF9mIDogdGhpcy5zdGF0ZS5uYW1lO1xuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSAoX2ggPSAoX2cgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9nID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZy5lcnJvck1lc3NhZ2UpICE9PSBudWxsICYmIF9oICE9PSB2b2lkIDAgPyBfaCA6IHRoaXMuc3RhdGUuZXJyb3JNZXNzYWdlO1xuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICB2aWV3TW9kZUVuYWJsZWQgPSB0aGlzLnByb3BzLnZpZXdNb2RlRW5hYmxlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIHplbk1vZGVFbmFibGVkID0gdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICBncmlkU2l6ZSA9IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkID8gR1JJRF9TSVpFIDogbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy5uYW1lICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgbmFtZSA9IHRoaXMucHJvcHMubmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGVkaXRpbmdFbGVtZW50ID0gZWRpdGluZ0VsZW1lbnQgfHwgKChfaiA9IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2ogPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9qLmVkaXRpbmdFbGVtZW50KSB8fCBudWxsO1xuXG4gICAgICAgIGlmIChlZGl0aW5nRWxlbWVudCA9PT0gbnVsbCB8fCBlZGl0aW5nRWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZWRpdGluZ0VsZW1lbnQuaXNEZWxldGVkKSB7XG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSA9PiB7XG4gICAgICAgICAgLy8gdXNpbmcgT2JqZWN0LmFzc2lnbiBpbnN0ZWFkIG9mIHNwcmVhZCB0byBmb29sIFRTIDQuMi4yKyBpbnRvXG4gICAgICAgICAgLy8gcmVnYXJkaW5nIHRoZSByZXN1bHRpbmcgdHlwZSBhcyBub3QgY29udGFpbmluZyB1bmRlZmluZWRcbiAgICAgICAgICAvLyAod2hpY2ggdGhlIGZvbGxvd2luZyBleHByZXNzaW9uIHdpbGwgbmV2ZXIgY29udGFpbilcbiAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihhY3Rpb25SZXN1bHQuYXBwU3RhdGUgfHwge30sIHtcbiAgICAgICAgICAgIC8vIE5PVEUgdGhpcyB3aWxsIHByZXZlbnQgb3BlbmluZyBjb250ZXh0IG1lbnUgdXNpbmcgYW4gYWN0aW9uXG4gICAgICAgICAgICAvLyBvciBwcm9ncmFtbWF0aWNhbGx5IGZyb20gdGhlIGhvc3QsIHNvIGl0IHdpbGwgbmVlZCB0byBiZVxuICAgICAgICAgICAgLy8gcmV3cml0dGVuIGxhdGVyXG4gICAgICAgICAgICBjb250ZXh0TWVudTogbnVsbCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50LFxuICAgICAgICAgICAgdmlld01vZGVFbmFibGVkLFxuICAgICAgICAgICAgemVuTW9kZUVuYWJsZWQsXG4gICAgICAgICAgICBncmlkU2l6ZSxcbiAgICAgICAgICAgIHRoZW1lLFxuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgaWYgKGFjdGlvblJlc3VsdC5zeW5jSGlzdG9yeSkge1xuICAgICAgICAgICAgdGhpcy5oaXN0b3J5LnNldEN1cnJlbnRTdGF0ZSh0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pOyAvLyBMaWZlY3ljbGVcblxuICAgIHRoaXMub25CbHVyID0gd2l0aEJhdGNoZWRVcGRhdGVzKCgpID0+IHtcbiAgICAgIGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogdHJ1ZVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLm9uVW5sb2FkID0gKCkgPT4ge1xuICAgICAgdGhpcy5vbkJsdXIoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5kaXNhYmxlRXZlbnQgPSBldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0SGlzdG9yeSA9ICgpID0+IHtcbiAgICAgIHRoaXMuaGlzdG9yeS5jbGVhcigpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmVzZXRzIHNjZW5lICYgaGlzdG9yeS5cbiAgICAgKiAhIERvIG5vdCB1c2UgdG8gY2xlYXIgc2NlbmUgdXNlciBhY3Rpb24gIVxuICAgICAqL1xuXG5cbiAgICB0aGlzLnJlc2V0U2NlbmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMob3B0cyA9PiB7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbXSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZ2V0RGVmYXVsdEFwcFN0YXRlKCkpLCB7XG4gICAgICAgIGlzTG9hZGluZzogKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yZXNldExvYWRpbmdTdGF0ZSkgPyBmYWxzZSA6IHN0YXRlLmlzTG9hZGluZyxcbiAgICAgICAgdGhlbWU6IHRoaXMuc3RhdGUudGhlbWVcbiAgICAgIH0pKTtcbiAgICAgIHRoaXMucmVzZXRIaXN0b3J5KCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmluaXRpYWxpemVTY2VuZSA9ICgpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgaWYgKFwibGF1bmNoUXVldWVcIiBpbiB3aW5kb3cgJiYgXCJMYXVuY2hQYXJhbXNcIiBpbiB3aW5kb3cpIHtcbiAgICAgICAgd2luZG93LmxhdW5jaFF1ZXVlLnNldENvbnN1bWVyKGxhdW5jaFBhcmFtcyA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgICAgaWYgKCFsYXVuY2hQYXJhbXMuZmlsZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgZmlsZUhhbmRsZSA9IGxhdW5jaFBhcmFtcy5maWxlc1swXTtcbiAgICAgICAgICBjb25zdCBibG9iID0geWllbGQgZmlsZUhhbmRsZS5nZXRGaWxlKCk7XG4gICAgICAgICAgdGhpcy5sb2FkRmlsZVRvQ2FudmFzKG5ldyBGaWxlKFtibG9iXSwgYmxvYi5uYW1lIHx8IFwiXCIsIHtcbiAgICAgICAgICAgIHR5cGU6IGJsb2IudHlwZVxuICAgICAgICAgIH0pLCBmaWxlSGFuZGxlKTtcbiAgICAgICAgfSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5wcm9wcy50aGVtZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmlzTG9hZGluZykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0xvYWRpbmc6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGxldCBpbml0aWFsRGF0YSA9IG51bGw7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGluaXRpYWxEYXRhID0gKHlpZWxkIHRoaXMucHJvcHMuaW5pdGlhbERhdGEpIHx8IG51bGw7XG5cbiAgICAgICAgaWYgKGluaXRpYWxEYXRhID09PSBudWxsIHx8IGluaXRpYWxEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpbml0aWFsRGF0YS5saWJyYXJ5SXRlbXMpIHtcbiAgICAgICAgICB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSh7XG4gICAgICAgICAgICBsaWJyYXJ5SXRlbXM6IGluaXRpYWxEYXRhLmxpYnJhcnlJdGVtcyxcbiAgICAgICAgICAgIG1lcmdlOiB0cnVlXG4gICAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICBpbml0aWFsRGF0YSA9IHtcbiAgICAgICAgICBhcHBTdGF0ZToge1xuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlIHx8IFwiRW5jb3VudGVyZWQgYW4gZXJyb3IgZHVyaW5nIGltcG9ydGluZyBvciByZXN0b3Jpbmcgc2NlbmUgZGF0YVwiXG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzY2VuZSA9IHJlc3RvcmUoaW5pdGlhbERhdGEsIG51bGwsIG51bGwsIHtcbiAgICAgICAgcmVwYWlyQmluZGluZ3M6IHRydWVcbiAgICAgIH0pO1xuICAgICAgc2NlbmUuYXBwU3RhdGUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlKSwge1xuICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZSB8fCBzY2VuZS5hcHBTdGF0ZS50aGVtZSxcbiAgICAgICAgLy8gd2UncmUgZmFsbGluZyBiYWNrIHRvIGN1cnJlbnQgKHByZS1pbml0KSBzdGF0ZSB3aGVuIGRlY2lkaW5nXG4gICAgICAgIC8vIHdoZXRoZXIgdG8gb3BlbiB0aGUgbGlicmFyeSwgdG8gaGFuZGxlIGEgY2FzZSB3aGVyZSB3ZVxuICAgICAgICAvLyB1cGRhdGUgdGhlIHN0YXRlIG91dHNpZGUgb2YgaW5pdGlhbERhdGEgKGUuZy4gd2hlbiBsb2FkaW5nIHRoZSBhcHBcbiAgICAgICAgLy8gd2l0aCBhIGxpYnJhcnkgaW5zdGFsbCBsaW5rLCB3aGljaCBzaG91bGQgYXV0by1vcGVuIHRoZSBsaWJyYXJ5KVxuICAgICAgICBvcGVuU2lkZWJhcjogKChfYSA9IHNjZW5lLmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eub3BlblNpZGViYXIpIHx8IHRoaXMuc3RhdGUub3BlblNpZGViYXIsXG4gICAgICAgIGFjdGl2ZVRvb2w6IHNjZW5lLmFwcFN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiID8gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sKSwge1xuICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgfSkgOiBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sLFxuICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICB0b2FzdDogdGhpcy5zdGF0ZS50b2FzdFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEuc2Nyb2xsVG9Db250ZW50KSB7XG4gICAgICAgIHNjZW5lLmFwcFN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIGNhbGN1bGF0ZVNjcm9sbENlbnRlcihzY2VuZS5lbGVtZW50cywgT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIHtcbiAgICAgICAgICB3aWR0aDogdGhpcy5zdGF0ZS53aWR0aCxcbiAgICAgICAgICBoZWlnaHQ6IHRoaXMuc3RhdGUuaGVpZ2h0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0XG4gICAgICAgIH0pKSk7XG4gICAgICB9IC8vIEZvbnRGYWNlU2V0IGxvYWRpbmdkb25lIGV2ZW50IHdlIGxpc3RlbiBvbiBtYXkgbm90IGFsd2F5cyBmaXJlXG4gICAgICAvLyAobG9va2luZyBhdCB5b3UgU2FmYXJpKSwgc28gb24gaW5pdCB3ZSBtYW51YWxseSBsb2FkIGZvbnRzIGZvciBjdXJyZW50XG4gICAgICAvLyB0ZXh0IGVsZW1lbnRzIG9uIGNhbnZhcywgYW5kIHJlcmVuZGVyIHRoZW0gb25jZSBkb25lLiBUaGlzIGFsc29cbiAgICAgIC8vIHNlZW1zIGZhc3RlciBldmVuIGluIGJyb3dzZXJzIHRoYXQgZG8gZmlyZSB0aGUgbG9hZGluZ2RvbmUgZXZlbnQuXG5cblxuICAgICAgdGhpcy5mb250cy5sb2FkRm9udHNGb3JFbGVtZW50cyhzY2VuZS5lbGVtZW50cyk7XG4gICAgICB0aGlzLnJlc2V0SGlzdG9yeSgpO1xuICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUpLCB7XG4gICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5pc01vYmlsZUJyZWFrcG9pbnQgPSAod2lkdGgsIGhlaWdodCkgPT4ge1xuICAgICAgcmV0dXJuIHdpZHRoIDwgTVFfTUFYX1dJRFRIX1BPUlRSQUlUIHx8IGhlaWdodCA8IE1RX01BWF9IRUlHSFRfTEFORFNDQVBFICYmIHdpZHRoIDwgTVFfTUFYX1dJRFRIX0xBTkRTQ0FQRTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZWZyZXNoVmlld3BvcnRCcmVha3BvaW50cyA9ICgpID0+IHtcbiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAoIWNvbnRhaW5lcikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgY2xpZW50V2lkdGg6IHZpZXdwb3J0V2lkdGgsXG4gICAgICAgIGNsaWVudEhlaWdodDogdmlld3BvcnRIZWlnaHRcbiAgICAgIH0gPSBkb2N1bWVudC5ib2R5O1xuICAgICAgY29uc3QgcHJldlZpZXdwb3J0U3RhdGUgPSB0aGlzLmRldmljZS52aWV3cG9ydDtcbiAgICAgIGNvbnN0IG5leHRWaWV3cG9ydFN0YXRlID0gdXBkYXRlT2JqZWN0KHByZXZWaWV3cG9ydFN0YXRlLCB7XG4gICAgICAgIGlzTGFuZHNjYXBlOiB2aWV3cG9ydFdpZHRoID4gdmlld3BvcnRIZWlnaHQsXG4gICAgICAgIGlzTW9iaWxlOiB0aGlzLmlzTW9iaWxlQnJlYWtwb2ludCh2aWV3cG9ydFdpZHRoLCB2aWV3cG9ydEhlaWdodClcbiAgICAgIH0pO1xuXG4gICAgICBpZiAocHJldlZpZXdwb3J0U3RhdGUgIT09IG5leHRWaWV3cG9ydFN0YXRlKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmRldmljZSksIHtcbiAgICAgICAgICB2aWV3cG9ydDogbmV4dFZpZXdwb3J0U3RhdGVcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMucmVmcmVzaEVkaXRvckJyZWFrcG9pbnRzID0gKCkgPT4ge1xuICAgICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG5cbiAgICAgIGlmICghY29udGFpbmVyKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICB3aWR0aDogZWRpdG9yV2lkdGgsXG4gICAgICAgIGhlaWdodDogZWRpdG9ySGVpZ2h0XG4gICAgICB9ID0gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgY29uc3Qgc2lkZWJhckJyZWFrcG9pbnQgPSB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCAhPSBudWxsID8gdGhpcy5wcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgOiBNUV9SSUdIVF9TSURFQkFSX01JTl9XSURUSDtcbiAgICAgIGNvbnN0IHByZXZFZGl0b3JTdGF0ZSA9IHRoaXMuZGV2aWNlLmVkaXRvcjtcbiAgICAgIGNvbnN0IG5leHRFZGl0b3JTdGF0ZSA9IHVwZGF0ZU9iamVjdChwcmV2RWRpdG9yU3RhdGUsIHtcbiAgICAgICAgaXNNb2JpbGU6IHRoaXMuaXNNb2JpbGVCcmVha3BvaW50KGVkaXRvcldpZHRoLCBlZGl0b3JIZWlnaHQpLFxuICAgICAgICBjYW5GaXRTaWRlYmFyOiBlZGl0b3JXaWR0aCA+IHNpZGViYXJCcmVha3BvaW50XG4gICAgICB9KTtcblxuICAgICAgaWYgKHByZXZFZGl0b3JTdGF0ZSAhPT0gbmV4dEVkaXRvclN0YXRlKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmRldmljZSksIHtcbiAgICAgICAgICBlZGl0b3I6IG5leHRFZGl0b3JTdGF0ZVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgdGhpcy5vblJlc2l6ZSA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZvckVhY2goZWxlbWVudCA9PiBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KSk7XG4gICAgICB0aGlzLnJlZnJlc2hWaWV3cG9ydEJyZWFrcG9pbnRzKCk7XG4gICAgICB0aGlzLnVwZGF0ZURPTVJlY3QoKTtcblxuICAgICAgaWYgKCFzdXBwb3J0c1Jlc2l6ZU9ic2VydmVyKSB7XG4gICAgICAgIHRoaXMucmVmcmVzaEVkaXRvckJyZWFrcG9pbnRzKCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe30pO1xuICAgIH0pO1xuXG4gICAgdGhpcy5yZW5kZXJJbnRlcmFjdGl2ZVNjZW5lQ2FsbGJhY2sgPSAoe1xuICAgICAgYXRMZWFzdE9uZVZpc2libGVFbGVtZW50LFxuICAgICAgc2Nyb2xsQmFycyxcbiAgICAgIGVsZW1lbnRzXG4gICAgfSkgPT4ge1xuICAgICAgaWYgKHNjcm9sbEJhcnMpIHtcbiAgICAgICAgY3VycmVudFNjcm9sbEJhcnMgPSBzY3JvbGxCYXJzO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzY3JvbGxlZE91dHNpZGUgPSAvLyBoaWRlIHdoZW4gZWRpdGluZyB0ZXh0XG4gICAgICBpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID8gZmFsc2UgOiAhYXRMZWFzdE9uZVZpc2libGVFbGVtZW50ICYmIGVsZW1lbnRzLmxlbmd0aCA+IDA7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNjcm9sbGVkT3V0c2lkZSAhPT0gc2Nyb2xsZWRPdXRzaWRlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNjcm9sbGVkT3V0c2lkZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zY2hlZHVsZUltYWdlUmVmcmVzaCgpO1xuICAgIH07XG5cbiAgICB0aGlzLm9uU2Nyb2xsID0gZGVib3VuY2UoKCkgPT4ge1xuICAgICAgY29uc3Qge1xuICAgICAgICBvZmZzZXRUb3AsXG4gICAgICAgIG9mZnNldExlZnRcbiAgICAgIH0gPSB0aGlzLmdldENhbnZhc09mZnNldHMoKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICBpZiAoc3RhdGUub2Zmc2V0TGVmdCA9PT0gb2Zmc2V0TGVmdCAmJiBzdGF0ZS5vZmZzZXRUb3AgPT09IG9mZnNldFRvcCkge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBvZmZzZXRUb3AsXG4gICAgICAgICAgb2Zmc2V0TGVmdFxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfSwgU0NST0xMX1RJTUVPVVQpOyAvLyBDb3B5L3Bhc3RlXG5cbiAgICB0aGlzLm9uQ3V0ID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaXNFeGNhbGlkcmF3QWN0aXZlID0gKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jb250YWlucyhkb2N1bWVudC5hY3RpdmVFbGVtZW50KTtcblxuICAgICAgaWYgKCFpc0V4Y2FsaWRyYXdBY3RpdmUgfHwgaXNXcml0YWJsZUVsZW1lbnQoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkN1dCwgXCJrZXlib2FyZFwiLCBldmVudCk7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfSk7XG4gICAgdGhpcy5vbkNvcHkgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBpc0V4Y2FsaWRyYXdBY3RpdmUgPSAoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNvbnRhaW5zKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpO1xuXG4gICAgICBpZiAoIWlzRXhjYWxpZHJhd0FjdGl2ZSB8fCBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uQ29weSwgXCJrZXlib2FyZFwiLCBldmVudCk7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLm9uVG91Y2hTdGFydCA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIGZpeCBmb3IgQXBwbGUgUGVuY2lsIFNjcmliYmxlXG4gICAgICAvLyBPbiBBbmRyb2lkLCBwcmV2ZW50aW5nIHRoZSBldmVudCB3b3VsZCBkaXNhYmxlIGNvbnRleHRNZW51IG9uIHRhcC1ob2xkXG4gICAgICBpZiAoIWlzQW5kcm9pZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWRpZFRhcFR3aWNlKSB7XG4gICAgICAgIGRpZFRhcFR3aWNlID0gdHJ1ZTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRhcHBlZFR3aWNlVGltZXIpO1xuICAgICAgICB0YXBwZWRUd2ljZVRpbWVyID0gd2luZG93LnNldFRpbWVvdXQoQXBwLnJlc2V0VGFwVHdpY2UsIFRBUF9UV0lDRV9USU1FT1VUKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBpbnNlcnQgdGV4dCBvbmx5IGlmIHdlIHRhcHBlZCB0d2ljZSB3aXRoIGEgc2luZ2xlIGZpbmdlclxuICAgICAgLy8gZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDEgd2lsbCBhbHNvIHByZXZlbnQgaW5zZXJ0aW5nIHRleHQgd2hlbiB1c2VyJ3Mgem9vbWluZ1xuXG5cbiAgICAgIGlmIChkaWRUYXBUd2ljZSAmJiBldmVudC50b3VjaGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBjb25zdCB0b3VjaCA9IGV2ZW50LnRvdWNoZXNbMF07IC8vIEB0cy1pZ25vcmVcblxuICAgICAgICB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrKHtcbiAgICAgICAgICBjbGllbnRYOiB0b3VjaC5jbGllbnRYLFxuICAgICAgICAgIGNsaWVudFk6IHRvdWNoLmNsaWVudFlcbiAgICAgICAgfSk7XG4gICAgICAgIGRpZFRhcFR3aWNlID0gZmFsc2U7XG4gICAgICAgIGNsZWFyVGltZW91dCh0YXBwZWRUd2ljZVRpbWVyKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzQW5kcm9pZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5vblRvdWNoRW5kID0gZXZlbnQgPT4ge1xuICAgICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIoKTtcblxuICAgICAgaWYgKGV2ZW50LnRvdWNoZXMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczoge30sXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh0aGlzLnN0YXRlLnByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzLCB0aGlzLnN0YXRlKVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUucG9pbnRlcnMuY2xlYXIoKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5wYXN0ZUZyb21DbGlwYm9hcmQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdmFyIF9iLCBfYywgX2Q7XG5cbiAgICAgIGNvbnN0IGlzUGxhaW5QYXN0ZSA9ICEhSVNfUExBSU5fUEFTVEU7IC8vICM2ODZcblxuICAgICAgY29uc3QgdGFyZ2V0ID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcbiAgICAgIGNvbnN0IGlzRXhjYWxpZHJhd0FjdGl2ZSA9IChfYiA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY29udGFpbnModGFyZ2V0KTtcblxuICAgICAgaWYgKGV2ZW50ICYmICFpc0V4Y2FsaWRyYXdBY3RpdmUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50VW5kZXJDdXJzb3IgPSBkb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCwgdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55KTtcblxuICAgICAgaWYgKGV2ZW50ICYmICghKGVsZW1lbnRVbmRlckN1cnNvciBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50KSB8fCBpc1dyaXRhYmxlRWxlbWVudCh0YXJnZXQpKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeDogc2NlbmVYLFxuICAgICAgICB5OiBzY2VuZVlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgIGNsaWVudFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueVxuICAgICAgfSwgdGhpcy5zdGF0ZSk7IC8vIG11c3QgYmUgY2FsbGVkIGluIHRoZSBzYW1lIGZyYW1lICh0aHVzIGJlZm9yZSBhbnkgYXdhaXRzKSBhcyB0aGUgcGFzdGVcbiAgICAgIC8vIGV2ZW50IGVsc2Ugc29tZSBicm93c2VycyAoRkYuLi4pIHdpbGwgY2xlYXIgdGhlIGNsaXBib2FyZERhdGFcbiAgICAgIC8vIChzb21ldGhpbmcgc29tZXRoaW5nIHNlY3VyaXR5KVxuXG4gICAgICBsZXQgZmlsZSA9IChfYyA9IGV2ZW50ID09PSBudWxsIHx8IGV2ZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBldmVudC5jbGlwYm9hcmREYXRhKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZmlsZXNbMF07XG4gICAgICBjb25zdCBkYXRhID0geWllbGQgcGFyc2VDbGlwYm9hcmQoZXZlbnQsIGlzUGxhaW5QYXN0ZSk7XG5cbiAgICAgIGlmICghZmlsZSAmJiAhaXNQbGFpblBhc3RlKSB7XG4gICAgICAgIGlmIChkYXRhLm1peGVkQ29udGVudCkge1xuICAgICAgICAgIHJldHVybiB0aGlzLmFkZEVsZW1lbnRzRnJvbU1peGVkQ29udGVudFBhc3RlKGRhdGEubWl4ZWRDb250ZW50LCB7XG4gICAgICAgICAgICBpc1BsYWluUGFzdGUsXG4gICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICBzY2VuZVlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLnRleHQpIHtcbiAgICAgICAgICBjb25zdCBzdHJpbmcgPSBkYXRhLnRleHQudHJpbSgpO1xuXG4gICAgICAgICAgaWYgKHN0cmluZy5zdGFydHNXaXRoKFwiPHN2Z1wiKSAmJiBzdHJpbmcuZW5kc1dpdGgoXCI8L3N2Zz5cIikpIHtcbiAgICAgICAgICAgIC8vIGlnbm9yZSBTVkcgdmFsaWRhdGlvbi9ub3JtYWxpemF0aW9uIHdoaWNoIHdpbGwgYmUgZG9uZSBkdXJpbmcgaW1hZ2VcbiAgICAgICAgICAgIC8vIGluaXRpYWxpemF0aW9uXG4gICAgICAgICAgICBmaWxlID0gU1ZHU3RyaW5nVG9GaWxlKHN0cmluZyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IC8vIHByZWZlciBzcHJlYWRzaGVldCBkYXRhIG92ZXIgaW1hZ2UgZmlsZSAoTVMgT2ZmaWNlL0xpYnJlIE9mZmljZSlcblxuXG4gICAgICBpZiAoaXNTdXBwb3J0ZWRJbWFnZUZpbGUoZmlsZSkgJiYgIWRhdGEuc3ByZWFkc2hlZXQpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzVG9vbFN1cHBvcnRlZChcImltYWdlXCIpKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6IHQoXCJlcnJvcnMuaW1hZ2VUb29sTm90U3VwcG9ydGVkXCIpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQoe1xuICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICBzY2VuZVlcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgZmlsZSk7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlRGltZW5zaW9ucyhpbWFnZUVsZW1lbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgIFtpbWFnZUVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMucHJvcHMub25QYXN0ZSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmICgoeWllbGQgdGhpcy5wcm9wcy5vblBhc3RlKGRhdGEsIGV2ZW50KSkgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChkYXRhLmVycm9yTWVzc2FnZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGRhdGEuZXJyb3JNZXNzYWdlXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLnNwcmVhZHNoZWV0ICYmICFpc1BsYWluUGFzdGUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcGFzdGVEaWFsb2c6IHtcbiAgICAgICAgICAgIGRhdGE6IGRhdGEuc3ByZWFkc2hlZXQsXG4gICAgICAgICAgICBzaG93bjogdHJ1ZVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZWxlbWVudHMpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSBkYXRhLnByb2dyYW1tYXRpY0FQSSA/IGNvbnZlcnRUb0V4Y2FsaWRyYXdFbGVtZW50cyhkYXRhLmVsZW1lbnRzKSA6IGRhdGEuZWxlbWVudHM7IC8vIFRPRE8gcmVtb3ZlIGZvcm1hdHRpbmcgZnJvbSBlbGVtZW50cyBpZiBpc1BsYWluUGFzdGVcblxuICAgICAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5KHtcbiAgICAgICAgICBlbGVtZW50cyxcbiAgICAgICAgICBmaWxlczogZGF0YS5maWxlcyB8fCBudWxsLFxuICAgICAgICAgIHBvc2l0aW9uOiBcImN1cnNvclwiLFxuICAgICAgICAgIHJldGFpblNlZWQ6IGlzUGxhaW5QYXN0ZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS50ZXh0KSB7XG4gICAgICAgIGNvbnN0IG1heWJlVXJsID0gZXh0cmFjdFNyYyhkYXRhLnRleHQpO1xuXG4gICAgICAgIGlmICghaXNQbGFpblBhc3RlICYmIGVtYmVkZGFibGVVUkxWYWxpZGF0b3IobWF5YmVVcmwsIHRoaXMucHJvcHMudmFsaWRhdGVFbWJlZGRhYmxlKSAmJiAoL14oaHR0cHxodHRwcyk6XFwvXFwvW15cXHMvJC4/I10uW15cXHNdKiQvLnRlc3QobWF5YmVVcmwpIHx8ICgoX2QgPSBnZXRFbWJlZExpbmsobWF5YmVVcmwpKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QudHlwZSkgPT09IFwidmlkZW9cIikpIHtcbiAgICAgICAgICBjb25zdCBlbWJlZGRhYmxlID0gdGhpcy5pbnNlcnRFbWJlZGRhYmxlRWxlbWVudCh7XG4gICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgICBsaW5rOiBub3JtYWxpemVMaW5rKG1heWJlVXJsKVxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKGVtYmVkZGFibGUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICAgICAgICBbZW1iZWRkYWJsZS5pZF06IHRydWVcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5hZGRUZXh0RnJvbVBhc3RlKGRhdGEudGV4dCwgaXNQbGFpblBhc3RlKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgfSk7XG4gICAgICBldmVudCA9PT0gbnVsbCB8fCBldmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9KSk7XG5cbiAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5ID0gb3B0cyA9PiB7XG4gICAgICBjb25zdCBlbGVtZW50cyA9IHJlc3RvcmVFbGVtZW50cyhvcHRzLmVsZW1lbnRzLCBudWxsLCB1bmRlZmluZWQpO1xuICAgICAgY29uc3QgW21pblgsIG1pblksIG1heFgsIG1heFldID0gZ2V0Q29tbW9uQm91bmRzKGVsZW1lbnRzKTtcbiAgICAgIGNvbnN0IGVsZW1lbnRzQ2VudGVyWCA9IGRpc3RhbmNlKG1pblgsIG1heFgpIC8gMjtcbiAgICAgIGNvbnN0IGVsZW1lbnRzQ2VudGVyWSA9IGRpc3RhbmNlKG1pblksIG1heFkpIC8gMjtcbiAgICAgIGNvbnN0IGNsaWVudFggPSB0eXBlb2Ygb3B0cy5wb3NpdGlvbiA9PT0gXCJvYmplY3RcIiA/IG9wdHMucG9zaXRpb24uY2xpZW50WCA6IG9wdHMucG9zaXRpb24gPT09IFwiY3Vyc29yXCIgPyB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnggOiB0aGlzLnN0YXRlLndpZHRoIC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0TGVmdDtcbiAgICAgIGNvbnN0IGNsaWVudFkgPSB0eXBlb2Ygb3B0cy5wb3NpdGlvbiA9PT0gXCJvYmplY3RcIiA/IG9wdHMucG9zaXRpb24uY2xpZW50WSA6IG9wdHMucG9zaXRpb24gPT09IFwiY3Vyc29yXCIgPyB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnkgOiB0aGlzLnN0YXRlLmhlaWdodCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldFRvcDtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgIGNsaWVudFgsXG4gICAgICAgIGNsaWVudFlcbiAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgZHggPSB4IC0gZWxlbWVudHNDZW50ZXJYO1xuICAgICAgY29uc3QgZHkgPSB5IC0gZWxlbWVudHNDZW50ZXJZO1xuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoZHgsIGR5LCB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IG5ld0VsZW1lbnRzID0gZHVwbGljYXRlRWxlbWVudHMoZWxlbWVudHMubWFwKGVsZW1lbnQgPT4ge1xuICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlbWVudCwge1xuICAgICAgICAgIHg6IGVsZW1lbnQueCArIGdyaWRYIC0gbWluWCxcbiAgICAgICAgICB5OiBlbGVtZW50LnkgKyBncmlkWSAtIG1pbllcbiAgICAgICAgfSk7XG4gICAgICB9KSwge1xuICAgICAgICByYW5kb21pemVTZWVkOiAhb3B0cy5yZXRhaW5TZWVkXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IG5leHRFbGVtZW50cyA9IFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCAuLi5uZXdFbGVtZW50c107XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0RWxlbWVudHMpO1xuICAgICAgbmV3RWxlbWVudHMuZm9yRWFjaChuZXdFbGVtZW50ID0+IHtcbiAgICAgICAgaWYgKGlzVGV4dEVsZW1lbnQobmV3RWxlbWVudCkgJiYgaXNCb3VuZFRvQ29udGFpbmVyKG5ld0VsZW1lbnQpKSB7XG4gICAgICAgICAgY29uc3QgY29udGFpbmVyID0gZ2V0Q29udGFpbmVyRWxlbWVudChuZXdFbGVtZW50KTtcbiAgICAgICAgICByZWRyYXdUZXh0Qm91bmRpbmdCb3gobmV3RWxlbWVudCwgY29udGFpbmVyKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIGlmIChvcHRzLmZpbGVzKSB7XG4gICAgICAgIHRoaXMuZmlsZXMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZmlsZXMpLCBvcHRzLmZpbGVzKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgY29uc3QgbmV4dEVsZW1lbnRzVG9TZWxlY3QgPSBleGNsdWRlRWxlbWVudHNJbkZyYW1lc0Zyb21TZWxlY3Rpb24obmV3RWxlbWVudHMpO1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgLy8ga2VlcCBzaWRlYmFyIChwcmVzdW1hYmx5IHRoZSBsaWJyYXJ5KSBvcGVuIGlmIGl0J3MgZG9ja2VkIGFuZFxuICAgICAgICAvLyBjYW4gZml0LlxuICAgICAgICAvL1xuICAgICAgICAvLyBOb3RlLCB3ZSBzaG91bGQgY2xvc2UgdGhlIHNpZGViYXIgb25seSBpZiB3ZSdyZSBkcm9wcGluZyBpdGVtc1xuICAgICAgICAvLyBmcm9tIGxpYnJhcnksIG5vdCB3aGVuIHBhc3RpbmcgZnJvbSBjbGlwYm9hcmQuIEFsYXMuXG4gICAgICAgIG9wZW5TaWRlYmFyOiB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyICYmIHRoaXMuZGV2aWNlLmVkaXRvci5jYW5GaXRTaWRlYmFyICYmIGpvdGFpU3RvcmUuZ2V0KGlzU2lkZWJhckRvY2tlZEF0b20pID8gdGhpcy5zdGF0ZS5vcGVuU2lkZWJhciA6IG51bGxcbiAgICAgIH0pLCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dEVsZW1lbnRzVG9TZWxlY3QucmVkdWNlKChhY2MsIGVsZW1lbnQpID0+IHtcbiAgICAgICAgICBpZiAoIWlzQm91bmRUb0NvbnRhaW5lcihlbGVtZW50KSkge1xuICAgICAgICAgICAgYWNjW2VsZW1lbnQuaWRdID0gdHJ1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICB9LCB7fSlcbiAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHRoaXMpKSwgKCkgPT4ge1xuICAgICAgICBpZiAob3B0cy5maWxlcykge1xuICAgICAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgfSk7XG5cbiAgICAgIGlmIChvcHRzLmZpdFRvQ29udGVudCkge1xuICAgICAgICB0aGlzLnNjcm9sbFRvQ29udGVudChuZXdFbGVtZW50cywge1xuICAgICAgICAgIGZpdFRvQ29udGVudDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5zZXRBcHBTdGF0ZSA9IChzdGF0ZSwgY2FsbGJhY2spID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUsIGNhbGxiYWNrKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZW1vdmVQb2ludGVyID0gZXZlbnQgPT4ge1xuICAgICAgaWYgKHRvdWNoVGltZW91dCkge1xuICAgICAgICB0aGlzLnJlc2V0Q29udGV4dE1lbnVUaW1lcigpO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLnBvaW50ZXJzLmRlbGV0ZShldmVudC5wb2ludGVySWQpO1xuICAgIH07XG5cbiAgICB0aGlzLnRvZ2dsZUxvY2sgPSAoc291cmNlID0gXCJ1aVwiKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgdHJhY2tFdmVudChcInRvb2xiYXJcIiwgXCJ0b2dnbGVMb2NrXCIsIGAke3NvdXJjZX0gKCR7dGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlID8gXCJtb2JpbGVcIiA6IFwiZGVza3RvcFwifSlgKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuYWN0aXZlVG9vbCksIHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwgcHJldlN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkID8ge1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0gOiBwcmV2U3RhdGUuYWN0aXZlVG9vbCkpLCB7XG4gICAgICAgICAgICBsb2NrZWQ6ICFwcmV2U3RhdGUuYWN0aXZlVG9vbC5sb2NrZWRcbiAgICAgICAgICB9KVxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMudXBkYXRlRnJhbWVSZW5kZXJpbmcgPSBvcHRzID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kO1xuXG4gICAgICAgIGNvbnN0IG5leHQgPSB0eXBlb2Ygb3B0cyA9PT0gXCJmdW5jdGlvblwiID8gb3B0cyhwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcpIDogb3B0cztcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBmcmFtZVJlbmRlcmluZzoge1xuICAgICAgICAgICAgZW5hYmxlZDogKF9hID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0LmVuYWJsZWQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5lbmFibGVkLFxuICAgICAgICAgICAgY2xpcDogKF9iID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0LmNsaXApICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5jbGlwLFxuICAgICAgICAgICAgbmFtZTogKF9jID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0Lm5hbWUpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lLFxuICAgICAgICAgICAgb3V0bGluZTogKF9kID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0Lm91dGxpbmUpICE9PSBudWxsICYmIF9kICE9PSB2b2lkIDAgPyBfZCA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5vdXRsaW5lXG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMudG9nZ2xlUGVuTW9kZSA9IGZvcmNlID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBwZW5Nb2RlOiBmb3JjZSAhPT0gbnVsbCAmJiBmb3JjZSAhPT0gdm9pZCAwID8gZm9yY2UgOiAhcHJldlN0YXRlLnBlbk1vZGUsXG4gICAgICAgICAgcGVuRGV0ZWN0ZWQ6IHRydWVcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLm9uSGFuZFRvb2xUb2dnbGUgPSAoKSA9PiB7XG4gICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25Ub2dnbGVIYW5kVG9vbCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBab29tcyBvbiBjYW52YXMgdmlld3BvcnQgY2VudGVyXG4gICAgICovXG5cblxuICAgIHRoaXMuem9vbUNhbnZhcyA9IChcbiAgICAvKiogZGVjaW1hbCBmcmFjdGlvbiBiZXR3ZWVuIDAuMSAoMTAlIHpvb20pIGFuZCAzMCAoMzAwMCUgem9vbSkgKi9cbiAgICB2YWx1ZSkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKHt9LCBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICB2aWV3cG9ydFg6IHRoaXMuc3RhdGUud2lkdGggLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICB2aWV3cG9ydFk6IHRoaXMuc3RhdGUuaGVpZ2h0IC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20odmFsdWUpXG4gICAgICB9LCB0aGlzLnN0YXRlKSkpO1xuICAgIH07XG5cbiAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9IG51bGw7XG5cbiAgICB0aGlzLnNjcm9sbFRvQ29udGVudCA9ICh0YXJnZXQgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBvcHRzKSA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAoX2EgPSB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwodGhpcyk7IC8vIGNvbnZlcnQgcHJvdmlkZWQgdGFyZ2V0IGludG8gRXhjYWxpZHJhd0VsZW1lbnRbXSBpZiBuZWNlc3NhcnlcblxuICAgICAgY29uc3QgdGFyZ2V0RWxlbWVudHMgPSBBcnJheS5pc0FycmF5KHRhcmdldCkgPyB0YXJnZXQgOiBbdGFyZ2V0XTtcbiAgICAgIGxldCB6b29tID0gdGhpcy5zdGF0ZS56b29tO1xuICAgICAgbGV0IHNjcm9sbFggPSB0aGlzLnN0YXRlLnNjcm9sbFg7XG4gICAgICBsZXQgc2Nyb2xsWSA9IHRoaXMuc3RhdGUuc2Nyb2xsWTtcblxuICAgICAgaWYgKChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZml0VG9Db250ZW50KSB8fCAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvVmlld3BvcnQpKSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBhcHBTdGF0ZVxuICAgICAgICB9ID0gem9vbVRvRml0KHtcbiAgICAgICAgICB0YXJnZXRFbGVtZW50cyxcbiAgICAgICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgICAgICBmaXRUb1ZpZXdwb3J0OiAhIShvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZml0VG9WaWV3cG9ydCksXG4gICAgICAgICAgdmlld3BvcnRab29tRmFjdG9yOiBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMudmlld3BvcnRab29tRmFjdG9yXG4gICAgICAgIH0pO1xuICAgICAgICB6b29tID0gYXBwU3RhdGUuem9vbTtcbiAgICAgICAgc2Nyb2xsWCA9IGFwcFN0YXRlLnNjcm9sbFg7XG4gICAgICAgIHNjcm9sbFkgPSBhcHBTdGF0ZS5zY3JvbGxZO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gY29tcHV0ZSBvbmx5IHRoZSB2aWV3cG9ydCBsb2NhdGlvbiwgd2l0aG91dCBhbnkgem9vbSBhZGp1c3RtZW50XG4gICAgICAgIGNvbnN0IHNjcm9sbCA9IGNhbGN1bGF0ZVNjcm9sbENlbnRlcih0YXJnZXRFbGVtZW50cywgdGhpcy5zdGF0ZSk7XG4gICAgICAgIHNjcm9sbFggPSBzY3JvbGwuc2Nyb2xsWDtcbiAgICAgICAgc2Nyb2xsWSA9IHNjcm9sbC5zY3JvbGxZO1xuICAgICAgfSAvLyB3aGVuIGFuaW1hdGluZywgd2UgdXNlIFJlcXVlc3RBbmltYXRpb25GcmFtZSB0byBwcmV2ZW50IHRoZSBhbmltYXRpb25cbiAgICAgIC8vIGZyb20gc2xvd2luZyBkb3duIG90aGVyIHByb2Nlc3Nlc1xuXG5cbiAgICAgIGlmIChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuYW5pbWF0ZSkge1xuICAgICAgICBjb25zdCBvcmlnU2Nyb2xsWCA9IHRoaXMuc3RhdGUuc2Nyb2xsWDtcbiAgICAgICAgY29uc3Qgb3JpZ1Njcm9sbFkgPSB0aGlzLnN0YXRlLnNjcm9sbFk7XG4gICAgICAgIGNvbnN0IG9yaWdab29tID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgICBjb25zdCBjYW5jZWwgPSBlYXNlVG9WYWx1ZXNSQUYoe1xuICAgICAgICAgIGZyb21WYWx1ZXM6IHtcbiAgICAgICAgICAgIHNjcm9sbFg6IG9yaWdTY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWTogb3JpZ1Njcm9sbFksXG4gICAgICAgICAgICB6b29tOiBvcmlnWm9vbVxuICAgICAgICAgIH0sXG4gICAgICAgICAgdG9WYWx1ZXM6IHtcbiAgICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgem9vbTogem9vbS52YWx1ZVxuICAgICAgICAgIH0sXG4gICAgICAgICAgaW50ZXJwb2xhdGVWYWx1ZTogKGZyb20sIHRvLCBwcm9ncmVzcywga2V5KSA9PiB7XG4gICAgICAgICAgICAvLyBmb3Igem9vbSwgdXNlIGRpZmZlcmVudCBlYXNpbmdcbiAgICAgICAgICAgIGlmIChrZXkgPT09IFwiem9vbVwiKSB7XG4gICAgICAgICAgICAgIHJldHVybiBmcm9tICogTWF0aC5wb3codG8gLyBmcm9tLCBlYXNlT3V0KHByb2dyZXNzKSk7XG4gICAgICAgICAgICB9IC8vIGhhbmRsZSB1c2luZyBkZWZhdWx0XG5cblxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uU3RlcDogKHtcbiAgICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgem9vbVxuICAgICAgICAgIH0pID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgICB6b29tOiB7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHpvb21cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblN0YXJ0OiAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uRW5kOiAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvbkNhbmNlbDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgZHVyYXRpb246IChfYiA9IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5kdXJhdGlvbikgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogNTAwXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uID0gKCkgPT4ge1xuICAgICAgICAgIGNhbmNlbCgpO1xuICAgICAgICAgIHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uID0gbnVsbDtcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICB6b29tXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG4gICAgLyoqIHVzZSB3aGVuIGNoYW5naW5nIHNjcm9sbFgvc2Nyb2xsWS96b29tIGJhc2VkIG9uIHVzZXIgaW50ZXJhY3Rpb24gKi9cblxuXG4gICAgdGhpcy50cmFuc2xhdGVDYW52YXMgPSBzdGF0ZSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIChfYSA9IHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY2FsbCh0aGlzKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUpO1xuICAgIH07XG5cbiAgICB0aGlzLnNldFRvYXN0ID0gdG9hc3QgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHRvYXN0XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXN0b3JlRmlsZUZyb21TaGFyZSA9ICgpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHdlYlNoYXJlVGFyZ2V0Q2FjaGUgPSB5aWVsZCBjYWNoZXMub3BlbihcIndlYi1zaGFyZS10YXJnZXRcIik7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0geWllbGQgd2ViU2hhcmVUYXJnZXRDYWNoZS5tYXRjaChcInNoYXJlZC1maWxlXCIpO1xuXG4gICAgICAgIGlmIChyZXNwb25zZSkge1xuICAgICAgICAgIGNvbnN0IGJsb2IgPSB5aWVsZCByZXNwb25zZS5ibG9iKCk7XG4gICAgICAgICAgY29uc3QgZmlsZSA9IG5ldyBGaWxlKFtibG9iXSwgYmxvYi5uYW1lIHx8IFwiXCIsIHtcbiAgICAgICAgICAgIHR5cGU6IGJsb2IudHlwZVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhmaWxlLCBudWxsKTtcbiAgICAgICAgICB5aWVsZCB3ZWJTaGFyZVRhcmdldENhY2hlLmRlbGV0ZShcInNoYXJlZC1maWxlXCIpO1xuICAgICAgICAgIHdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZShudWxsLCBBUFBfTkFNRSwgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIC8qKiBhZGRzIHN1cHBsaWVkIGZpbGVzIHRvIGV4aXN0aW5nIGZpbGVzIGluIHRoZSBhcHBTdGF0ZSAqL1xuXG5cbiAgICB0aGlzLmFkZEZpbGVzID0gd2l0aEJhdGNoZWRVcGRhdGVzKGZpbGVzID0+IHtcbiAgICAgIGNvbnN0IGZpbGVzTWFwID0gZmlsZXMucmVkdWNlKChhY2MsIGZpbGVEYXRhKSA9PiB7XG4gICAgICAgIGFjYy5zZXQoZmlsZURhdGEuaWQsIGZpbGVEYXRhKTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIG5ldyBNYXAoKSk7XG4gICAgICB0aGlzLmZpbGVzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgT2JqZWN0LmZyb21FbnRyaWVzKGZpbGVzTWFwKSk7XG4gICAgICB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGVsZW1lbnQpICYmIGZpbGVzTWFwLmhhcyhlbGVtZW50LmZpbGVJZCkpIHtcbiAgICAgICAgICB0aGlzLmltYWdlQ2FjaGUuZGVsZXRlKGVsZW1lbnQuZmlsZUlkKTtcbiAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLmluZm9ybU11dGF0aW9uKCk7XG4gICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgIH0pO1xuICAgIHRoaXMudXBkYXRlU2NlbmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoc2NlbmVEYXRhID0+IHtcbiAgICAgIGlmIChzY2VuZURhdGEuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNjZW5lRGF0YS5hcHBTdGF0ZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHNjZW5lRGF0YS5hcHBTdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuZWxlbWVudHMpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoc2NlbmVEYXRhLmVsZW1lbnRzKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNjZW5lRGF0YS5jb2xsYWJvcmF0b3JzKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbGxhYm9yYXRvcnM6IHNjZW5lRGF0YS5jb2xsYWJvcmF0b3JzXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5vblNjZW5lVXBkYXRlZCA9ICgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe30pO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybnMgd2hldGhlciB0aGUgbWVudSB3YXMgdG9nZ2xlZCBvbiBvciBvZmZcbiAgICAgKi9cblxuXG4gICAgdGhpcy50b2dnbGVTaWRlYmFyID0gKHtcbiAgICAgIG5hbWUsXG4gICAgICB0YWIsXG4gICAgICBmb3JjZVxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgbGV0IG5leHROYW1lO1xuXG4gICAgICBpZiAoZm9yY2UgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBuZXh0TmFtZSA9ICgoX2EgPSB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EubmFtZSkgPT09IG5hbWUgPyBudWxsIDogbmFtZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5leHROYW1lID0gZm9yY2UgPyBuYW1lIDogbnVsbDtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG9wZW5TaWRlYmFyOiBuZXh0TmFtZSA/IHtcbiAgICAgICAgICBuYW1lOiBuZXh0TmFtZSxcbiAgICAgICAgICB0YWJcbiAgICAgICAgfSA6IG51bGxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuICEhbmV4dE5hbWU7XG4gICAgfTtcblxuICAgIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnkgPSBldmVudC5jbGllbnRZO1xuICAgIH0pOyAvLyBJbnB1dCBoYW5kbGluZ1xuXG4gICAgdGhpcy5vbktleURvd24gPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgLy8gbm9ybWFsaXplIGBldmVudC5rZXlgIHdoZW4gQ2Fwc0xvY2sgaXMgcHJlc3NlZCAjMjM3MlxuICAgICAgaWYgKFwiUHJveHlcIiBpbiB3aW5kb3cgJiYgKCFldmVudC5zaGlmdEtleSAmJiAvXltBLVpdJC8udGVzdChldmVudC5rZXkpIHx8IGV2ZW50LnNoaWZ0S2V5ICYmIC9eW2Etel0kLy50ZXN0KGV2ZW50LmtleSkpKSB7XG4gICAgICAgIGV2ZW50ID0gbmV3IFByb3h5KGV2ZW50LCB7XG4gICAgICAgICAgZ2V0KGV2LCBwcm9wKSB7XG4gICAgICAgICAgICBjb25zdCB2YWx1ZSA9IGV2W3Byb3BdO1xuXG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgLy8gZml4IGZvciBQcm94aWVzIGhpamFja2luZyBgdGhpc2BcbiAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlLmJpbmQoZXYpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcHJvcCA9PT0gXCJrZXlcIiA/IC8vIENhcHNMb2NrIGludmVydHMgY2FwaXRhbGl6YXRpb24gYmFzZWQgb24gU2hpZnRLZXksIHNvIGludmVydFxuICAgICAgICAgICAgLy8gaXQgYmFja1xuICAgICAgICAgICAgZXZlbnQuc2hpZnRLZXkgPyBldi5rZXkudG9VcHBlckNhc2UoKSA6IGV2LmtleS50b0xvd2VyQ2FzZSgpIDogdmFsdWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgZXZlbnQua2V5LnRvTG93ZXJDYXNlKCkgPT09IEtFWVMuVikge1xuICAgICAgICBJU19QTEFJTl9QQVNURSA9IGV2ZW50LnNoaWZ0S2V5O1xuICAgICAgICBjbGVhclRpbWVvdXQoSVNfUExBSU5fUEFTVEVfVElNRVIpOyAvLyByZXNldCAoMTAwbXMgdG8gYmUgc2FmZSB0aGF0IHdlIGl0IHJ1bnMgYWZ0ZXIgdGhlIGVuc3VpbmdcbiAgICAgICAgLy8gcGFzdGUgZXZlbnQpLiBUaG91Z2gsIHRlY2huaWNhbGx5IHVubmVjZXNzYXJ5IHRvIHJlc2V0IHNpbmNlIHdlXG4gICAgICAgIC8vIChyZSlzZXQgdGhlIGZsYWcgYmVmb3JlIGVhY2ggcGFzdGUgZXZlbnQuXG5cbiAgICAgICAgSVNfUExBSU5fUEFTVEVfVElNRVIgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgSVNfUExBSU5fUEFTVEUgPSBmYWxzZTtcbiAgICAgICAgfSwgMTAwKTtcbiAgICAgIH0gLy8gcHJldmVudCBicm93c2VyIHpvb20gaW4gaW5wdXQgZmllbGRzXG5cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIGlzV3JpdGFibGVFbGVtZW50KGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgaWYgKGV2ZW50LmNvZGUgPT09IENPREVTLk1JTlVTIHx8IGV2ZW50LmNvZGUgPT09IENPREVTLkVRVUFMKSB7XG4gICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gLy8gYmFpbCBpZlxuXG5cbiAgICAgIGlmICggLy8gaW5zaWRlIGFuIGlucHV0XG4gICAgICBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpICYmIC8vIHVubGVzcyBwcmVzc2luZyBlc2NhcGUgKGZpbmFsaXplIGFjdGlvbilcbiAgICAgIGV2ZW50LmtleSAhPT0gS0VZUy5FU0NBUEUgfHwgLy8gb3IgdW5sZXNzIHVzaW5nIGFycm93cyAodG8gbW92ZSBiZXR3ZWVuIGJ1dHRvbnMpXG4gICAgICBpc0Fycm93S2V5KGV2ZW50LmtleSkgJiYgaXNJbnB1dExpa2UoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuUVVFU1RJT05fTUFSSykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBvcGVuRGlhbG9nOiBcImhlbHBcIlxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkudG9Mb3dlckNhc2UoKSA9PT0gS0VZUy5FICYmIGV2ZW50LnNoaWZ0S2V5ICYmIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIG9wZW5EaWFsb2c6IFwiaW1hZ2VFeHBvcnRcIlxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfVVAgfHwgZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfRE9XTikge1xuICAgICAgICBsZXQgb2Zmc2V0ID0gKGV2ZW50LnNoaWZ0S2V5ID8gdGhpcy5zdGF0ZS53aWR0aCA6IHRoaXMuc3RhdGUuaGVpZ2h0KSAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfRE9XTikge1xuICAgICAgICAgIG9mZnNldCA9IC1vZmZzZXQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2Nyb2xsWDogc3RhdGUuc2Nyb2xsWCArIG9mZnNldFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2Nyb2xsWTogc3RhdGUuc2Nyb2xsWSArIG9mZnNldFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5hY3Rpb25NYW5hZ2VyLmhhbmRsZUtleURvd24oZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIHRoaXMuc3RhdGUuaXNCaW5kaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzQXJyb3dLZXkoZXZlbnQua2V5KSkge1xuICAgICAgICBjb25zdCBzdGVwID0gdGhpcy5zdGF0ZS5ncmlkU2l6ZSAmJiAoZXZlbnQuc2hpZnRLZXkgPyBFTEVNRU5UX1RSQU5TTEFURV9BTU9VTlQgOiB0aGlzLnN0YXRlLmdyaWRTaXplKSB8fCAoZXZlbnQuc2hpZnRLZXkgPyBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQgOiBFTEVNRU5UX1RSQU5TTEFURV9BTU9VTlQpO1xuICAgICAgICBsZXQgb2Zmc2V0WCA9IDA7XG4gICAgICAgIGxldCBvZmZzZXRZID0gMDtcblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX0xFRlQpIHtcbiAgICAgICAgICBvZmZzZXRYID0gLXN0ZXA7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX1JJR0hUKSB7XG4gICAgICAgICAgb2Zmc2V0WCA9IHN0ZXA7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX1VQKSB7XG4gICAgICAgICAgb2Zmc2V0WSA9IC1zdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19ET1dOKSB7XG4gICAgICAgICAgb2Zmc2V0WSA9IHN0ZXA7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzLFxuICAgICAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlLFxuICAgICAgICAgIGluY2x1ZGVFbGVtZW50c0luRnJhbWVzOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICBzZWxlY3RlZEVsZW1lbnRzLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICB4OiBlbGVtZW50LnggKyBvZmZzZXRYLFxuICAgICAgICAgICAgeTogZWxlbWVudC55ICsgb2Zmc2V0WVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHVwZGF0ZUJvdW5kRWxlbWVudHMoZWxlbWVudCwge1xuICAgICAgICAgICAgc2ltdWx0YW5lb3VzbHlVcGRhdGVkOiBzZWxlY3RlZEVsZW1lbnRzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5FTlRFUikge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudCA9IHNlbGVjdGVkRWxlbWVudHNbMF07XG5cbiAgICAgICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgICAgIGlmIChpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgIT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3Ioc2VsZWN0ZWRFbGVtZW50LCB0aGlzLnNjZW5lKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkgfHwgaXNWYWxpZFRleHRDb250YWluZXIoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgbGV0IGNvbnRhaW5lcjtcblxuICAgICAgICAgICAgaWYgKCFpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgY29udGFpbmVyID0gc2VsZWN0ZWRFbGVtZW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBtaWRQb2ludCA9IGdldENvbnRhaW5lckNlbnRlcihzZWxlY3RlZEVsZW1lbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3Qgc2NlbmVYID0gbWlkUG9pbnQueDtcbiAgICAgICAgICAgIGNvbnN0IHNjZW5lWSA9IG1pZFBvaW50Lnk7XG4gICAgICAgICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICAgIHNjZW5lWSxcbiAgICAgICAgICAgICAgY29udGFpbmVyXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSBlbHNlIGlmIChpc0ZyYW1lRWxlbWVudChzZWxlY3RlZEVsZW1lbnQpKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0ZyYW1lOiBzZWxlY3RlZEVsZW1lbnQuaWRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICghZXZlbnQuY3RybEtleSAmJiAhZXZlbnQuYWx0S2V5ICYmICFldmVudC5tZXRhS2V5ICYmIHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50ID09PSBudWxsKSB7XG4gICAgICAgIGNvbnN0IHNoYXBlID0gZmluZFNoYXBlQnlLZXkoZXZlbnQua2V5KTtcblxuICAgICAgICBpZiAoc2hhcGUpIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IHNoYXBlKSB7XG4gICAgICAgICAgICB0cmFja0V2ZW50KFwidG9vbGJhclwiLCBzaGFwZSwgYGtleWJvYXJkICgke3RoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSA/IFwibW9iaWxlXCIgOiBcImRlc2t0b3BcIn0pYCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgICAgIHR5cGU6IHNoYXBlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlEpIHtcbiAgICAgICAgICB0aGlzLnRvZ2dsZUxvY2soXCJrZXlib2FyZFwiKTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlNQQUNFICYmIGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMCkge1xuICAgICAgICBpc0hvbGRpbmdTcGFjZSA9IHRydWU7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCKTtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKChldmVudC5rZXkgPT09IEtFWVMuRyB8fCBldmVudC5rZXkgPT09IEtFWVMuUykgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgIXNlbGVjdGVkRWxlbWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5HICYmIChoYXNCYWNrZ3JvdW5kKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSB8fCBzZWxlY3RlZEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiBoYXNCYWNrZ3JvdW5kKGVsZW1lbnQudHlwZSkpKSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgb3BlblBvcHVwOiBcImVsZW1lbnRCYWNrZ3JvdW5kXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuUykge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgb3BlblBvcHVwOiBcImVsZW1lbnRTdHJva2VcIlxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuSyAmJiAhZXZlbnQuYWx0S2V5ICYmICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIikge1xuICAgICAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgICAgIHR5cGU6IFwibGFzZXJcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgKGV2ZW50LmtleSA9PT0gS0VZUy5CQUNLU1BBQ0UgfHwgZXZlbnQua2V5ID09PSBLRVlTLkRFTEVURSkpIHtcbiAgICAgICAgam90YWlTdG9yZS5zZXQoYWN0aXZlQ29uZmlybURpYWxvZ0F0b20sIFwiY2xlYXJDYW52YXNcIik7XG4gICAgICB9IC8vIGV5ZSBkcm9wcGVyXG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbiAgICAgIGNvbnN0IGxvd2VyQ2FzZWQgPSBldmVudC5rZXkudG9Mb2NhbGVMb3dlckNhc2UoKTtcbiAgICAgIGNvbnN0IGlzUGlja2luZ1N0cm9rZSA9IGxvd2VyQ2FzZWQgPT09IEtFWVMuUyAmJiBldmVudC5zaGlmdEtleTtcbiAgICAgIGNvbnN0IGlzUGlja2luZ0JhY2tncm91bmQgPSBldmVudC5rZXkgPT09IEtFWVMuSSB8fCBsb3dlckNhc2VkID09PSBLRVlTLkcgJiYgZXZlbnQuc2hpZnRLZXk7XG5cbiAgICAgIGlmIChpc1BpY2tpbmdTdHJva2UgfHwgaXNQaWNraW5nQmFja2dyb3VuZCkge1xuICAgICAgICB0aGlzLm9wZW5FeWVEcm9wcGVyKHtcbiAgICAgICAgICB0eXBlOiBpc1BpY2tpbmdTdHJva2UgPyBcInN0cm9rZVwiIDogXCJiYWNrZ3JvdW5kXCJcbiAgICAgICAgfSk7XG4gICAgICB9IC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICB9KTtcbiAgICB0aGlzLm9uV2hlZWwgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgLy8gcHJldmVudCBicm93c2VyIHBpbmNoIHpvb20gb24gRE9NIGVsZW1lbnRzXG4gICAgICBpZiAoIShldmVudC50YXJnZXQgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCkgJiYgZXZlbnQuY3RybEtleSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMub25LZXlVcCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlNQQUNFKSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiAhdGhpcy5zdGF0ZS5pc0JpbmRpbmdFbmFibGVkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGlzQmluZGluZ0VuYWJsZWQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0Fycm93S2V5KGV2ZW50LmtleSkpIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgICAgaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSA/IGJpbmRPclVuYmluZFNlbGVjdGVkRWxlbWVudHMoc2VsZWN0ZWRFbGVtZW50cykgOiB1bmJpbmRMaW5lYXJFbGVtZW50cyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pOyAvLyBXZSBwdXJwb3NlbHkgd2lkZW4gdGhlIGB0b29sYCB0eXBlIHNvIHRoaXMgaGVscGVyIGNhbiBiZSBjYWxsZWQgd2l0aFxuICAgIC8vIGFueSB0b29sIHdpdGhvdXQgaGF2aW5nIHRvIHR5cGUgY2hlY2sgaXRcblxuICAgIHRoaXMuaXNUb29sU3VwcG9ydGVkID0gdG9vbCA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIHJldHVybiAoKF9hID0gdGhpcy5wcm9wcy5VSU9wdGlvbnMudG9vbHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVt0b29sXSkgIT09IGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLnNldEFjdGl2ZVRvb2wgPSB0b29sID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgaWYgKCF0aGlzLmlzVG9vbFN1cHBvcnRlZCh0b29sLnR5cGUpKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgXCIke3Rvb2wudHlwZX1cIiB0b29sIGlzIGRpc2FibGVkIHZpYSBcIlVJT3B0aW9ucy5jYW52YXNBY3Rpb25zLnRvb2xzLiR7dG9vbC50eXBlfVwiYCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbmV4dEFjdGl2ZVRvb2wgPSB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHRvb2wpO1xuXG4gICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSA9PT0gXCJoYW5kXCIpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgfSBlbHNlIGlmICghaXNIb2xkaW5nU3BhY2UpIHtcbiAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc1Rvb2xJY29uKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpKSB7XG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc0xpbmVhckVsZW1lbnRUeXBlKG5leHRBY3RpdmVUb29sLnR5cGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICB0aGlzLm9uSW1hZ2VBY3Rpb24oe1xuICAgICAgICAgIGluc2VydE9uQ2FudmFzRGlyZWN0bHk6IChfYSA9IHRvb2wudHlwZSA9PT0gXCJpbWFnZVwiICYmIHRvb2wuaW5zZXJ0T25DYW52YXNEaXJlY3RseSkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgY29uc3QgY29tbW9uUmVzZXRzID0ge1xuICAgICAgICAgIHNuYXBMaW5lczogcHJldlN0YXRlLnNuYXBMaW5lcy5sZW5ndGggPyBbXSA6IHByZXZTdGF0ZS5zbmFwTGluZXMsXG4gICAgICAgICAgb3JpZ2luU25hcE9mZnNldDogbnVsbCxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHtcbiAgICAgICAgICAgIGFjdGl2ZVRvb2w6IG5leHRBY3RpdmVUb29sLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgcHJldlN0YXRlKSxcbiAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCBwcmV2U3RhdGUpLFxuICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgICBtdWx0aUVsZW1lbnQ6IG51bGxcbiAgICAgICAgICB9KSwgY29tbW9uUmVzZXRzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IG5leHRBY3RpdmVUb29sXG4gICAgICAgIH0pLCBjb21tb25SZXNldHMpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc2V0T3BlbkRpYWxvZyA9IGRpYWxvZ1R5cGUgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG9wZW5EaWFsb2c6IGRpYWxvZ1R5cGVcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnNldEN1cnNvciA9IGN1cnNvciA9PiB7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgY3Vyc29yKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldEN1cnNvciA9ICgpID0+IHtcbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogcmV0dXJucyB3aGV0aGVyIHVzZXIgaXMgbWFraW5nIGEgZ2VzdHVyZSB3aXRoID49IDIgZmluZ2VycyAocG9pbnRzKVxuICAgICAqIG9uIG8gdG91Y2ggc2NyZWVuIChub3Qgb24gYSB0cmFja3BhZCkuIEN1cnJlbnRseSBvbmx5IHJlbGF0ZXMgdG8gRGFyd2luXG4gICAgICogKGlPUy9pUGFkT1MsTWFjT1MpLCBidXQgbWF5IHdvcmsgb24gb3RoZXIgZGV2aWNlcyBpbiB0aGUgZnV0dXJlIGlmXG4gICAgICogR2VzdHVyZUV2ZW50IGlzIHN0YW5kYXJkaXplZC5cbiAgICAgKi9cblxuXG4gICAgdGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUgPSAoKSA9PiB7XG4gICAgICAvLyB3ZSBkb24ndCB3YW50IHRvIGRlc2VsZWN0IHdoZW4gdXNpbmcgdHJhY2twYWQsIGFuZCBtdWx0aS1wb2ludCBnZXN0dXJlc1xuICAgICAgLy8gb25seSB3b3JrIG9uIHRvdWNoIHNjcmVlbnMsIHNvIGNoZWNraW5nIGZvciA+PSBwb2ludGVycyBtZWFucyB3ZSdyZSBvbiBhXG4gICAgICAvLyB0b3VjaHNjcmVlblxuICAgICAgcmV0dXJuIGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA+PSAyO1xuICAgIH07IC8vIGZpcmVzIG9ubHkgb24gU2FmYXJpXG5cblxuICAgIHRoaXMub25HZXN0dXJlU3RhcnQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gd2Ugb25seSB3YW50IHRvIGRlc2VsZWN0IG9uIHRvdWNoIHNjcmVlbnMgYmVjYXVzZSB1c2VyIG1heSBoYXZlIHNlbGVjdGVkXG4gICAgICAvLyBlbGVtZW50cyBieSBtaXN0YWtlIHdoaWxlIHpvb21pbmdcblxuICAgICAgaWYgKHRoaXMuaXNUb3VjaFNjcmVlbk11bHRpVG91Y2hHZXN0dXJlKCkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgfSk7IC8vIGZpcmVzIG9ubHkgb24gU2FmYXJpXG5cbiAgICB0aGlzLm9uR2VzdHVyZUNoYW5nZSA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyBvbkdlc3R1cmVDaGFuZ2Ugb25seSBoYXMgem9vbSBmYWN0b3IgYnV0IG5vdCB0aGUgY2VudGVyLlxuICAgICAgLy8gSWYgd2UncmUgb24gaVBhZCBvciBpUGhvbmUsIHRoZW4gd2UgcmVjb2duaXplIG11bHRpLXRvdWNoIGFuZCB3aWxsXG4gICAgICAvLyB6b29tIGluIGF0IHRoZSByaWdodCBsb2NhdGlvbiBpbiB0aGUgdG91Y2htb3ZlIGhhbmRsZXJcbiAgICAgIC8vIChoYW5kbGVDYW52YXNQb2ludGVyTW92ZSkuXG4gICAgICAvL1xuICAgICAgLy8gT24gTWFjYm9vayB0cmFja3BhZCwgd2UgZG9uJ3QgaGF2ZSB0aG9zZSBldmVudHMgc28gd2lsbCB6b29tIGluIGF0IHRoZVxuICAgICAgLy8gY3VycmVudCBsb2NhdGlvbiBpbnN0ZWFkLlxuICAgICAgLy9cbiAgICAgIC8vIEFzIHN1Y2gsIGJhaWwgZnJvbSB0aGlzIGhhbmRsZXIgb24gdG91Y2ggZGV2aWNlcy5cblxuICAgICAgaWYgKHRoaXMuaXNUb3VjaFNjcmVlbk11bHRpVG91Y2hHZXN0dXJlKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbml0aWFsU2NhbGUgPSBnZXN0dXJlLmluaXRpYWxTY2FsZTtcblxuICAgICAgaWYgKGluaXRpYWxTY2FsZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IE9iamVjdC5hc3NpZ24oe30sIGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgdmlld3BvcnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgICAgdmlld3BvcnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnksXG4gICAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKGluaXRpYWxTY2FsZSAqIGV2ZW50LnNjYWxlKVxuICAgICAgICB9LCBzdGF0ZSkpKTtcbiAgICAgIH1cbiAgICB9KTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuICAgIHRoaXMub25HZXN0dXJlRW5kID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIHJlc2VsZWN0IGVsZW1lbnRzIG9ubHkgb24gdG91Y2ggc2NyZWVucyAoc2VlIG9uR2VzdHVyZVN0YXJ0KVxuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczoge30sXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh0aGlzLnN0YXRlLnByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzLCB0aGlzLnN0YXRlKVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSBudWxsO1xuICAgIH0pO1xuXG4gICAgdGhpcy5zdGFydFRleHRFZGl0aW5nID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWSxcbiAgICAgIGluc2VydEF0UGFyZW50Q2VudGVyID0gdHJ1ZSxcbiAgICAgIGNvbnRhaW5lclxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgIGxldCBzaG91bGRCaW5kVG9Db250YWluZXIgPSBmYWxzZTtcbiAgICAgIGxldCBwYXJlbnRDZW50ZXJQb3NpdGlvbiA9IGluc2VydEF0UGFyZW50Q2VudGVyICYmIHRoaXMuZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwgdGhpcy5zdGF0ZSwgY29udGFpbmVyKTtcblxuICAgICAgaWYgKGNvbnRhaW5lciAmJiBwYXJlbnRDZW50ZXJQb3NpdGlvbikge1xuICAgICAgICBjb25zdCBib3VuZFRleHRFbGVtZW50VG9Db250YWluZXIgPSBnZXRCb3VuZFRleHRFbGVtZW50KGNvbnRhaW5lcik7XG5cbiAgICAgICAgaWYgKCFib3VuZFRleHRFbGVtZW50VG9Db250YWluZXIpIHtcbiAgICAgICAgICBzaG91bGRCaW5kVG9Db250YWluZXIgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxldCBleGlzdGluZ1RleHRFbGVtZW50ID0gbnVsbDtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBpZiAoaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnRzWzBdKSkge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBzZWxlY3RlZEVsZW1lbnRzWzBdO1xuICAgICAgICB9IGVsc2UgaWYgKGNvbnRhaW5lcikge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBnZXRCb3VuZFRleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSB0aGlzLmdldFRleHRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSB0aGlzLmdldFRleHRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZvbnRGYW1pbHkgPSAoZXhpc3RpbmdUZXh0RWxlbWVudCA9PT0gbnVsbCB8fCBleGlzdGluZ1RleHRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBleGlzdGluZ1RleHRFbGVtZW50LmZvbnRGYW1pbHkpIHx8IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250RmFtaWx5O1xuICAgICAgY29uc3QgbGluZUhlaWdodCA9IChleGlzdGluZ1RleHRFbGVtZW50ID09PSBudWxsIHx8IGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nVGV4dEVsZW1lbnQubGluZUhlaWdodCkgfHwgZ2V0RGVmYXVsdExpbmVIZWlnaHQoZm9udEZhbWlseSk7XG4gICAgICBjb25zdCBmb250U2l6ZSA9IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250U2l6ZTtcblxuICAgICAgaWYgKCFleGlzdGluZ1RleHRFbGVtZW50ICYmIHNob3VsZEJpbmRUb0NvbnRhaW5lciAmJiBjb250YWluZXIgJiYgIWlzQXJyb3dFbGVtZW50KGNvbnRhaW5lcikpIHtcbiAgICAgICAgY29uc3QgZm9udFN0cmluZyA9IHtcbiAgICAgICAgICBmb250U2l6ZSxcbiAgICAgICAgICBmb250RmFtaWx5XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IG1pbldpZHRoID0gZ2V0QXBwcm94TWluTGluZVdpZHRoKGdldEZvbnRTdHJpbmcoZm9udFN0cmluZyksIGxpbmVIZWlnaHQpO1xuICAgICAgICBjb25zdCBtaW5IZWlnaHQgPSBnZXRBcHByb3hNaW5MaW5lSGVpZ2h0KGZvbnRTaXplLCBsaW5lSGVpZ2h0KTtcbiAgICAgICAgY29uc3QgbmV3SGVpZ2h0ID0gTWF0aC5tYXgoY29udGFpbmVyLmhlaWdodCwgbWluSGVpZ2h0KTtcbiAgICAgICAgY29uc3QgbmV3V2lkdGggPSBNYXRoLm1heChjb250YWluZXIud2lkdGgsIG1pbldpZHRoKTtcbiAgICAgICAgbXV0YXRlRWxlbWVudChjb250YWluZXIsIHtcbiAgICAgICAgICBoZWlnaHQ6IG5ld0hlaWdodCxcbiAgICAgICAgICB3aWR0aDogbmV3V2lkdGhcbiAgICAgICAgfSk7XG4gICAgICAgIHNjZW5lWCA9IGNvbnRhaW5lci54ICsgbmV3V2lkdGggLyAyO1xuICAgICAgICBzY2VuZVkgPSBjb250YWluZXIueSArIG5ld0hlaWdodCAvIDI7XG5cbiAgICAgICAgaWYgKHBhcmVudENlbnRlclBvc2l0aW9uKSB7XG4gICAgICAgICAgcGFyZW50Q2VudGVyUG9zaXRpb24gPSB0aGlzLmdldFRleHRXeXNpd3lnU25hcHBlZFRvQ2VudGVyUG9zaXRpb24oc2NlbmVYLCBzY2VuZVksIHRoaXMuc3RhdGUsIGNvbnRhaW5lcik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSk7XG4gICAgICBjb25zdCBlbGVtZW50ID0gZXhpc3RpbmdUZXh0RWxlbWVudCA/IGV4aXN0aW5nVGV4dEVsZW1lbnQgOiBuZXdUZXh0RWxlbWVudCh7XG4gICAgICAgIHg6IHBhcmVudENlbnRlclBvc2l0aW9uID8gcGFyZW50Q2VudGVyUG9zaXRpb24uZWxlbWVudENlbnRlclggOiBzY2VuZVgsXG4gICAgICAgIHk6IHBhcmVudENlbnRlclBvc2l0aW9uID8gcGFyZW50Q2VudGVyUG9zaXRpb24uZWxlbWVudENlbnRlclkgOiBzY2VuZVksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICB0ZXh0OiBcIlwiLFxuICAgICAgICBmb250U2l6ZSxcbiAgICAgICAgZm9udEZhbWlseSxcbiAgICAgICAgdGV4dEFsaWduOiBwYXJlbnRDZW50ZXJQb3NpdGlvbiA/IFwiY2VudGVyXCIgOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtVGV4dEFsaWduLFxuICAgICAgICB2ZXJ0aWNhbEFsaWduOiBwYXJlbnRDZW50ZXJQb3NpdGlvbiA/IFZFUlRJQ0FMX0FMSUdOLk1JRERMRSA6IERFRkFVTFRfVkVSVElDQUxfQUxJR04sXG4gICAgICAgIGNvbnRhaW5lcklkOiBzaG91bGRCaW5kVG9Db250YWluZXIgPyBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuaWQgOiB1bmRlZmluZWQsXG4gICAgICAgIGdyb3VwSWRzOiAoX2EgPSBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuZ3JvdXBJZHMpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IFtdLFxuICAgICAgICBsaW5lSGVpZ2h0LFxuICAgICAgICBhbmdsZTogKF9iID0gY29udGFpbmVyID09PSBudWxsIHx8IGNvbnRhaW5lciA9PT0gdm9pZCAwID8gdm9pZCAwIDogY29udGFpbmVyLmFuZ2xlKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyICYmIGNvbnRhaW5lcikge1xuICAgICAgICBtdXRhdGVFbGVtZW50KGNvbnRhaW5lciwge1xuICAgICAgICAgIGJvdW5kRWxlbWVudHM6IChjb250YWluZXIuYm91bmRFbGVtZW50cyB8fCBbXSkuY29uY2F0KHtcbiAgICAgICAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgICAgICAgaWQ6IGVsZW1lbnQuaWRcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBlbGVtZW50XG4gICAgICB9KTtcblxuICAgICAgaWYgKCFleGlzdGluZ1RleHRFbGVtZW50KSB7XG4gICAgICAgIGlmIChjb250YWluZXIgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyKSB7XG4gICAgICAgICAgY29uc3QgY29udGFpbmVySW5kZXggPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRJbmRleChjb250YWluZXIuaWQpO1xuICAgICAgICAgIHRoaXMuc2NlbmUuaW5zZXJ0RWxlbWVudEF0SW5kZXgoZWxlbWVudCwgY29udGFpbmVySW5kZXggKyAxKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBlbGVtZW50XG4gICAgICB9KTtcbiAgICAgIHRoaXMuaGFuZGxlVGV4dFd5c2l3eWcoZWxlbWVudCwge1xuICAgICAgICBpc0V4aXN0aW5nRWxlbWVudDogISFleGlzdGluZ1RleHRFbGVtZW50XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNEb3VibGVDbGljayA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIGNhc2U6IGRvdWJsZS1jbGlja2luZyB3aXRoIGFycm93L2xpbmUgdG9vbCBzZWxlY3RlZCB3b3VsZCBib3RoIGNyZWF0ZVxuICAgICAgLy8gdGV4dCBhbmQgZW50ZXIgbXVsdGlFbGVtZW50IG1vZGVcbiAgICAgIGlmICh0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHdlIHNob3VsZCBvbmx5IGJlIGFibGUgdG8gZG91YmxlIGNsaWNrIHdoZW4gbW9kZSBpcyBzZWxlY3Rpb25cblxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNMaW5lYXJFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pKSB7XG4gICAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiAoIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgIT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpKSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKHNlbGVjdGVkRWxlbWVudHNbMF0sIHRoaXMuc2NlbmUpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgPT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICBsZXQge1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBzZWxlY3RlZEdyb3VwSWRzID0gZ2V0U2VsZWN0ZWRHcm91cElkcyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkR3JvdXBJZHMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkR3JvdXBJZCA9IGhpdEVsZW1lbnQgJiYgZ2V0U2VsZWN0ZWRHcm91cElkRm9yRWxlbWVudChoaXRFbGVtZW50LCB0aGlzLnN0YXRlLnNlbGVjdGVkR3JvdXBJZHMpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEdyb3VwSWQpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHNlbGVjdGVkR3JvdXBJZCxcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuXG4gICAgICBpZiAoIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICF0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG5cbiAgICAgICAgaWYgKGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IHtcbiAgICAgICAgICAgICAgZWxlbWVudDogaGl0RWxlbWVudCxcbiAgICAgICAgICAgICAgc3RhdGU6IFwiYWN0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjb250YWluZXIgPSBnZXRUZXh0QmluZGFibGVDb250YWluZXJBdFBvc2l0aW9uKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgICBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgaWYgKGhhc0JvdW5kVGV4dEVsZW1lbnQoY29udGFpbmVyKSB8fCAhaXNUcmFuc3BhcmVudChjb250YWluZXIuYmFja2dyb3VuZENvbG9yKSB8fCBpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveChjb250YWluZXIsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIFtzY2VuZVgsIHNjZW5lWV0pKSB7XG4gICAgICAgICAgICBjb25zdCBtaWRQb2ludCA9IGdldENvbnRhaW5lckNlbnRlcihjb250YWluZXIsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgc2NlbmVYID0gbWlkUG9pbnQueDtcbiAgICAgICAgICAgIHNjZW5lWSA9IG1pZFBvaW50Lnk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zdGFydFRleHRFZGl0aW5nKHtcbiAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgc2NlbmVZLFxuICAgICAgICAgIGluc2VydEF0UGFyZW50Q2VudGVyOiAhZXZlbnQuYWx0S2V5LFxuICAgICAgICAgIGNvbnRhaW5lclxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24gPSAoc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KSA9PiB7XG4gICAgICAvLyBSZXZlcnNpbmcgc28gd2UgdHJhdmVyc2UgdGhlIGVsZW1lbnRzIGluIGRlY3JlYXNpbmcgb3JkZXJcbiAgICAgIC8vIG9mIHotaW5kZXhcbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5zbGljZSgpLnJldmVyc2UoKTtcbiAgICAgIGxldCBoaXRFbGVtZW50SW5kZXggPSBJbmZpbml0eTtcbiAgICAgIHJldHVybiBlbGVtZW50cy5maW5kKChlbGVtZW50LCBpbmRleCkgPT4ge1xuICAgICAgICBpZiAoaGl0RWxlbWVudCAmJiBlbGVtZW50LmlkID09PSBoaXRFbGVtZW50LmlkKSB7XG4gICAgICAgICAgaGl0RWxlbWVudEluZGV4ID0gaW5kZXg7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlbWVudC5saW5rICYmIGluZGV4IDw9IGhpdEVsZW1lbnRJbmRleCAmJiBpc1BvaW50SGl0dGluZ0xpbmsoZWxlbWVudCwgdGhpcy5zdGF0ZSwgW3NjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueV0sIHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZWRpcmVjdFRvTGluayA9IChldmVudCwgaXNUb3VjaFNjcmVlbikgPT4ge1xuICAgICAgY29uc3QgZHJhZ2dlZERpc3RhbmNlID0gZGlzdGFuY2UyZCh0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50LmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQuY2xpZW50WSwgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WSk7XG5cbiAgICAgIGlmICghdGhpcy5oaXRMaW5rRWxlbWVudCB8fCAvLyBGb3IgdG91Y2ggc2NyZWVuIGFsbG93IGRyYWdnaW5nIHRocmVzaG9sZCBlbHNlIHN0cmljdCBjaGVja1xuICAgICAgaXNUb3VjaFNjcmVlbiAmJiBkcmFnZ2VkRGlzdGFuY2UgPiBEUkFHR0lOR19USFJFU0hPTEQgfHwgIWlzVG91Y2hTY3JlZW4gJiYgZHJhZ2dlZERpc3RhbmNlICE9PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbGFzdFBvaW50ZXJEb3duQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJEb3duSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlckRvd25Db29yZHMueCwgbGFzdFBvaW50ZXJEb3duQ29vcmRzLnldLCB0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJVcENvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh0aGlzLmxhc3RQb2ludGVyVXBFdmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlclVwQ29vcmRzLngsIGxhc3RQb2ludGVyVXBDb29yZHMueV0sIHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSk7XG5cbiAgICAgIGlmIChsYXN0UG9pbnRlckRvd25IaXR0aW5nTGlua0ljb24gJiYgbGFzdFBvaW50ZXJVcEhpdHRpbmdMaW5rSWNvbikge1xuICAgICAgICBsZXQgdXJsID0gdGhpcy5oaXRMaW5rRWxlbWVudC5saW5rO1xuXG4gICAgICAgIGlmICh1cmwpIHtcbiAgICAgICAgICB1cmwgPSBub3JtYWxpemVMaW5rKHVybCk7XG4gICAgICAgICAgbGV0IGN1c3RvbUV2ZW50O1xuXG4gICAgICAgICAgaWYgKHRoaXMucHJvcHMub25MaW5rT3Blbikge1xuICAgICAgICAgICAgY3VzdG9tRXZlbnQgPSB3cmFwRXZlbnQoRVZFTlQuRVhDQUxJRFJBV19MSU5LLCBldmVudC5uYXRpdmVFdmVudCk7XG4gICAgICAgICAgICB0aGlzLnByb3BzLm9uTGlua09wZW4oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmhpdExpbmtFbGVtZW50KSwge1xuICAgICAgICAgICAgICBsaW5rOiB1cmxcbiAgICAgICAgICAgIH0pLCBjdXN0b21FdmVudCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCEoY3VzdG9tRXZlbnQgPT09IG51bGwgfHwgY3VzdG9tRXZlbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGN1c3RvbUV2ZW50LmRlZmF1bHRQcmV2ZW50ZWQpKSB7XG4gICAgICAgICAgICBjb25zdCB0YXJnZXQgPSBpc0xvY2FsTGluayh1cmwpID8gXCJfc2VsZlwiIDogXCJfYmxhbmtcIjtcbiAgICAgICAgICAgIGNvbnN0IG5ld1dpbmRvdyA9IHdpbmRvdy5vcGVuKHVuZGVmaW5lZCwgdGFyZ2V0KTsgLy8gaHR0cHM6Ly9tYXRoaWFzYnluZW5zLmdpdGh1Yi5pby9yZWwtbm9vcGVuZXIvXG5cbiAgICAgICAgICAgIGlmIChuZXdXaW5kb3cpIHtcbiAgICAgICAgICAgICAgbmV3V2luZG93Lm9wZW5lciA9IG51bGw7XG4gICAgICAgICAgICAgIG5ld1dpbmRvdy5sb2NhdGlvbiA9IHVybDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3JkcyA9IHNjZW5lQ29vcmRzID0+IHtcbiAgICAgIGNvbnN0IGZyYW1lcyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLmZpbHRlcihmcmFtZSA9PiBpc0N1cnNvckluRnJhbWUoc2NlbmVDb29yZHMsIGZyYW1lKSk7XG4gICAgICByZXR1cm4gZnJhbWVzLmxlbmd0aCA/IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gOiBudWxsO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlID0gZXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCB0aGlzLnN0YXRlLmN1cnNvckJ1dHRvbik7XG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLmhhcyhldmVudC5wb2ludGVySWQpKSB7XG4gICAgICAgIGdlc3R1cmUucG9pbnRlcnMuc2V0KGV2ZW50LnBvaW50ZXJJZCwge1xuICAgICAgICAgIHg6IGV2ZW50LmNsaWVudFgsXG4gICAgICAgICAgeTogZXZlbnQuY2xpZW50WVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaW5pdGlhbFNjYWxlID0gZ2VzdHVyZS5pbml0aWFsU2NhbGU7XG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLnNpemUgPT09IDIgJiYgZ2VzdHVyZS5sYXN0Q2VudGVyICYmIGluaXRpYWxTY2FsZSAmJiBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSkge1xuICAgICAgICBjb25zdCBjZW50ZXIgPSBnZXRDZW50ZXIoZ2VzdHVyZS5wb2ludGVycyk7XG4gICAgICAgIGNvbnN0IGRlbHRhWCA9IGNlbnRlci54IC0gZ2VzdHVyZS5sYXN0Q2VudGVyLng7XG4gICAgICAgIGNvbnN0IGRlbHRhWSA9IGNlbnRlci55IC0gZ2VzdHVyZS5sYXN0Q2VudGVyLnk7XG4gICAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGNlbnRlcjtcbiAgICAgICAgY29uc3QgZGlzdGFuY2UgPSBnZXREaXN0YW5jZShBcnJheS5mcm9tKGdlc3R1cmUucG9pbnRlcnMudmFsdWVzKCkpKTtcbiAgICAgICAgY29uc3Qgc2NhbGVGYWN0b3IgPSB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmVlZHJhd1wiICYmIHRoaXMuc3RhdGUucGVuTW9kZSA/IDEgOiBkaXN0YW5jZSAvIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlO1xuICAgICAgICBjb25zdCBuZXh0Wm9vbSA9IHNjYWxlRmFjdG9yID8gZ2V0Tm9ybWFsaXplZFpvb20oaW5pdGlhbFNjYWxlICogc2NhbGVGYWN0b3IpIDogdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IHtcbiAgICAgICAgICBjb25zdCB6b29tU3RhdGUgPSBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICAgICAgdmlld3BvcnRYOiBjZW50ZXIueCxcbiAgICAgICAgICAgIHZpZXdwb3J0WTogY2VudGVyLnksXG4gICAgICAgICAgICBuZXh0Wm9vbVxuICAgICAgICAgIH0sIHN0YXRlKTtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyh7XG4gICAgICAgICAgICB6b29tOiB6b29tU3RhdGUuem9vbSxcbiAgICAgICAgICAgIHNjcm9sbFg6IHpvb21TdGF0ZS5zY3JvbGxYICsgZGVsdGFYIC8gbmV4dFpvb20sXG4gICAgICAgICAgICBzY3JvbGxZOiB6b29tU3RhdGUuc2Nyb2xsWSArIGRlbHRhWSAvIG5leHRab29tLFxuICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBnZXN0dXJlLmxhc3RDZW50ZXIgPSBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSA9IGdlc3R1cmUuaW5pdGlhbFNjYWxlID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzSG9sZGluZ1NwYWNlIHx8IGlzUGFubmluZyB8fCBpc0RyYWdnaW5nU2Nyb2xsQmFyIHx8IGlzSGFuZFRvb2xBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc1BvaW50ZXJPdmVyU2Nyb2xsQmFycyA9IGlzT3ZlclNjcm9sbEJhcnMoY3VycmVudFNjcm9sbEJhcnMsIGV2ZW50LmNsaWVudFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIGV2ZW50LmNsaWVudFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcCk7XG4gICAgICBjb25zdCBpc092ZXJTY3JvbGxCYXIgPSBpc1BvaW50ZXJPdmVyU2Nyb2xsQmFycy5pc092ZXJFaXRoZXI7XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIGlmIChpc092ZXJTY3JvbGxCYXIpIHtcbiAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3Qge1xuICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICB9ID0gc2NlbmVQb2ludGVyO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50ICYmIGlzQWN0aXZlVG9vbE5vbkxpbmVhclNuYXBwYWJsZSh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG9yaWdpbk9mZnNldCxcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSA9IGdldFNuYXBMaW5lc0F0UG9pbnRlcih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgeDogc2NlbmVQb2ludGVyWCxcbiAgICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICAgIH0sIGV2ZW50KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzLFxuICAgICAgICAgIG9yaWdpblNuYXBPZmZzZXQ6IG9yaWdpbk9mZnNldFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoIXRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNuYXBMaW5lczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgY29uc3QgZWRpdGluZ0xpbmVhckVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJNb3ZlKGV2ZW50LCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZWRpdGluZ0xpbmVhckVsZW1lbnQgIT09IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSBudWxsIHx8IGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlZGl0aW5nTGluZWFyRWxlbWVudC5sYXN0VW5jb21taXR0ZWRQb2ludCkgIT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0F0Q3Vyc29yKHNjZW5lUG9pbnRlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gY2F1c2VzIHN0YWNrIG92ZXJmbG93IGlmIG5vdCBzeW5jXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50VHlwZSh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgLy8gSG92ZXJpbmcgd2l0aCBhIHNlbGVjdGVkIHRvb2wgb3IgY3JlYXRpbmcgbmV3IGxpbmVhciBlbGVtZW50IHZpYSBjbGlja1xuICAgICAgICAvLyBhbmQgcG9pbnRcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBpZiAoaXNCaW5kaW5nRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ3NGb3JMaW5lYXJFbGVtZW50QXRDb29yZHMoZHJhZ2dpbmdFbGVtZW50LCBbc2NlbmVQb2ludGVyXSwgdGhpcy5zdGF0ZS5zdGFydEJvdW5kRWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3Ioc2NlbmVQb2ludGVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG11bHRpRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHJ4LFxuICAgICAgICAgIHk6IHJ5XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBwb2ludHMsXG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IGxhc3RQb2ludCA9IHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV07XG4gICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChsYXN0UG9pbnQgPT09IGxhc3RDb21taXR0ZWRQb2ludCkge1xuICAgICAgICAgIC8vIGlmIHdlIGhhdmVuJ3QgeWV0IGNyZWF0ZWQgYSB0ZW1wIHBvaW50IGFuZCB3ZSdyZSBiZXlvbmQgY29tbWl0LXpvbmVcbiAgICAgICAgICAvLyB0aHJlc2hvbGQsIGFkZCBhIHBvaW50XG4gICAgICAgICAgaWYgKGRpc3RhbmNlMmQoc2NlbmVQb2ludGVyWCAtIHJ4LCBzY2VuZVBvaW50ZXJZIC0gcnksIGxhc3RQb2ludFswXSwgbGFzdFBvaW50WzFdKSA+PSBMSU5FX0NPTkZJUk1fVEhSRVNIT0xEKSB7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeV1dXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpOyAvLyBpbiB0aGlzIGJyYW5jaCwgd2UncmUgaW5zaWRlIHRoZSBjb21taXQgem9uZSwgYW5kIG5vIHVuY29tbWl0dGVkXG4gICAgICAgICAgICAvLyBwb2ludCBleGlzdHMuIFRodXMgZG8gbm90aGluZyAoZG9uJ3QgYWRkL3JlbW92ZSBwb2ludHMpLlxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID4gMiAmJiBsYXN0Q29tbWl0dGVkUG9pbnQgJiYgZGlzdGFuY2UyZChzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeSwgbGFzdENvbW1pdHRlZFBvaW50WzBdLCBsYXN0Q29tbWl0dGVkUG9pbnRbMV0pIDwgTElORV9DT05GSVJNX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBwb2ludHMuc2xpY2UoMCwgLTEpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgICAgY29uc3QgW2xhc3RDb21taXR0ZWRYLCBsYXN0Q29tbWl0dGVkWV0gPSAoX2EgPSBtdWx0aUVsZW1lbnQgPT09IG51bGwgfHwgbXVsdGlFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBtdWx0aUVsZW1lbnQubGFzdENvbW1pdHRlZFBvaW50KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBbMCwgMF07XG4gICAgICAgICAgbGV0IGR4RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWCAtIHJ4IC0gbGFzdENvbW1pdHRlZFg7XG4gICAgICAgICAgbGV0IGR5RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWSAtIHJ5IC0gbGFzdENvbW1pdHRlZFk7XG5cbiAgICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpKSB7XG4gICAgICAgICAgICAoe1xuICAgICAgICAgICAgICB3aWR0aDogZHhGcm9tTGFzdENvbW1pdHRlZCxcbiAgICAgICAgICAgICAgaGVpZ2h0OiBkeUZyb21MYXN0Q29tbWl0dGVkXG4gICAgICAgICAgICB9ID0gZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplKCAvLyBhY3R1YWwgY29vcmRpbmF0ZSBvZiB0aGUgbGFzdCBjb21taXR0ZWQgcG9pbnRcbiAgICAgICAgICAgIGxhc3RDb21taXR0ZWRYICsgcngsIGxhc3RDb21taXR0ZWRZICsgcnksIC8vIGN1cnNvci1ncmlkIGNvb3JkaW5hdGVcbiAgICAgICAgICAgIGdyaWRYLCBncmlkWSkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChpc1BhdGhBTG9vcChwb2ludHMsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpIHtcbiAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICB9IC8vIHVwZGF0ZSBsYXN0IHVuY29tbWl0dGVkIHBvaW50XG5cblxuICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMuc2xpY2UoMCwgLTEpLCBbbGFzdENvbW1pdHRlZFggKyBkeEZyb21MYXN0Q29tbWl0dGVkLCBsYXN0Q29tbWl0dGVkWSArIGR5RnJvbUxhc3RDb21taXR0ZWRdXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNEZXNlbGVjdGVkQnV0dG9uID0gQm9vbGVhbihldmVudC5idXR0b25zKTtcblxuICAgICAgaWYgKGhhc0Rlc2VsZWN0ZWRCdXR0b24gfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwidGV4dFwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICFpc092ZXJTY3JvbGxCYXIgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlKGVsZW1lbnRzLCB0aGlzLnN0YXRlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICBpZiAoZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlICYmIGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS50cmFuc2Zvcm1IYW5kbGVUeXBlKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIGdldEN1cnNvckZvclJlc2l6aW5nRWxlbWVudChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiAxICYmICFpc092ZXJTY3JvbGxCYXIpIHtcbiAgICAgICAgY29uc3QgdHJhbnNmb3JtSGFuZGxlVHlwZSA9IGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzKGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG5cbiAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50KHtcbiAgICAgICAgICAgIHRyYW5zZm9ybUhhbmRsZVR5cGVcbiAgICAgICAgICB9KSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICB0aGlzLmhpdExpbmtFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KTtcblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGl0TGlua0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuaGl0TGlua0VsZW1lbnQuaWRdKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgc2hvd0h5cGVybGlua1Rvb2x0aXAodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoaWRlSHlwZXJsaW5rVG9vbGlwKCk7XG5cbiAgICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgKGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpKSAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSAmJiAhdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiAhdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXApIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogXCJpbmZvXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgaXNUZXh0RWxlbWVudChoaXRFbGVtZW50KSA/IENVUlNPUl9UWVBFLlRFWFQgOiBDVVJTT1JfVFlQRS5DUk9TU0hBSVIpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICB9IGVsc2UgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlSG92ZXJTZWxlY3RlZExpbmVhckVsZW1lbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpO1xuICAgICAgICB9IGVsc2UgaWYgKCAvLyBpZiB1c2luZyBjbWQvY3RybCwgd2UncmUgbm90IGRyYWdnaW5nXG4gICAgICAgICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICAgIGlmICgoaGl0RWxlbWVudCB8fCB0aGlzLmlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHNjZW5lUG9pbnRlciwgc2VsZWN0ZWRFbGVtZW50cykpICYmICEoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmxvY2tlZCkpIHtcbiAgICAgICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgZXZlbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICAgICAgZWxlbWVudDogaGl0RWxlbWVudCxcbiAgICAgICAgICAgICAgICAgIHN0YXRlOiBcImhvdmVyXCJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuXG4gICAgICAgICAgICAgIGlmICgoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImhvdmVyXCIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQVVUTyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVFcmFzZXIgPSAoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUsIHNjZW5lUG9pbnRlcikgPT4ge1xuICAgICAgY29uc3QgdXBkYXRlRWxlbWVudElkcyA9IGVsZW1lbnRzID0+IHtcbiAgICAgICAgZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoZWxlbWVudC5sb2NrZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZHNUb1VwZGF0ZS5wdXNoKGVsZW1lbnQuaWQpO1xuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSkge1xuICAgICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlbWVudC5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXS5lcmFzZSkge1xuICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdLmVyYXNlID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmICghcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSA9IHtcbiAgICAgICAgICAgICAgZXJhc2U6IHRydWUsXG4gICAgICAgICAgICAgIG9wYWNpdHk6IGVsZW1lbnQub3BhY2l0eVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfTtcblxuICAgICAgY29uc3QgaWRzVG9VcGRhdGUgPSBbXTtcbiAgICAgIGNvbnN0IGRpc3RhbmNlID0gZGlzdGFuY2UyZChwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnksIHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICBjb25zdCB0aHJlc2hvbGQgPSAxMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgIGNvbnN0IHBvaW50ID0gT2JqZWN0LmFzc2lnbih7fSwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzKTtcbiAgICAgIGxldCBzYW1wbGluZ0ludGVydmFsID0gMDtcblxuICAgICAgd2hpbGUgKHNhbXBsaW5nSW50ZXJ2YWwgPD0gZGlzdGFuY2UpIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbihwb2ludC54LCBwb2ludC55KTtcbiAgICAgICAgdXBkYXRlRWxlbWVudElkcyhoaXRFbGVtZW50cyk7IC8vIEV4aXQgc2luY2Ugd2UgcmVhY2hlZCBjdXJyZW50IHBvaW50XG5cbiAgICAgICAgaWYgKHNhbXBsaW5nSW50ZXJ2YWwgPT09IGRpc3RhbmNlKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gLy8gQ2FsY3VsYXRlIG5leHQgcG9pbnQgaW4gdGhlIGxpbmUgYXQgYSBkaXN0YW5jZSBvZiBzYW1wbGluZyBpbnRlcnZhbFxuXG5cbiAgICAgICAgc2FtcGxpbmdJbnRlcnZhbCA9IE1hdGgubWluKHNhbXBsaW5nSW50ZXJ2YWwgKyB0aHJlc2hvbGQsIGRpc3RhbmNlKTtcbiAgICAgICAgY29uc3QgZGlzdGFuY2VSYXRpbyA9IHNhbXBsaW5nSW50ZXJ2YWwgLyBkaXN0YW5jZTtcbiAgICAgICAgY29uc3QgbmV4dFggPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueCArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueDtcbiAgICAgICAgY29uc3QgbmV4dFkgPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueSArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueTtcbiAgICAgICAgcG9pbnQueCA9IG5leHRYO1xuICAgICAgICBwb2ludC55ID0gbmV4dFk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWxlID0+IHtcbiAgICAgICAgY29uc3QgaWQgPSBpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBpZHNUb1VwZGF0ZS5pbmNsdWRlcyhlbGUuY29udGFpbmVySWQpID8gZWxlLmNvbnRhaW5lcklkIDogZWxlLmlkO1xuXG4gICAgICAgIGlmIChpZHNUb1VwZGF0ZS5pbmNsdWRlcyhpZCkpIHtcbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0uZXJhc2UgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXS5vcGFjaXR5XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICAgIG9wYWNpdHk6IEVMRU1FTlRfUkVBRFlfVE9fRVJBU0VfT1BBQ0lUWVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBzY2VuZVBvaW50ZXIueDtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gc2NlbmVQb2ludGVyLnk7XG4gICAgfTsgLy8gc2V0IHRvdWNoIG1vdmluZyBmb3IgbW9iaWxlIGNvbnRleHQgbWVudVxuXG5cbiAgICB0aGlzLmhhbmRsZVRvdWNoTW92ZSA9IGV2ZW50ID0+IHtcbiAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IHRydWU7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24gPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBzaW5jZSBjb250ZXh0TWVudSBvcHRpb25zIGFyZSBwb3RlbnRpYWxseSBldmFsdWF0ZWQgb24gZWFjaCByZW5kZXIsXG4gICAgICAvLyBhbmQgYW4gY29udGV4dE1lbnUgYWN0aW9uIG1heSBkZXBlbmQgb24gc2VsZWN0aW9uIHN0YXRlLCB3ZSBtdXN0XG4gICAgICAvLyBjbG9zZSB0aGUgY29udGV4dE1lbnUgYmVmb3JlIHdlIHVwZGF0ZSB0aGUgc2VsZWN0aW9uIG9uIHBvaW50ZXJEb3duXG4gICAgICAvLyAoZS5nLiByZXNldHRpbmcgc2VsZWN0aW9uKVxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zbmFwTGluZXMpIHtcbiAgICAgICAgdGhpcy5zZXRBcHBTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy51cGRhdGVHZXN0dXJlT25Qb2ludGVyRG93bihldmVudCk7IC8vIGlmIGRyYWdnaW5nIGVsZW1lbnQgaXMgZnJlZWRyYXcgYW5kIGFub3RoZXIgcG9pbnRlcmRvd24gZXZlbnQgb2NjdXJzXG4gICAgICAvLyBhIHNlY29uZCBmaW5nZXIgaXMgb24gdGhlIHNjcmVlblxuICAgICAgLy8gZGlzY2FyZCB0aGUgZnJlZWRyYXcgZWxlbWVudCBpZiBpdCBpcyB2ZXJ5IHNob3J0IGJlY2F1c2UgaXQgaXMgbGlrZWx5XG4gICAgICAvLyBqdXN0IGEgc3Bpa2UsIG90aGVyd2lzZSBmaW5hbGl6ZSB0aGUgZnJlZWRyYXcgZWxlbWVudCB3aGVuIHRoZSBzZWNvbmRcbiAgICAgIC8vIGZpbmdlciBpcyBsaWZ0ZWRcblxuICAgICAgaWYgKGV2ZW50LnBvaW50ZXJUeXBlID09PSBcInRvdWNoXCIgJiYgdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudDtcbiAgICAgICAgdGhpcy51cGRhdGVTY2VuZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGVsZW1lbnQucG9pbnRzLmxlbmd0aCA8IDEwID8ge1xuICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbHRlcihlbCA9PiBlbC5pZCAhPT0gZWxlbWVudC5pZClcbiAgICAgICAgfSA6IHt9KSwge1xuICAgICAgICAgIGFwcFN0YXRlOiB7XG4gICAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgIHN0YXJ0Qm91bmRFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3Qua2V5cyh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcykuZmlsdGVyKGtleSA9PiBrZXkgIT09IGVsZW1lbnQuaWQpLnJlZHVjZSgob2JqLCBrZXkpID0+IHtcbiAgICAgICAgICAgICAgb2JqW2tleV0gPSB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1trZXldO1xuICAgICAgICAgICAgICByZXR1cm4gb2JqO1xuICAgICAgICAgICAgfSwge30pLCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSkpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHJlbW92ZSBhbnkgYWN0aXZlIHNlbGVjdGlvbiB3aGVuIHdlIHN0YXJ0IHRvIGludGVyYWN0IHdpdGggY2FudmFzXG4gICAgICAvLyAobWFpbmx5LCB3ZSBjYXJlIGFib3V0IHJlbW92aW5nIHNlbGVjdGlvbiBvdXRzaWRlIHRoZSBjb21wb25lbnQgd2hpY2hcbiAgICAgIC8vICB3b3VsZCBwcmV2ZW50IG91ciBjb3B5IGhhbmRsaW5nIG90aGVyd2lzZSlcblxuXG4gICAgICBjb25zdCBzZWxlY3Rpb24gPSBkb2N1bWVudC5nZXRTZWxlY3Rpb24oKTtcblxuICAgICAgaWYgKHNlbGVjdGlvbiA9PT0gbnVsbCB8fCBzZWxlY3Rpb24gPT09IHZvaWQgMCA/IHZvaWQgMCA6IHNlbGVjdGlvbi5hbmNob3JOb2RlKSB7XG4gICAgICAgIHNlbGVjdGlvbi5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tYXliZU9wZW5Db250ZXh0TWVudUFmdGVyUG9pbnRlckRvd25PblRvdWNoRGV2aWNlcyhldmVudCk7XG4gICAgICB0aGlzLm1heWJlQ2xlYW51cEFmdGVyTWlzc2luZ1BvaW50ZXJVcChldmVudCk7IC8vZmlyZXMgb25seSBvbmNlLCBpZiBwZW4gaXMgZGV0ZWN0ZWQsIHBlbk1vZGUgaXMgZW5hYmxlZFxuICAgICAgLy90aGUgdXNlciBjYW4gZGlzYWJsZSB0aGlzIGJ5IHRvZ2dsaW5nIHRoZSBwZW5Nb2RlIGJ1dHRvblxuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUucGVuRGV0ZWN0ZWQgJiYgZXZlbnQucG9pbnRlclR5cGUgPT09IFwicGVuXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBwZW5Nb2RlOiB0cnVlLFxuICAgICAgICAgICAgcGVuRGV0ZWN0ZWQ6IHRydWVcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuICYmIFtcInBlblwiLCBcInRvdWNoXCJdLmluY2x1ZGVzKGV2ZW50LnBvaW50ZXJUeXBlKSkge1xuICAgICAgICB0aGlzLmRldmljZSA9IHVwZGF0ZU9iamVjdCh0aGlzLmRldmljZSwge1xuICAgICAgICAgIGlzVG91Y2hTY3JlZW46IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc1Bhbm5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50ID0gZXZlbnQ7IC8vIHdlIG11c3QgZXhpdCBiZWZvcmUgd2Ugc2V0IGBjdXJzb3JCdXR0b25gIHN0YXRlIGFuZCBgc2F2ZVBvaW50ZXJgXG4gICAgICAvLyBlbHNlIGl0IHdpbGwgc2VuZCBwb2ludGVyIHN0YXRlICYgbGFzZXIgcG9pbnRlciBldmVudHMgaW4gY29sbGFiIHdoZW5cbiAgICAgIC8vIHBhbm5pbmdcblxuICAgICAgaWYgKHRoaXMuaGFuZGxlQ2FudmFzUGFuVXNpbmdXaGVlbE9yU3BhY2VEcmFnKGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBsYXN0UG9pbnRlckRvd25XaXRoOiBldmVudC5wb2ludGVyVHlwZSxcbiAgICAgICAgY3Vyc29yQnV0dG9uOiBcImRvd25cIlxuICAgICAgfSk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIFwiZG93blwiKTsgLy8gb25seSBoYW5kbGUgbGVmdCBtb3VzZSBidXR0b24gb3IgdG91Y2hcblxuICAgICAgaWYgKGV2ZW50LmJ1dHRvbiAhPT0gUE9JTlRFUl9CVVRUT04uTUFJTiAmJiBldmVudC5idXR0b24gIT09IFBPSU5URVJfQlVUVE9OLlRPVUNIKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gZG9uJ3Qgc2VsZWN0IHdoaWxlIHBhbm5pbmdcblxuXG4gICAgICBpZiAoZ2VzdHVyZS5wb2ludGVycy5zaXplID4gMSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIFN0YXRlIGZvciB0aGUgZHVyYXRpb24gb2YgYSBwb2ludGVyIGludGVyYWN0aW9uLCB3aGljaCBzdGFydHMgd2l0aCBhXG4gICAgICAvLyBwb2ludGVyRG93biBldmVudCwgZW5kcyB3aXRoIGEgcG9pbnRlclVwIGV2ZW50IChvciBhbm90aGVyIHBvaW50ZXJEb3duKVxuXG5cbiAgICAgIGNvbnN0IHBvaW50ZXJEb3duU3RhdGUgPSB0aGlzLmluaXRpYWxQb2ludGVyRG93blN0YXRlKGV2ZW50KTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkOiBmYWxzZVxuICAgICAgfSk7XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZURyYWdnaW5nU2Nyb2xsQmFyKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuY2xlYXJTZWxlY3Rpb25JZk5vdFVzaW5nU2VsZWN0aW9uKCk7XG4gICAgICB0aGlzLnVwZGF0ZUJpbmRpbmdFbmFibGVkT25Qb2ludGVyTW92ZShldmVudCk7XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZVNlbGVjdGlvbk9uUG9pbnRlckRvd24oZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgYWxsb3dPblBvaW50ZXJEb3duID0gIXRoaXMuc3RhdGUucGVuTW9kZSB8fCBldmVudC5wb2ludGVyVHlwZSAhPT0gXCJ0b3VjaFwiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInRleHRcIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiO1xuXG4gICAgICBpZiAoIWFsbG93T25Qb2ludGVyRG93bikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVUZXh0T25Qb2ludGVyRG93bihldmVudCwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiYXJyb3dcIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsaW5lXCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVMaW5lYXJFbGVtZW50T25Qb2ludGVyRG93bihldmVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiKSB7XG4gICAgICAgIC8vIHJlc2V0IGltYWdlIHByZXZpZXcgb24gcG9pbnRlcmRvd25cbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkNST1NTSEFJUik7IC8vIHJldHJpZXZlIHRoZSBsYXRlc3QgZWxlbWVudCBhcyB0aGUgc3RhdGUgbWF5IGJlIHN0YWxlXG5cbiAgICAgICAgY29uc3QgcGVuZGluZ0ltYWdlRWxlbWVudCA9IHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkICYmIHRoaXMuc2NlbmUuZ2V0RWxlbWVudCh0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCk7XG5cbiAgICAgICAgaWYgKCFwZW5kaW5nSW1hZ2VFbGVtZW50KSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBwZW5kaW5nSW1hZ2VFbGVtZW50LFxuICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBwZW5kaW5nSW1hZ2VFbGVtZW50LFxuICAgICAgICAgIHBlbmRpbmdJbWFnZUVsZW1lbnRJZDogbnVsbCxcbiAgICAgICAgICBtdWx0aUVsZW1lbnQ6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0pO1xuICAgICAgICBtdXRhdGVFbGVtZW50KHBlbmRpbmdJbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHksXG4gICAgICAgICAgZnJhbWVJZDogZnJhbWUgPyBmcmFtZS5pZCA6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVGcmVlRHJhd0VsZW1lbnRPblBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImN1c3RvbVwiKSB7XG4gICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgIHRoaXMuY3JlYXRlRnJhbWVFbGVtZW50T25Qb2ludGVyRG93bihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIikge1xuICAgICAgICB0aGlzLmxhc2VyUGF0aE1hbmFnZXIuc3RhcnRQYXRoKHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54LCBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImhhbmRcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUdlbmVyaWNFbGVtZW50T25Qb2ludGVyRG93bih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vblBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIudHJpZ2dlcih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wsIHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB0aGlzLm9uUG9pbnRlck1vdmVGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgY29uc3Qgb25Qb2ludGVyVXAgPSB0aGlzLm9uUG9pbnRlclVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5RG93biA9IHRoaXMub25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5VXAgPSB0aGlzLm9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgbGFzdFBvaW50ZXJVcCA9IG9uUG9pbnRlclVwO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgb25Qb2ludGVyVXApO1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlET1dOLCBvbktleURvd24pO1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgb25LZXlVcCk7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25Nb3ZlID0gb25Qb2ludGVyTW92ZTtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vblVwID0gb25Qb2ludGVyVXA7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlVcCA9IG9uS2V5VXA7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlEb3duID0gb25LZXlEb3duO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJVcCA9IGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgIHRoaXMucmVtb3ZlUG9pbnRlcihldmVudCk7XG4gICAgICB0aGlzLmxhc3RQb2ludGVyVXBFdmVudCA9IGV2ZW50O1xuICAgICAgY29uc3Qgc2NlbmVQb2ludGVyID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgY2xpZW50WDogZXZlbnQuY2xpZW50WCxcbiAgICAgICAgY2xpZW50WTogZXZlbnQuY2xpZW50WVxuICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBjbGlja2xlbmd0aCA9IGV2ZW50LnRpbWVTdGFtcCAtICgoX2IgPSAoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudGltZVN0YW1wKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwKTtcblxuICAgICAgaWYgKHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSAmJiBjbGlja2xlbmd0aCA8IDMwMCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpO1xuXG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpICYmIHRoaXMuaXNFbWJlZGRhYmxlQ2VudGVyKGhpdEVsZW1lbnQsIGV2ZW50LCBzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpKSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2soaGl0RWxlbWVudCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICAgIHRoaXMuaGl0TGlua0VsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbihzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5oaXRMaW5rRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5oaXRMaW5rRWxlbWVudC5pZF0pIHtcbiAgICAgICAgaWYgKGNsaWNrbGVuZ3RoIDwgMzAwICYmIHRoaXMuaGl0TGlua0VsZW1lbnQudHlwZSA9PT0gXCJlbWJlZGRhYmxlXCIgJiYgIWlzUG9pbnRIaXR0aW5nTGlua0ljb24odGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSwgW3NjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueV0pKSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2sodGhpcy5oaXRMaW5rRWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5yZWRpcmVjdFRvTGluayhldmVudCwgdGhpcy5kZXZpY2UuaXNUb3VjaFNjcmVlbik7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbCxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHt9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLm1heWJlT3BlbkNvbnRleHRNZW51QWZ0ZXJQb2ludGVyRG93bk9uVG91Y2hEZXZpY2VzID0gZXZlbnQgPT4ge1xuICAgICAgLy8gZGVhbCB3aXRoIG9wZW5pbmcgY29udGV4dCBtZW51IG9uIHRvdWNoIGRldmljZXNcbiAgICAgIGlmIChldmVudC5wb2ludGVyVHlwZSA9PT0gXCJ0b3VjaFwiKSB7XG4gICAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IGZhbHNlO1xuXG4gICAgICAgIGlmICh0b3VjaFRpbWVvdXQpIHtcbiAgICAgICAgICAvLyBJZiB0aGVyZSdzIGFscmVhZHkgYSB0b3VjaFRpbWVvdXQsIHRoaXMgbWVhbnMgdGhhdCB0aGVyZSdzIGFub3RoZXJcbiAgICAgICAgICAvLyB0b3VjaCBkb3duIGFuZCB3ZSBhcmUgZG9pbmcgYW5vdGhlciB0b3VjaCwgc28gd2Ugc2hvdWxkbid0IG9wZW4gdGhlXG4gICAgICAgICAgLy8gY29udGV4dCBtZW51LlxuICAgICAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gb3BlbiB0aGUgY29udGV4dCBtZW51IHdpdGggdGhlIGZpcnN0IHRvdWNoJ3MgY2xpZW50WCBhbmQgY2xpZW50WVxuICAgICAgICAgIC8vIGlmIHRoZSB0b3VjaCBpcyBub3QgbW92aW5nXG4gICAgICAgICAgdG91Y2hUaW1lb3V0ID0gd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgdG91Y2hUaW1lb3V0ID0gMDtcblxuICAgICAgICAgICAgaWYgKCFpbnZhbGlkYXRlQ29udGV4dE1lbnUpIHtcbiAgICAgICAgICAgICAgdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudShldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSwgVE9VQ0hfQ1RYX01FTlVfVElNRU9VVCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIgPSAoKSA9PiB7XG4gICAgICBjbGVhclRpbWVvdXQodG91Y2hUaW1lb3V0KTtcbiAgICAgIHRvdWNoVGltZW91dCA9IDA7XG4gICAgICBpbnZhbGlkYXRlQ29udGV4dE1lbnUgPSBmYWxzZTtcbiAgICB9OyAvLyBSZXR1cm5zIHdoZXRoZXIgdGhlIGV2ZW50IGlzIGEgcGFubmluZ1xuXG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc1BhblVzaW5nV2hlZWxPclNwYWNlRHJhZyA9IGV2ZW50ID0+IHtcbiAgICAgIGlmICghKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA8PSAxICYmIChldmVudC5idXR0b24gPT09IFBPSU5URVJfQlVUVE9OLldIRUVMIHx8IGV2ZW50LmJ1dHRvbiA9PT0gUE9JTlRFUl9CVVRUT04uTUFJTiAmJiBpc0hvbGRpbmdTcGFjZSB8fCBpc0hhbmRUb29sQWN0aXZlKHRoaXMuc3RhdGUpIHx8IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSkgfHwgaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlzUGFubmluZyA9IHRydWU7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgbGV0IG5leHRQYXN0ZVByZXZlbnRlZCA9IGZhbHNlO1xuICAgICAgY29uc3QgaXNMaW51eCA9IC9MaW51eC8udGVzdCh3aW5kb3cubmF2aWdhdG9yLnBsYXRmb3JtKTtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCQklORyk7XG4gICAgICBsZXQge1xuICAgICAgICBjbGllbnRYOiBsYXN0WCxcbiAgICAgICAgY2xpZW50WTogbGFzdFlcbiAgICAgIH0gPSBldmVudDtcbiAgICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQoZXZlbnQgPT4ge1xuICAgICAgICBjb25zdCBkZWx0YVggPSBsYXN0WCAtIGV2ZW50LmNsaWVudFg7XG4gICAgICAgIGNvbnN0IGRlbHRhWSA9IGxhc3RZIC0gZXZlbnQuY2xpZW50WTtcbiAgICAgICAgbGFzdFggPSBldmVudC5jbGllbnRYO1xuICAgICAgICBsYXN0WSA9IGV2ZW50LmNsaWVudFk7XG4gICAgICAgIC8qXG4gICAgICAgICAqIFByZXZlbnQgcGFzdGUgZXZlbnQgaWYgd2UgbW92ZSB3aGlsZSBtaWRkbGUgY2xpY2tpbmcgb24gTGludXguXG4gICAgICAgICAqIFNlZSBpc3N1ZSAjMTM4My5cbiAgICAgICAgICovXG5cbiAgICAgICAgaWYgKGlzTGludXggJiYgIW5leHRQYXN0ZVByZXZlbnRlZCAmJiAoTWF0aC5hYnMoZGVsdGFYKSA+IDEgfHwgTWF0aC5hYnMoZGVsdGFZKSA+IDEpKSB7XG4gICAgICAgICAgbmV4dFBhc3RlUHJldmVudGVkID0gdHJ1ZTtcbiAgICAgICAgICAvKiBQcmV2ZW50IHRoZSBuZXh0IHBhc3RlIGV2ZW50ICovXG5cbiAgICAgICAgICBjb25zdCBwcmV2ZW50TmV4dFBhc3RlID0gZXZlbnQgPT4ge1xuICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCBwcmV2ZW50TmV4dFBhc3RlKTtcbiAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgIH07XG4gICAgICAgICAgLypcbiAgICAgICAgICAgKiBSZWVuYWJsZSBuZXh0IHBhc3RlIGluIGNhc2Ugb2YgZGlzYWJsZWQgbWlkZGxlIGNsaWNrIHBhc3RlIGZvclxuICAgICAgICAgICAqIGFueSByZWFzb246XG4gICAgICAgICAgICogLSByaWdodCBjbGljayBwYXN0ZVxuICAgICAgICAgICAqIC0gZW1wdHkgY2xpcGJvYXJkXG4gICAgICAgICAgICovXG5cblxuICAgICAgICAgIGNvbnN0IGVuYWJsZU5leHRQYXN0ZSA9ICgpID0+IHtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHByZXZlbnROZXh0UGFzdGUpO1xuICAgICAgICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBlbmFibGVOZXh0UGFzdGUpO1xuICAgICAgICAgICAgfSwgMTAwKTtcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCBwcmV2ZW50TmV4dFBhc3RlKTtcbiAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBlbmFibGVOZXh0UGFzdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoe1xuICAgICAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCAtIGRlbHRhWCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSxcbiAgICAgICAgICBzY3JvbGxZOiB0aGlzLnN0YXRlLnNjcm9sbFkgLSBkZWx0YVkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHRlYXJkb3duID0gd2l0aEJhdGNoZWRVcGRhdGVzKGxhc3RQb2ludGVyVXAgPSAoKSA9PiB7XG4gICAgICAgIGxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgICAgICBpc1Bhbm5pbmcgPSBmYWxzZTtcblxuICAgICAgICBpZiAoIWlzSG9sZGluZ1NwYWNlKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGN1cnNvckJ1dHRvbjogXCJ1cFwiXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRlYXJkb3duKTtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGVhcmRvd24pO1xuICAgICAgICBvblBvaW50ZXJNb3ZlLmZsdXNoKCk7XG4gICAgICB9KTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkJMVVIsIHRlYXJkb3duKTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSwge1xuICAgICAgICBwYXNzaXZlOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRlYXJkb3duKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH07XG5cbiAgICB0aGlzLmNsZWFyU2VsZWN0aW9uSWZOb3RVc2luZ1NlbGVjdGlvbiA9ICgpID0+IHtcbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybnMgd2hldGhlciB0aGUgcG9pbnRlciBldmVudCBoYXMgYmVlbiBjb21wbGV0ZWx5IGhhbmRsZWRcbiAgICAgKi9cblxuXG4gICAgdGhpcy5oYW5kbGVTZWxlY3Rpb25PblBvaW50ZXJEb3duID0gKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCk7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlKGVsZW1lbnRzLCB0aGlzLnN0YXRlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHJlc2l6aW5nRWxlbWVudDogZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLmVsZW1lbnRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSA9IGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS50cmFuc2Zvcm1IYW5kbGVUeXBlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlID0gZ2V0VHJhbnNmb3JtSGFuZGxlVHlwZUZyb21Db29yZHMoZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaXNSZXNpemluZyA9IHRydWU7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUub2Zmc2V0ID0gdHVwbGVUb0Nvb3JzKGdldFJlc2l6ZU9mZnNldFhZKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHMsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpKTtcblxuICAgICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkgJiYgc2VsZWN0ZWRFbGVtZW50c1swXS5wb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5hcnJvd0RpcmVjdGlvbiA9IGdldFJlc2l6ZUFycm93RGlyZWN0aW9uKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHNbMF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgIGNvbnN0IGxpbmVhckVsZW1lbnRFZGl0b3IgPSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50O1xuICAgICAgICAgICAgY29uc3QgcmV0ID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludGVyRG93bihldmVudCwgdGhpcy5zdGF0ZSwgdGhpcy5oaXN0b3J5LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbiwgbGluZWFyRWxlbWVudEVkaXRvcik7XG5cbiAgICAgICAgICAgIGlmIChyZXQuaGl0RWxlbWVudCkge1xuICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50ID0gcmV0LmhpdEVsZW1lbnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChyZXQubGluZWFyRWxlbWVudEVkaXRvcikge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IHJldC5saW5lYXJFbGVtZW50RWRpdG9yXG4gICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogcmV0LmxpbmVhckVsZW1lbnRFZGl0b3JcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAocmV0LmRpZEFkZFBvaW50KSB7XG4gICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gaGl0RWxlbWVudCBtYXkgYWxyZWFkeSBiZSBzZXQgYWJvdmUsIHNvIGNoZWNrIGZpcnN0XG5cblxuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQgPSAoX2EgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpO1xuXG4gICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpIHtcbiAgICAgICAgICAgIC8vIEVhcmx5IHJldHVybiBpZiBwb2ludGVyIGlzIGhpdHRpbmcgbGluayBpY29uXG4gICAgICAgICAgICBjb25zdCBoaXRMaW5rRWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudExpbmtBdFBvc2l0aW9uKHtcbiAgICAgICAgICAgICAgeDogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCxcbiAgICAgICAgICAgICAgeTogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueVxuICAgICAgICAgICAgfSwgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCk7XG5cbiAgICAgICAgICAgIGlmIChoaXRMaW5rRWxlbWVudCkge1xuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBGb3Igb3ZlcmxhcHBlZCBlbGVtZW50cyBvbmUgcG9zaXRpb24gbWF5IGhpdFxuICAgICAgICAgIC8vIG11bHRpcGxlIGVsZW1lbnRzXG5cblxuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzID0gdGhpcy5nZXRFbGVtZW50c0F0UG9zaXRpb24ocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSk7XG4gICAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQ7XG4gICAgICAgICAgY29uc3Qgc29tZUhpdEVsZW1lbnRJc1NlbGVjdGVkID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuYWxsSGl0RWxlbWVudHMuc29tZShlbGVtZW50ID0+IHRoaXMuaXNBU2VsZWN0ZWRFbGVtZW50KGVsZW1lbnQpKTtcblxuICAgICAgICAgIGlmICgoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCAhc29tZUhpdEVsZW1lbnRJc1NlbGVjdGVkKSAmJiAhZXZlbnQuc2hpZnRLZXkgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgICAgICAgICB0aGlzLmNsZWFyU2VsZWN0aW9uKGhpdEVsZW1lbnQpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICAgICAgW3RoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkXTogdHJ1ZVxuICAgICAgICAgICAgICB9LCB0aGlzLnN0YXRlKVxuICAgICAgICAgICAgfSk7IC8vIElmIHdlIGNsaWNrIG9uIHNvbWV0aGluZ1xuICAgICAgICAgIH0gZWxzZSBpZiAoaGl0RWxlbWVudCAhPSBudWxsKSB7XG4gICAgICAgICAgICAvLyBvbiBDTUQvQ1RSTCwgZHJpbGwgZG93biB0byBoaXQgZWxlbWVudCByZWdhcmRsZXNzIG9mIGdyb3VwcyBldGMuXG4gICAgICAgICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0Lndhc0FkZGVkVG9TZWxlY3Rpb24gPSB0cnVlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBlZGl0R3JvdXBGb3JTZWxlY3RlZEVsZW1lbnQocHJldlN0YXRlLCBoaXRFbGVtZW50KSksIHtcbiAgICAgICAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczogdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgfSkpOyAvLyBtYXJrIGFzIG5vdCBjb21wbGV0ZWx5IGhhbmRsZWQgc28gYXMgdG8gYWxsb3cgZHJhZ2dpbmcgZXRjLlxuXG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH0gLy8gZGVzZWxlY3QgaWYgaXRlbSBpcyBzZWxlY3RlZFxuICAgICAgICAgICAgLy8gaWYgc2hpZnQgaXMgbm90IGNsaWNrZWQsIHRoaXMgd2lsbCBhbHdheXMgcmV0dXJuIHRydWVcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSwgaXQgd2lsbCB0cmlnZ2VyIHNlbGVjdGlvbiBiYXNlZCBvbiBjdXJyZW50XG4gICAgICAgICAgICAvLyBzdGF0ZSBvZiB0aGUgYm94XG5cblxuICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgICAvLyBpZiB3ZSBhcmUgY3VycmVudGx5IGVkaXRpbmcgYSBncm91cCwgZXhpdGluZyBlZGl0aW5nIG1vZGUgYW5kIGRlc2VsZWN0IHRoZSBncm91cC5cbiAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQgJiYgIWlzRWxlbWVudEluR3JvdXAoaGl0RWxlbWVudCwgdGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSAvLyBBZGQgaGl0IGVsZW1lbnQgdG8gc2VsZWN0aW9uLiBBdCB0aGlzIHBvaW50IGlmIHdlJ3JlIG5vdCBob2xkaW5nXG4gICAgICAgICAgICAgIC8vIFNISUZUIHRoZSBwcmV2aW91c2x5IHNlbGVjdGVkIGVsZW1lbnQocykgd2VyZSBkZXNlbGVjdGVkIGFib3ZlXG4gICAgICAgICAgICAgIC8vIChtYWtlIHN1cmUgeW91IHVzZSBzZXRTdGF0ZSB1cGRhdGVyIHRvIHVzZSBsYXRlc3Qgc3RhdGUpXG4gICAgICAgICAgICAgIC8vIFdpdGggc2hpZnQtc2VsZWN0aW9uLCB3ZSB3YW50IHRvIG1ha2Ugc3VyZSB0aGF0IGZyYW1lcyBhbmQgdGhlaXIgY29udGFpbmluZ1xuICAgICAgICAgICAgICAvLyBlbGVtZW50cyBhcmUgbm90IHNlbGVjdGVkIGF0IHRoZSBzYW1lIHRpbWUuXG5cblxuICAgICAgICAgICAgICBpZiAoIXNvbWVIaXRFbGVtZW50SXNTZWxlY3RlZCAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgY29uc3QgcHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMgPSBbXTtcbiAgICAgICAgICAgICAgICAgIE9iamVjdC5rZXlzKHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLmZvckVhY2goaWQgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KGlkKTtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudCAmJiBwcmV2aW91c2x5U2VsZWN0ZWRFbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgICAgfSk7IC8vIGlmIGhpdEVsZW1lbnQgaXMgZnJhbWUsIGRlc2VsZWN0IGFsbCBvZiBpdHMgZWxlbWVudHMgaWYgdGhleSBhcmUgc2VsZWN0ZWRcblxuICAgICAgICAgICAgICAgICAgaWYgKGhpdEVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGdldEZyYW1lQ2hpbGRyZW4ocHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMsIGhpdEVsZW1lbnQuaWQpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChoaXRFbGVtZW50LmZyYW1lSWQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gaWYgaGl0RWxlbWVudCBpcyBpbiBhIGZyYW1lIGFuZCBpdHMgZnJhbWUgaGFzIGJlZW4gc2VsZWN0ZWRcbiAgICAgICAgICAgICAgICAgICAgLy8gZGlzYWJsZSBzZWxlY3Rpb24gZm9yIHRoZSBnaXZlbiBlbGVtZW50XG4gICAgICAgICAgICAgICAgICAgIGlmIChuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuZnJhbWVJZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gaGl0RWxlbWVudCBpcyBuZWl0aGVyIGEgZnJhbWUgbm9yIGFuIGVsZW1lbnQgaW4gYSBmcmFtZVxuICAgICAgICAgICAgICAgICAgICAvLyBidXQgc2luY2UgaGl0RWxlbWVudCBjb3VsZCBiZSBpbiBhIGdyb3VwIHdpdGggc29tZSBmcmFtZXNcbiAgICAgICAgICAgICAgICAgICAgLy8gdGhpcyBtZWFucyBzZWxlY3RpbmcgaGl0RWxlbWVudCB3aWxsIGhhdmUgdGhlIGZyYW1lcyBzZWxlY3RlZCBhcyB3ZWxsXG4gICAgICAgICAgICAgICAgICAgIC8vIGJlY2F1c2Ugd2Ugd2FudCB0byBrZWVwIHRoZSBpbnZhcmlhbnQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIC0gZnJhbWVzIGFuZCB0aGVpciBlbGVtZW50cyBhcmUgbm90IHNlbGVjdGVkIGF0IHRoZSBzYW1lIHRpbWVcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgZGVzZWxlY3QgZWxlbWVudHMgaW4gdGhvc2UgZnJhbWVzIHRoYXQgd2VyZSBwcmV2aW91c2x5IHNlbGVjdGVkXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGdyb3VwSWRzID0gaGl0RWxlbWVudC5ncm91cElkcztcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZnJhbWVzSW5Hcm91cHMgPSBuZXcgU2V0KGdyb3VwSWRzLmZsYXRNYXAoZ2lkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBnaWQpKS5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIikubWFwKGZyYW1lID0+IGZyYW1lLmlkKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGZyYW1lc0luR3JvdXBzLnNpemUgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LmZyYW1lSWQgJiYgZnJhbWVzSW5Hcm91cHMuaGFzKGVsZW1lbnQuZnJhbWVJZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGVzZWxlY3QgZWxlbWVudCBhbmQgZ3JvdXBzIGNvbnRhaW5pbmcgdGhlIGVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZ3JvdXBJZHMuZmxhdE1hcChnaWQgPT4gZ2V0RWxlbWVudHNJbkdyb3VwKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGdpZCkpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogaGl0RWxlbWVudC5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZVRleHRPblBvaW50ZXJEb3duID0gKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICAvLyBpZiB3ZSdyZSBjdXJyZW50bHkgc3RpbGwgZWRpdGluZyB0ZXh0LCBjbGlja2luZyBvdXRzaWRlXG4gICAgICAvLyBzaG91bGQgb25seSBmaW5hbGl6ZSBpdCwgbm90IGNyZWF0ZSBhbm90aGVyIChpcnJlc3BlY3RpdmVcbiAgICAgIC8vIG9mIHN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKVxuICAgICAgaWYgKGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsZXQgc2NlbmVYID0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueDtcbiAgICAgIGxldCBzY2VuZVkgPSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55O1xuICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVYLCBzY2VuZVksIHtcbiAgICAgICAgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQ6IHRydWVcbiAgICAgIH0pOyAvLyBGSVhNRVxuXG4gICAgICBsZXQgY29udGFpbmVyID0gZ2V0VGV4dEJpbmRhYmxlQ29udGFpbmVyQXRQb3NpdGlvbih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCBzY2VuZVgsIHNjZW5lWSk7XG5cbiAgICAgIGlmIChoYXNCb3VuZFRleHRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgIGNvbnRhaW5lciA9IGVsZW1lbnQ7XG4gICAgICAgIHNjZW5lWCA9IGVsZW1lbnQueCArIGVsZW1lbnQud2lkdGggLyAyO1xuICAgICAgICBzY2VuZVkgPSBlbGVtZW50LnkgKyBlbGVtZW50LmhlaWdodCAvIDI7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc3RhcnRUZXh0RWRpdGluZyh7XG4gICAgICAgIHNjZW5lWCxcbiAgICAgICAgc2NlbmVZLFxuICAgICAgICBpbnNlcnRBdFBhcmVudENlbnRlcjogIWV2ZW50LmFsdEtleSxcbiAgICAgICAgY29udGFpbmVyXG4gICAgICB9KTtcbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlRnJlZURyYXdFbGVtZW50T25Qb2ludGVyRG93biA9IChldmVudCwgZWxlbWVudFR5cGUsIHBvaW50ZXJEb3duU3RhdGUpID0+IHtcbiAgICAgIC8vIEJlZ2luIGEgbWFyayBjYXB0dXJlLiBUaGlzIGRvZXMgbm90IGhhdmUgdG8gdXBkYXRlIHN0YXRlIHlldC5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIG51bGwpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0ZyZWVEcmF3RWxlbWVudCh7XG4gICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlLFxuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICByb3VuZG5lc3M6IG51bGwsXG4gICAgICAgIHNpbXVsYXRlUHJlc3N1cmU6IGV2ZW50LnByZXNzdXJlID09PSAwLjUsXG4gICAgICAgIGxvY2tlZDogZmFsc2UsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTtcbiAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRFbGVtZW50SWRzLCBwcmV2U3RhdGUpXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGVsZW1lbnQuc2ltdWxhdGVQcmVzc3VyZSA/IGVsZW1lbnQucHJlc3N1cmVzIDogWy4uLmVsZW1lbnQucHJlc3N1cmVzLCBldmVudC5wcmVzc3VyZV07XG4gICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgcG9pbnRzOiBbWzAsIDBdXSxcbiAgICAgICAgcHJlc3N1cmVzXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGJvdW5kRWxlbWVudCA9IGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZyhwb2ludGVyRG93blN0YXRlLm9yaWdpbiwgdGhpcy5zY2VuZSk7XG4gICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBlbGVtZW50LFxuICAgICAgICBlZGl0aW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IGJvdW5kRWxlbWVudCxcbiAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICB9KTtcbiAgICB9OyAvL2NyZWF0ZSByZWN0YW5nbGUgZWxlbWVudCB3aXRoIHlvdXR1YmUgdG9wIGxlZnQgb24gbmVhcmVzdCBncmlkIHBvaW50IHdpZHRoIC8gaGlnaHQgNjQwLzM2MFxuXG5cbiAgICB0aGlzLmluc2VydEVtYmVkZGFibGVFbGVtZW50ID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWSxcbiAgICAgIGxpbmtcbiAgICB9KSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHNjZW5lWCwgc2NlbmVZLCAoKF9hID0gdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hW0tFWVMuQ1RSTF9PUl9DTURdKSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IGVtYmVkTGluayA9IGdldEVtYmVkTGluayhsaW5rKTtcblxuICAgICAgaWYgKCFlbWJlZExpbmspIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZW1iZWRMaW5rLndhcm5pbmcpIHtcbiAgICAgICAgdGhpcy5zZXRUb2FzdCh7XG4gICAgICAgICAgbWVzc2FnZTogZW1iZWRMaW5rLndhcm5pbmcsXG4gICAgICAgICAgY2xvc2FibGU6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdFbWJlZGRhYmxlRWxlbWVudCh7XG4gICAgICAgIHR5cGU6IFwiZW1iZWRkYWJsZVwiLFxuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiBcInRyYW5zcGFyZW50XCIsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogXCJ0cmFuc3BhcmVudFwiLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgcm91bmRuZXNzOiB0aGlzLmdldEN1cnJlbnRJdGVtUm91bmRuZXNzKFwiZW1iZWRkYWJsZVwiKSxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIGxvY2tlZDogZmFsc2UsXG4gICAgICAgIHdpZHRoOiBlbWJlZExpbmsuYXNwZWN0UmF0aW8udyxcbiAgICAgICAgaGVpZ2h0OiBlbWJlZExpbmsuYXNwZWN0UmF0aW8uaCxcbiAgICAgICAgbGluayxcbiAgICAgICAgdmFsaWRhdGVkOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBlbGVtZW50XSk7XG4gICAgICByZXR1cm4gZWxlbWVudDtcbiAgICB9O1xuXG4gICAgdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZLFxuICAgICAgYWRkVG9GcmFtZVVuZGVyQ3Vyc29yID0gdHJ1ZVxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVYLCBzY2VuZVksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IGFkZFRvRnJhbWVVbmRlckN1cnNvciA/IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pIDogbnVsbDtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdJbWFnZUVsZW1lbnQoe1xuICAgICAgICB0eXBlOiBcImltYWdlXCIsXG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgICAgbG9ja2VkOiBmYWxzZSxcbiAgICAgICAgZnJhbWVJZDogdG9wTGF5ZXJGcmFtZSA/IHRvcExheWVyRnJhbWUuaWQgOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiBlbGVtZW50O1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUxpbmVhckVsZW1lbnRPblBvaW50ZXJEb3duID0gKGV2ZW50LCBlbGVtZW50VHlwZSwgcG9pbnRlckRvd25TdGF0ZSkgPT4ge1xuICAgICAgaWYgKHRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBtdWx0aUVsZW1lbnRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7IC8vIGZpbmFsaXplIGlmIGNvbXBsZXRpbmcgYSBsb29wXG5cbiAgICAgICAgaWYgKG11bHRpRWxlbWVudC50eXBlID09PSBcImxpbmVcIiAmJiBpc1BhdGhBTG9vcChtdWx0aUVsZW1lbnQucG9pbnRzLCB0aGlzLnN0YXRlLnpvb20udmFsdWUpKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICAgIGxhc3RDb21taXR0ZWRQb2ludDogbXVsdGlFbGVtZW50LnBvaW50c1ttdWx0aUVsZW1lbnQucG9pbnRzLmxlbmd0aCAtIDFdXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiByeCxcbiAgICAgICAgICB5OiByeSxcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnRcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDsgLy8gY2xpY2tpbmcgaW5zaWRlIGNvbW1pdCB6b25lIOKGkiBmaW5hbGl6ZSBhcnJvd1xuXG4gICAgICAgIGlmIChtdWx0aUVsZW1lbnQucG9pbnRzLmxlbmd0aCA+IDEgJiYgbGFzdENvbW1pdHRlZFBvaW50ICYmIGRpc3RhbmNlMmQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCAtIHJ4LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55IC0gcnksIGxhc3RDb21taXR0ZWRQb2ludFswXSwgbGFzdENvbW1pdHRlZFBvaW50WzFdKSA8IExJTkVfQ09ORklSTV9USFJFU0hPTEQpIHtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgIFttdWx0aUVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgfSksIHByZXZTdGF0ZSlcbiAgICAgICAgfSkpOyAvLyBjbGlja2luZyBvdXRzaWRlIGNvbW1pdCB6b25lIOKGkiB1cGRhdGUgcmVmZXJlbmNlIGZvciBsYXN0IGNvbW1pdHRlZFxuICAgICAgICAvLyBwb2ludFxuXG4gICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50OiBtdWx0aUVsZW1lbnQucG9pbnRzW211bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoIC0gMV1cbiAgICAgICAgfSk7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgICAgeTogZ3JpZFlcbiAgICAgICAgfSk7XG4gICAgICAgIC8qIElmIGFycm93IGlzIHByZS1hcnJvd2hlYWRzLCBpdCB3aWxsIGhhdmUgdW5kZWZpbmVkIGZvciBib3RoIHN0YXJ0IGFuZCBlbmQgYXJyb3doZWFkcy5cbiAgICAgICAgSWYgc28sIHdlIHdhbnQgaXQgdG8gYmUgbnVsbCBmb3Igc3RhcnQgYW5kIFwiYXJyb3dcIiBmb3IgZW5kLiBJZiB0aGUgbGluZWFyIGl0ZW0gaXMgbm90XG4gICAgICAgIGFuIGFycm93LCB3ZSB3YW50IGl0IHRvIGJlIG51bGwgZm9yIGJvdGguIE90aGVyd2lzZSwgd2Ugd2FudCBpdCB0byB1c2UgdGhlXG4gICAgICAgIHZhbHVlcyBmcm9tIGFwcFN0YXRlLiAqL1xuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBjdXJyZW50SXRlbVN0YXJ0QXJyb3doZWFkLFxuICAgICAgICAgIGN1cnJlbnRJdGVtRW5kQXJyb3doZWFkXG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICBjb25zdCBbc3RhcnRBcnJvd2hlYWQsIGVuZEFycm93aGVhZF0gPSBlbGVtZW50VHlwZSA9PT0gXCJhcnJvd1wiID8gW2N1cnJlbnRJdGVtU3RhcnRBcnJvd2hlYWQsIGN1cnJlbnRJdGVtRW5kQXJyb3doZWFkXSA6IFtudWxsLCBudWxsXTtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0xpbmVhckVsZW1lbnQoe1xuICAgICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlLFxuICAgICAgICAgIHg6IGdyaWRYLFxuICAgICAgICAgIHk6IGdyaWRZLFxuICAgICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICAgIHJvdW5kbmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdW5kbmVzcyA9PT0gXCJyb3VuZFwiID8ge1xuICAgICAgICAgICAgdHlwZTogUk9VTkRORVNTLlBST1BPUlRJT05BTF9SQURJVVNcbiAgICAgICAgICB9IDogbnVsbCxcbiAgICAgICAgICBzdGFydEFycm93aGVhZCxcbiAgICAgICAgICBlbmRBcnJvd2hlYWQsXG4gICAgICAgICAgbG9ja2VkOiBmYWxzZSxcbiAgICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7XG4gICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMobmV4dFNlbGVjdGVkRWxlbWVudElkcywgcHJldlN0YXRlKVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICBwb2ludHM6IFsuLi5lbGVtZW50LnBvaW50cywgWzAsIDBdXVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgYm91bmRFbGVtZW50ID0gZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLCB0aGlzLnNjZW5lKTtcbiAgICAgICAgdGhpcy5zY2VuZS5hZGROZXdFbGVtZW50KGVsZW1lbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IGJvdW5kRWxlbWVudCxcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlR2VuZXJpY0VsZW1lbnRPblBvaW50ZXJEb3duID0gKGVsZW1lbnRUeXBlLCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgYmFzZUVsZW1lbnRBdHRyaWJ1dGVzID0ge1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICByb3VuZG5lc3M6IHRoaXMuZ2V0Q3VycmVudEl0ZW1Sb3VuZG5lc3MoZWxlbWVudFR5cGUpLFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH07XG4gICAgICBsZXQgZWxlbWVudDtcblxuICAgICAgaWYgKGVsZW1lbnRUeXBlID09PSBcImVtYmVkZGFibGVcIikge1xuICAgICAgICBlbGVtZW50ID0gbmV3RW1iZWRkYWJsZUVsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdHlwZTogXCJlbWJlZGRhYmxlXCIsXG4gICAgICAgICAgdmFsaWRhdGVkOiBudWxsXG4gICAgICAgIH0sIGJhc2VFbGVtZW50QXR0cmlidXRlcykpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWxlbWVudCA9IG5ld0VsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdHlwZTogZWxlbWVudFR5cGVcbiAgICAgICAgfSwgYmFzZUVsZW1lbnRBdHRyaWJ1dGVzKSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbGVtZW50LnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0aW9uRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIG11bHRpRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlRnJhbWVFbGVtZW50T25Qb2ludGVyRG93biA9IHBvaW50ZXJEb3duU3RhdGUgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCAoKF9hID0gdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hW0tFWVMuQ1RSTF9PUl9DTURdKSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IGZyYW1lID0gbmV3RnJhbWVFbGVtZW50KE9iamVjdC5hc3NpZ24oe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlXG4gICAgICB9LCBGUkFNRV9TVFlMRSkpO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoWy4uLnRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGZyYW1lXSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgbXVsdGlFbGVtZW50OiBudWxsLFxuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGZyYW1lLFxuICAgICAgICBlZGl0aW5nRWxlbWVudDogZnJhbWVcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc3RvcmVSZWFkeVRvRXJhc2VFbGVtZW50cyA9IHBvaW50ZXJEb3duU3RhdGUgPT4ge1xuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGUgPT4ge1xuICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmlkXS5vcGFjaXR5XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNCb3VuZFRvQ29udGFpbmVyKGVsZSkgJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXS5vcGFjaXR5XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZWxlLmZyYW1lSWQgJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuZnJhbWVJZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuZnJhbWVJZF0uZXJhc2UpIHtcbiAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXS5vcGFjaXR5XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgfTtcblxuICAgIHRoaXMuZXJhc2VFbGVtZW50cyA9IHBvaW50ZXJEb3duU3RhdGUgPT4ge1xuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGUgPT4ge1xuICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGlzQm91bmRUb0NvbnRhaW5lcihlbGUpICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5jb250YWluZXJJZF0uZXJhc2UpIHtcbiAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICBpc0RlbGV0ZWQ6IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChlbGUuZnJhbWVJZCAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgIH07XG5cbiAgICB0aGlzLmluaXRpYWxpemVJbWFnZSA9ICh7XG4gICAgICBpbWFnZUZpbGUsXG4gICAgICBpbWFnZUVsZW1lbnQ6IF9pbWFnZUVsZW1lbnQsXG4gICAgICBzaG93Q3Vyc29ySW1hZ2VQcmV2aWV3ID0gZmFsc2VcbiAgICB9KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB2YXIgX2UsIF9mLCBfZywgX2g7IC8vIGF0IHRoaXMgcG9pbnQgdGhpcyBzaG91bGQgYmUgZ3VhcmFudGVlZCBpbWFnZSBmaWxlLCBidXQgd2UgZG8gdGhpcyBjaGVja1xuICAgICAgLy8gdG8gc2F0aXNmeSBUUyBkb3duIHRoZSBsaW5lXG5cblxuICAgICAgaWYgKCFpc1N1cHBvcnRlZEltYWdlRmlsZShpbWFnZUZpbGUpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcih0KFwiZXJyb3JzLnVuc3VwcG9ydGVkRmlsZVR5cGVcIikpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtaW1lVHlwZSA9IGltYWdlRmlsZS50eXBlO1xuICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIFwid2FpdFwiKTtcblxuICAgICAgaWYgKG1pbWVUeXBlID09PSBNSU1FX1RZUEVTLnN2Zykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGltYWdlRmlsZSA9IFNWR1N0cmluZ1RvRmlsZSh5aWVsZCBub3JtYWxpemVTVkcoeWllbGQgaW1hZ2VGaWxlLnRleHQoKSksIGltYWdlRmlsZS5uYW1lKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oZXJyb3IpO1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0KFwiZXJyb3JzLnN2Z0ltYWdlSW5zZXJ0RXJyb3JcIikpO1xuICAgICAgICB9XG4gICAgICB9IC8vIGdlbmVyYXRlIGltYWdlIGlkIChieSBkZWZhdWx0IHRoZSBmaWxlIGRpZ2VzdCkgYmVmb3JlIGFueVxuICAgICAgLy8gcmVzaXppbmcvY29tcHJlc3Npb24gdGFrZXMgcGxhY2UgdG8ga2VlcCBpdCBtb3JlIHBvcnRhYmxlXG5cblxuICAgICAgY29uc3QgZmlsZUlkID0geWllbGQgKChfZiA9IChfZSA9IHRoaXMucHJvcHMpLmdlbmVyYXRlSWRGb3JGaWxlKSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuY2FsbChfZSwgaW1hZ2VGaWxlKSkgfHwgZ2VuZXJhdGVJZEZyb21GaWxlKGltYWdlRmlsZSk7XG5cbiAgICAgIGlmICghZmlsZUlkKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIkNvdWxkbid0IGdlbmVyYXRlIGZpbGUgaWQgb3IgdGhlIHN1cHBsaWVkIGBnZW5lcmF0ZUlkRm9yRmlsZWAgZGlkbid0IHJlc29sdmUgdG8gb25lLlwiKTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMuaW1hZ2VJbnNlcnRFcnJvclwiKSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGV4aXN0aW5nRmlsZURhdGEgPSB0aGlzLmZpbGVzW2ZpbGVJZF07XG5cbiAgICAgIGlmICghKGV4aXN0aW5nRmlsZURhdGEgPT09IG51bGwgfHwgZXhpc3RpbmdGaWxlRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhpc3RpbmdGaWxlRGF0YS5kYXRhVVJMKSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGltYWdlRmlsZSA9IHlpZWxkIHJlc2l6ZUltYWdlRmlsZShpbWFnZUZpbGUsIHtcbiAgICAgICAgICAgIG1heFdpZHRoT3JIZWlnaHQ6IERFRkFVTFRfTUFYX0lNQUdFX1dJRFRIX09SX0hFSUdIVFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJlcnJvciB0cnlpbmcgdG8gcmVzaW5nIGltYWdlIGZpbGUgb24gaW5zZXJ0aW9uXCIsIGVycm9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpbWFnZUZpbGUuc2l6ZSA+IE1BWF9BTExPV0VEX0ZJTEVfQllURVMpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodChcImVycm9ycy5maWxlVG9vQmlnXCIsIHtcbiAgICAgICAgICAgIG1heFNpemU6IGAke01hdGgudHJ1bmMoTUFYX0FMTE9XRURfRklMRV9CWVRFUyAvIDEwMjQgLyAxMDI0KX1NQmBcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHNob3dDdXJzb3JJbWFnZVByZXZpZXcpIHtcbiAgICAgICAgY29uc3QgZGF0YVVSTCA9IChfZyA9IHRoaXMuZmlsZXNbZmlsZUlkXSkgPT09IG51bGwgfHwgX2cgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9nLmRhdGFVUkw7IC8vIG9wdGltaXphdGlvbiBzbyB0aGF0IHdlIGRvbid0IHVubmVjZXNzYXJpbHkgcmVzaXplIHRoZSBvcmlnaW5hbFxuICAgICAgICAvLyBmdWxsLXNpemUgZmlsZSBmb3IgY3Vyc29yIHByZXZpZXdcbiAgICAgICAgLy8gKGl0J3MgbXVjaCBmYXN0ZXIgdG8gY29udmVydCB0aGUgcmVzaXplZCBkYXRhVVJMIHRvIEZpbGUpXG5cbiAgICAgICAgY29uc3QgcmVzaXplZEZpbGUgPSBkYXRhVVJMICYmIGRhdGFVUkxUb0ZpbGUoZGF0YVVSTCk7XG4gICAgICAgIHRoaXMuc2V0SW1hZ2VQcmV2aWV3Q3Vyc29yKHJlc2l6ZWRGaWxlIHx8IGltYWdlRmlsZSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRhdGFVUkwgPSAoKF9oID0gdGhpcy5maWxlc1tmaWxlSWRdKSA9PT0gbnVsbCB8fCBfaCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2guZGF0YVVSTCkgfHwgKHlpZWxkIGdldERhdGFVUkwoaW1hZ2VGaWxlKSk7XG4gICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSBtdXRhdGVFbGVtZW50KF9pbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgZmlsZUlkXG4gICAgICB9LCBmYWxzZSk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgICB2YXIgX2o7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0aGlzLmZpbGVzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwge1xuICAgICAgICAgICAgW2ZpbGVJZF06IHtcbiAgICAgICAgICAgICAgbWltZVR5cGUsXG4gICAgICAgICAgICAgIGlkOiBmaWxlSWQsXG4gICAgICAgICAgICAgIGRhdGFVUkwsXG4gICAgICAgICAgICAgIGNyZWF0ZWQ6IERhdGUubm93KCksXG4gICAgICAgICAgICAgIGxhc3RSZXRyaWV2ZWQ6IERhdGUubm93KClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICBjb25zdCBjYWNoZWRJbWFnZURhdGEgPSB0aGlzLmltYWdlQ2FjaGUuZ2V0KGZpbGVJZCk7XG5cbiAgICAgICAgICBpZiAoIWNhY2hlZEltYWdlRGF0YSkge1xuICAgICAgICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICAgICAgICAgIHlpZWxkIHRoaXMudXBkYXRlSW1hZ2VDYWNoZShbaW1hZ2VFbGVtZW50XSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKChjYWNoZWRJbWFnZURhdGEgPT09IG51bGwgfHwgY2FjaGVkSW1hZ2VEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjYWNoZWRJbWFnZURhdGEuaW1hZ2UpIGluc3RhbmNlb2YgUHJvbWlzZSkge1xuICAgICAgICAgICAgeWllbGQgY2FjaGVkSW1hZ2VEYXRhLmltYWdlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCAhPT0gaW1hZ2VFbGVtZW50LmlkICYmICgoX2ogPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCkgPT09IG51bGwgfHwgX2ogPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9qLmlkKSAhPT0gaW1hZ2VFbGVtZW50LmlkKSB7XG4gICAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50LCB0cnVlKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXNvbHZlKGltYWdlRWxlbWVudCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcih0KFwiZXJyb3JzLmltYWdlSW5zZXJ0RXJyb3JcIikpKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBpZiAoIXNob3dDdXJzb3JJbWFnZVByZXZpZXcpIHtcbiAgICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSkpO1xuICAgIH0pO1xuICAgIC8qKlxuICAgICAqIGluc2VydHMgaW1hZ2UgaW50byBlbGVtZW50cyBhcnJheSBhbmQgcmVyZW5kZXJzXG4gICAgICovXG5cblxuICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50ID0gKGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlLCBzaG93Q3Vyc29ySW1hZ2VQcmV2aWV3KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAvLyB3ZSBzaG91bGQgYmUgaGFuZGxpbmcgYWxsIGNhc2VzIHVwc3RyZWFtLCBidXQgaW4gY2FzZSB3ZSBmb3JnZXQgdG8gaGFuZGxlXG4gICAgICAvLyBhIGZ1dHVyZSBjYXNlLCBsZXQncyB0aHJvdyBoZXJlXG4gICAgICBpZiAoIXRoaXMuaXNUb29sU3VwcG9ydGVkKFwiaW1hZ2VcIikpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiB0KFwiZXJyb3JzLmltYWdlVG9vbE5vdFN1cHBvcnRlZFwiKVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoaW1hZ2VFbGVtZW50KTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIHlpZWxkIHRoaXMuaW5pdGlhbGl6ZUltYWdlKHtcbiAgICAgICAgICBpbWFnZUZpbGUsXG4gICAgICAgICAgaW1hZ2VFbGVtZW50LFxuICAgICAgICAgIHNob3dDdXJzb3JJbWFnZVByZXZpZXdcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UgfHwgdChcImVycm9ycy5pbWFnZUluc2VydEVycm9yXCIpXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuc2V0SW1hZ2VQcmV2aWV3Q3Vyc29yID0gaW1hZ2VGaWxlID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIC8vIG11c3RuJ3QgYmUgbGFyZ2VyIHRoYW4gMTI4IHB4XG4gICAgICAvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9DU1MvQ1NTX0Jhc2ljX1VzZXJfSW50ZXJmYWNlL1VzaW5nX1VSTF92YWx1ZXNfZm9yX3RoZV9jdXJzb3JfcHJvcGVydHlcbiAgICAgIGNvbnN0IGN1cnNvckltYWdlU2l6ZVB4ID0gOTY7XG4gICAgICBjb25zdCBpbWFnZVByZXZpZXcgPSB5aWVsZCByZXNpemVJbWFnZUZpbGUoaW1hZ2VGaWxlLCB7XG4gICAgICAgIG1heFdpZHRoT3JIZWlnaHQ6IGN1cnNvckltYWdlU2l6ZVB4XG4gICAgICB9KTtcbiAgICAgIGxldCBwcmV2aWV3RGF0YVVSTCA9IHlpZWxkIGdldERhdGFVUkwoaW1hZ2VQcmV2aWV3KTsgLy8gU1ZHIGNhbm5vdCBiZSByZXNpemVkIHZpYSBgcmVzaXplSW1hZ2VGaWxlYCBzbyB3ZSByZXNpemUgYnkgcmVuZGVyaW5nIHRvXG4gICAgICAvLyBhIHNtYWxsIGNhbnZhc1xuXG4gICAgICBpZiAoaW1hZ2VGaWxlLnR5cGUgPT09IE1JTUVfVFlQRVMuc3ZnKSB7XG4gICAgICAgIGNvbnN0IGltZyA9IHlpZWxkIGxvYWRIVE1MSW1hZ2VFbGVtZW50KHByZXZpZXdEYXRhVVJMKTtcbiAgICAgICAgbGV0IGhlaWdodCA9IE1hdGgubWluKGltZy5oZWlnaHQsIGN1cnNvckltYWdlU2l6ZVB4KTtcbiAgICAgICAgbGV0IHdpZHRoID0gaGVpZ2h0ICogKGltZy53aWR0aCAvIGltZy5oZWlnaHQpO1xuXG4gICAgICAgIGlmICh3aWR0aCA+IGN1cnNvckltYWdlU2l6ZVB4KSB7XG4gICAgICAgICAgd2lkdGggPSBjdXJzb3JJbWFnZVNpemVQeDtcbiAgICAgICAgICBoZWlnaHQgPSB3aWR0aCAqIChpbWcuaGVpZ2h0IC8gaW1nLndpZHRoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgICAgIGNhbnZhcy5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgICAgIGNhbnZhcy53aWR0aCA9IHdpZHRoO1xuICAgICAgICBjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoXCIyZFwiKTtcbiAgICAgICAgY29udGV4dC5kcmF3SW1hZ2UoaW1nLCAwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICAgICAgcHJldmlld0RhdGFVUkwgPSBjYW52YXMudG9EYXRhVVJMKE1JTUVfVFlQRVMuc3ZnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBgdXJsKCR7cHJldmlld0RhdGFVUkx9KSA0IDQsIGF1dG9gKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub25JbWFnZUFjdGlvbiA9ICh7XG4gICAgICBpbnNlcnRPbkNhbnZhc0RpcmVjdGx5XG4gICAgfSkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY2xpZW50WCA9IHRoaXMuc3RhdGUud2lkdGggLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0O1xuICAgICAgICBjb25zdCBjbGllbnRZID0gdGhpcy5zdGF0ZS5oZWlnaHQgLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRUb3A7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgY2xpZW50WCxcbiAgICAgICAgICBjbGllbnRZXG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBpbWFnZUZpbGUgPSB5aWVsZCBmaWxlT3Blbih7XG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiSW1hZ2VcIixcbiAgICAgICAgICBleHRlbnNpb25zOiBPYmplY3Qua2V5cyhJTUFHRV9NSU1FX1RZUEVTKVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQoe1xuICAgICAgICAgIHNjZW5lWDogeCxcbiAgICAgICAgICBzY2VuZVk6IHksXG4gICAgICAgICAgYWRkVG9GcmFtZVVuZGVyQ3Vyc29yOiBmYWxzZVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoaW5zZXJ0T25DYW52YXNEaXJlY3RseSkge1xuICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlKTtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IGltYWdlRWxlbWVudC5pZFxuICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlLFxuICAgICAgICAgICAgLyogc2hvd0N1cnNvckltYWdlUHJldmlldyAqL1xuICAgICAgICAgICAgdHJ1ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmIChlcnJvci5uYW1lICE9PSBcIkFib3J0RXJyb3JcIikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGwsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMgPSAoaW1hZ2VFbGVtZW50LCBmb3JjZU5hdHVyYWxTaXplID0gZmFsc2UpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaW1hZ2UgPSBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCkgJiYgKChfYSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoaW1hZ2VFbGVtZW50LmZpbGVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pbWFnZSk7XG5cbiAgICAgIGlmICghaW1hZ2UgfHwgaW1hZ2UgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgIGlmIChpbWFnZUVsZW1lbnQud2lkdGggPCBEUkFHR0lOR19USFJFU0hPTEQgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUgJiYgaW1hZ2VFbGVtZW50LmhlaWdodCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkge1xuICAgICAgICAgIGNvbnN0IHBsYWNlaG9sZGVyU2l6ZSA9IDEwMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgICAgeDogaW1hZ2VFbGVtZW50LnggLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgeTogaW1hZ2VFbGVtZW50LnkgLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgd2lkdGg6IHBsYWNlaG9sZGVyU2l6ZSxcbiAgICAgICAgICAgIGhlaWdodDogcGxhY2Vob2xkZXJTaXplXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChmb3JjZU5hdHVyYWxTaXplIHx8IC8vIGlmIHVzZXItY3JlYXRlZCBib3VuZGluZyBib3ggaXMgYmVsb3cgdGhyZXNob2xkLCBhc3N1bWUgdGhlXG4gICAgICAvLyBpbnRlbnRpb24gd2FzIHRvIGNsaWNrIGluc3RlYWQgb2YgZHJhZywgYW5kIHVzZSB0aGUgaW1hZ2Unc1xuICAgICAgLy8gaW50cmluc2ljIHNpemVcbiAgICAgIGltYWdlRWxlbWVudC53aWR0aCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSAmJiBpbWFnZUVsZW1lbnQuaGVpZ2h0IDwgRFJBR0dJTkdfVEhSRVNIT0xEIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlKSB7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IE1hdGgubWF4KHRoaXMuc3RhdGUuaGVpZ2h0IC0gMTIwLCAxNjApOyAvLyBtYXggNjUlIG9mIGNhbnZhcyBoZWlnaHQsIGNsYW1wZWQgdG8gPDMwMHB4LCB2aCAtIDEyMHB4PlxuXG4gICAgICAgIGNvbnN0IG1heEhlaWdodCA9IE1hdGgubWluKG1pbkhlaWdodCwgTWF0aC5mbG9vcih0aGlzLnN0YXRlLmhlaWdodCAqIDAuNSkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUpO1xuICAgICAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1pbihpbWFnZS5uYXR1cmFsSGVpZ2h0LCBtYXhIZWlnaHQpO1xuICAgICAgICBjb25zdCB3aWR0aCA9IGhlaWdodCAqIChpbWFnZS5uYXR1cmFsV2lkdGggLyBpbWFnZS5uYXR1cmFsSGVpZ2h0KTsgLy8gYWRkIGN1cnJlbnQgaW1hZ2VFbGVtZW50IHdpZHRoL2hlaWdodCB0byBhY2NvdW50IGZvciBwcmV2aW91cyBjZW50ZXJpbmdcbiAgICAgICAgLy8gb2YgdGhlIHBsYWNlaG9sZGVyIGltYWdlXG5cbiAgICAgICAgY29uc3QgeCA9IGltYWdlRWxlbWVudC54ICsgaW1hZ2VFbGVtZW50LndpZHRoIC8gMiAtIHdpZHRoIC8gMjtcbiAgICAgICAgY29uc3QgeSA9IGltYWdlRWxlbWVudC55ICsgaW1hZ2VFbGVtZW50LmhlaWdodCAvIDIgLSBoZWlnaHQgLyAyO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeSxcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHRcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcbiAgICAvKiogdXBkYXRlcyBpbWFnZSBjYWNoZSwgcmVmcmVzaGluZyB1cGRhdGVkIGVsZW1lbnRzIGFuZC9vciBzZXR0aW5nIHN0YXR1c1xuICAgICAgICB0byBlcnJvciBmb3IgaW1hZ2VzIHRoYXQgZmFpbCBkdXJpbmcgPGltZz4gZWxlbWVudCBjcmVhdGlvbiAqL1xuXG5cbiAgICB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUgPSAoZWxlbWVudHMsIGZpbGVzID0gdGhpcy5maWxlcykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgY29uc3Qge1xuICAgICAgICB1cGRhdGVkRmlsZXMsXG4gICAgICAgIGVycm9yZWRGaWxlc1xuICAgICAgfSA9IHlpZWxkIF91cGRhdGVJbWFnZUNhY2hlKHtcbiAgICAgICAgaW1hZ2VDYWNoZTogdGhpcy5pbWFnZUNhY2hlLFxuICAgICAgICBmaWxlSWRzOiBlbGVtZW50cy5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgICAgIGZpbGVzXG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplIHx8IGVycm9yZWRGaWxlcy5zaXplKSB7XG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgIGlmICh1cGRhdGVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChlcnJvcmVkRmlsZXMuc2l6ZSkge1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChlbGVtZW50KSAmJiBlcnJvcmVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgc3RhdHVzOiBcImVycm9yXCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBlbGVtZW50O1xuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHVwZGF0ZWRGaWxlcyxcbiAgICAgICAgZXJyb3JlZEZpbGVzXG4gICAgICB9O1xuICAgIH0pO1xuICAgIC8qKiBhZGRzIG5ldyBpbWFnZXMgdG8gaW1hZ2VDYWNoZSBhbmQgcmUtcmVuZGVycyBpZiBuZWVkZWQgKi9cblxuXG4gICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUgPSAoaW1hZ2VFbGVtZW50cyA9IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSwgZmlsZXMgPSB0aGlzLmZpbGVzKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCB1bmNhY2hlZEltYWdlRWxlbWVudHMgPSBpbWFnZUVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+ICFlbGVtZW50LmlzRGVsZXRlZCAmJiAhdGhpcy5pbWFnZUNhY2hlLmhhcyhlbGVtZW50LmZpbGVJZCkpO1xuXG4gICAgICBpZiAodW5jYWNoZWRJbWFnZUVsZW1lbnRzLmxlbmd0aCkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgdXBkYXRlZEZpbGVzXG4gICAgICAgIH0gPSB5aWVsZCB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUodW5jYWNoZWRJbWFnZUVsZW1lbnRzLCBmaWxlcyk7XG5cbiAgICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplKSB7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgLyoqIGdlbmVyYWxseSB5b3Ugc2hvdWxkIHVzZSBgYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKClgIGRpcmVjdGx5IGlmIHlvdSBuZWVkXG4gICAgICogIHRvIHJlbmRlciBuZXcgaW1hZ2VzLiBUaGlzIGlzIGp1c3QgYSBmYWlsc2FmZSAgKi9cblxuXG4gICAgdGhpcy5zY2hlZHVsZUltYWdlUmVmcmVzaCA9IHRocm90dGxlKCgpID0+IHtcbiAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgfSwgSU1BR0VfUkVOREVSX1RJTUVPVVQpO1xuXG4gICAgdGhpcy51cGRhdGVCaW5kaW5nRW5hYmxlZE9uUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICBjb25zdCBzaG91bGRFbmFibGVCaW5kaW5nID0gc2hvdWxkRW5hYmxlQmluZGluZ0ZvclBvaW50ZXJFdmVudChldmVudCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQgIT09IHNob3VsZEVuYWJsZUJpbmRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogc2hvdWxkRW5hYmxlQmluZGluZ1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3IgPSBwb2ludGVyQ29vcmRzID0+IHtcbiAgICAgIGNvbnN0IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckNvb3JkcywgdGhpcy5zY2VuZSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgIT0gbnVsbCA/IFtob3ZlcmVkQmluZGFibGVFbGVtZW50XSA6IFtdXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyA9IChsaW5lYXJFbGVtZW50LFxuICAgIC8qKiBzY2VuZSBjb29yZHMgKi9cbiAgICBwb2ludGVyQ29vcmRzLCAvLyBEdXJpbmcgbGluZSBjcmVhdGlvbiB0aGUgc3RhcnQgYmluZGluZyBoYXNuJ3QgYmVlbiB3cml0dGVuIHlldFxuICAgIC8vIGludG8gYGxpbmVhckVsZW1lbnRgXG4gICAgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50KSA9PiB7XG4gICAgICBpZiAoIXBvaW50ZXJDb29yZHMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3VnZ2VzdGVkQmluZGluZ3MgPSBwb2ludGVyQ29vcmRzLnJlZHVjZSgoYWNjLCBjb29yZHMpID0+IHtcbiAgICAgICAgY29uc3QgaG92ZXJlZEJpbmRhYmxlRWxlbWVudCA9IGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZyhjb29yZHMsIHRoaXMuc2NlbmUpO1xuXG4gICAgICAgIGlmIChob3ZlcmVkQmluZGFibGVFbGVtZW50ICE9IG51bGwgJiYgIWlzTGluZWFyRWxlbWVudFNpbXBsZUFuZEFscmVhZHlCb3VuZChsaW5lYXJFbGVtZW50LCBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQgPT09IG51bGwgfHwgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQuaWQsIGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQpKSB7XG4gICAgICAgICAgYWNjLnB1c2goaG92ZXJlZEJpbmRhYmxlRWxlbWVudCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwgW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVJbnRlcmFjdGl2ZUNhbnZhc1JlZiA9IGNhbnZhcyA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYzsgLy8gY2FudmFzIGlzIG51bGwgd2hlbiB1bm1vdW50aW5nXG5cblxuICAgICAgaWYgKGNhbnZhcyAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzID0gY2FudmFzOyAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAvLyBOT1RFIHdoZWVsLCB0b3VjaHN0YXJ0LCB0b3VjaGVuZCBldmVudHMgbXVzdCBiZSByZWdpc3RlcmVkIG91dHNpZGVcbiAgICAgICAgLy8gb2YgcmVhY3QgYmVjYXVzZSByZWFjdCBiaW5kcyB0aGVtIHRoZW0gcGFzc2l2ZWx5IChzbyB3ZSBjYW4ndCBwcmV2ZW50XG4gICAgICAgIC8vIGRlZmF1bHQgb24gdGhlbSlcblxuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuV0hFRUwsIHRoaXMuaGFuZGxlV2hlZWwpO1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlRPVUNIX0VORCwgdGhpcy5vblRvdWNoRW5kKTsgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIChfYSA9IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLmhhbmRsZVdoZWVsKTtcbiAgICAgICAgKF9iID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgKF9jID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfRU5ELCB0aGlzLm9uVG91Y2hFbmQpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUFwcE9uRHJvcCA9IGV2ZW50ID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfaywgX2wsIF9tLCBfbzsgLy8gbXVzdCBiZSByZXRyaWV2ZWQgZmlyc3QsIGluIHRoZSBzYW1lIGZyYW1lXG5cblxuICAgICAgY29uc3Qge1xuICAgICAgICBmaWxlLFxuICAgICAgICBmaWxlSGFuZGxlXG4gICAgICB9ID0geWllbGQgZ2V0RmlsZUZyb21FdmVudChldmVudCk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gaWYgaW1hZ2UgdG9vbCBub3Qgc3VwcG9ydGVkLCBkb24ndCBzaG93IGFuIGVycm9yIGhlcmUgYW5kIGxldCBpdCBmYWxsXG4gICAgICAgIC8vIHRocm91Z2ggc28gd2Ugc3RpbGwgc3VwcG9ydCBpbXBvcnRpbmcgc2NlbmUgZGF0YSBmcm9tIGltYWdlcy4gSWYgbm9cbiAgICAgICAgLy8gc2NlbmUgZGF0YSBlbmNvZGVkLCB3ZSdsbCBzaG93IGFuIGVycm9yIHRoZW5cbiAgICAgICAgaWYgKGlzU3VwcG9ydGVkSW1hZ2VGaWxlKGZpbGUpICYmIHRoaXMuaXNUb29sU3VwcG9ydGVkKFwiaW1hZ2VcIikpIHtcbiAgICAgICAgICAvLyBmaXJzdCBhdHRlbXB0IHRvIGRlY29kZSBzY2VuZSBmcm9tIHRoZSBpbWFnZSBpZiBpdCdzIGVtYmVkZGVkXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgICAgaWYgKChmaWxlID09PSBudWxsIHx8IGZpbGUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGZpbGUudHlwZSkgPT09IE1JTUVfVFlQRVMucG5nIHx8IChmaWxlID09PSBudWxsIHx8IGZpbGUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGZpbGUudHlwZSkgPT09IE1JTUVfVFlQRVMuc3ZnKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCBzY2VuZSA9IHlpZWxkIGxvYWRGcm9tQmxvYihmaWxlLCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBmaWxlSGFuZGxlKTtcbiAgICAgICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUpLCB7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUgfHwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGlzTG9hZGluZzogZmFsc2VcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICByZXBsYWNlRmlsZXM6IHRydWUsXG4gICAgICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgaWYgKGVycm9yLm5hbWUgIT09IFwiRW5jb2RpbmdFcnJvclwiKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIGlmIG5vIHNjZW5lIGlzIGVtYmVkZGVkIG9yIHdlIGZhaWwgZm9yIHdoYXRldmVyIHJlYXNvbiwgZmFsbCBiYWNrXG4gICAgICAgICAgLy8gdG8gaW1wb3J0aW5nIGFzIHJlZ3VsYXIgaW1hZ2VcbiAgICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gICAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQoe1xuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5pbnNlcnRJbWFnZUVsZW1lbnQoaW1hZ2VFbGVtZW50LCBmaWxlKTtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbGlicmFyeUpTT04gPSBldmVudC5kYXRhVHJhbnNmZXIuZ2V0RGF0YShNSU1FX1RZUEVTLmV4Y2FsaWRyYXdsaWIpO1xuXG4gICAgICBpZiAobGlicmFyeUpTT04gJiYgdHlwZW9mIGxpYnJhcnlKU09OID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgbGlicmFyeUl0ZW1zID0gcGFyc2VMaWJyYXJ5SlNPTihsaWJyYXJ5SlNPTik7XG4gICAgICAgICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSh7XG4gICAgICAgICAgICBlbGVtZW50czogZGlzdHJpYnV0ZUxpYnJhcnlJdGVtc09uU3F1YXJlR3JpZChsaWJyYXJ5SXRlbXMpLFxuICAgICAgICAgICAgcG9zaXRpb246IGV2ZW50LFxuICAgICAgICAgICAgZmlsZXM6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZmlsZSkge1xuICAgICAgICAvLyBhdGV0bXB0IHRvIHBhcnNlIGFuIGV4Y2FsaWRyYXcvZXhjYWxpZHJhd2xpYiBmaWxlXG4gICAgICAgIHlpZWxkIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhmaWxlLCBmaWxlSGFuZGxlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKChfbCA9IChfayA9IGV2ZW50LmRhdGFUcmFuc2ZlcikgPT09IG51bGwgfHwgX2sgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9rLnR5cGVzKSA9PT0gbnVsbCB8fCBfbCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2wuaW5jbHVkZXMoXCJ0ZXh0L3BsYWluXCIpKSB7XG4gICAgICAgIGNvbnN0IHRleHQgPSAoX20gPSBldmVudC5kYXRhVHJhbnNmZXIpID09PSBudWxsIHx8IF9tID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfbS5nZXREYXRhKFwidGV4dFwiKTtcblxuICAgICAgICBpZiAodGV4dCAmJiBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yKHRleHQsIHRoaXMucHJvcHMudmFsaWRhdGVFbWJlZGRhYmxlKSAmJiAoL14oaHR0cHxodHRwcyk6XFwvXFwvW15cXHMvJC4/I10uW15cXHNdKiQvLnRlc3QodGV4dCkgfHwgKChfbyA9IGdldEVtYmVkTGluayh0ZXh0KSkgPT09IG51bGwgfHwgX28gPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9vLnR5cGUpID09PSBcInZpZGVvXCIpKSB7XG4gICAgICAgICAgY29uc3QgZW1iZWRkYWJsZSA9IHRoaXMuaW5zZXJ0RW1iZWRkYWJsZUVsZW1lbnQoe1xuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZLFxuICAgICAgICAgICAgbGluazogbm9ybWFsaXplTGluayh0ZXh0KVxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKGVtYmVkZGFibGUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICAgICAgICBbZW1iZWRkYWJsZS5pZF06IHRydWVcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmxvYWRGaWxlVG9DYW52YXMgPSAoZmlsZSwgZmlsZUhhbmRsZSkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgZmlsZSA9IHlpZWxkIG5vcm1hbGl6ZUZpbGUoZmlsZSk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJldCA9IHlpZWxkIGxvYWRTY2VuZU9yTGlicmFyeUZyb21CbG9iKGZpbGUsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGZpbGVIYW5kbGUpO1xuXG4gICAgICAgIGlmIChyZXQudHlwZSA9PT0gTUlNRV9UWVBFUy5leGNhbGlkcmF3KSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBpc0xvYWRpbmc6IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCByZXQuZGF0YSksIHtcbiAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHJldC5kYXRhLmFwcFN0YXRlIHx8IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgIGlzTG9hZGluZzogZmFsc2VcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgcmVwbGFjZUZpbGVzOiB0cnVlLFxuICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgfSkpO1xuICAgICAgICB9IGVsc2UgaWYgKHJldC50eXBlID09PSBNSU1FX1RZUEVTLmV4Y2FsaWRyYXdsaWIpIHtcbiAgICAgICAgICB5aWVsZCB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSh7XG4gICAgICAgICAgICBsaWJyYXJ5SXRlbXM6IGZpbGUsXG4gICAgICAgICAgICBtZXJnZTogdHJ1ZSxcbiAgICAgICAgICAgIG9wZW5MaWJyYXJ5TWVudTogdHJ1ZVxuICAgICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogdChcImVycm9ycy5pbXBvcnRMaWJyYXJ5RXJyb3JcIilcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBJbWFnZVNjZW5lRGF0YUVycm9yICYmIGVycm9yLmNvZGUgPT09IFwiSU1BR0VfTk9UX0NPTlRBSU5TX1NDRU5FX0RBVEFcIiAmJiAhdGhpcy5pc1Rvb2xTdXBwb3J0ZWQoXCJpbWFnZVwiKSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogdChcImVycm9ycy5pbWFnZVRvb2xOb3RTdXBwb3J0ZWRcIilcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUgPSBldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAoKFwicG9pbnRlclR5cGVcIiBpbiBldmVudC5uYXRpdmVFdmVudCAmJiBldmVudC5uYXRpdmVFdmVudC5wb2ludGVyVHlwZSA9PT0gXCJ0b3VjaFwiIHx8IFwicG9pbnRlclR5cGVcIiBpbiBldmVudC5uYXRpdmVFdmVudCAmJiBldmVudC5uYXRpdmVFdmVudC5wb2ludGVyVHlwZSA9PT0gXCJwZW5cIiAmJiAvLyBhbHdheXMgYWxsb3cgaWYgdXNlciB1c2VzIGEgcGVuIHNlY29uZGFyeSBidXR0b25cbiAgICAgIGV2ZW50LmJ1dHRvbiAhPT0gUE9JTlRFUl9CVVRUT04uU0VDT05EQVJZKSAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbih4LCB5LCB7XG4gICAgICAgIHByZWZlclNlbGVjdGVkOiB0cnVlLFxuICAgICAgICBpbmNsdWRlTG9ja2VkRWxlbWVudHM6IHRydWVcbiAgICAgIH0pO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGlzSGl0dGlnbkNvbW1vbkJvdW5kQm94ID0gdGhpcy5pc0hpdHRpbmdDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0sIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgY29uc3QgdHlwZSA9IGVsZW1lbnQgfHwgaXNIaXR0aWduQ29tbW9uQm91bmRCb3ggPyBcImVsZW1lbnRcIiA6IFwiY2FudmFzXCI7XG4gICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgdG9wOiBvZmZzZXRUb3AsXG4gICAgICAgIGxlZnQ6IG9mZnNldExlZnRcbiAgICAgIH0gPSBjb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICBjb25zdCBsZWZ0ID0gZXZlbnQuY2xpZW50WCAtIG9mZnNldExlZnQ7XG4gICAgICBjb25zdCB0b3AgPSBldmVudC5jbGllbnRZIC0gb2Zmc2V0VG9wO1xuICAgICAgdHJhY2tFdmVudChcImNvbnRleHRNZW51XCIsIFwib3BlbkNvbnRleHRNZW51XCIsIHR5cGUpO1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdID8gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgIFtlbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICB9XG4gICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBpc0xpbmVhckVsZW1lbnQoZWxlbWVudCkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihlbGVtZW50LCB0aGlzLnNjZW5lKSA6IG51bGxcbiAgICAgIH0pIDogdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBmYWxzZVxuICAgICAgfSksICgpID0+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgY29udGV4dE1lbnU6IHtcbiAgICAgICAgICAgIHRvcCxcbiAgICAgICAgICAgIGxlZnQsXG4gICAgICAgICAgICBpdGVtczogdGhpcy5nZXRDb250ZXh0TWVudUl0ZW1zKHR5cGUpXG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50ID0gKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lO1xuXG4gICAgICBjb25zdCBkcmFnZ2luZ0VsZW1lbnQgPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudDtcbiAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHM7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcInNlbGVjdGlvblwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyQ29vcmRzLngpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBwb2ludGVyQ29vcmRzLnkpLCBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgICAgY29uc3QgaW1hZ2UgPSBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgJiYgKChfYSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoZHJhZ2dpbmdFbGVtZW50LmZpbGVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pbWFnZSk7XG4gICAgICAgIGNvbnN0IGFzcGVjdFJhdGlvID0gaW1hZ2UgJiYgIShpbWFnZSBpbnN0YW5jZW9mIFByb21pc2UpID8gaW1hZ2Uud2lkdGggLyBpbWFnZS5oZWlnaHQgOiBudWxsO1xuICAgICAgICB0aGlzLm1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBbZHJhZ2dpbmdFbGVtZW50XSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBzbmFwT2Zmc2V0LFxuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9ID0gc25hcE5ld0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlLCBldmVudCwge1xuICAgICAgICAgIHg6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnggKyAoKF9jID0gKF9iID0gdGhpcy5zdGF0ZS5vcmlnaW5TbmFwT2Zmc2V0KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IueCkgIT09IG51bGwgJiYgX2MgIT09IHZvaWQgMCA/IF9jIDogMCksXG4gICAgICAgICAgeTogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueSArICgoX2UgPSAoX2QgPSB0aGlzLnN0YXRlLm9yaWdpblNuYXBPZmZzZXQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC55KSAhPT0gbnVsbCAmJiBfZSAhPT0gdm9pZCAwID8gX2UgOiAwKVxuICAgICAgICB9LCB7XG4gICAgICAgICAgeDogZ3JpZFggLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54LFxuICAgICAgICAgIHk6IGdyaWRZIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueVxuICAgICAgICB9KTtcbiAgICAgICAgZ3JpZFggKz0gc25hcE9mZnNldC54O1xuICAgICAgICBncmlkWSArPSBzbmFwT2Zmc2V0Lnk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9KTtcbiAgICAgICAgZHJhZ05ld0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueSwgZ3JpZFgsIGdyaWRZLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54LCBncmlkWCksIGRpc3RhbmNlKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnksIGdyaWRZKSwgaXNJbWFnZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSA/ICFzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSA6IHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyKGV2ZW50KSwgYXNwZWN0UmF0aW8sIHRoaXMuc3RhdGUub3JpZ2luU25hcE9mZnNldCk7XG4gICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChbZHJhZ2dpbmdFbGVtZW50XSk7IC8vIGhpZ2hsaWdodCBlbGVtZW50cyB0aGF0IGFyZSB0byBiZSBhZGRlZCB0byBmcmFtZXMgb24gZnJhbWVzIGNyZWF0aW9uXG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyYW1lXCIpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVsZW1lbnRzVG9IaWdobGlnaHQ6IGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLm1heWJlSGFuZGxlUmVzaXplID0gKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSA9PiB7XG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRGcmFtZXMgPSBzZWxlY3RlZEVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKTtcbiAgICAgIGNvbnN0IHRyYW5zZm9ybUhhbmRsZVR5cGUgPSBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRGcmFtZXMubGVuZ3RoID4gMCAmJiB0cmFuc2Zvcm1IYW5kbGVUeXBlID09PSBcInJvdGF0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgLy8gVE9ETzogcmVuYW1lIHRoaXMgc3RhdGUgZmllbGQgdG8gXCJpc1NjYWxpbmdcIiB0byBkaXN0aW5ndWlzaFxuICAgICAgICAvLyBpdCBmcm9tIHRoZSBnZW5lcmljIFwiaXNSZXNpemluZ1wiIHdoaWNoIGluY2x1ZGVzIHNjYWxpbmcgYW5kXG4gICAgICAgIC8vIHJvdGF0aW5nXG4gICAgICAgIGlzUmVzaXppbmc6IHRyYW5zZm9ybUhhbmRsZVR5cGUgJiYgdHJhbnNmb3JtSGFuZGxlVHlwZSAhPT0gXCJyb3RhdGlvblwiLFxuICAgICAgICBpc1JvdGF0aW5nOiB0cmFuc2Zvcm1IYW5kbGVUeXBlID09PSBcInJvdGF0aW9uXCIsXG4gICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3JkcztcbiAgICAgIGxldCBbcmVzaXplWCwgcmVzaXplWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54IC0gcG9pbnRlckRvd25TdGF0ZS5yZXNpemUub2Zmc2V0LngsIHBvaW50ZXJDb29yZHMueSAtIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldC55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwID0gbmV3IE1hcCgpO1xuICAgICAgc2VsZWN0ZWRGcmFtZXMuZm9yRWFjaChmcmFtZSA9PiB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzSW5GcmFtZSA9IGdldEZyYW1lQ2hpbGRyZW4odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZnJhbWUuaWQpO1xuICAgICAgICBlbGVtZW50c0luRnJhbWUuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5zZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkLCB7XG4gICAgICAgICAgICB4OiBlbGVtZW50LnggLSBmcmFtZS54LFxuICAgICAgICAgICAgeTogZWxlbWVudC55IC0gZnJhbWUueVxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0pOyAvLyBjaGVjayBuZWVkZWQgZm9yIGF2b2lkaW5nIGZsaWNrZXJpbmcgd2hlbiBhIGtleSBnZXRzIHByZXNzZWRcbiAgICAgIC8vIGR1cmluZyBkcmFnZ2luZ1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZCkge1xuICAgICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgIGNvbnN0IGRyYWdPZmZzZXQgPSB7XG4gICAgICAgICAgeDogZ3JpZFggLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54LFxuICAgICAgICAgIHk6IGdyaWRZIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueVxuICAgICAgICB9O1xuICAgICAgICBjb25zdCBvcmlnaW5hbEVsZW1lbnRzID0gWy4uLnBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50cy52YWx1ZXMoKV07XG4gICAgICAgIHRoaXMubWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgc25hcE9mZnNldCxcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSA9IHNuYXBSZXNpemluZ0VsZW1lbnRzKHNlbGVjdGVkRWxlbWVudHMsIGdldFNlbGVjdGVkRWxlbWVudHMob3JpZ2luYWxFbGVtZW50cywgdGhpcy5zdGF0ZSksIHRoaXMuc3RhdGUsIGV2ZW50LCBkcmFnT2Zmc2V0LCB0cmFuc2Zvcm1IYW5kbGVUeXBlKTtcbiAgICAgICAgcmVzaXplWCArPSBzbmFwT2Zmc2V0Lng7XG4gICAgICAgIHJlc2l6ZVkgKz0gc25hcE9mZnNldC55O1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0cmFuc2Zvcm1FbGVtZW50cyhwb2ludGVyRG93blN0YXRlLCB0cmFuc2Zvcm1IYW5kbGVUeXBlLCBzZWxlY3RlZEVsZW1lbnRzLCBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5hcnJvd0RpcmVjdGlvbiwgc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyKGV2ZW50KSwgc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNJbWFnZUVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkgPyAhc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCkgOiBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgcmVzaXplWCwgcmVzaXplWSwgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuY2VudGVyLngsIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmNlbnRlci55LCB0aGlzLnN0YXRlKSkge1xuICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzVG9IaWdobGlnaHQgPSBuZXcgU2V0KCk7XG4gICAgICAgIHNlbGVjdGVkRnJhbWVzLmZvckVhY2goZnJhbWUgPT4ge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzSW5GcmFtZSA9IGdldEZyYW1lQ2hpbGRyZW4odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZnJhbWUuaWQpOyAvLyBrZWVwIGVsZW1lbnRzJyBwb3NpdGlvbnMgcmVsYXRpdmUgdG8gdGhlaXIgZnJhbWVzIG9uIGZyYW1lcyByZXNpemluZ1xuXG4gICAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICAgIGlmICh0cmFuc2Zvcm1IYW5kbGVUeXBlLmluY2x1ZGVzKFwid1wiKSkge1xuICAgICAgICAgICAgICBlbGVtZW50c0luRnJhbWUuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICB4OiBmcmFtZS54ICsgKCgoX2EgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLngpIHx8IDApLFxuICAgICAgICAgICAgICAgICAgeTogZnJhbWUueSArICgoKF9iID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi55KSB8fCAwKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUuaW5jbHVkZXMoXCJuXCIpKSB7XG4gICAgICAgICAgICAgIGVsZW1lbnRzSW5GcmFtZS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgIHg6IGZyYW1lLnggKyAoKChfYSA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EueCkgfHwgMCksXG4gICAgICAgICAgICAgICAgICB5OiBmcmFtZS55ICsgKCgoX2IgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnkpIHx8IDApXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLCB0aGlzLnN0YXRlKS5mb3JFYWNoKGVsZW1lbnQgPT4gZWxlbWVudHNUb0hpZ2hsaWdodC5hZGQoZWxlbWVudCkpO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZWxlbWVudHNUb0hpZ2hsaWdodDogWy4uLmVsZW1lbnRzVG9IaWdobGlnaHRdXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLmdldENvbnRleHRNZW51SXRlbXMgPSB0eXBlID0+IHtcbiAgICAgIGNvbnN0IG9wdGlvbnMgPSBbXTtcbiAgICAgIG9wdGlvbnMucHVzaChhY3Rpb25Db3B5QXNQbmcsIGFjdGlvbkNvcHlBc1N2Zyk7IC8vIGNhbnZhcyBjb250ZXh0TWVudVxuICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgICBpZiAodHlwZSA9PT0gXCJjYW52YXNcIikge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICByZXR1cm4gWy4uLm9wdGlvbnMsIGFjdGlvblRvZ2dsZUdyaWRNb2RlLCBhY3Rpb25Ub2dnbGVaZW5Nb2RlLCBhY3Rpb25Ub2dnbGVWaWV3TW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHNdO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFthY3Rpb25QYXN0ZSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcsIGNvcHlUZXh0LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25TZWxlY3RBbGwsIGFjdGlvblVubG9ja0FsbEVsZW1lbnRzLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlT2JqZWN0c1NuYXBNb2RlLCBhY3Rpb25Ub2dnbGVaZW5Nb2RlLCBhY3Rpb25Ub2dnbGVWaWV3TW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHNdO1xuICAgICAgfSAvLyBlbGVtZW50IGNvbnRleHRNZW51XG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuICAgICAgb3B0aW9ucy5wdXNoKGNvcHlUZXh0KTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHJldHVybiBbYWN0aW9uQ29weSwgLi4ub3B0aW9uc107XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBbYWN0aW9uQ3V0LCBhY3Rpb25Db3B5LCBhY3Rpb25QYXN0ZSwgYWN0aW9uU2VsZWN0QWxsRWxlbWVudHNJbkZyYW1lLCBhY3Rpb25SZW1vdmVBbGxFbGVtZW50c0Zyb21GcmFtZSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgLi4ub3B0aW9ucywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQ29weVN0eWxlcywgYWN0aW9uUGFzdGVTdHlsZXMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkdyb3VwLCBhY3Rpb25VbmJpbmRUZXh0LCBhY3Rpb25CaW5kVGV4dCwgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciwgYWN0aW9uVW5ncm91cCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQWRkVG9MaWJyYXJ5LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25TZW5kQmFja3dhcmQsIGFjdGlvbkJyaW5nRm9yd2FyZCwgYWN0aW9uU2VuZFRvQmFjaywgYWN0aW9uQnJpbmdUb0Zyb250LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25GbGlwSG9yaXpvbnRhbCwgYWN0aW9uRmxpcFZlcnRpY2FsLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Ub2dnbGVMaW5lYXJFZGl0b3IsIGFjdGlvbkxpbmssIGFjdGlvbkR1cGxpY2F0ZVNlbGVjdGlvbiwgYWN0aW9uVG9nZ2xlRWxlbWVudExvY2ssIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkRlbGV0ZVNlbGVjdGVkXTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVXaGVlbCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAoaXNQYW5uaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICBkZWx0YVgsXG4gICAgICAgIGRlbHRhWVxuICAgICAgfSA9IGV2ZW50OyAvLyBub3RlIHRoYXQgZXZlbnQuY3RybEtleSBpcyBuZWNlc3NhcnkgdG8gaGFuZGxlIHBpbmNoIHpvb21pbmdcblxuICAgICAgaWYgKGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuY3RybEtleSkge1xuICAgICAgICBjb25zdCBzaWduID0gTWF0aC5zaWduKGRlbHRhWSk7XG4gICAgICAgIGNvbnN0IE1BWF9TVEVQID0gWk9PTV9TVEVQICogMTAwO1xuICAgICAgICBjb25zdCBhYnNEZWx0YSA9IE1hdGguYWJzKGRlbHRhWSk7XG4gICAgICAgIGxldCBkZWx0YSA9IGRlbHRhWTtcblxuICAgICAgICBpZiAoYWJzRGVsdGEgPiBNQVhfU1RFUCkge1xuICAgICAgICAgIGRlbHRhID0gTUFYX1NURVAgKiBzaWduO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG5ld1pvb20gPSB0aGlzLnN0YXRlLnpvb20udmFsdWUgLSBkZWx0YSAvIDEwMDsgLy8gaW5jcmVhc2Ugem9vbSBzdGVwcyB0aGUgbW9yZSB6b29tZWQtaW4gd2UgYXJlIChhcHBsaWVzIHRvID4xMDAlIG9ubHkpXG5cbiAgICAgICAgbmV3Wm9vbSArPSBNYXRoLmxvZzEwKE1hdGgubWF4KDEsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpICogLXNpZ24gKiAvLyByZWR1Y2VkIGFtcGxpZmljYXRpb24gZm9yIHNtYWxsIGRlbHRhcyAoc21hbGwgbW92ZW1lbnRzIG9uIGEgdHJhY2twYWQpXG4gICAgICAgIE1hdGgubWluKDEsIGFic0RlbHRhIC8gMjApO1xuICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgdmlld3BvcnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgICAgdmlld3BvcnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnksXG4gICAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKG5ld1pvb20pXG4gICAgICAgIH0sIHN0YXRlKSksIHtcbiAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgfSkpO1xuICAgICAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gc2Nyb2xsIGhvcml6b250YWxseSB3aGVuIHNoaWZ0IHByZXNzZWRcblxuXG4gICAgICBpZiAoZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoKHtcbiAgICAgICAgICB6b29tLFxuICAgICAgICAgIHNjcm9sbFhcbiAgICAgICAgfSkgPT4gKHtcbiAgICAgICAgICAvLyBvbiBNYWMsIHNoaWZ0K3doZWVsIHRlbmRzIHRvIHJlc3VsdCBpbiBkZWx0YVhcbiAgICAgICAgICBzY3JvbGxYOiBzY3JvbGxYIC0gKGRlbHRhWSB8fCBkZWx0YVgpIC8gem9vbS52YWx1ZVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoKHtcbiAgICAgICAgem9vbSxcbiAgICAgICAgc2Nyb2xsWCxcbiAgICAgICAgc2Nyb2xsWVxuICAgICAgfSkgPT4gKHtcbiAgICAgICAgc2Nyb2xsWDogc2Nyb2xsWCAtIGRlbHRhWCAvIHpvb20udmFsdWUsXG4gICAgICAgIHNjcm9sbFk6IHNjcm9sbFkgLSBkZWx0YVkgLyB6b29tLnZhbHVlXG4gICAgICB9KSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnNhdmVQb2ludGVyID0gKHgsIHksIGJ1dHRvbikgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgaWYgKCF4IHx8ICF5KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgIGNsaWVudFg6IHgsXG4gICAgICAgIGNsaWVudFk6IHlcbiAgICAgIH0sIHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoaXNOYU4oc2NlbmVYKSB8fCBpc05hTihzY2VuZVkpKSB7Ly8gc29tZXRpbWVzIHRoZSBwb2ludGVyIGdvZXMgb2ZmIHNjcmVlblxuICAgICAgfVxuXG4gICAgICBjb25zdCBwb2ludGVyID0ge1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWSxcbiAgICAgICAgdG9vbDogdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIiA/IFwibGFzZXJcIiA6IFwicG9pbnRlclwiXG4gICAgICB9O1xuICAgICAgKF9iID0gKF9hID0gdGhpcy5wcm9wcykub25Qb2ludGVyVXBkYXRlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwge1xuICAgICAgICBwb2ludGVyLFxuICAgICAgICBidXR0b24sXG4gICAgICAgIHBvaW50ZXJzTWFwOiBnZXN0dXJlLnBvaW50ZXJzXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldFNob3VsZENhY2hlSWdub3JlWm9vbURlYm91bmNlZCA9IGRlYm91bmNlKCgpID0+IHtcbiAgICAgIGlmICghdGhpcy51bm1vdW50ZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LCAzMDApO1xuXG4gICAgdGhpcy51cGRhdGVET01SZWN0ID0gY2IgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBpZiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkge1xuICAgICAgICBjb25zdCBleGNhbGlkcmF3Q29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgbGVmdDogb2Zmc2V0TGVmdCxcbiAgICAgICAgICB0b3A6IG9mZnNldFRvcFxuICAgICAgICB9ID0gZXhjYWxpZHJhd0NvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHdpZHRoOiBjdXJyZW50V2lkdGgsXG4gICAgICAgICAgaGVpZ2h0OiBjdXJyZW50SGVpZ2h0LFxuICAgICAgICAgIG9mZnNldFRvcDogY3VycmVudE9mZnNldFRvcCxcbiAgICAgICAgICBvZmZzZXRMZWZ0OiBjdXJyZW50T2Zmc2V0TGVmdFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBpZiAod2lkdGggPT09IGN1cnJlbnRXaWR0aCAmJiBoZWlnaHQgPT09IGN1cnJlbnRIZWlnaHQgJiYgb2Zmc2V0TGVmdCA9PT0gY3VycmVudE9mZnNldExlZnQgJiYgb2Zmc2V0VG9wID09PSBjdXJyZW50T2Zmc2V0VG9wKSB7XG4gICAgICAgICAgaWYgKGNiKSB7XG4gICAgICAgICAgICBjYigpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHdpZHRoLFxuICAgICAgICAgIGhlaWdodCxcbiAgICAgICAgICBvZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcFxuICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgY2IgJiYgY2IoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMucmVmcmVzaCA9ICgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5nZXRDYW52YXNPZmZzZXRzKCkpKTtcbiAgICB9O1xuXG4gICAgY29uc3QgZGVmYXVsdEFwcFN0YXRlID0gZ2V0RGVmYXVsdEFwcFN0YXRlKCk7XG4gICAgY29uc3Qge1xuICAgICAgZXhjYWxpZHJhd0FQSSxcbiAgICAgIHZpZXdNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgemVuTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIGdyaWRNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgb2JqZWN0c1NuYXBNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgdGhlbWUgPSBkZWZhdWx0QXBwU3RhdGUudGhlbWUsXG4gICAgICBuYW1lID0gZGVmYXVsdEFwcFN0YXRlLm5hbWVcbiAgICB9ID0gcHJvcHM7XG4gICAgdGhpcy5zdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGRlZmF1bHRBcHBTdGF0ZSksIHtcbiAgICAgIHRoZW1lLFxuICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgfSksIHRoaXMuZ2V0Q2FudmFzT2Zmc2V0cygpKSwge1xuICAgICAgdmlld01vZGVFbmFibGVkLFxuICAgICAgemVuTW9kZUVuYWJsZWQsXG4gICAgICBvYmplY3RzU25hcE1vZGVFbmFibGVkLFxuICAgICAgZ3JpZFNpemU6IGdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGwsXG4gICAgICBuYW1lLFxuICAgICAgd2lkdGg6IHdpbmRvdy5pbm5lcldpZHRoLFxuICAgICAgaGVpZ2h0OiB3aW5kb3cuaW5uZXJIZWlnaHRcbiAgICB9KTtcbiAgICB0aGlzLmlkID0gbmFub2lkKCk7XG4gICAgdGhpcy5saWJyYXJ5ID0gbmV3IExpYnJhcnkodGhpcyk7XG4gICAgdGhpcy5zY2VuZSA9IG5ldyBTY2VuZSgpO1xuICAgIHRoaXMuY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgICB0aGlzLnJjID0gcm91Z2guY2FudmFzKHRoaXMuY2FudmFzKTtcbiAgICB0aGlzLnJlbmRlcmVyID0gbmV3IFJlbmRlcmVyKHRoaXMuc2NlbmUpO1xuXG4gICAgaWYgKGV4Y2FsaWRyYXdBUEkpIHtcbiAgICAgIGNvbnN0IGFwaSA9IHtcbiAgICAgICAgdXBkYXRlU2NlbmU6IHRoaXMudXBkYXRlU2NlbmUsXG4gICAgICAgIHVwZGF0ZUxpYnJhcnk6IHRoaXMubGlicmFyeS51cGRhdGVMaWJyYXJ5LFxuICAgICAgICBhZGRGaWxlczogdGhpcy5hZGRGaWxlcyxcbiAgICAgICAgcmVzZXRTY2VuZTogdGhpcy5yZXNldFNjZW5lLFxuICAgICAgICBnZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZDogdGhpcy5nZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCxcbiAgICAgICAgaGlzdG9yeToge1xuICAgICAgICAgIGNsZWFyOiB0aGlzLnJlc2V0SGlzdG9yeVxuICAgICAgICB9LFxuICAgICAgICBzY3JvbGxUb0NvbnRlbnQ6IHRoaXMuc2Nyb2xsVG9Db250ZW50LFxuICAgICAgICBnZXRTY2VuZUVsZW1lbnRzOiB0aGlzLmdldFNjZW5lRWxlbWVudHMsXG4gICAgICAgIGdldEFwcFN0YXRlOiAoKSA9PiB0aGlzLnN0YXRlLFxuICAgICAgICBnZXRGaWxlczogKCkgPT4gdGhpcy5maWxlcyxcbiAgICAgICAgcmVmcmVzaDogdGhpcy5yZWZyZXNoLFxuICAgICAgICBzZXRUb2FzdDogdGhpcy5zZXRUb2FzdCxcbiAgICAgICAgaWQ6IHRoaXMuaWQsXG4gICAgICAgIHNldEFjdGl2ZVRvb2w6IHRoaXMuc2V0QWN0aXZlVG9vbCxcbiAgICAgICAgc2V0Q3Vyc29yOiB0aGlzLnNldEN1cnNvcixcbiAgICAgICAgcmVzZXRDdXJzb3I6IHRoaXMucmVzZXRDdXJzb3IsXG4gICAgICAgIHVwZGF0ZUZyYW1lUmVuZGVyaW5nOiB0aGlzLnVwZGF0ZUZyYW1lUmVuZGVyaW5nLFxuICAgICAgICB0b2dnbGVTaWRlYmFyOiB0aGlzLnRvZ2dsZVNpZGViYXIsXG4gICAgICAgIG9uQ2hhbmdlOiBjYiA9PiB0aGlzLm9uQ2hhbmdlRW1pdHRlci5vbihjYiksXG4gICAgICAgIG9uUG9pbnRlckRvd246IGNiID0+IHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIub24oY2IpLFxuICAgICAgICBvblBvaW50ZXJVcDogY2IgPT4gdGhpcy5vblBvaW50ZXJVcEVtaXR0ZXIub24oY2IpXG4gICAgICB9O1xuXG4gICAgICBpZiAodHlwZW9mIGV4Y2FsaWRyYXdBUEkgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBleGNhbGlkcmF3QVBJKGFwaSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiZXhjYWxpZHJhd0FQSSBzaG91bGQgYmUgYSBmdW5jdGlvbiFcIik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWUgPSB7XG4gICAgICBjb250YWluZXI6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LFxuICAgICAgaWQ6IHRoaXMuaWRcbiAgICB9O1xuICAgIHRoaXMuZm9udHMgPSBuZXcgRm9udHMoe1xuICAgICAgc2NlbmU6IHRoaXMuc2NlbmUsXG4gICAgICBvblNjZW5lVXBkYXRlZDogdGhpcy5vblNjZW5lVXBkYXRlZFxuICAgIH0pO1xuICAgIHRoaXMuaGlzdG9yeSA9IG5ldyBIaXN0b3J5KCk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyID0gbmV3IEFjdGlvbk1hbmFnZXIodGhpcy5zeW5jQWN0aW9uUmVzdWx0LCAoKSA9PiB0aGlzLnN0YXRlLCAoKSA9PiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBbGwoYWN0aW9ucyk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVVuZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVJlZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gIH1cblxuICBvbldpbmRvd01lc3NhZ2UoZXZlbnQpIHtcbiAgICBpZiAoZXZlbnQub3JpZ2luICE9PSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiICYmIGV2ZW50Lm9yaWdpbiAhPT0gXCJodHRwczovL3d3dy55b3V0dWJlLmNvbVwiKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IGRhdGEgPSBudWxsO1xuXG4gICAgdHJ5IHtcbiAgICAgIGRhdGEgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG5cbiAgICBpZiAoIWRhdGEpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKGV2ZW50Lm9yaWdpbikge1xuICAgICAgY2FzZSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiOlxuICAgICAgICAvL0FsbG93aW5nIGZvciBtdWx0aXBsZSBpbnN0YW5jZXMgb2YgRXhjYWxpZHJhdyBydW5uaW5nIGluIHRoZSB3aW5kb3dcbiAgICAgICAgaWYgKGRhdGEubWV0aG9kID09PSBcInBhdXNlZFwiKSB7XG4gICAgICAgICAgbGV0IHNvdXJjZSA9IG51bGw7XG4gICAgICAgICAgY29uc3QgaWZyYW1lcyA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvckFsbChcImlmcmFtZS5leGNhbGlkcmF3X19lbWJlZGRhYmxlXCIpO1xuXG4gICAgICAgICAgaWYgKCFpZnJhbWVzKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBmb3IgKGNvbnN0IGlmcmFtZSBvZiBpZnJhbWVzKSB7XG4gICAgICAgICAgICBpZiAoaWZyYW1lLmNvbnRlbnRXaW5kb3cgPT09IGV2ZW50LnNvdXJjZSkge1xuICAgICAgICAgICAgICBzb3VyY2UgPSBpZnJhbWUuY29udGVudFdpbmRvdztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzb3VyY2UgPT09IG51bGwgfHwgc291cmNlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBzb3VyY2UucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgbWV0aG9kOiBkYXRhLnZhbHVlID8gXCJwbGF5XCIgOiBcInBhdXNlXCIsXG4gICAgICAgICAgICB2YWx1ZTogdHJ1ZVxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBcImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tXCI6XG4gICAgICAgIGlmIChkYXRhLmV2ZW50ID09PSBcImluZm9EZWxpdmVyeVwiICYmIGRhdGEuaW5mbyAmJiBkYXRhLmlkICYmIHR5cGVvZiBkYXRhLmluZm8ucGxheWVyU3RhdGUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICBjb25zdCBpZCA9IGRhdGEuaWQ7XG4gICAgICAgICAgY29uc3QgcGxheWVyU3RhdGUgPSBkYXRhLmluZm8ucGxheWVyU3RhdGU7XG5cbiAgICAgICAgICBpZiAoT2JqZWN0LnZhbHVlcyhZT1VUVUJFX1NUQVRFUykuaW5jbHVkZXMocGxheWVyU3RhdGUpKSB7XG4gICAgICAgICAgICBZT1VUVUJFX1ZJREVPX1NUQVRFUy5zZXQoaWQsIHBsYXllclN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICB1cGRhdGVFbWJlZGRhYmxlUmVmKGlkLCByZWYpIHtcbiAgICBpZiAocmVmKSB7XG4gICAgICB0aGlzLmlGcmFtZVJlZnMuc2V0KGlkLCByZWYpO1xuICAgIH1cbiAgfVxuXG4gIGdldEhUTUxJRnJhbWVFbGVtZW50KGlkKSB7XG4gICAgcmV0dXJuIHRoaXMuaUZyYW1lUmVmcy5nZXQoaWQpO1xuICB9XG5cbiAgaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKGVsZW1lbnQpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG5cbiAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpID09PSBlbGVtZW50ICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiYWN0aXZlXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9IC8vIFRoZSBkZWxheSBzZXJ2ZXMgdHdvIHB1cnBvc2VzXG4gICAgLy8gMS4gVG8gcHJldmVudCBmaXJzdCBjbGljayBwcm9wYWdhdGluZyB0byBpZnJhbWUgb24gbW9iaWxlLFxuICAgIC8vICAgIGVsc2UgdGhlIGNsaWNrIHdpbGwgaW1tZWRpYXRlbHkgc3RhcnQgYW5kIHN0b3AgdGhlIHZpZGVvXG4gICAgLy8gMi4gSWYgdGhlIHVzZXIgZG91YmxlIGNsaWNrcyB0aGUgZnJhbWUgY2VudGVyIHRvIGFjdGl2YXRlIGl0XG4gICAgLy8gICAgd2l0aG91dCB0aGUgZGVsYXkgeW91dHViZSB3aWxsIGltbWVkaWF0ZWx5IG9wZW4gdGhlIHZpZGVvXG4gICAgLy8gICAgaW4gZnVsbHNjcmVlbiBtb2RlXG5cblxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IHtcbiAgICAgICAgICBlbGVtZW50LFxuICAgICAgICAgIHN0YXRlOiBcImFjdGl2ZVwiXG4gICAgICAgIH0sXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgIFtlbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGlvbkVsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH0sIDEwMCk7XG4gICAgY29uc3QgaWZyYW1lID0gdGhpcy5nZXRIVE1MSUZyYW1lRWxlbWVudChlbGVtZW50LmlkKTtcblxuICAgIGlmICghKGlmcmFtZSA9PT0gbnVsbCB8fCBpZnJhbWUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGlmcmFtZS5jb250ZW50V2luZG93KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpZnJhbWUuc3JjLmluY2x1ZGVzKFwieW91dHViZVwiKSkge1xuICAgICAgY29uc3Qgc3RhdGUgPSBZT1VUVUJFX1ZJREVPX1NUQVRFUy5nZXQoZWxlbWVudC5pZCk7XG5cbiAgICAgIGlmICghc3RhdGUpIHtcbiAgICAgICAgWU9VVFVCRV9WSURFT19TVEFURVMuc2V0KGVsZW1lbnQuaWQsIFlPVVRVQkVfU1RBVEVTLlVOU1RBUlRFRCk7XG4gICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBldmVudDogXCJsaXN0ZW5pbmdcIixcbiAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgfVxuXG4gICAgICBzd2l0Y2ggKHN0YXRlKSB7XG4gICAgICAgIGNhc2UgWU9VVFVCRV9TVEFURVMuUExBWUlORzpcbiAgICAgICAgY2FzZSBZT1VUVUJFX1NUQVRFUy5CVUZGRVJJTkc6XG4gICAgICAgICAgKF9jID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBhdXNlVmlkZW9cIixcbiAgICAgICAgICAgIGFyZ3M6IFwiXCJcbiAgICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgKF9kID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBsYXlWaWRlb1wiLFxuICAgICAgICAgICAgYXJnczogXCJcIlxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGlmcmFtZS5zcmMuaW5jbHVkZXMoXCJwbGF5ZXIudmltZW8uY29tXCIpKSB7XG4gICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIG1ldGhvZDogXCJwYXVzZWRcIiAvL3ZpZGVvIHBsYXkvcGF1c2UgaW4gb25XaW5kb3dNZXNzYWdlIGhhbmRsZXJcblxuICAgICAgfSksIFwiKlwiKTtcbiAgICB9XG4gIH1cblxuICBpc0VtYmVkZGFibGVDZW50ZXIoZWwsIGV2ZW50LCBzY2VuZVgsIHNjZW5lWSkge1xuICAgIHZhciBfYSwgX2I7XG5cbiAgICByZXR1cm4gZWwgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQuc2hpZnRLZXkgJiYgIWV2ZW50Lm1ldGFLZXkgJiYgIWV2ZW50LmN0cmxLZXkgJiYgKCgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSAhPT0gZWwgfHwgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJob3ZlclwiIHx8ICF0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpICYmIHNjZW5lWCA+PSBlbC54ICsgZWwud2lkdGggLyAzICYmIHNjZW5lWCA8PSBlbC54ICsgMiAqIGVsLndpZHRoIC8gMyAmJiBzY2VuZVkgPj0gZWwueSArIGVsLmhlaWdodCAvIDMgJiYgc2NlbmVZIDw9IGVsLnkgKyAyICogZWwuaGVpZ2h0IC8gMztcbiAgfVxuXG4gIHJlbmRlckVtYmVkZGFibGVzKCkge1xuICAgIGNvbnN0IHNjYWxlID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRXaWR0aCA9IHRoaXMuc3RhdGUud2lkdGg7XG4gICAgY29uc3Qgbm9ybWFsaXplZEhlaWdodCA9IHRoaXMuc3RhdGUuaGVpZ2h0O1xuICAgIGNvbnN0IGVtYmVkZGFibGVFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsID0+IGlzRW1iZWRkYWJsZUVsZW1lbnQoZWwpICYmICEhZWwudmFsaWRhdGVkKTtcbiAgICByZXR1cm4gX2pzeChfRnJhZ21lbnQsIHtcbiAgICAgIGNoaWxkcmVuOiBlbWJlZGRhYmxlRWxlbWVudHMubWFwKGVsID0+IHtcbiAgICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaDtcblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogZWwueCxcbiAgICAgICAgICBzY2VuZVk6IGVsLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGVtYmVkTGluayA9IGdldEVtYmVkTGluayh0b1ZhbGlkVVJMKGVsLmxpbmsgfHwgXCJcIikpO1xuICAgICAgICBjb25zdCBpc1Zpc2libGUgPSBpc0VsZW1lbnRJblZpZXdwb3J0KGVsLCBub3JtYWxpemVkV2lkdGgsIG5vcm1hbGl6ZWRIZWlnaHQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBpc0FjdGl2ZSA9ICgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSA9PT0gZWwgJiYgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJhY3RpdmVcIjtcbiAgICAgICAgY29uc3QgaXNIb3ZlcmVkID0gKChfYyA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmVsZW1lbnQpID09PSBlbCAmJiAoKF9kID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Quc3RhdGUpID09PSBcImhvdmVyXCI7XG4gICAgICAgIHJldHVybiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgIGNsYXNzTmFtZTogY2xzeChcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtY29udGFpbmVyXCIsIHtcbiAgICAgICAgICAgIFwiaXMtaG92ZXJlZFwiOiBpc0hvdmVyZWRcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgdHJhbnNmb3JtOiBpc1Zpc2libGUgPyBgdHJhbnNsYXRlKCR7eCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdH1weCwgJHt5IC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3B9cHgpIHNjYWxlKCR7c2NhbGV9KWAgOiBcIm5vbmVcIixcbiAgICAgICAgICAgIGRpc3BsYXk6IGlzVmlzaWJsZSA/IFwiYmxvY2tcIiA6IFwibm9uZVwiLFxuICAgICAgICAgICAgb3BhY2l0eTogZWwub3BhY2l0eSAvIDEwMCxcbiAgICAgICAgICAgIFtcIi0tZW1iZWRkYWJsZS1yYWRpdXNcIl06IGAke2dldENvcm5lclJhZGl1cyhNYXRoLm1pbihlbC53aWR0aCwgZWwuaGVpZ2h0KSwgZWwpfXB4YFxuICAgICAgICAgIH1cbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBfanN4cyhcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgIC8vdGhpcyBpcyBhIGhhY2sgdGhhdCBhZGRyZXNzZXMgaXNzZSB3aXRoIGVtYmVkZGVkIGV4Y2FsaWRyYXcuY29tIGVtYmVkZGFibGVcbiAgICAgICAgICAgIC8vaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzY2OTEjaXNzdWVjb21tZW50LTE2MDczODM5MzhcblxuICAgICAgICAgICAgLypyZWY9eyhyZWYpID0+IHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgICAgICAgICAgY29uc3Qgc2ggPSBjb250YWluZXIuc2Nyb2xsSGVpZ2h0O1xuICAgICAgICAgICAgICBjb25zdCBjaCA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQ7XG4gICAgICAgICAgICAgIGlmIChzaCAhPT0gY2gpIHtcbiAgICAgICAgICAgICAgICBjb250YWluZXIuc3R5bGUuaGVpZ2h0ID0gYCR7c2h9cHhgO1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgY29udGFpbmVyLnN0eWxlLmhlaWdodCA9IGAxMDAlYDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfX0qL1xuICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtY29udGFpbmVyX19pbm5lclwiLFxuICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgd2lkdGg6IGlzVmlzaWJsZSA/IGAke2VsLndpZHRofXB4YCA6IDAsXG4gICAgICAgICAgICAgIGhlaWdodDogaXNWaXNpYmxlID8gYCR7ZWwuaGVpZ2h0fXB4YCA6IDAsXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogaXNWaXNpYmxlID8gYHJvdGF0ZSgke2VsLmFuZ2xlfXJhZClgIDogXCJub25lXCIsXG4gICAgICAgICAgICAgIHBvaW50ZXJFdmVudHM6IGlzQWN0aXZlID8gUE9JTlRFUl9FVkVOVFMuZW5hYmxlZCA6IFBPSU5URVJfRVZFTlRTLmRpc2FibGVkXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgY2hpbGRyZW46IFtpc0hvdmVyZWQgJiYgX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtaGludFwiXG4gICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgIGNoaWxkcmVuOiB0KFwiYnV0dG9ucy5lbWJlZGRhYmxlSW50ZXJhY3Rpb25CdXR0b25cIilcbiAgICAgICAgICAgIH0pKSwgX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGVfX291dGVyXCIsXG4gICAgICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgcGFkZGluZzogYCR7ZWwuc3Ryb2tlV2lkdGh9cHhgXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IChfZyA9IChfZiA9IChfZSA9IHRoaXMucHJvcHMpLnJlbmRlckVtYmVkZGFibGUpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5jYWxsKF9lLCBlbCwgdGhpcy5zdGF0ZSkpICE9PSBudWxsICYmIF9nICE9PSB2b2lkIDAgPyBfZyA6IF9qc3goXCJpZnJhbWVcIiwge1xuICAgICAgICAgICAgICAgIHJlZjogcmVmID0+IHRoaXMudXBkYXRlRW1iZWRkYWJsZVJlZihlbC5pZCwgcmVmKSxcbiAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZVwiLFxuICAgICAgICAgICAgICAgIHNyY0RvYzogKGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay50eXBlKSA9PT0gXCJkb2N1bWVudFwiID8gZW1iZWRMaW5rLnNyY2RvYyh0aGlzLnN0YXRlLnRoZW1lKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBzcmM6IChlbWJlZExpbmsgPT09IG51bGwgfHwgZW1iZWRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbWJlZExpbmsudHlwZSkgIT09IFwiZG9jdW1lbnRcIiA/IChfaCA9IGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay5saW5rKSAhPT0gbnVsbCAmJiBfaCAhPT0gdm9pZCAwID8gX2ggOiBcIlwiIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcS8xODQ3MDAxNVxuICAgICAgICAgICAgICAgIHNjcm9sbGluZzogXCJub1wiLFxuICAgICAgICAgICAgICAgIHJlZmVycmVyUG9saWN5OiBcIm5vLXJlZmVycmVyLXdoZW4tZG93bmdyYWRlXCIsXG4gICAgICAgICAgICAgICAgdGl0bGU6IFwiRXhjYWxpZHJhdyBFbWJlZGRlZCBDb250ZW50XCIsXG4gICAgICAgICAgICAgICAgYWxsb3c6IFwiYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZVwiLFxuICAgICAgICAgICAgICAgIGFsbG93RnVsbFNjcmVlbjogdHJ1ZSxcbiAgICAgICAgICAgICAgICBzYW5kYm94OiBcImFsbG93LXNhbWUtb3JpZ2luIGFsbG93LXNjcmlwdHMgYWxsb3ctZm9ybXMgYWxsb3ctcG9wdXBzIGFsbG93LXBvcHVwcy10by1lc2NhcGUtc2FuZGJveCBhbGxvdy1wcmVzZW50YXRpb24gYWxsb3ctZG93bmxvYWRzXCJcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pKV1cbiAgICAgICAgICB9KSlcbiAgICAgICAgfSksIGVsLmlkKTtcbiAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICByZW5kZXIoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2M7XG5cbiAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHtcbiAgICAgIHJlbmRlclRvcFJpZ2h0VUksXG4gICAgICByZW5kZXJDdXN0b21TdGF0c1xuICAgIH0gPSB0aGlzLnByb3BzO1xuICAgIGNvbnN0IHZlcnNpb25Ob25jZSA9IHRoaXMuc2NlbmUuZ2V0VmVyc2lvbk5vbmNlKCk7XG4gICAgY29uc3Qge1xuICAgICAgY2FudmFzRWxlbWVudHMsXG4gICAgICB2aXNpYmxlRWxlbWVudHNcbiAgICB9ID0gdGhpcy5yZW5kZXJlci5nZXRSZW5kZXJhYmxlRWxlbWVudHMoe1xuICAgICAgdmVyc2lvbk5vbmNlLFxuICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLFxuICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgb2Zmc2V0VG9wOiB0aGlzLnN0YXRlLm9mZnNldFRvcCxcbiAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCxcbiAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgIGhlaWdodDogdGhpcy5zdGF0ZS5oZWlnaHQsXG4gICAgICB3aWR0aDogdGhpcy5zdGF0ZS53aWR0aCxcbiAgICAgIGVkaXRpbmdFbGVtZW50OiB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50LFxuICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiB0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZFxuICAgIH0pO1xuICAgIGNvbnN0IHNob3VsZEJsb2NrUG9pbnRlckV2ZW50cyA9ICEodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAmJiBpc0xpbmVhckVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkpICYmICh0aGlzLnN0YXRlLnNlbGVjdGlvbkVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgfHwgdGhpcy5zdGF0ZS5yZXNpemluZ0VsZW1lbnQgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIiAmJiAvLyB0ZWNobmljYWxseSB3ZSBjYW4ganVzdCB0ZXN0IG9uIHRoaXMgb25jZSB3ZSBtYWtlIGl0IG1vcmUgc2FmZVxuICAgIHRoaXMuc3RhdGUuY3Vyc29yQnV0dG9uID09PSBcImRvd25cIiB8fCB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICYmICFpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpKTtcbiAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgIGNsYXNzTmFtZTogY2xzeChcImV4Y2FsaWRyYXcgZXhjYWxpZHJhdy1jb250YWluZXJcIiwge1xuICAgICAgICBcImV4Y2FsaWRyYXctLXZpZXctbW9kZVwiOiB0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCxcbiAgICAgICAgXCJleGNhbGlkcmF3LS1tb2JpbGVcIjogdGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlXG4gICAgICB9KSxcbiAgICAgIHN0eWxlOiB7XG4gICAgICAgIFtcIi0tdWktcG9pbnRlckV2ZW50c1wiXTogc2hvdWxkQmxvY2tQb2ludGVyRXZlbnRzID8gUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5lbmFibGVkXG4gICAgICB9LFxuICAgICAgcmVmOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYsXG4gICAgICBvbkRyb3A6IHRoaXMuaGFuZGxlQXBwT25Ecm9wLFxuICAgICAgdGFiSW5kZXg6IDAsXG4gICAgICBvbktleURvd246IHRoaXMucHJvcHMuaGFuZGxlS2V5Ym9hcmRHbG9iYWxseSA/IHVuZGVmaW5lZCA6IHRoaXMub25LZXlEb3duXG4gICAgfSwge1xuICAgICAgY2hpbGRyZW46IF9qc3goQXBwQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgIHZhbHVlOiB0aGlzXG4gICAgICB9LCB7XG4gICAgICAgIGNoaWxkcmVuOiBfanN4KEFwcFByb3BzQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdmFsdWU6IHRoaXMucHJvcHNcbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJWYWx1ZVxuICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KERldmljZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5kZXZpY2VcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc2V0QXBwU3RhdGVcbiAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc3RhdGVcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICBjaGlsZHJlbjogX2pzeHMoRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpXG4gICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbX2pzeHMoRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5hY3Rpb25NYW5hZ2VyXG4gICAgICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW19qc3hzKExheWVyVUksIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmNhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZXM6IHRoaXMuZmlsZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRBcHBTdGF0ZTogdGhpcy5zZXRBcHBTdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGlvbk1hbmFnZXI6IHRoaXMuYWN0aW9uTWFuYWdlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Mb2NrVG9nZ2xlOiB0aGlzLnRvZ2dsZUxvY2ssXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBlbk1vZGVUb2dnbGU6IHRoaXMudG9nZ2xlUGVuTW9kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uSGFuZFRvb2xUb2dnbGU6IHRoaXMub25IYW5kVG9vbFRvZ2dsZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhbmdDb2RlOiBnZXRMYW5ndWFnZSgpLmNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJUb3BSaWdodFVJOiByZW5kZXJUb3BSaWdodFVJLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyQ3VzdG9tU3RhdHM6IHJlbmRlckN1c3RvbVN0YXRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2hvd0V4aXRaZW5Nb2RlQnRuOiB0eXBlb2YgKChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS56ZW5Nb2RlRW5hYmxlZCkgPT09IFwidW5kZWZpbmVkXCIgJiYgdGhpcy5zdGF0ZS56ZW5Nb2RlRW5hYmxlZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIFVJT3B0aW9uczogdGhpcy5wcm9wcy5VSU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkV4cG9ydEltYWdlOiB0aGlzLm9uRXhwb3J0SW1hZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJXZWxjb21lU2NyZWVuOiAhdGhpcy5zdGF0ZS5pc0xvYWRpbmcgJiYgdGhpcy5zdGF0ZS5zaG93V2VsY29tZVNjcmVlbiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiAhdGhpcy5zdGF0ZS56ZW5Nb2RlRW5hYmxlZCAmJiAhdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICBhcHA6IHRoaXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0NvbGxhYm9yYXRpbmc6IHRoaXMucHJvcHMuaXNDb2xsYWJvcmF0aW5nXG4gICAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IFt0aGlzLnByb3BzLmNoaWxkcmVuLCB0aGlzLnN0YXRlLm9wZW5EaWFsb2cgPT09IFwibWVybWFpZFwiICYmIF9qc3goTWVybWFpZFRvRXhjYWxpZHJhdywge30pXVxuICAgICAgICAgICAgICAgICAgICAgIH0pKSwgX2pzeChcImRpdlwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhdy10ZXh0RWRpdG9yQ29udGFpbmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgX2pzeChcImRpdlwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhdy1jb250ZXh0TWVudUNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctZXllLWRyb3BwZXItY29udGFpbmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgX2pzeChMYXNlclRvb2xPdmVybGF5LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtYW5hZ2VyOiB0aGlzLmxhc2VyUGF0aE1hbmFnZXJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgIXRoaXMuc3RhdGUuY29udGV4dE1lbnUgJiYgdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXAgJiYgX2pzeChIeXBlcmxpbmssIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHNlbGVjdGVkRWxlbWVudHNbMF0sXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRBcHBTdGF0ZTogdGhpcy5zZXRBcHBTdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uTGlua09wZW46IHRoaXMucHJvcHMub25MaW5rT3BlbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFRvYXN0OiB0aGlzLnNldFRvYXN0XG4gICAgICAgICAgICAgICAgICAgICAgfSwgc2VsZWN0ZWRFbGVtZW50c1swXS5pZCksIHRoaXMuc3RhdGUudG9hc3QgIT09IG51bGwgJiYgX2pzeChUb2FzdCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogdGhpcy5zdGF0ZS50b2FzdC5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25DbG9zZTogKCkgPT4gdGhpcy5zZXRUb2FzdChudWxsKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiB0aGlzLnN0YXRlLnRvYXN0LmR1cmF0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2xvc2FibGU6IHRoaXMuc3RhdGUudG9hc3QuY2xvc2FibGVcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiBfanN4KENvbnRleHRNZW51LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtczogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS5pdGVtcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvcDogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS50b3AsXG4gICAgICAgICAgICAgICAgICAgICAgICBsZWZ0OiB0aGlzLnN0YXRlLmNvbnRleHRNZW51LmxlZnQsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25NYW5hZ2VyOiB0aGlzLmFjdGlvbk1hbmFnZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkNsb3NlOiBjYWxsYmFjayA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRleHRNZW51OiBudWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZvY3VzQ29udGFpbmVyKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sgPT09IG51bGwgfHwgY2FsbGJhY2sgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KFN0YXRpY0NhbnZhcywge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmNhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJjOiB0aGlzLnJjLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IGNhbnZhc0VsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZUVsZW1lbnRzOiB2aXNpYmxlRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IHZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdGlvbk5vbmNlOiAoX2IgPSB0aGlzLnN0YXRlLnNlbGVjdGlvbkVsZW1lbnQpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi52ZXJzaW9uTm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZTogd2luZG93LmRldmljZVBpeGVsUmF0aW8sXG4gICAgICAgICAgICAgICAgICAgICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlckNvbmZpZzoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZUNhY2hlOiB0aGlzLmltYWdlQ2FjaGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlzRXhwb3J0aW5nOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyR3JpZDogdHJ1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KEludGVyYWN0aXZlQ2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250YWluZXJSZWY6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbnZhczogdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzOiBjYW52YXNFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpc2libGVFbGVtZW50czogdmlzaWJsZUVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50czogc2VsZWN0ZWRFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb25Ob25jZTogdmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uTm9uY2U6IChfYyA9IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrOiB0aGlzLnJlbmRlckludGVyYWN0aXZlU2NlbmVDYWxsYmFjayxcbiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZUNhbnZhc1JlZjogdGhpcy5oYW5kbGVJbnRlcmFjdGl2ZUNhbnZhc1JlZixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ29udGV4dE1lbnU6IHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJNb3ZlOiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Qb2ludGVyVXA6IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlclVwLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Qb2ludGVyQ2FuY2VsOiB0aGlzLnJlbW92ZVBvaW50ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblRvdWNoTW92ZTogdGhpcy5oYW5kbGVUb3VjaE1vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJEb3duOiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJEb3duLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Eb3VibGVDbGljazogdGhpcy5oYW5kbGVDYW52YXNEb3VibGVDbGlja1xuICAgICAgICAgICAgICAgICAgICAgIH0pLCB0aGlzLnJlbmRlckZyYW1lTmFtZXMoKV1cbiAgICAgICAgICAgICAgICAgICAgfSkpLCB0aGlzLnJlbmRlckVtYmVkZGFibGVzKCldXG4gICAgICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgICAgfSkpXG4gICAgICAgICAgICB9KSlcbiAgICAgICAgICB9KSlcbiAgICAgICAgfSkpXG4gICAgICB9KSlcbiAgICB9KSk7XG4gIH1cblxuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICB2YXIgX2E7XG5cbiAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlLmNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IEVOVi5URVNUIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICAgICAgICBjb25zdCBzZXRTdGF0ZSA9IHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMod2luZG93LmgsIHtcbiAgICAgICAgICBzdGF0ZToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZ2V0OiAoKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2V0U3RhdGU6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiAoLi4uYXJncykgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSguLi5hcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIGFwcDoge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHRoaXNcbiAgICAgICAgICB9LFxuICAgICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmhpc3RvcnlcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNjZW5lLmFkZENhbGxiYWNrKHRoaXMub25TY2VuZVVwZGF0ZWQpO1xuICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVycygpO1xuXG4gICAgICBpZiAodGhpcy5wcm9wcy5hdXRvRm9jdXMgJiYgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIC8vIGJvdW5kaW5nIHJlY3RzIGRvbid0IHdvcmsgaW4gdGVzdHMgc28gdXBkYXRpbmdcbiAgICAgIC8vIHRoZSBzdGF0ZSBvbiBpbml0IHdvdWxkIHJlc3VsdCBpbiBtYWtpbmcgdGhlIHRlc3QgZW52aXJvIHJ1blxuICAgICAgLy8gaW4gbW9iaWxlIGJyZWFrcG9pbnQgKDAgd2lkdGgvaGVpZ2h0KSwgbWFraW5nIGV2ZXJ5dGhpbmcgZmFpbFxuICAgICAgIWlzVGVzdEVudigpKSB7XG4gICAgICAgIHRoaXMucmVmcmVzaFZpZXdwb3J0QnJlYWtwb2ludHMoKTtcbiAgICAgICAgdGhpcy5yZWZyZXNoRWRpdG9yQnJlYWtwb2ludHMoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHN1cHBvcnRzUmVzaXplT2JzZXJ2ZXIgJiYgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgdGhpcy5yZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5yZWZyZXNoRWRpdG9yQnJlYWtwb2ludHMoKTtcbiAgICAgICAgICB0aGlzLnVwZGF0ZURPTVJlY3QoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIChfYSA9IHRoaXMucmVzaXplT2JzZXJ2ZXIpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vYnNlcnZlKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VhcmNoUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoLnNsaWNlKDEpKTtcblxuICAgICAgaWYgKHNlYXJjaFBhcmFtcy5oYXMoXCJ3ZWItc2hhcmUtdGFyZ2V0XCIpKSB7XG4gICAgICAgIC8vIE9idGFpbiBhIGZpbGUgdGhhdCB3YXMgc2hhcmVkIHZpYSB0aGUgV2ViIFNoYXJlIFRhcmdldCBBUEkuXG4gICAgICAgIHRoaXMucmVzdG9yZUZpbGVGcm9tU2hhcmUoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCh0aGlzLmluaXRpYWxpemVTY2VuZSk7XG4gICAgICB9IC8vIG5vdGUgdGhhdCB0aGlzIGNoZWNrIHNlZW1zIHRvIGFsd2F5cyBwYXNzIGluIGxvY2FsaG9zdFxuXG5cbiAgICAgIGlmIChpc0JyYXZlKCkgJiYgIWlzTWVhc3VyZVRleHRTdXBwb3J0ZWQoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IF9qc3goQnJhdmVNZWFzdXJlVGV4dEVycm9yLCB7fSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICB2YXIgX2E7XG5cbiAgICB0aGlzLnJlbmRlcmVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLnNjZW5lID0gbmV3IFNjZW5lKCk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcbiAgICB0aGlzLmZpbGVzID0ge307XG4gICAgdGhpcy5pbWFnZUNhY2hlLmNsZWFyKCk7XG4gICAgKF9hID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmRpc2Nvbm5lY3QoKTtcbiAgICB0aGlzLnVubW91bnRlZCA9IHRydWU7XG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHRoaXMuc2NlbmUuZGVzdHJveSgpO1xuICAgIHRoaXMubGlicmFyeS5kZXN0cm95KCk7XG4gICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyLmRlc3Ryb3koKTtcbiAgICB0aGlzLm9uQ2hhbmdlRW1pdHRlci5kZXN0cm95KCk7XG4gICAgU2hhcGVDYWNoZS5kZXN0cm95KCk7XG4gICAgU25hcENhY2hlLmRlc3Ryb3koKTtcbiAgICBjbGVhclRpbWVvdXQodG91Y2hUaW1lb3V0KTtcbiAgICBpc1NvbWVFbGVtZW50U2VsZWN0ZWQuY2xlYXJDYWNoZSgpO1xuICAgIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMuY2xlYXJDYWNoZSgpO1xuICAgIHRvdWNoVGltZW91dCA9IDA7XG4gIH1cblxuICByZW1vdmVFdmVudExpc3RlbmVycygpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG5cbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRoaXMucmVtb3ZlUG9pbnRlcik7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5DT1BZLCB0aGlzLm9uQ29weSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QQVNURSwgdGhpcy5wYXN0ZUZyb21DbGlwYm9hcmQpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuQ1VULCB0aGlzLm9uQ3V0KTtcbiAgICAoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuV0hFRUwsIHRoaXMub25XaGVlbCk7XG4gICAgKF9iID0gdGhpcy5uZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lcikgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuU0NST0xMLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHRoaXMub25LZXlEb3duLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5NT1VTRV9NT1ZFLCB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbiwgZmFsc2UpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIHRoaXMub25LZXlVcCk7XG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUkVTSVpFLCB0aGlzLm9uUmVzaXplLCBmYWxzZSk7XG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVU5MT0FELCB0aGlzLm9uVW5sb2FkLCBmYWxzZSk7XG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGhpcy5vbkJsdXIsIGZhbHNlKTtcbiAgICAoX2MgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuRFJBR19PVkVSLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICAgIChfZCA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5EUk9QLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9TVEFSVCwgdGhpcy5vbkdlc3R1cmVTdGFydCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9DSEFOR0UsIHRoaXMub25HZXN0dXJlQ2hhbmdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0VORCwgdGhpcy5vbkdlc3R1cmVFbmQsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5NRVNTQUdFLCB0aGlzLm9uV2luZG93TWVzc2FnZSwgZmFsc2UpO1xuICB9XG5cbiAgYWRkRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZTtcblxuICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5NRVNTQUdFLCB0aGlzLm9uV2luZG93TWVzc2FnZSwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGhpcy5yZW1vdmVQb2ludGVyKTsgLy8gIzM1NTNcblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuQ09QWSwgdGhpcy5vbkNvcHkpO1xuICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5XSEVFTCwgdGhpcy5vbldoZWVsLCB7XG4gICAgICBwYXNzaXZlOiBmYWxzZVxuICAgIH0pO1xuXG4gICAgaWYgKHRoaXMucHJvcHMuaGFuZGxlS2V5Ym9hcmRHbG9iYWxseSkge1xuICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlET1dOLCB0aGlzLm9uS2V5RG93biwgZmFsc2UpO1xuICAgIH1cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIHRoaXMub25LZXlVcCwge1xuICAgICAgcGFzc2l2ZTogdHJ1ZVxuICAgIH0pO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuTU9VU0VfTU9WRSwgdGhpcy51cGRhdGVDdXJyZW50Q3Vyc29yUG9zaXRpb24pOyAvLyByZXJlbmRlciB0ZXh0IGVsZW1lbnRzIG9uIGZvbnQgbG9hZCB0byBmaXggIzYzNyAmJiAjMTU1M1xuXG4gICAgKF9jID0gKF9iID0gZG9jdW1lbnQuZm9udHMpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5hZGRFdmVudExpc3RlbmVyKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuY2FsbChfYiwgXCJsb2FkaW5nZG9uZVwiLCBldmVudCA9PiB7XG4gICAgICBjb25zdCBsb2FkZWRGb250RmFjZXMgPSBldmVudC5mb250ZmFjZXM7XG4gICAgICB0aGlzLmZvbnRzLm9uRm9udHNMb2FkZWQobG9hZGVkRm9udEZhY2VzKTtcbiAgICB9KTsgLy8gU2FmYXJpLW9ubHkgZGVza3RvcCBwaW5jaCB6b29tXG5cbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfU1RBUlQsIHRoaXMub25HZXN0dXJlU3RhcnQsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfQ0hBTkdFLCB0aGlzLm9uR2VzdHVyZUNoYW5nZSwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9FTkQsIHRoaXMub25HZXN0dXJlRW5kLCBmYWxzZSk7XG5cbiAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5DVVQsIHRoaXMub25DdXQpO1xuXG4gICAgaWYgKHRoaXMucHJvcHMuZGV0ZWN0U2Nyb2xsKSB7XG4gICAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyID0gZ2V0TmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgdGhpcy5uZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lci5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlNDUk9MTCwgdGhpcy5vblNjcm9sbCk7XG4gICAgfVxuXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUkVTSVpFLCB0aGlzLm9uUmVzaXplLCBmYWxzZSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuVU5MT0FELCB0aGlzLm9uVW5sb2FkLCBmYWxzZSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGhpcy5vbkJsdXIsIGZhbHNlKTtcbiAgICAoX2QgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuRFJBR19PVkVSLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICAgIChfZSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2UuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5EUk9QLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICB9XG5cbiAgY29tcG9uZW50RGlkVXBkYXRlKHByZXZQcm9wcywgcHJldlN0YXRlKSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2Y7XG5cbiAgICB0aGlzLnVwZGF0ZUVtYmVkZGFibGVzKCk7XG5cbiAgICBpZiAoIXRoaXMuc3RhdGUuc2hvd1dlbGNvbWVTY3JlZW4gJiYgIXRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubGVuZ3RoKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2hvd1dlbGNvbWVTY3JlZW46IHRydWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50ICE9PSB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCkge1xuICAgICAgdGhpcy5yZWZyZXNoRWRpdG9yQnJlYWtwb2ludHMoKTtcbiAgICB9XG5cbiAgICBpZiAocHJldlN0YXRlLnNjcm9sbFggIT09IHRoaXMuc3RhdGUuc2Nyb2xsWCB8fCBwcmV2U3RhdGUuc2Nyb2xsWSAhPT0gdGhpcy5zdGF0ZS5zY3JvbGxZKSB7XG4gICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eub25TY3JvbGxDaGFuZ2UpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5jYWxsKF9hLCB0aGlzLnN0YXRlLnNjcm9sbFgsIHRoaXMuc3RhdGUuc2Nyb2xsWSk7XG4gICAgfVxuXG4gICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5sZW5ndGggJiYgaXNFcmFzZXJBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBhY3RpdmVUb29sOiB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgIH0pXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZXJhc2VyXCIgJiYgcHJldlN0YXRlLnRoZW1lICE9PSB0aGlzLnN0YXRlLnRoZW1lKSB7XG4gICAgICBzZXRFcmFzZXJDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZS50aGVtZSk7XG4gICAgfSAvLyBIaWRlIGh5cGVybGluayBwb3B1cCBpZiBzaG93biB3aGVuIGVsZW1lbnQgdHlwZSBpcyBub3Qgc2VsZWN0aW9uXG5cblxuICAgIGlmIChwcmV2U3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiICYmIHRoaXMuc3RhdGUuc2hvd0h5cGVybGlua1BvcHVwKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBmYWxzZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy5sYW5nQ29kZSAhPT0gdGhpcy5wcm9wcy5sYW5nQ29kZSkge1xuICAgICAgdGhpcy51cGRhdGVMYW5ndWFnZSgpO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMudmlld01vZGVFbmFibGVkICE9PSB0aGlzLnByb3BzLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHZpZXdNb2RlRW5hYmxlZDogISF0aGlzLnByb3BzLnZpZXdNb2RlRW5hYmxlZFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZTdGF0ZS52aWV3TW9kZUVuYWJsZWQgIT09IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXJzKCk7XG4gICAgICB0aGlzLmRlc2VsZWN0RWxlbWVudHMoKTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLnplbk1vZGVFbmFibGVkICE9PSB0aGlzLnByb3BzLnplbk1vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgemVuTW9kZUVuYWJsZWQ6ICEhdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy50aGVtZSAhPT0gdGhpcy5wcm9wcy50aGVtZSAmJiB0aGlzLnByb3BzLnRoZW1lKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMuZ3JpZE1vZGVFbmFibGVkICE9PSB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGdyaWRTaXplOiB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnByb3BzLm5hbWUgJiYgcHJldlByb3BzLm5hbWUgIT09IHRoaXMucHJvcHMubmFtZSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG5hbWU6IHRoaXMucHJvcHMubmFtZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgKF9jID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5jbGFzc0xpc3QudG9nZ2xlKFwidGhlbWUtLWRhcmtcIiwgdGhpcy5zdGF0ZS50aGVtZSA9PT0gXCJkYXJrXCIpO1xuXG4gICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkXSkge1xuICAgICAgLy8gZGVmZXIgc28gdGhhdCB0aGUgY29tbWl0VG9IaXN0b3J5IGZsYWcgaXNuJ3QgcmVzZXQgdmlhIGN1cnJlbnQgdXBkYXRlXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgLy8gZXhlY3V0ZSBvbmx5IGlmIHRoZSBjb25kaXRpb24gc3RpbGwgaG9sZHMgd2hlbiB0aGUgZGVmZXJyZWQgY2FsbGJhY2tcbiAgICAgICAgLy8gZXhlY3V0ZXMgKGl0IGNhbiBiZSBzY2hlZHVsZWQgbXVsdGlwbGUgdGltZXMgZGVwZW5kaW5nIG9uIGhvd1xuICAgICAgICAvLyBtYW55IHRpbWVzIHRoZSBjb21wb25lbnQgcmVuZGVycylcbiAgICAgICAgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICB9KTtcbiAgICB9IC8vIGZhaWxzYWZlIGluIGNhc2UgdGhlIHN0YXRlIGlzIGJlaW5nIHVwZGF0ZWQgaW4gaW5jb3JyZWN0IG9yZGVyIHJlc3VsdGluZ1xuICAgIC8vIGluIHRoZSBlZGl0aW5nRWxlbWVudCBiZWluZyBub3cgYSBkZWxldGVkIGVsZW1lbnRcblxuXG4gICAgaWYgKChfZCA9IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5pc0RlbGV0ZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBlZGl0aW5nRWxlbWVudDogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5lbGVtZW50SWRdKSB7XG4gICAgICAvLyBUbyBtYWtlIHN1cmUgYHNlbGVjdGVkTGluZWFyRWxlbWVudGAgaXMgaW4gc3luYyB3aXRoIGBzZWxlY3RlZEVsZW1lbnRJZHNgLCBob3dldmVyIHRoaXMgc2hvdWxkbid0IGJlIG5lZWRlZCBvbmNlXG4gICAgICAvLyB3ZSBoYXZlIGEgc2luZ2xlIEFQSSB0byB1cGRhdGUgYHNlbGVjdGVkRWxlbWVudElkc2BcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IHtcbiAgICAgIG11bHRpRWxlbWVudFxuICAgIH0gPSBwcmV2U3RhdGU7XG5cbiAgICBpZiAocHJldlN0YXRlLmFjdGl2ZVRvb2wgIT09IHRoaXMuc3RhdGUuYWN0aXZlVG9vbCAmJiBtdWx0aUVsZW1lbnQgIT0gbnVsbCAmJiBpc0JpbmRpbmdFbmFibGVkKHRoaXMuc3RhdGUpICYmIGlzQmluZGluZ0VsZW1lbnQobXVsdGlFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgIG1heWJlQmluZExpbmVhckVsZW1lbnQobXVsdGlFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLCB0dXBsZVRvQ29vcnMoTGluZWFyRWxlbWVudEVkaXRvci5nZXRQb2ludEF0SW5kZXhHbG9iYWxDb29yZGluYXRlcyhtdWx0aUVsZW1lbnQsIC0xKSkpO1xuICAgIH1cblxuICAgIHRoaXMuaGlzdG9yeS5yZWNvcmQodGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSk7IC8vIERvIG5vdCBub3RpZnkgY29uc3VtZXJzIGlmIHdlJ3JlIHN0aWxsIGxvYWRpbmcgdGhlIHNjZW5lLiBBbW9uZyBvdGhlclxuICAgIC8vIHBvdGVudGlhbCBpc3N1ZXMsIHRoaXMgZml4ZXMgYSBjYXNlIHdoZXJlIHRoZSB0YWIgaXNuJ3QgZm9jdXNlZCBkdXJpbmdcbiAgICAvLyBpbml0LCB3aGljaCB3b3VsZCB0cmlnZ2VyIG9uQ2hhbmdlIHdpdGggZW1wdHkgZWxlbWVudHMsIHdoaWNoIHdvdWxkIHRoZW5cbiAgICAvLyBvdmVycmlkZSB3aGF0ZXZlciBpcyBpbiBsb2NhbFN0b3JhZ2UgY3VycmVudGx5LlxuXG4gICAgaWYgKCF0aGlzLnN0YXRlLmlzTG9hZGluZykge1xuICAgICAgKF9mID0gKF9lID0gdGhpcy5wcm9wcykub25DaGFuZ2UpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5jYWxsKF9lLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzLnN0YXRlLCB0aGlzLmZpbGVzKTtcbiAgICAgIHRoaXMub25DaGFuZ2VFbWl0dGVyLnRyaWdnZXIodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcyk7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIHJlc2V0VGFwVHdpY2UoKSB7XG4gICAgZGlkVGFwVHdpY2UgPSBmYWxzZTtcbiAgfSAvLyBUT0RPIHJld3JpdGUgdGhpcyB0byBwYXN0ZSBib3RoIHRleHQgJiBpbWFnZXMgYXQgdGhlIHNhbWUgdGltZSBpZlxuICAvLyBwYXN0ZWQgZGF0YSBjb250YWlucyBib3RoXG5cblxuICBhZGRFbGVtZW50c0Zyb21NaXhlZENvbnRlbnRQYXN0ZShtaXhlZENvbnRlbnQsIHtcbiAgICBpc1BsYWluUGFzdGUsXG4gICAgc2NlbmVYLFxuICAgIHNjZW5lWVxuICB9KSB7XG4gICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGlmICghaXNQbGFpblBhc3RlICYmIG1peGVkQ29udGVudC5zb21lKG5vZGUgPT4gbm9kZS50eXBlID09PSBcImltYWdlVXJsXCIpICYmIHRoaXMuaXNUb29sU3VwcG9ydGVkKFwiaW1hZ2VcIikpIHtcbiAgICAgICAgY29uc3QgaW1hZ2VVUkxzID0gbWl4ZWRDb250ZW50LmZpbHRlcihub2RlID0+IG5vZGUudHlwZSA9PT0gXCJpbWFnZVVybFwiKS5tYXAobm9kZSA9PiBub2RlLnZhbHVlKTtcbiAgICAgICAgY29uc3QgcmVzcG9uc2VzID0geWllbGQgUHJvbWlzZS5hbGwoaW1hZ2VVUkxzLm1hcCh1cmwgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBmaWxlOiB5aWVsZCBJbWFnZVVSTFRvRmlsZSh1cmwpXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICB9KSkpO1xuICAgICAgICBsZXQgeSA9IHNjZW5lWTtcbiAgICAgICAgbGV0IGZpcnN0SW1hZ2VZT2Zmc2V0RG9uZSA9IGZhbHNlO1xuICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRJZHMgPSB7fTtcblxuICAgICAgICBmb3IgKGNvbnN0IHJlc3BvbnNlIG9mIHJlc3BvbnNlcykge1xuICAgICAgICAgIGlmIChyZXNwb25zZS5maWxlKSB7XG4gICAgICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSB0aGlzLmNyZWF0ZUltYWdlRWxlbWVudCh7XG4gICAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgICAgc2NlbmVZOiB5XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnN0IGluaXRpYWxpemVkSW1hZ2VFbGVtZW50ID0geWllbGQgdGhpcy5pbnNlcnRJbWFnZUVsZW1lbnQoaW1hZ2VFbGVtZW50LCByZXNwb25zZS5maWxlKTtcblxuICAgICAgICAgICAgaWYgKGluaXRpYWxpemVkSW1hZ2VFbGVtZW50KSB7XG4gICAgICAgICAgICAgIC8vIHZlcnRpY2FsbHkgY2VudGVyIGZpcnN0IGltYWdlIGluIHRoZSBiYXRjaFxuICAgICAgICAgICAgICBpZiAoIWZpcnN0SW1hZ2VZT2Zmc2V0RG9uZSkge1xuICAgICAgICAgICAgICAgIGZpcnN0SW1hZ2VZT2Zmc2V0RG9uZSA9IHRydWU7XG4gICAgICAgICAgICAgICAgeSAtPSBpbml0aWFsaXplZEltYWdlRWxlbWVudC5oZWlnaHQgLyAyO1xuICAgICAgICAgICAgICB9IC8vIGhhY2sgdG8gcmVzZXQgdGhlIGB5YCBjb29yZCBiZWNhdXNlIHdlIHZlcnRpY2FsbHkgY2VudGVyIGR1cmluZ1xuICAgICAgICAgICAgICAvLyBpbnNlcnRJbWFnZUVsZW1lbnRcblxuXG4gICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoaW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICB5XG4gICAgICAgICAgICAgIH0sIGZhbHNlKTtcbiAgICAgICAgICAgICAgeSA9IGltYWdlRWxlbWVudC55ICsgaW1hZ2VFbGVtZW50LmhlaWdodCArIDI1O1xuICAgICAgICAgICAgICBuZXh0U2VsZWN0ZWRJZHNbaW1hZ2VFbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRJZHMsIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBlcnJvciA9IHJlc3BvbnNlcy5maW5kKHJlc3BvbnNlID0+ICEhcmVzcG9uc2UuZXJyb3JNZXNzYWdlKTtcblxuICAgICAgICBpZiAoZXJyb3IgJiYgZXJyb3IuZXJyb3JNZXNzYWdlKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLmVycm9yTWVzc2FnZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB0ZXh0Tm9kZXMgPSBtaXhlZENvbnRlbnQuZmlsdGVyKG5vZGUgPT4gbm9kZS50eXBlID09PSBcInRleHRcIik7XG5cbiAgICAgICAgaWYgKHRleHROb2Rlcy5sZW5ndGgpIHtcbiAgICAgICAgICB0aGlzLmFkZFRleHRGcm9tUGFzdGUodGV4dE5vZGVzLm1hcChub2RlID0+IG5vZGUudmFsdWUpLmpvaW4oXCJcXG5cXG5cIiksIGlzUGxhaW5QYXN0ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGFkZFRleHRGcm9tUGFzdGUodGV4dCwgaXNQbGFpblBhc3RlID0gZmFsc2UpIHtcbiAgICBjb25zdCB7XG4gICAgICB4LFxuICAgICAgeVxuICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgY2xpZW50WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgY2xpZW50WTogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55XG4gICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgY29uc3QgdGV4dEVsZW1lbnRQcm9wcyA9IHtcbiAgICAgIHgsXG4gICAgICB5LFxuICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICB0ZXh0LFxuICAgICAgZm9udFNpemU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250U2l6ZSxcbiAgICAgIGZvbnRGYW1pbHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250RmFtaWx5LFxuICAgICAgdGV4dEFsaWduOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtVGV4dEFsaWduLFxuICAgICAgdmVydGljYWxBbGlnbjogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgIGxvY2tlZDogZmFsc2VcbiAgICB9O1xuICAgIGNvbnN0IExJTkVfR0FQID0gMTA7XG4gICAgbGV0IGN1cnJlbnRZID0geTtcbiAgICBjb25zdCBsaW5lcyA9IGlzUGxhaW5QYXN0ZSA/IFt0ZXh0XSA6IHRleHQuc3BsaXQoXCJcXG5cIik7XG4gICAgY29uc3QgdGV4dEVsZW1lbnRzID0gbGluZXMucmVkdWNlKChhY2MsIGxpbmUsIGlkeCkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCB0ZXh0ID0gbGluZS50cmltKCk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gZ2V0RGVmYXVsdExpbmVIZWlnaHQodGV4dEVsZW1lbnRQcm9wcy5mb250RmFtaWx5KTtcblxuICAgICAgaWYgKHRleHQubGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHk6IGN1cnJlbnRZXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBlbGVtZW50ID0gbmV3VGV4dEVsZW1lbnQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0ZXh0RWxlbWVudFByb3BzKSwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeTogY3VycmVudFksXG4gICAgICAgICAgdGV4dCxcbiAgICAgICAgICBsaW5lSGVpZ2h0LFxuICAgICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgICB9KSk7XG4gICAgICAgIGFjYy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICBjdXJyZW50WSArPSBlbGVtZW50LmhlaWdodCArIExJTkVfR0FQO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcHJldkxpbmUgPSAoX2EgPSBsaW5lc1tpZHggLSAxXSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRyaW0oKTsgLy8gYWRkIHBhcmFncmFwaCBvbmx5IGlmIHByZXZpb3VzIGxpbmUgd2FzIG5vdCBlbXB0eSwgSU9XIGRvbid0IGFkZFxuICAgICAgICAvLyBtb3JlIHRoYW4gb25lIGVtcHR5IGxpbmVcblxuICAgICAgICBpZiAocHJldkxpbmUpIHtcbiAgICAgICAgICBjdXJyZW50WSArPSBnZXRMaW5lSGVpZ2h0SW5QeCh0ZXh0RWxlbWVudFByb3BzLmZvbnRTaXplLCBsaW5lSGVpZ2h0KSArIExJTkVfR0FQO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwgW10pO1xuXG4gICAgaWYgKHRleHRFbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBmcmFtZUlkID0gdGV4dEVsZW1lbnRzWzBdLmZyYW1lSWQ7XG5cbiAgICBpZiAoZnJhbWVJZCkge1xuICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50c0F0SW5kZXgodGV4dEVsZW1lbnRzLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRJbmRleChmcmFtZUlkKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCAuLi50ZXh0RWxlbWVudHNdKTtcbiAgICB9XG5cbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmZyb21FbnRyaWVzKHRleHRFbGVtZW50cy5tYXAoZWwgPT4gW2VsLmlkLCB0cnVlXSkpLCB0aGlzLnN0YXRlKVxuICAgIH0pO1xuXG4gICAgaWYgKCFpc1BsYWluUGFzdGUgJiYgdGV4dEVsZW1lbnRzLmxlbmd0aCA+IDEgJiYgUExBSU5fUEFTVEVfVE9BU1RfU0hPV04gPT09IGZhbHNlICYmICF0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGUpIHtcbiAgICAgIHRoaXMuc2V0VG9hc3Qoe1xuICAgICAgICBtZXNzYWdlOiB0KFwidG9hc3QucGFzdGVBc1NpbmdsZUVsZW1lbnRcIiwge1xuICAgICAgICAgIHNob3J0Y3V0OiBnZXRTaG9ydGN1dEtleShcIkN0cmxPckNtZCtTaGlmdCtWXCIpXG4gICAgICAgIH0pLFxuICAgICAgICBkdXJhdGlvbjogNTAwMFxuICAgICAgfSk7XG4gICAgICBQTEFJTl9QQVNURV9UT0FTVF9TSE9XTiA9IHRydWU7XG4gICAgfVxuXG4gICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICB9XG5cbiAgaGFuZGxlVGV4dFd5c2l3eWcoZWxlbWVudCwge1xuICAgIGlzRXhpc3RpbmdFbGVtZW50ID0gZmFsc2VcbiAgfSkge1xuICAgIGNvbnN0IHVwZGF0ZUVsZW1lbnQgPSAodGV4dCwgb3JpZ2luYWxUZXh0LCBpc0RlbGV0ZWQpID0+IHtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChfZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChfZWxlbWVudC5pZCA9PT0gZWxlbWVudC5pZCAmJiBpc1RleHRFbGVtZW50KF9lbGVtZW50KSkge1xuICAgICAgICAgIHJldHVybiB1cGRhdGVUZXh0RWxlbWVudChfZWxlbWVudCwge1xuICAgICAgICAgICAgdGV4dCxcbiAgICAgICAgICAgIGlzRGVsZXRlZCxcbiAgICAgICAgICAgIG9yaWdpbmFsVGV4dFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF9lbGVtZW50O1xuICAgICAgfSldKTtcbiAgICB9O1xuXG4gICAgdGV4dFd5c2l3eWcoe1xuICAgICAgaWQ6IGVsZW1lbnQuaWQsXG4gICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgZ2V0Vmlld3BvcnRDb29yZHM6ICh4LCB5KSA9PiB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB2aWV3cG9ydFgsXG4gICAgICAgICAgeTogdmlld3BvcnRZXG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogeCxcbiAgICAgICAgICBzY2VuZVk6IHlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIHJldHVybiBbdmlld3BvcnRYIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LCB2aWV3cG9ydFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcF07XG4gICAgICB9LFxuICAgICAgb25DaGFuZ2U6IHdpdGhCYXRjaGVkVXBkYXRlcyh0ZXh0ID0+IHtcbiAgICAgICAgdXBkYXRlRWxlbWVudCh0ZXh0LCB0ZXh0LCBmYWxzZSk7XG5cbiAgICAgICAgaWYgKGlzTm9uRGVsZXRlZEVsZW1lbnQoZWxlbWVudCkpIHtcbiAgICAgICAgICB1cGRhdGVCb3VuZEVsZW1lbnRzKGVsZW1lbnQpO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICAgIG9uU3VibWl0OiB3aXRoQmF0Y2hlZFVwZGF0ZXMoKHtcbiAgICAgICAgdGV4dCxcbiAgICAgICAgdmlhS2V5Ym9hcmQsXG4gICAgICAgIG9yaWdpbmFsVGV4dFxuICAgICAgfSkgPT4ge1xuICAgICAgICBjb25zdCBpc0RlbGV0ZWQgPSAhdGV4dC50cmltKCk7XG4gICAgICAgIHVwZGF0ZUVsZW1lbnQodGV4dCwgb3JpZ2luYWxUZXh0LCBpc0RlbGV0ZWQpOyAvLyBzZWxlY3QgdGhlIGNyZWF0ZWQgdGV4dCBlbGVtZW50IG9ubHkgaWYgc3VibWl0dGluZyB2aWEga2V5Ym9hcmRcbiAgICAgICAgLy8gKHdoZW4gc3VibWl0dGluZyB2aWEgY2xpY2sgaXQgc2hvdWxkIGFjdCBhcyBzaWduYWwgdG8gZGVzZWxlY3QpXG5cbiAgICAgICAgaWYgKCFpc0RlbGV0ZWQgJiYgdmlhS2V5Ym9hcmQpIHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50SWRUb1NlbGVjdCA9IGVsZW1lbnQuY29udGFpbmVySWQgPyBlbGVtZW50LmNvbnRhaW5lcklkIDogZWxlbWVudC5pZDtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgIFtlbGVtZW50SWRUb1NlbGVjdF06IHRydWVcbiAgICAgICAgICAgIH0pLCBwcmV2U3RhdGUpXG4gICAgICAgICAgfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzRGVsZXRlZCkge1xuICAgICAgICAgIGZpeEJpbmRpbmdzQWZ0ZXJEZWxldGlvbih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBbZWxlbWVudF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFpc0RlbGV0ZWQgfHwgaXNFeGlzdGluZ0VsZW1lbnQpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH0pLFxuICAgICAgZWxlbWVudCxcbiAgICAgIGV4Y2FsaWRyYXdDb250YWluZXI6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LFxuICAgICAgYXBwOiB0aGlzXG4gICAgfSk7IC8vIGRlc2VsZWN0IGFsbCBvdGhlciBlbGVtZW50cyB3aGVuIGluc2VydGluZyB0ZXh0XG5cbiAgICB0aGlzLmRlc2VsZWN0RWxlbWVudHMoKTsgLy8gZG8gYW4gaW5pdGlhbCB1cGRhdGUgdG8gcmUtaW5pdGlhbGl6ZSBlbGVtZW50IHBvc2l0aW9uIHNpbmNlIHdlIHdlcmVcbiAgICAvLyBtb2RpZnlpbmcgZWxlbWVudCdzIHgveSBmb3Igc2FrZSBvZiBlZGl0b3IgKGNhc2U6IHN5bmNpbmcgdG8gcmVtb3RlKVxuXG4gICAgdXBkYXRlRWxlbWVudChlbGVtZW50LnRleHQsIGVsZW1lbnQub3JpZ2luYWxUZXh0LCBmYWxzZSk7XG4gIH1cblxuICBkZXNlbGVjdEVsZW1lbnRzKCkge1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgIH0pO1xuICB9XG5cbiAgZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHgsIHkpIHtcbiAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbih4LCB5LCB7XG4gICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZVxuICAgIH0pO1xuXG4gICAgaWYgKGVsZW1lbnQgJiYgaXNUZXh0RWxlbWVudChlbGVtZW50KSAmJiAhZWxlbWVudC5pc0RlbGV0ZWQpIHtcbiAgICAgIHJldHVybiBlbGVtZW50O1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZ2V0RWxlbWVudEF0UG9zaXRpb24oeCwgeSwgb3B0cykge1xuICAgIGNvbnN0IGFsbEhpdEVsZW1lbnRzID0gdGhpcy5nZXRFbGVtZW50c0F0UG9zaXRpb24oeCwgeSwgb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmluY2x1ZGVCb3VuZFRleHRFbGVtZW50LCBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuaW5jbHVkZUxvY2tlZEVsZW1lbnRzKTtcblxuICAgIGlmIChhbGxIaXRFbGVtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICBpZiAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnByZWZlclNlbGVjdGVkKSB7XG4gICAgICAgIGZvciAobGV0IGluZGV4ID0gYWxsSGl0RWxlbWVudHMubGVuZ3RoIC0gMTsgaW5kZXggPiAtMTsgaW5kZXgtLSkge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1thbGxIaXRFbGVtZW50c1tpbmRleF0uaWRdKSB7XG4gICAgICAgICAgICByZXR1cm4gYWxsSGl0RWxlbWVudHNbaW5kZXhdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50V2l0aEhpZ2hlc3RaSW5kZXggPSBhbGxIaXRFbGVtZW50c1thbGxIaXRFbGVtZW50cy5sZW5ndGggLSAxXTsgLy8gSWYgd2UncmUgaGl0dGluZyBlbGVtZW50IHdpdGggaGlnaGVzdCB6LWluZGV4IG9ubHkgb24gaXRzIGJvdW5kaW5nIGJveFxuICAgICAgLy8gd2hpbGUgYWxzbyBoaXR0aW5nIG90aGVyIGVsZW1lbnQgZmlndXJlLCB0aGUgbGF0dGVyIHNob3VsZCBiZSBjb25zaWRlcmVkLlxuXG4gICAgICByZXR1cm4gaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50KGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgeCwgeSkgPyBhbGxIaXRFbGVtZW50c1thbGxIaXRFbGVtZW50cy5sZW5ndGggLSAyXSA6IGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleDtcbiAgICB9XG5cbiAgICBpZiAoYWxsSGl0RWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICByZXR1cm4gYWxsSGl0RWxlbWVudHNbMF07XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBnZXRFbGVtZW50c0F0UG9zaXRpb24oeCwgeSwgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgPSBmYWxzZSwgaW5jbHVkZUxvY2tlZEVsZW1lbnRzID0gZmFsc2UpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGluY2x1ZGVCb3VuZFRleHRFbGVtZW50ICYmIGluY2x1ZGVMb2NrZWRFbGVtZW50cyA/IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkgOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLmZpbHRlcihlbGVtZW50ID0+IChpbmNsdWRlTG9ja2VkRWxlbWVudHMgfHwgIWVsZW1lbnQubG9ja2VkKSAmJiAoaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgfHwgIShpc1RleHRFbGVtZW50KGVsZW1lbnQpICYmIGVsZW1lbnQuY29udGFpbmVySWQpKSk7XG4gICAgcmV0dXJuIGdldEVsZW1lbnRzQXRQb3NpdGlvbihlbGVtZW50cywgZWxlbWVudCA9PiBoaXRUZXN0KGVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHgsIHkpKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAvLyBoaXR0aW5nIGEgZnJhbWUncyBlbGVtZW50IGZyb20gb3V0c2lkZSB0aGUgZnJhbWUgaXMgbm90IGNvbnNpZGVyZWQgYSBoaXRcbiAgICAgIGNvbnN0IGNvbnRhaW5pbmdGcmFtZSA9IGdldENvbnRhaW5pbmdGcmFtZShlbGVtZW50KTtcbiAgICAgIHJldHVybiBjb250YWluaW5nRnJhbWUgJiYgdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5lbmFibGVkICYmIHRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuY2xpcCA/IGlzQ3Vyc29ySW5GcmFtZSh7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0sIGNvbnRhaW5pbmdGcmFtZSkgOiB0cnVlO1xuICAgIH0pO1xuICB9XG5cbiAgaGFuZGxlSG92ZXJTZWxlY3RlZExpbmVhckVsZW1lbnQobGluZWFyRWxlbWVudEVkaXRvciwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmdldEVsZW1lbnQobGluZWFyRWxlbWVudEVkaXRvci5lbGVtZW50SWQpO1xuICAgIGNvbnN0IGJvdW5kVGV4dEVsZW1lbnQgPSBnZXRCb3VuZFRleHRFbGVtZW50KGVsZW1lbnQpO1xuXG4gICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICBsZXQgaG92ZXJQb2ludEluZGV4ID0gLTE7XG4gICAgICBsZXQgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3JkcyA9IG51bGw7XG5cbiAgICAgIGlmIChpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveChlbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBbc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWV0pKSB7XG4gICAgICAgIGhvdmVyUG9pbnRJbmRleCA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0UG9pbnRJbmRleFVuZGVyQ3Vyc29yKGVsZW1lbnQsIHRoaXMuc3RhdGUuem9vbSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSk7XG4gICAgICAgIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmdldFNlZ21lbnRNaWRwb2ludEhpdENvb3JkcyhsaW5lYXJFbGVtZW50RWRpdG9yLCB7XG4gICAgICAgICAgeDogc2NlbmVQb2ludGVyWCxcbiAgICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChob3ZlclBvaW50SW5kZXggPj0gMCB8fCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5NT1ZFKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzaG91bGRTaG93Qm91bmRpbmdCb3goW2VsZW1lbnRdLCB0aGlzLnN0YXRlKSAmJiBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQoZWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgfSBlbHNlIGlmIChib3VuZFRleHRFbGVtZW50ICYmIGhpdFRlc3QoYm91bmRUZXh0RWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaG92ZXJQb2ludEluZGV4ICE9PSBob3ZlclBvaW50SW5kZXgpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgaG92ZXJQb2ludEluZGV4XG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghTGluZWFyRWxlbWVudEVkaXRvci5hcmVQb2ludHNFcXVhbCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5zZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzLCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzXG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICB9XG4gIH1cblxuICBtYXliZUNsZWFudXBBZnRlck1pc3NpbmdQb2ludGVyVXAoZXZlbnQpIHtcbiAgICBpZiAobGFzdFBvaW50ZXJVcCAhPT0gbnVsbCkge1xuICAgICAgLy8gVW5mb3J0dW5hdGVseSwgc29tZXRpbWVzIHdlIGRvbid0IGdldCBhIHBvaW50ZXJ1cCBhZnRlciBhIHBvaW50ZXJkb3duLFxuICAgICAgLy8gdGhpcyBjYW4gaGFwcGVuIHdoZW4gYSBjb250ZXh0dWFsIG1lbnUgb3IgYWxlcnQgaXMgdHJpZ2dlcmVkLiBJbiBvcmRlciB0byBhdm9pZFxuICAgICAgLy8gYmVpbmcgaW4gYSB3ZWlyZCBzdGF0ZSwgd2UgY2xlYW4gdXAgb24gdGhlIG5leHQgcG9pbnRlcmRvd25cbiAgICAgIGxhc3RQb2ludGVyVXAoZXZlbnQpO1xuICAgIH1cbiAgfVxuXG4gIHVwZGF0ZUdlc3R1cmVPblBvaW50ZXJEb3duKGV2ZW50KSB7XG4gICAgZ2VzdHVyZS5wb2ludGVycy5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICB4OiBldmVudC5jbGllbnRYLFxuICAgICAgeTogZXZlbnQuY2xpZW50WVxuICAgIH0pO1xuXG4gICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMikge1xuICAgICAgZ2VzdHVyZS5sYXN0Q2VudGVyID0gZ2V0Q2VudGVyKGdlc3R1cmUucG9pbnRlcnMpO1xuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSA9IGdldERpc3RhbmNlKEFycmF5LmZyb20oZ2VzdHVyZS5wb2ludGVycy52YWx1ZXMoKSkpO1xuICAgIH1cbiAgfVxuXG4gIGluaXRpYWxQb2ludGVyRG93blN0YXRlKGV2ZW50KSB7XG4gICAgY29uc3Qgb3JpZ2luID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IFttaW5YLCBtaW5ZLCBtYXhYLCBtYXhZXSA9IGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICByZXR1cm4ge1xuICAgICAgb3JpZ2luLFxuICAgICAgd2l0aENtZE9yQ3RybDogZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0sXG4gICAgICBvcmlnaW5JbkdyaWQ6IHR1cGxlVG9Db29ycyhnZXRHcmlkUG9pbnQob3JpZ2luLngsIG9yaWdpbi55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKSksXG4gICAgICBzY3JvbGxiYXJzOiBpc092ZXJTY3JvbGxCYXJzKGN1cnJlbnRTY3JvbGxCYXJzLCBldmVudC5jbGllbnRYIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LCBldmVudC5jbGllbnRZIC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3ApLFxuICAgICAgLy8gd2UgbmVlZCB0byBkdXBsaWNhdGUgYmVjYXVzZSB3ZSdsbCBiZSB1cGRhdGluZyB0aGlzIHN0YXRlXG4gICAgICBsYXN0Q29vcmRzOiBPYmplY3QuYXNzaWduKHt9LCBvcmlnaW4pLFxuICAgICAgb3JpZ2luYWxFbGVtZW50czogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5yZWR1Y2UoKGFjYywgZWxlbWVudCkgPT4ge1xuICAgICAgICBhY2Muc2V0KGVsZW1lbnQuaWQsIGRlZXBDb3B5RWxlbWVudChlbGVtZW50KSk7XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCBuZXcgTWFwKCkpLFxuICAgICAgcmVzaXplOiB7XG4gICAgICAgIGhhbmRsZVR5cGU6IGZhbHNlLFxuICAgICAgICBpc1Jlc2l6aW5nOiBmYWxzZSxcbiAgICAgICAgb2Zmc2V0OiB7XG4gICAgICAgICAgeDogMCxcbiAgICAgICAgICB5OiAwXG4gICAgICAgIH0sXG4gICAgICAgIGFycm93RGlyZWN0aW9uOiBcIm9yaWdpblwiLFxuICAgICAgICBjZW50ZXI6IHtcbiAgICAgICAgICB4OiAobWF4WCArIG1pblgpIC8gMixcbiAgICAgICAgICB5OiAobWF4WSArIG1pblkpIC8gMlxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgaGl0OiB7XG4gICAgICAgIGVsZW1lbnQ6IG51bGwsXG4gICAgICAgIGFsbEhpdEVsZW1lbnRzOiBbXSxcbiAgICAgICAgd2FzQWRkZWRUb1NlbGVjdGlvbjogZmFsc2UsXG4gICAgICAgIGhhc0JlZW5EdXBsaWNhdGVkOiBmYWxzZSxcbiAgICAgICAgaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHM6IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMob3JpZ2luLCBzZWxlY3RlZEVsZW1lbnRzKVxuICAgICAgfSxcbiAgICAgIGRyYWc6IHtcbiAgICAgICAgaGFzT2NjdXJyZWQ6IGZhbHNlLFxuICAgICAgICBvZmZzZXQ6IG51bGxcbiAgICAgIH0sXG4gICAgICBldmVudExpc3RlbmVyczoge1xuICAgICAgICBvbk1vdmU6IG51bGwsXG4gICAgICAgIG9uVXA6IG51bGwsXG4gICAgICAgIG9uS2V5VXA6IG51bGwsXG4gICAgICAgIG9uS2V5RG93bjogbnVsbFxuICAgICAgfSxcbiAgICAgIGJveFNlbGVjdGlvbjoge1xuICAgICAgICBoYXNPY2N1cnJlZDogZmFsc2VcbiAgICAgIH0sXG4gICAgICBlbGVtZW50SWRzVG9FcmFzZToge31cbiAgICB9O1xuICB9IC8vIFJldHVybnMgd2hldGhlciB0aGUgZXZlbnQgaXMgYSBkcmFnZ2luZyBhIHNjcm9sbGJhclxuXG5cbiAgaGFuZGxlRHJhZ2dpbmdTY3JvbGxCYXIoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICBpZiAoIShwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVyRWl0aGVyICYmICF0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gdHJ1ZTtcbiAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IGV2ZW50LmNsaWVudFg7XG4gICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBldmVudC5jbGllbnRZO1xuICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQoZXZlbnQgPT4ge1xuICAgICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0O1xuXG4gICAgICBpZiAoISh0YXJnZXQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgIH0pO1xuICAgIGNvbnN0IG9uUG9pbnRlclVwID0gd2l0aEJhdGNoZWRVcGRhdGVzKCgpID0+IHtcbiAgICAgIGlzRHJhZ2dpbmdTY3JvbGxCYXIgPSBmYWxzZTtcbiAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgY3Vyc29yQnV0dG9uOiBcInVwXCJcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICAgIG9uUG9pbnRlck1vdmUuZmx1c2goKTtcbiAgICB9KTtcbiAgICBsYXN0UG9pbnRlclVwID0gb25Qb2ludGVyVXA7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBvblBvaW50ZXJVcCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBpc0FTZWxlY3RlZEVsZW1lbnQoaGl0RWxlbWVudCkge1xuICAgIHJldHVybiBoaXRFbGVtZW50ICE9IG51bGwgJiYgdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF07XG4gIH1cblxuICBpc0hpdHRpbmdDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cyhwb2ludCwgc2VsZWN0ZWRFbGVtZW50cykge1xuICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA8IDIpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IC8vIEhvdyBtYW55IHBpeGVscyBvZmYgdGhlIHNoYXBlIGJvdW5kYXJ5IHdlIHN0aWxsIGNvbnNpZGVyIGEgaGl0XG5cblxuICAgIGNvbnN0IHRocmVzaG9sZCA9IDEwIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgIGNvbnN0IFt4MSwgeTEsIHgyLCB5Ml0gPSBnZXRDb21tb25Cb3VuZHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgcmV0dXJuIHBvaW50LnggPiB4MSAtIHRocmVzaG9sZCAmJiBwb2ludC54IDwgeDIgKyB0aHJlc2hvbGQgJiYgcG9pbnQueSA+IHkxIC0gdGhyZXNob2xkICYmIHBvaW50LnkgPCB5MiArIHRocmVzaG9sZDtcbiAgfVxuXG4gIGdldEN1cnJlbnRJdGVtUm91bmRuZXNzKGVsZW1lbnRUeXBlKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VuZG5lc3MgPT09IFwicm91bmRcIiA/IHtcbiAgICAgIHR5cGU6IGlzVXNpbmdBZGFwdGl2ZVJhZGl1cyhlbGVtZW50VHlwZSkgPyBST1VORE5FU1MuQURBUFRJVkVfUkFESVVTIDogUk9VTkRORVNTLlBST1BPUlRJT05BTF9SQURJVVNcbiAgICB9IDogbnVsbDtcbiAgfVxuXG4gIG1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzLCByZWNvbXB1dGVBbnl3YXlzID0gZmFsc2UpIHtcbiAgICBpZiAoaXNTbmFwcGluZ0VuYWJsZWQoe1xuICAgICAgZXZlbnQsXG4gICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgIHNlbGVjdGVkRWxlbWVudHNcbiAgICB9KSAmJiAocmVjb21wdXRlQW55d2F5cyB8fCAhU25hcENhY2hlLmdldFJlZmVyZW5jZVNuYXBQb2ludHMoKSkpIHtcbiAgICAgIFNuYXBDYWNoZS5zZXRSZWZlcmVuY2VTbmFwUG9pbnRzKGdldFJlZmVyZW5jZVNuYXBQb2ludHModGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgc2VsZWN0ZWRFbGVtZW50cywgdGhpcy5zdGF0ZSkpO1xuICAgIH1cbiAgfVxuXG4gIG1heWJlQ2FjaGVWaXNpYmxlR2FwcyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgcmVjb21wdXRlQW55d2F5cyA9IGZhbHNlKSB7XG4gICAgaWYgKGlzU25hcHBpbmdFbmFibGVkKHtcbiAgICAgIGV2ZW50LFxuICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICBzZWxlY3RlZEVsZW1lbnRzXG4gICAgfSkgJiYgKHJlY29tcHV0ZUFueXdheXMgfHwgIVNuYXBDYWNoZS5nZXRWaXNpYmxlR2FwcygpKSkge1xuICAgICAgU25hcENhY2hlLnNldFZpc2libGVHYXBzKGdldFZpc2libGVHYXBzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHNlbGVjdGVkRWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcbiAgICB9XG4gIH1cblxuICBvbktleURvd25Gcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGlmICh0aGlzLm1heWJlSGFuZGxlUmVzaXplKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubWF5YmVEcmFnTmV3R2VuZXJpY0VsZW1lbnQocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpO1xuICAgIH0pO1xuICB9XG5cbiAgb25LZXlVcEZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSkge1xuICAgIHJldHVybiB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgLy8gUHJldmVudHMgZm9jdXMgZnJvbSBlc2NhcGluZyBleGNhbGlkcmF3IHRhYlxuICAgICAgZXZlbnQua2V5ID09PSBLRVlTLkFMVCAmJiBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uUG9pbnRlck1vdmVGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzVGhyb3R0bGVkKGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2I7IC8vIFdlIG5lZWQgdG8gaW5pdGlhbGl6ZSBkcmFnT2Zmc2V0WFkgb25seSBhZnRlciB3ZSd2ZSB1cGRhdGVkXG4gICAgICAvLyBgc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzYCBvbiBwb2ludGVyRG93bi4gRG9pbmcgaXQgaGVyZSBpbiBwb2ludGVyTW92ZVxuICAgICAgLy8gZXZlbnQgaGFuZGxlciBzaG91bGQgaG9wZWZ1bGx5IGVuc3VyZSB3ZSdyZSBhbHJlYWR5IHdvcmtpbmcgd2l0aFxuICAgICAgLy8gdGhlIHVwZGF0ZWQgc3RhdGUuXG5cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5vZmZzZXQgPT09IG51bGwpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLm9mZnNldCA9IHR1cGxlVG9Db29ycyhnZXREcmFnT2Zmc2V0WFkodGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldDtcblxuICAgICAgaWYgKCEodGFyZ2V0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlRXJhc2VyKGV2ZW50LCBwb2ludGVyRG93blN0YXRlLCBwb2ludGVyQ29vcmRzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIikge1xuICAgICAgICB0aGlzLmxhc2VyUGF0aE1hbmFnZXIuYWRkUG9pbnRUb1BhdGgocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnkpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7IC8vIGZvciBhcnJvd3MvbGluZXMsIGRvbid0IHN0YXJ0IGRyYWdnaW5nIHVudGlsIGEgZ2l2ZW4gdGhyZXNob2xkXG4gICAgICAvLyB0byBlbnN1cmUgd2UgZG9uJ3QgY3JlYXRlIGEgMi1wb2ludCBhcnJvdyBieSBtaXN0YWtlIHdoZW5cbiAgICAgIC8vIHVzZXIgY2xpY2tzIG1vdXNlIGluIGEgd2F5IHRoYXQgaXQgbW92ZXMgYSB0aW55IGJpdCAodGh1c1xuICAgICAgLy8gdHJpZ2dlcmluZyBwb2ludGVybW92ZSlcblxuICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImFycm93XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGluZVwiKSkge1xuICAgICAgICBpZiAoZGlzdGFuY2UyZChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkgPCBEUkFHR0lOR19USFJFU0hPTEQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmlzUmVzaXppbmcpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuXG4gICAgICAgIGlmICh0aGlzLm1heWJlSGFuZGxlUmVzaXplKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICBjb25zdCBsaW5lYXJFbGVtZW50RWRpdG9yID0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudDtcblxuICAgICAgICBpZiAoTGluZWFyRWxlbWVudEVkaXRvci5zaG91bGRBZGRNaWRwb2ludCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgcG9pbnRlckNvb3JkcywgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgICBjb25zdCByZXQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmFkZE1pZHBvaW50KHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LCBwb2ludGVyQ29vcmRzLCB0aGlzLnN0YXRlLCAhZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pO1xuXG4gICAgICAgICAgaWYgKCFyZXQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9IC8vIFNpbmNlIHdlIGFyZSByZWFkaW5nIGZyb20gcHJldmlvdXMgc3RhdGUgd2hpY2ggaXMgbm90IHBvc3NpYmxlIHdpdGhcbiAgICAgICAgICAvLyBhdXRvbWF0aWMgYmF0Y2hpbmcgaW4gUmVhY3QgMTggaGVuY2UgdXNpbmcgZmx1c2ggc3luYyB0byBzeW5jaHJvbm91c2x5XG4gICAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZS4gQ2hlY2sgaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzU1MDggZm9yIG1vcmUgZGV0YWlscy5cblxuXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlOiByZXQucG9pbnRlckRvd25TdGF0ZSxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkUG9pbnRzSW5kaWNlczogcmV0LnNlbGVjdGVkUG9pbnRzSW5kaWNlc1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZTogcmV0LnBvaW50ZXJEb3duU3RhdGUsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IHJldC5zZWxlY3RlZFBvaW50c0luZGljZXNcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAobGluZWFyRWxlbWVudEVkaXRvci5wb2ludGVyRG93blN0YXRlLnNlZ21lbnRNaWRwb2ludC52YWx1ZSAhPT0gbnVsbCAmJiAhbGluZWFyRWxlbWVudEVkaXRvci5wb2ludGVyRG93blN0YXRlLnNlZ21lbnRNaWRwb2ludC5hZGRlZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRpZERyYWcgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50RHJhZ2dpbmcoZXZlbnQsIHRoaXMuc3RhdGUsIHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCAoZWxlbWVudCwgcG9pbnRzU2NlbmVDb29yZHMpID0+IHtcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdzRm9yTGluZWFyRWxlbWVudEF0Q29vcmRzKGVsZW1lbnQsIHBvaW50c1NjZW5lQ29vcmRzKTtcbiAgICAgICAgfSwgbGluZWFyRWxlbWVudEVkaXRvcik7XG5cbiAgICAgICAgaWYgKGRpZERyYWcpIHtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHBvaW50ZXJDb29yZHMueDtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgPSB0cnVlO1xuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICAgICAgaXNEcmFnZ2luZzogdHJ1ZVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgIGlzRHJhZ2dpbmc6IHRydWVcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNIaXRBU2VsZWN0ZWRFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuYWxsSGl0RWxlbWVudHMuc29tZShlbGVtZW50ID0+IHRoaXMuaXNBU2VsZWN0ZWRFbGVtZW50KGVsZW1lbnQpKTtcbiAgICAgIGNvbnN0IGlzU2VsZWN0aW5nUG9pbnRzSW5MaW5lRWRpdG9yID0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiBldmVudC5zaGlmdEtleSAmJiB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCA9PT0gKChfYSA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pZCk7XG5cbiAgICAgIGlmICgoaGFzSGl0QVNlbGVjdGVkRWxlbWVudCB8fCBwb2ludGVyRG93blN0YXRlLmhpdC5oYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cykgJiYgIWlzU2VsZWN0aW5nUG9pbnRzSW5MaW5lRWRpdG9yKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMuZXZlcnkoZWxlbWVudCA9PiBlbGVtZW50LmxvY2tlZCkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzSGFzQUZyYW1lID0gc2VsZWN0ZWRFbGVtZW50cy5maW5kKGUgPT4gaXNGcmFtZUVsZW1lbnQoZSkpO1xuICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyhwb2ludGVyQ29vcmRzKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZnJhbWVUb0hpZ2hsaWdodDogdG9wTGF5ZXJGcmFtZSAmJiAhc2VsZWN0ZWRFbGVtZW50c0hhc0FGcmFtZSA/IHRvcExheWVyRnJhbWUgOiBudWxsXG4gICAgICAgIH0pOyAvLyBNYXJraW5nIHRoYXQgY2xpY2sgd2FzIHVzZWQgZm9yIGRyYWdnaW5nIHRvIGNoZWNrXG4gICAgICAgIC8vIGlmIGVsZW1lbnRzIHNob3VsZCBiZSBkZXNlbGVjdGVkIG9uIHBvaW50ZXJ1cFxuXG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCA9IHRydWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IHRydWVcbiAgICAgICAgfSk7IC8vIHByZXZlbnQgZHJhZ2dpbmcgZXZlbiBpZiB3ZSdyZSBubyBsb25nZXIgaG9sZGluZyBjbWQvY3RybCBvdGhlcndpc2VcbiAgICAgICAgLy8gaXQgd291bGQgaGF2ZSB3ZWlyZCByZXN1bHRzIChzdHVmZiBqdW1waW5nIGFsbCBvdmVyIHRoZSBzY3JlZW4pXG4gICAgICAgIC8vIENoZWNraW5nIGZvciBlZGl0aW5nRWxlbWVudCB0byBhdm9pZCBqdW1wIHdoaWxlIGVkaXRpbmcgb24gbW9iaWxlICM2NTAzXG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID4gMCAmJiAhcG9pbnRlckRvd25TdGF0ZS53aXRoQ21kT3JDdHJsICYmICF0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgIT09IFwiYWN0aXZlXCIpIHtcbiAgICAgICAgICBjb25zdCBkcmFnT2Zmc2V0ID0ge1xuICAgICAgICAgICAgeDogcG9pbnRlckNvb3Jkcy54IC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCxcbiAgICAgICAgICAgIHk6IHBvaW50ZXJDb29yZHMueSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnlcbiAgICAgICAgICB9O1xuICAgICAgICAgIGNvbnN0IG9yaWdpbmFsRWxlbWVudHMgPSBbLi4ucG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLnZhbHVlcygpXTsgLy8gV2Ugb25seSBkcmFnIGluIG9uZSBkaXJlY3Rpb24gaWYgc2hpZnQgaXMgcHJlc3NlZFxuXG4gICAgICAgICAgY29uc3QgbG9ja0RpcmVjdGlvbiA9IGV2ZW50LnNoaWZ0S2V5O1xuXG4gICAgICAgICAgaWYgKGxvY2tEaXJlY3Rpb24pIHtcbiAgICAgICAgICAgIGNvbnN0IGRpc3RhbmNlWCA9IE1hdGguYWJzKGRyYWdPZmZzZXQueCk7XG4gICAgICAgICAgICBjb25zdCBkaXN0YW5jZVkgPSBNYXRoLmFicyhkcmFnT2Zmc2V0LnkpO1xuICAgICAgICAgICAgY29uc3QgbG9ja1ggPSBsb2NrRGlyZWN0aW9uICYmIGRpc3RhbmNlWCA8IGRpc3RhbmNlWTtcbiAgICAgICAgICAgIGNvbnN0IGxvY2tZID0gbG9ja0RpcmVjdGlvbiAmJiBkaXN0YW5jZVggPiBkaXN0YW5jZVk7XG5cbiAgICAgICAgICAgIGlmIChsb2NrWCkge1xuICAgICAgICAgICAgICBkcmFnT2Zmc2V0LnggPSAwO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAobG9ja1kpIHtcbiAgICAgICAgICAgICAgZHJhZ09mZnNldC55ID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIFNuYXAgY2FjaGUgKm11c3QqIGJlIHN5bmNocm9ub3VzbHkgcG9wdXBsYXRlZCBiZWZvcmUgaW5pdGlhbCBkcmFnLFxuICAgICAgICAgIC8vIG90aGVyd2lzZSB0aGUgZmlyc3QgZHJhZyBldmVuIHdpbGwgbm90IHNuYXAsIGNhdXNpbmcgYSBqdW1wIGJlZm9yZVxuICAgICAgICAgIC8vIGl0IHNuYXBzIHRvIGl0cyBwb3NpdGlvbiBpZiBwcmV2aW91c2x5IHNuYXBwZWQgYWxyZWFkeS5cblxuXG4gICAgICAgICAgdGhpcy5tYXliZUNhY2hlVmlzaWJsZUdhcHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgIHNuYXBPZmZzZXQsXG4gICAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgICB9ID0gc25hcERyYWdnZWRFbGVtZW50cyhnZXRTZWxlY3RlZEVsZW1lbnRzKG9yaWdpbmFsRWxlbWVudHMsIHRoaXMuc3RhdGUpLCBkcmFnT2Zmc2V0LCB0aGlzLnN0YXRlLCBldmVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgICB9KTsgLy8gd2hlbiB3ZSdyZSBlZGl0aW5nIHRoZSBuYW1lIG9mIGEgZnJhbWUsIHdlIHdhbnQgdGhlIHVzZXIgdG8gYmVcbiAgICAgICAgICAvLyBhYmxlIHRvIHNlbGVjdCBhbmQgaW50ZXJhY3Qgd2l0aCB0aGUgdGV4dCBpbnB1dFxuXG4gICAgICAgICAgIXRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lICYmIGRyYWdTZWxlY3RlZEVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUsIHNlbGVjdGVkRWxlbWVudHMsIGRyYWdPZmZzZXQsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUsIHNuYXBPZmZzZXQsIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKTsgLy8gV2UgZHVwbGljYXRlIHRoZSBzZWxlY3RlZCBlbGVtZW50IGlmIGFsdCBpcyBwcmVzc2VkIG9uIHBvaW50ZXIgbW92ZVxuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQpIHtcbiAgICAgICAgICAgIC8vIE1vdmUgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBlbGVtZW50cyB0byB0aGUgdG9wIG9mIHRoZSB6IGluZGV4IHN0YWNrLCBhbmRcbiAgICAgICAgICAgIC8vIHB1dCB0aGUgZHVwbGljYXRlcyB3aGVyZSB0aGUgc2VsZWN0ZWQgZWxlbWVudHMgdXNlZCB0byBiZS5cbiAgICAgICAgICAgIC8vICh0aGUgb3JpZ2luIHBvaW50IHdoZXJlIHRoZSBkcmFnZ2luZyBzdGFydGVkKVxuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29uc3QgbmV4dEVsZW1lbnRzID0gW107XG4gICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvQXBwZW5kID0gW107XG4gICAgICAgICAgICBjb25zdCBncm91cElkTWFwID0gbmV3IE1hcCgpO1xuICAgICAgICAgICAgY29uc3Qgb2xkSWRUb0R1cGxpY2F0ZWRJZCA9IG5ldyBNYXAoKTtcbiAgICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuICAgICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50SWRzID0gbmV3IFNldCh0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzLFxuICAgICAgICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZSxcbiAgICAgICAgICAgICAgaW5jbHVkZUVsZW1lbnRzSW5GcmFtZXM6IHRydWVcbiAgICAgICAgICAgIH0pLm1hcChlbGVtZW50ID0+IGVsZW1lbnQuaWQpKTtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRJZHMuaGFzKGVsZW1lbnQuaWQpIHx8IC8vIGNhc2U6IHRoZSBzdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMgbWlnaHQgbm90IGhhdmUgYmVlblxuICAgICAgICAgICAgICAvLyB1cGRhdGVkIHlldCBieSB0aGUgdGltZSB0aGlzIG1vdXNlbW92ZSBldmVudCBpcyBmaXJlZFxuICAgICAgICAgICAgICBlbGVtZW50LmlkID09PSAoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmlkKSAmJiBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZHVwbGljYXRlZEVsZW1lbnQgPSBkdXBsaWNhdGVFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQsIGdyb3VwSWRNYXAsIGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IG9yaWdFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLmdldChlbGVtZW50LmlkKTtcbiAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGR1cGxpY2F0ZWRFbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICB4OiBvcmlnRWxlbWVudC54LFxuICAgICAgICAgICAgICAgICAgeTogb3JpZ0VsZW1lbnQueVxuICAgICAgICAgICAgICAgIH0pOyAvLyBwdXQgZHVwbGljYXRlZCBlbGVtZW50IHRvIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50c1xuICAgICAgICAgICAgICAgIC8vIHNvIHRoYXQgd2UgY2FuIHNuYXAgdG8gdGhlIGR1cGxpY2F0ZWQgZWxlbWVudCB3aXRob3V0IHJlbGVhc2luZ1xuXG4gICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLnNldChkdXBsaWNhdGVkRWxlbWVudC5pZCwgZHVwbGljYXRlZEVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIG5leHRFbGVtZW50cy5wdXNoKGR1cGxpY2F0ZWRFbGVtZW50KTtcbiAgICAgICAgICAgICAgICBlbGVtZW50c1RvQXBwZW5kLnB1c2goZWxlbWVudCk7XG4gICAgICAgICAgICAgICAgb2xkSWRUb0R1cGxpY2F0ZWRJZC5zZXQoZWxlbWVudC5pZCwgZHVwbGljYXRlZEVsZW1lbnQuaWQpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG5leHRFbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IG5leHRTY2VuZUVsZW1lbnRzID0gWy4uLm5leHRFbGVtZW50cywgLi4uZWxlbWVudHNUb0FwcGVuZF07XG4gICAgICAgICAgICBiaW5kVGV4dFRvU2hhcGVBZnRlckR1cGxpY2F0aW9uKG5leHRFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCk7XG4gICAgICAgICAgICBmaXhCaW5kaW5nc0FmdGVyRHVwbGljYXRpb24obmV4dFNjZW5lRWxlbWVudHMsIGVsZW1lbnRzVG9BcHBlbmQsIG9sZElkVG9EdXBsaWNhdGVkSWQsIFwiZHVwbGljYXRlc1NlcnZlQXNPbGRcIik7XG4gICAgICAgICAgICBiaW5kRWxlbWVudHNUb0ZyYW1lc0FmdGVyRHVwbGljYXRpb24obmV4dFNjZW5lRWxlbWVudHMsIGVsZW1lbnRzVG9BcHBlbmQsIG9sZElkVG9EdXBsaWNhdGVkSWQpO1xuICAgICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dFNjZW5lRWxlbWVudHMpO1xuICAgICAgICAgICAgdGhpcy5tYXliZUNhY2hlVmlzaWJsZUdhcHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMsIHRydWUpO1xuICAgICAgICAgICAgdGhpcy5tYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgdHJ1ZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IC8vIEl0IGlzIHZlcnkgaW1wb3J0YW50IHRvIHJlYWQgdGhpcy5zdGF0ZSB3aXRoaW4gZWFjaCBtb3ZlIGV2ZW50LFxuICAgICAgLy8gb3RoZXJ3aXNlIHdlIHdvdWxkIHJlYWQgYSBzdGFsZSBvbmUhXG5cblxuICAgICAgY29uc3QgZHJhZ2dpbmdFbGVtZW50ID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQ7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgY29uc3QgZHggPSBwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgY29uc3QgZHkgPSBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcbiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9pbnRzLmxlbmd0aCA+IDAgJiYgcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXTtcbiAgICAgICAgY29uc3QgZGlzY2FyZFBvaW50ID0gbGFzdFBvaW50ICYmIGxhc3RQb2ludFswXSA9PT0gZHggJiYgbGFzdFBvaW50WzFdID09PSBkeTtcblxuICAgICAgICBpZiAoIWRpc2NhcmRQb2ludCkge1xuICAgICAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGRyYWdnaW5nRWxlbWVudC5zaW11bGF0ZVByZXNzdXJlID8gZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcyA6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucHJlc3N1cmVzLCBldmVudC5wcmVzc3VyZV07XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dLFxuICAgICAgICAgICAgcHJlc3N1cmVzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoaXNMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgbGV0IGR4ID0gZ3JpZFggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgbGV0IGR5ID0gZ3JpZFkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcblxuICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpICYmIHBvaW50cy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICAoe1xuICAgICAgICAgICAgd2lkdGg6IGR4LFxuICAgICAgICAgICAgaGVpZ2h0OiBkeVxuICAgICAgICAgIH0gPSBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUoZHJhZ2dpbmdFbGVtZW50LngsIGRyYWdnaW5nRWxlbWVudC55LCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBvaW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLCBbZHgsIGR5XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cy5zbGljZSgwLCAtMSksIFtkeCwgZHldXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgICAgICAvLyBXaGVuIGNyZWF0aW5nIGEgbGluZWFyIGVsZW1lbnQgYnkgZHJhZ2dpbmdcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdzRm9yTGluZWFyRWxlbWVudEF0Q29vcmRzKGRyYWdnaW5nRWxlbWVudCwgW3BvaW50ZXJDb29yZHNdLCB0aGlzLnN0YXRlLnN0YXJ0Qm91bmRFbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuICAgICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuYm94U2VsZWN0aW9uLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpOyAvLyBib3gtc2VsZWN0IGxpbmUgZWRpdG9yIHBvaW50c1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVCb3hTZWxlY3Rpb24oZXZlbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKSk7IC8vIHJlZ3VsYXIgYm94LXNlbGVjdFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxldCBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IHRydWU7XG5cbiAgICAgICAgICBpZiAoIWV2ZW50LnNoaWZ0S2V5ICYmIGlzU29tZUVsZW1lbnRTZWxlY3RlZChlbGVtZW50cywgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLndpdGhDbWRPckN0cmwgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgICAgW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uID0gZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24oZWxlbWVudHMsIGRyYWdnaW5nRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2hvdWxkUmV1c2VTZWxlY3Rpb24gJiYgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgIGFjY1tlbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgICAgIHJldHVybiBhY2M7XG4gICAgICAgICAgICB9LCB7fSkpO1xuXG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICAvLyBpZiB1c2luZyBjdHJsL2NtZCwgc2VsZWN0IHRoZSBoaXRFbGVtZW50IG9ubHkgaWYgd2VcbiAgICAgICAgICAgICAgLy8gaGF2ZW4ndCBib3gtc2VsZWN0ZWQgYW55dGhpbmcgZWxzZVxuICAgICAgICAgICAgICBpZiAoIWVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudC5pZF0gPSB0cnVlO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXZTdGF0ZSA9ICFzaG91bGRSZXVzZVNlbGVjdGlvbiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGxcbiAgICAgICAgICAgIH0pIDogcHJldlN0YXRlO1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dFNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgLy8gc2VsZWN0IGxpbmVhciBlbGVtZW50IG9ubHkgd2hlbiB3ZSBoYXZlbid0IGJveC1zZWxlY3RlZCBhbnl0aGluZyBlbHNlXG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24ubGVuZ3RoID09PSAxICYmIGlzTGluZWFyRWxlbWVudChlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSwgdGhpcy5zY2VuZSkgOiBudWxsLFxuICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCA9PT0gMSAmJiAoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0ubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdKSkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9IC8vIFJldHVybnMgd2hldGhlciB0aGUgcG9pbnRlciBtb3ZlIGhhcHBlbmVkIG92ZXIgZWl0aGVyIHNjcm9sbGJhclxuXG5cbiAgaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSkge1xuICAgIGlmIChwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVySG9yaXpvbnRhbCkge1xuICAgICAgY29uc3QgeCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICBjb25zdCBkeCA9IHggLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueDtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYIC0gZHggLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSB4O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJWZXJ0aWNhbCkge1xuICAgICAgY29uc3QgeSA9IGV2ZW50LmNsaWVudFk7XG4gICAgICBjb25zdCBkeSA9IHkgLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueTtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZIC0gZHkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSB5O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgb25Qb2ludGVyVXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGNoaWxkRXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2Y7XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSkge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZS5mbHVzaCgpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIGRyYWdnaW5nRWxlbWVudCxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50LFxuICAgICAgICBtdWx0aUVsZW1lbnQsXG4gICAgICAgIGFjdGl2ZVRvb2wsXG4gICAgICAgIGlzUmVzaXppbmcsXG4gICAgICAgIGlzUm90YXRpbmdcbiAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzUmVzaXppbmc6IGZhbHNlLFxuICAgICAgICBpc1JvdGF0aW5nOiBmYWxzZSxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50OiBudWxsLFxuICAgICAgICBzZWxlY3Rpb25FbGVtZW50OiBudWxsLFxuICAgICAgICBmcmFtZVRvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIixcbiAgICAgICAgLy8gdGV4dCBlbGVtZW50cyBhcmUgcmVzZXQgb24gZmluYWxpemUsIGFuZCByZXNldHRpbmcgb24gcG9pbnRlcnVwXG4gICAgICAgIC8vIG1heSBjYXVzZSBpc3N1ZXMgd2l0aCBkb3VibGUgdGFwc1xuICAgICAgICBlZGl0aW5nRWxlbWVudDogbXVsdGlFbGVtZW50IHx8IGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPyB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50IDogbnVsbCxcbiAgICAgICAgc25hcExpbmVzOiBbXSxcbiAgICAgICAgb3JpZ2luU25hcE9mZnNldDogbnVsbFxuICAgICAgfSk7XG4gICAgICBTbmFwQ2FjaGUuc2V0UmVmZXJlbmNlU25hcFBvaW50cyhudWxsKTtcbiAgICAgIFNuYXBDYWNoZS5zZXRWaXNpYmxlR2FwcyhudWxsKTtcbiAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoY2hpbGRFdmVudC5jbGllbnRYLCBjaGlsZEV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogZmFsc2VcbiAgICAgIH0pOyAvLyBIYW5kbGUgZW5kIG9mIGRyYWdnaW5nIGEgcG9pbnQgb2YgYSBsaW5lYXIgZWxlbWVudCwgbWlnaHQgY2xvc2UgYSBsb29wXG4gICAgICAvLyBhbmQgc2V0cyBiaW5kaW5nIGVsZW1lbnRcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmJveFNlbGVjdGlvbi5oYXNPY2N1cnJlZCAmJiAoKF9iID0gKF9hID0gcG9pbnRlckRvd25TdGF0ZS5oaXQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuaWQpICE9PSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCkge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBlZGl0aW5nTGluZWFyRWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlclVwKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgICAgaWYgKGVkaXRpbmdMaW5lYXJFbGVtZW50ICE9PSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQsXG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgIGlmICgoKF9kID0gKF9jID0gcG9pbnRlckRvd25TdGF0ZS5oaXQpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5lbGVtZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuaWQpICE9PSB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5lbGVtZW50SWQpIHtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVMZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpOyAvLyBzZXQgc2VsZWN0ZWRMaW5lYXJFbGVtZW50IHRvIG51bGwgaWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSBlbGVtZW50IHNlbGVjdGVkIHNpbmNlIHdlIGRvbid0IHdhbnQgdG8gc2hvdyBsaW5lYXIgZWxlbWVudCBoYW5kbGVzXG5cbiAgICAgICAgICBpZiAoc2VsZWN0ZWRFTGVtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBudWxsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudEVkaXRvciA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlclVwKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICBjb25zdCB7XG4gICAgICAgICAgICBzdGFydEJpbmRpbmdFbGVtZW50LFxuICAgICAgICAgICAgZW5kQmluZGluZ0VsZW1lbnRcbiAgICAgICAgICB9ID0gbGluZWFyRWxlbWVudEVkaXRvcjtcbiAgICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KGxpbmVhckVsZW1lbnRFZGl0b3IuZWxlbWVudElkKTtcblxuICAgICAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgICBiaW5kT3JVbmJpbmRMaW5lYXJFbGVtZW50KGVsZW1lbnQsIHN0YXJ0QmluZGluZ0VsZW1lbnQsIGVuZEJpbmRpbmdFbGVtZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAobGluZWFyRWxlbWVudEVkaXRvciAhPT0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgbGluZWFyRWxlbWVudEVkaXRvciksIHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IG51bGxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSk7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uVXApO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbktleURvd24pO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlVcCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMub25Qb2ludGVyVXBFbWl0dGVyLnRyaWdnZXIodGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlLCBjaGlsZEV2ZW50KTtcblxuICAgICAgaWYgKChkcmFnZ2luZ0VsZW1lbnQgPT09IG51bGwgfHwgZHJhZ2dpbmdFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBkcmFnZ2luZ0VsZW1lbnQudHlwZSkgPT09IFwiZnJlZWRyYXdcIikge1xuICAgICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBwb2ludHMgPSBkcmFnZ2luZ0VsZW1lbnQucG9pbnRzO1xuICAgICAgICBsZXQgZHggPSBwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgbGV0IGR5ID0gcG9pbnRlckNvb3Jkcy55IC0gZHJhZ2dpbmdFbGVtZW50Lnk7IC8vIEFsbG93cyBkb3RzIHRvIGF2b2lkIGJlaW5nIGZsYWdnZWQgYXMgaW5maW5pdGVseSBzbWFsbFxuXG4gICAgICAgIGlmIChkeCA9PT0gcG9pbnRzWzBdWzBdICYmIGR5ID09PSBwb2ludHNbMF1bMV0pIHtcbiAgICAgICAgICBkeSArPSAwLjAwMDE7XG4gICAgICAgICAgZHggKz0gMC4wMDAxO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcHJlc3N1cmVzID0gZHJhZ2dpbmdFbGVtZW50LnNpbXVsYXRlUHJlc3N1cmUgPyBbXSA6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucHJlc3N1cmVzLCBjaGlsZEV2ZW50LnByZXNzdXJlXTtcbiAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtkeCwgZHldXSxcbiAgICAgICAgICBwcmVzc3VyZXMsXG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50OiBbZHgsIGR5XVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0ltYWdlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpKSB7XG4gICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IGRyYWdnaW5nRWxlbWVudDtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlRGltZW5zaW9ucyhpbWFnZUVsZW1lbnQpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICAgIFtpbWFnZUVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICB9LCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbHRlcihlbCA9PiBlbC5pZCAhPT0gaW1hZ2VFbGVtZW50LmlkKSk7XG4gICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC5wb2ludHMubGVuZ3RoID4gMSkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoY2hpbGRFdmVudCwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgZHJhZ2dpbmdFbGVtZW50ICYmICFtdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4uZHJhZ2dpbmdFbGVtZW50LnBvaW50cywgW3BvaW50ZXJDb29yZHMueCAtIGRyYWdnaW5nRWxlbWVudC54LCBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueV1dXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBtdWx0aUVsZW1lbnQ6IGRyYWdnaW5nRWxlbWVudCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiAhbXVsdGlFbGVtZW50KSB7XG4gICAgICAgICAgaWYgKGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgJiYgaXNCaW5kaW5nRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgICAgICAgbWF5YmVCaW5kTGluZWFyRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUsIHBvaW50ZXJDb29yZHMpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdLFxuICAgICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IG51bGxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmICghYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgICBhY3RpdmVUb29sOiB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgICBbZHJhZ2dpbmdFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9KSwgcHJldlN0YXRlKSxcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc2NlbmUpXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbFxuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiAmJiBkcmFnZ2luZ0VsZW1lbnQgJiYgaXNJbnZpc2libHlTbWFsbEVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSkge1xuICAgICAgICAvLyByZW1vdmUgaW52aXNpYmxlIGVsZW1lbnQgd2hpY2ggd2FzIGFkZGVkIGluIG9uUG9pbnRlckRvd25cbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5maWx0ZXIoZWwgPT4gZWwuaWQgIT09IGRyYWdnaW5nRWxlbWVudC5pZCkpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudCkge1xuICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkKSB7XG4gICAgICAgICAgY29uc3Qgc2NlbmVDb29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoY2hpbGRFdmVudCwgdGhpcy5zdGF0ZSk7IC8vIHdoZW4gZWRpdGluZyB0aGUgcG9pbnRzIG9mIGEgbGluZWFyIGVsZW1lbnQsIHdlIGNoZWNrIGlmIHRoZVxuICAgICAgICAgIC8vIGxpbmVhciBlbGVtZW50IHN0aWxsIGlzIGluIHRoZSBmcmFtZSBhZnRlcndhcmRzXG4gICAgICAgICAgLy8gaWYgbm90LCB0aGUgbGluZWFyIGVsZW1lbnQgd2lsbCBiZSByZW1vdmVkIGZyb20gaXRzIGZyYW1lIChpZiBhbnkpXG5cbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQgJiYgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5lbGVtZW50SWQpO1xuXG4gICAgICAgICAgICBpZiAobGluZWFyRWxlbWVudCA9PT0gbnVsbCB8fCBsaW5lYXJFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBsaW5lYXJFbGVtZW50LmZyYW1lSWQpIHtcbiAgICAgICAgICAgICAgY29uc3QgZnJhbWUgPSBnZXRDb250YWluaW5nRnJhbWUobGluZWFyRWxlbWVudCk7XG5cbiAgICAgICAgICAgICAgaWYgKGZyYW1lICYmIGxpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWVsZW1lbnRPdmVybGFwc1dpdGhGcmFtZShsaW5lYXJFbGVtZW50LCBmcmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgbGluZWFyIGVsZW1lbnQgZnJvbSBhbGwgZ3JvdXBzXG4gICAgICAgICAgICAgICAgICAvLyBiZWZvcmUgcmVtb3ZpbmcgaXQgZnJvbSB0aGUgZnJhbWUgYXMgd2VsbFxuICAgICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChsaW5lYXJFbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICAgIGdyb3VwSWRzOiBbXVxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhyZW1vdmVFbGVtZW50c0Zyb21GcmFtZSh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBbbGluZWFyRWxlbWVudF0sIHRoaXMuc3RhdGUpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdXBkYXRlIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gc2VsZWN0ZWQgZWxlbWVudHMgYW5kIGZyYW1lc1xuICAgICAgICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoc2NlbmVDb29yZHMpO1xuICAgICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgICAgICAgIGxldCBuZXh0RWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuXG4gICAgICAgICAgICBjb25zdCB1cGRhdGVHcm91cElkc0FmdGVyRWRpdGluZ0dyb3VwID0gZWxlbWVudHMgPT4ge1xuICAgICAgICAgICAgICBpZiAoZWxlbWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgICAgICAgICAgY29uc3QgaW5kZXggPSBlbGVtZW50Lmdyb3VwSWRzLmluZGV4T2YodGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCk7XG4gICAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZHM6IGVsZW1lbnQuZ3JvdXBJZHMuc2xpY2UoMCwgaW5kZXgpXG4gICAgICAgICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC5ncm91cElkcy5sZW5ndGggJiYgZ2V0RWxlbWVudHNJbkdyb3VwKG5leHRFbGVtZW50cywgZWxlbWVudC5ncm91cElkc1tlbGVtZW50Lmdyb3VwSWRzLmxlbmd0aCAtIDFdKS5sZW5ndGggPCAyKSB7XG4gICAgICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWRzOiBbXVxuICAgICAgICAgICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAodG9wTGF5ZXJGcmFtZSAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdG9wTGF5ZXJGcmFtZS5pZF0pIHtcbiAgICAgICAgICAgICAgY29uc3QgZWxlbWVudHNUb0FkZCA9IHNlbGVjdGVkRWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC5mcmFtZUlkICE9PSB0b3BMYXllckZyYW1lLmlkICYmIGlzRWxlbWVudEluRnJhbWUoZWxlbWVudCwgbmV4dEVsZW1lbnRzLCB0aGlzLnN0YXRlKSk7XG5cbiAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICB1cGRhdGVHcm91cElkc0FmdGVyRWRpdGluZ0dyb3VwKGVsZW1lbnRzVG9BZGQpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzID0gYWRkRWxlbWVudHNUb0ZyYW1lKG5leHRFbGVtZW50cywgZWxlbWVudHNUb0FkZCwgdG9wTGF5ZXJGcmFtZSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCF0b3BMYXllckZyYW1lKSB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZWxlbWVudHNUb1JlbW92ZSA9IHNlbGVjdGVkRWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC5mcmFtZUlkICYmICFpc0VsZW1lbnRJbkZyYW1lKGVsZW1lbnQsIG5leHRFbGVtZW50cywgdGhpcy5zdGF0ZSkpO1xuICAgICAgICAgICAgICAgIHVwZGF0ZUdyb3VwSWRzQWZ0ZXJFZGl0aW5nR3JvdXAoZWxlbWVudHNUb1JlbW92ZSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbmV4dEVsZW1lbnRzID0gdXBkYXRlRnJhbWVNZW1iZXJzaGlwT2ZTZWxlY3RlZEVsZW1lbnRzKG5leHRFbGVtZW50cywgdGhpcy5zdGF0ZSwgdGhpcyk7XG4gICAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0RWxlbWVudHMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudHNJbnNpZGVGcmFtZSA9IGdldEVsZW1lbnRzSW5OZXdGcmFtZSh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBkcmFnZ2luZ0VsZW1lbnQpO1xuICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGFkZEVsZW1lbnRzVG9GcmFtZSh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBlbGVtZW50c0luc2lkZUZyYW1lLCBkcmFnZ2luZ0VsZW1lbnQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBnZXROb3JtYWxpemVkRGltZW5zaW9ucyhkcmFnZ2luZ0VsZW1lbnQpKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHJlc2l6aW5nRWxlbWVudCkge1xuICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChyZXNpemluZ0VsZW1lbnQgJiYgaXNJbnZpc2libHlTbWFsbEVsZW1lbnQocmVzaXppbmdFbGVtZW50KSkge1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbHRlcihlbCA9PiBlbC5pZCAhPT0gcmVzaXppbmdFbGVtZW50LmlkKSk7XG4gICAgICB9IC8vIGhhbmRsZSBmcmFtZSBtZW1iZXJzaGlwIGZvciByZXNpemluZyBmcmFtZXMgYW5kL29yIHNlbGVjdGVkIGVsZW1lbnRzXG5cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmlzUmVzaXppbmcpIHtcbiAgICAgICAgbGV0IG5leHRFbGVtZW50cyA9IHVwZGF0ZUZyYW1lTWVtYmVyc2hpcE9mU2VsZWN0ZWRFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzLnN0YXRlLCB0aGlzKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRGcmFtZXMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSkuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuXG4gICAgICAgIGZvciAoY29uc3QgZnJhbWUgb2Ygc2VsZWN0ZWRGcmFtZXMpIHtcbiAgICAgICAgICBuZXh0RWxlbWVudHMgPSByZXBsYWNlQWxsRWxlbWVudHNJbkZyYW1lKG5leHRFbGVtZW50cywgZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZnJhbWUsIHRoaXMuc3RhdGUpLCBmcmFtZSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0RWxlbWVudHMpO1xuICAgICAgfSAvLyBDb2RlIGJlbG93IGhhbmRsZXMgc2VsZWN0aW9uIHdoZW4gZWxlbWVudChzKSB3ZXJlbid0XG4gICAgICAvLyBkcmFnIG9yIGFkZGVkIHRvIHNlbGVjdGlvbiBvbiBwb2ludGVyIGRvd24gcGhhc2UuXG5cblxuICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQ7XG5cbiAgICAgIGlmICgoKF9lID0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5lbGVtZW50SWQpICE9PSAoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmlkKSAmJiBpc0xpbmVhckVsZW1lbnQoaGl0RWxlbWVudCkpIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFTGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTsgLy8gc2V0IHNlbGVjdGVkTGluZWFyRWxlbWVudCB3aGVuIG5vIG90aGVyIGVsZW1lbnQgc2VsZWN0ZWQgZXhjZXB0XG4gICAgICAgIC8vIHRoZSBvbmUgd2UndmUgaGl0XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRUxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKGhpdEVsZW1lbnQsIHRoaXMuc2NlbmUpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIGNvbnN0IGRyYWdnZWREaXN0YW5jZSA9IGRpc3RhbmNlMmQodGhpcy5sYXN0UG9pbnRlckRvd25FdmVudC5jbGllbnRYLCB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50LmNsaWVudFksIHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LmNsaWVudFkpO1xuXG4gICAgICAgIGlmIChkcmFnZ2VkRGlzdGFuY2UgPT09IDApIHtcbiAgICAgICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgY2xpZW50WDogdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WCxcbiAgICAgICAgICAgIGNsaWVudFk6IHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LmNsaWVudFlcbiAgICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICBjb25zdCBoaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICAgICAgaGl0RWxlbWVudHMuZm9yRWFjaChoaXRFbGVtZW50ID0+IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbaGl0RWxlbWVudC5pZF0gPSB7XG4gICAgICAgICAgICBlcmFzZTogdHJ1ZSxcbiAgICAgICAgICAgIG9wYWNpdHk6IGhpdEVsZW1lbnQub3BhY2l0eVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lcmFzZUVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2UpLmxlbmd0aCkge1xuICAgICAgICB0aGlzLnJlc3RvcmVSZWFkeVRvRXJhc2VFbGVtZW50cyhwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgIXBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQud2FzQWRkZWRUb1NlbGVjdGlvbiAmJiAoIC8vIGlmIHdlJ3JlIGVkaXRpbmcgYSBsaW5lLCBwb2ludGVydXAgc2hvdWxkbid0IHN3aXRjaCBzZWxlY3Rpb24gaWZcbiAgICAgIC8vIGJveCBzZWxlY3RlZFxuICAgICAgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgIXBvaW50ZXJEb3duU3RhdGUuYm94U2VsZWN0aW9uLmhhc09jY3VycmVkKSkge1xuICAgICAgICAvLyB3aGVuIGluc2lkZSBsaW5lIGVkaXRvciwgc2hpZnQgc2VsZWN0cyBwb2ludHMgaW5zdGVhZFxuICAgICAgICBpZiAoY2hpbGRFdmVudC5zaGlmdEtleSAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgaWYgKGlzU2VsZWN0ZWRWaWFHcm91cCh0aGlzLnN0YXRlLCBoaXRFbGVtZW50KSkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKF9wcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBfcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7IC8vIFdlIHdhbnQgdG8gdW5zZWxlY3QgYWxsIGdyb3VwcyBoaXRFbGVtZW50IGlzIHBhcnQgb2ZcbiAgICAgICAgICAgICAgICAvLyBhcyB3ZWxsIGFzIGFsbCBlbGVtZW50cyB0aGF0IGFyZSBwYXJ0IG9mIHRoZSBncm91cHNcbiAgICAgICAgICAgICAgICAvLyBoaXRFbGVtZW50IGlzIHBhcnQgb2ZcblxuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZ3JvdXBlZEVsZW1lbnQgb2YgaGl0RWxlbWVudC5ncm91cElkcy5mbGF0TWFwKGdyb3VwSWQgPT4gZ2V0RWxlbWVudHNJbkdyb3VwKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGdyb3VwSWQpKSkge1xuICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZ3JvdXBlZEVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIF9wcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwgaGl0RWxlbWVudC5ncm91cElkcy5tYXAoZ0lkID0+ICh7XG4gICAgICAgICAgICAgICAgICAgIFtnSWRdOiBmYWxzZVxuICAgICAgICAgICAgICAgICAgfSkpLnJlZHVjZSgocHJldiwgYWNjKSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXYpLCBhY2MpLCB7fSkpLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRFbGVtZW50SWRzLCBfcHJldlN0YXRlKVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIH0pOyAvLyBpZiBub3QgZ3JhZ2dpbmcgYSBsaW5lYXIgZWxlbWVudCBwb2ludCAob3V0c2lkZSBlZGl0b3IpXG4gICAgICAgICAgICB9IGVsc2UgaWYgKCEoKF9mID0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5pc0RyYWdnaW5nKSkge1xuICAgICAgICAgICAgICAvLyByZW1vdmUgZWxlbWVudCBmcm9tIHNlbGVjdGlvbiB3aGlsZVxuICAgICAgICAgICAgICAvLyBrZWVwaW5nIHByZXYgZWxlbWVudHMgc2VsZWN0ZWRcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5ld1NlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXdTZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgY29uc3QgbmV3U2VsZWN0ZWRFbGVtZW50cyA9IGdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwge1xuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXdTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5ld1NlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgICAgICAvLyBzZXQgc2VsZWN0ZWRMaW5lYXJFbGVtZW50IG9ubHkgaWYgdGhhdHMgdGhlIG9ubHkgZWxlbWVudCBzZWxlY3RlZFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBuZXdTZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQobmV3U2VsZWN0ZWRFbGVtZW50c1swXSkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihuZXdTZWxlY3RlZEVsZW1lbnRzWzBdLCB0aGlzLnNjZW5lKSA6IHByZXZTdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnRcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChoaXRFbGVtZW50LmZyYW1lSWQgJiYgdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5mcmFtZUlkXSkge1xuICAgICAgICAgICAgLy8gd2hlbiBoaXRFbGVtZW50IGlzIHBhcnQgb2YgYSBzZWxlY3RlZCBmcmFtZSwgZGVzZWxlY3QgdGhlIGZyYW1lXG4gICAgICAgICAgICAvLyB0byBhdm9pZCBmcmFtZSBhbmQgY29udGFpbmluZyBlbGVtZW50cyBzZWxlY3RlZCBzaW11bHRhbmVvdXNseVxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgICAgW2hpdEVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH0pOyAvLyBkZXNlbGVjdCB0aGUgZnJhbWVcblxuICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmZyYW1lSWRdOyAvLyBkZXNlbGVjdCBncm91cHMgY29udGFpbmluZyB0aGUgZnJhbWVcblxuICAgICAgICAgICAgICAoKF9iID0gKF9hID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KGhpdEVsZW1lbnQuZnJhbWVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5ncm91cElkcykgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogW10pLmZsYXRNYXAoZ2lkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBnaWQpKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpID8gXCJpbmZvXCIgOiBmYWxzZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBhZGQgZWxlbWVudCB0byBzZWxlY3Rpb24gd2hpbGUga2VlcGluZyBwcmV2IGVsZW1lbnRzIHNlbGVjdGVkXG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKF9wcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIF9wcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9KSwgX3ByZXZTdGF0ZSlcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgdmFyIF9hO1xuXG4gICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgW2hpdEVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogaXNMaW5lYXJFbGVtZW50KGhpdEVsZW1lbnQpICYmIC8vIERvbid0IHNldCBgc2VsZWN0ZWRMaW5lYXJFbGVtZW50YCBpZiBpdHMgc2FtZSBhcyB0aGUgaGl0RWxlbWVudCwgdGhpcyBpcyBtYWlubHkgdG8gcHJldmVudCByZXNldHRpbmcgdGhlIGBob3ZlclBvaW50SW5kZXhgIHRvIC0xLlxuICAgICAgICAgICAgICAvLyBGdXR1cmUgd2Ugc2hvdWxkIHVwZGF0ZSB0aGUgQVBJIHRvIHRha2UgY2FyZSBvZiBzZXR0aW5nIHRoZSBjb3JyZWN0IGBob3ZlclBvaW50SW5kZXhgIHdoZW4gaW5pdGlhbGl6ZWRcbiAgICAgICAgICAgICAgKChfYSA9IHByZXZTdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50SWQpICE9PSBoaXRFbGVtZW50LmlkID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoaGl0RWxlbWVudCwgdGhpcy5zY2VuZSkgOiBwcmV2U3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIXBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiAhdGhpcy5zdGF0ZS5pc1Jlc2l6aW5nICYmIChoaXRFbGVtZW50ICYmIGlzSGl0dGluZ0VsZW1lbnRCb3VuZGluZ0JveFdpdGhvdXRIaXR0aW5nRWxlbWVudChoaXRFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSB8fCAhaGl0RWxlbWVudCAmJiBwb2ludGVyRG93blN0YXRlLmhpdC5oYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cykpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50OiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRGVzZWxlY3Qgc2VsZWN0ZWQgZWxlbWVudHNcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKCFhY3RpdmVUb29sLmxvY2tlZCAmJiBhY3RpdmVUb29sLnR5cGUgIT09IFwiZnJlZWRyYXdcIiAmJiBkcmFnZ2luZ0VsZW1lbnQgJiYgZHJhZ2dpbmdFbGVtZW50LnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgIFtkcmFnZ2luZ0VsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgfSksIHByZXZTdGF0ZSksXG4gICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBpc0VtYmVkZGFibGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgJiYgIWRyYWdnaW5nRWxlbWVudC5saW5rID8gXCJlZGl0b3JcIiA6IHByZXZTdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXBcbiAgICAgICAgfSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiIHx8IGlzU29tZUVsZW1lbnRTZWxlY3RlZCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlKSkge1xuICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgfHwgaXNSZXNpemluZyB8fCBpc1JvdGF0aW5nKSB7XG4gICAgICAgIChpc0JpbmRpbmdFbmFibGVkKHRoaXMuc3RhdGUpID8gYmluZE9yVW5iaW5kU2VsZWN0ZWRFbGVtZW50cyA6IHVuYmluZExpbmVhckVsZW1lbnRzKSh0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyLmVuZFBhdGgoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWFjdGl2ZVRvb2wubG9ja2VkICYmIGFjdGl2ZVRvb2wudHlwZSAhPT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdLFxuICAgICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQgJiYgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCAmJiB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC50aW1lU3RhbXAgLSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50LnRpbWVTdGFtcCA8IDMwMCAmJiBnZXN0dXJlLnBvaW50ZXJzLnNpemUgPD0gMSAmJiBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpICYmIHRoaXMuaXNFbWJlZGRhYmxlQ2VudGVyKGhpdEVsZW1lbnQsIHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSkge1xuICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayhoaXRFbGVtZW50KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIG1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cykge1xuICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDUwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgc3VnZ2VzdGVkQmluZGluZ3MgPSBnZXRFbGlnaWJsZUVsZW1lbnRzRm9yQmluZGluZyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzXG4gICAgfSk7XG4gIH1cblxuICBjbGVhclNlbGVjdGlvbihoaXRFbGVtZW50KSB7XG4gICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHByZXZTdGF0ZSksXG4gICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsLFxuICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAvLyBDb250aW51ZSBlZGl0aW5nIHRoZSBzYW1lIGdyb3VwIGlmIHRoZSB1c2VyIHNlbGVjdGVkIGEgZGlmZmVyZW50XG4gICAgICAvLyBlbGVtZW50IGZyb20gaXRcbiAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQgJiYgaGl0RWxlbWVudCAhPSBudWxsICYmIGlzRWxlbWVudEluR3JvdXAoaGl0RWxlbWVudCwgcHJldlN0YXRlLmVkaXRpbmdHcm91cElkKSA/IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCA6IG51bGxcbiAgICB9KSk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGwsXG4gICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczogdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNcbiAgICB9KTtcbiAgfVxuXG4gIGdldFRleHRXeXNpd3lnU25hcHBlZFRvQ2VudGVyUG9zaXRpb24oeCwgeSwgYXBwU3RhdGUsIGNvbnRhaW5lcikge1xuICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgIGxldCBlbGVtZW50Q2VudGVyWCA9IGNvbnRhaW5lci54ICsgY29udGFpbmVyLndpZHRoIC8gMjtcbiAgICAgIGxldCBlbGVtZW50Q2VudGVyWSA9IGNvbnRhaW5lci55ICsgY29udGFpbmVyLmhlaWdodCAvIDI7XG4gICAgICBjb25zdCBlbGVtZW50Q2VudGVyID0gZ2V0Q29udGFpbmVyQ2VudGVyKGNvbnRhaW5lciwgYXBwU3RhdGUpO1xuXG4gICAgICBpZiAoZWxlbWVudENlbnRlcikge1xuICAgICAgICBlbGVtZW50Q2VudGVyWCA9IGVsZW1lbnRDZW50ZXIueDtcbiAgICAgICAgZWxlbWVudENlbnRlclkgPSBlbGVtZW50Q2VudGVyLnk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRpc3RhbmNlVG9DZW50ZXIgPSBNYXRoLmh5cG90KHggLSBlbGVtZW50Q2VudGVyWCwgeSAtIGVsZW1lbnRDZW50ZXJZKTtcbiAgICAgIGNvbnN0IGlzU25hcHBlZFRvQ2VudGVyID0gZGlzdGFuY2VUb0NlbnRlciA8IFRFWFRfVE9fQ0VOVEVSX1NOQVBfVEhSRVNIT0xEO1xuXG4gICAgICBpZiAoaXNTbmFwcGVkVG9DZW50ZXIpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHZpZXdwb3J0WCxcbiAgICAgICAgICB5OiB2aWV3cG9ydFlcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBlbGVtZW50Q2VudGVyWCxcbiAgICAgICAgICBzY2VuZVk6IGVsZW1lbnRDZW50ZXJZXG4gICAgICAgIH0sIGFwcFN0YXRlKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB2aWV3cG9ydFgsXG4gICAgICAgICAgdmlld3BvcnRZLFxuICAgICAgICAgIGVsZW1lbnRDZW50ZXJYLFxuICAgICAgICAgIGVsZW1lbnRDZW50ZXJZXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZ2V0Q2FudmFzT2Zmc2V0cygpIHtcbiAgICB2YXIgX2E7XG5cbiAgICBpZiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkge1xuICAgICAgY29uc3QgZXhjYWxpZHJhd0NvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgY29uc3Qge1xuICAgICAgICBsZWZ0LFxuICAgICAgICB0b3BcbiAgICAgIH0gPSBleGNhbGlkcmF3Q29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgb2Zmc2V0TGVmdDogbGVmdCxcbiAgICAgICAgb2Zmc2V0VG9wOiB0b3BcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIG9mZnNldExlZnQ6IDAsXG4gICAgICBvZmZzZXRUb3A6IDBcbiAgICB9O1xuICB9XG5cbiAgdXBkYXRlTGFuZ3VhZ2UoKSB7XG4gICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGNvbnN0IGN1cnJlbnRMYW5nID0gbGFuZ3VhZ2VzLmZpbmQobGFuZyA9PiBsYW5nLmNvZGUgPT09IHRoaXMucHJvcHMubGFuZ0NvZGUpIHx8IGRlZmF1bHRMYW5nO1xuICAgICAgeWllbGQgc2V0TGFuZ3VhZ2UoY3VycmVudExhbmcpO1xuICAgICAgdGhpcy5zZXRBcHBTdGF0ZSh7fSk7XG4gICAgfSk7XG4gIH1cblxufVxuXG5BcHAuZGVmYXVsdFByb3BzID0ge1xuICAvLyBuZWVkZWQgZm9yIHRlc3RzIHRvIHBhc3Mgc2luY2Ugd2UgZGlyZWN0bHkgcmVuZGVyIEFwcCBpbiBtYW55IHRlc3RzXG4gIFVJT3B0aW9uczogREVGQVVMVF9VSV9PUFRJT05TXG59O1xuXG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IEVOVi5URVNUIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICB3aW5kb3cuaCA9IHdpbmRvdy5oIHx8IHt9O1xuICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh3aW5kb3cuaCwge1xuICAgIGVsZW1lbnRzOiB7XG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG5cbiAgICAgIGdldCgpIHtcbiAgICAgICAgdmFyIF9hO1xuXG4gICAgICAgIHJldHVybiAoX2EgPSB0aGlzLmFwcCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuICAgICAgfSxcblxuICAgICAgc2V0KGVsZW1lbnRzKSB7XG4gICAgICAgIHZhciBfYTtcblxuICAgICAgICByZXR1cm4gKF9hID0gdGhpcy5hcHApID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgICAgfVxuXG4gICAgfVxuICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgQXBwOyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../components/App.tsx\n");
2510
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"ExcalidrawContainerContext\": () => (/* binding */ ExcalidrawContainerContext),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ \"useApp\": () => (/* binding */ useApp),\n/* harmony export */ \"useAppProps\": () => (/* binding */ useAppProps),\n/* harmony export */ \"useDevice\": () => (/* binding */ useDevice),\n/* harmony export */ \"useExcalidrawActionManager\": () => (/* binding */ useExcalidrawActionManager),\n/* harmony export */ \"useExcalidrawAppState\": () => (/* binding */ useExcalidrawAppState),\n/* harmony export */ \"useExcalidrawContainer\": () => (/* binding */ useExcalidrawContainer),\n/* harmony export */ \"useExcalidrawElements\": () => (/* binding */ useExcalidrawElements),\n/* harmony export */ \"useExcalidrawSetAppState\": () => (/* binding */ useExcalidrawSetAppState)\n/* harmony export */ });\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react/jsx-runtime */ \"react/jsx-runtime\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ \"react\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-dom */ \"react-dom\");\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! roughjs/bin/rough */ \"../../../node_modules/roughjs/bin/rough.js\");\n/* harmony import */ var clsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! clsx */ \"../../../node_modules/clsx/dist/clsx.m.js\");\n/* harmony import */ var nanoid__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(/*! nanoid */ \"../../../node_modules/nanoid/index.browser.js\");\n/* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../actions */ \"../../actions/index.ts\");\n/* harmony import */ var _actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../actions/actionHistory */ \"../../actions/actionHistory.tsx\");\n/* harmony import */ var _actions_manager__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../actions/manager */ \"../../actions/manager.tsx\");\n/* harmony import */ var _actions_register__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../actions/register */ \"../../actions/register.ts\");\n/* harmony import */ var _analytics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../analytics */ \"../../analytics.ts\");\n/* harmony import */ var _appState__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../appState */ \"../../appState.ts\");\n/* harmony import */ var _clipboard__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../clipboard */ \"../../clipboard.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\n/* harmony import */ var _data__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../data */ \"../../data/index.ts\");\n/* harmony import */ var _data_library__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../data/library */ \"../../data/library.ts\");\n/* harmony import */ var _data_restore__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../data/restore */ \"../../data/restore.ts\");\n/* harmony import */ var _element__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../element */ \"../../element/index.ts\");\n/* harmony import */ var _element_binding__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../element/binding */ \"../../element/binding.ts\");\n/* harmony import */ var _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../element/linearElementEditor */ \"../../element/linearElementEditor.ts\");\n/* harmony import */ var _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../element/mutateElement */ \"../../element/mutateElement.ts\");\n/* harmony import */ var _element_newElement__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../element/newElement */ \"../../element/newElement.ts\");\n/* harmony import */ var _element_typeChecks__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../element/typeChecks */ \"../../element/typeChecks.ts\");\n/* harmony import */ var _gesture__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../gesture */ \"../../gesture.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../groups */ \"../../groups.ts\");\n/* harmony import */ var _history__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../history */ \"../../history.ts\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../i18n */ \"../../i18n.ts\");\n/* harmony import */ var _keys__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ../keys */ \"../../keys.ts\");\n/* harmony import */ var _element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ../element/sizeHelpers */ \"../../element/sizeHelpers.ts\");\n/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ../math */ \"../../math.ts\");\n/* harmony import */ var _scene__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ../scene */ \"../../scene/index.ts\");\n/* harmony import */ var _scene_Scene__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ../scene/Scene */ \"../../scene/Scene.ts\");\n/* harmony import */ var _scene_zoom__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ../scene/zoom */ \"../../scene/zoom.ts\");\n/* harmony import */ var _shapes__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ../shapes */ \"../../shapes.tsx\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _element_embeddable__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ../element/embeddable */ \"../../element/embeddable.ts\");\n/* harmony import */ var _ContextMenu__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ./ContextMenu */ \"../../components/ContextMenu.tsx\");\n/* harmony import */ var _LayerUI__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./LayerUI */ \"../../components/LayerUI.tsx\");\n/* harmony import */ var _Toast__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./Toast */ \"../../components/Toast.tsx\");\n/* harmony import */ var _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ../actions/actionToggleViewMode */ \"../../actions/actionToggleViewMode.tsx\");\n/* harmony import */ var _data_blob__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ../data/blob */ \"../../data/blob.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ../element/image */ \"../../element/image.ts\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! lodash.throttle */ \"../../../node_modules/lodash.throttle/index.js\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default = /*#__PURE__*/__webpack_require__.n(lodash_throttle__WEBPACK_IMPORTED_MODULE_41__);\n/* harmony import */ var _data_filesystem__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! ../data/filesystem */ \"../../data/filesystem.ts\");\n/* harmony import */ var _element_textElement__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ../element/textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _element_collision__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ../element/collision */ \"../../element/collision.ts\");\n/* harmony import */ var _element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! ../element/Hyperlink */ \"../../element/Hyperlink.tsx\");\n/* harmony import */ var _data_url__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! ../data/url */ \"../../data/url.ts\");\n/* harmony import */ var _element_transformHandles__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! ../element/transformHandles */ \"../../element/transformHandles.ts\");\n/* harmony import */ var _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! ../actions/actionElementLock */ \"../../actions/actionElementLock.ts\");\n/* harmony import */ var _scene_Fonts__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! ../scene/Fonts */ \"../../scene/Fonts.ts\");\n/* harmony import */ var _frame__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! ../frame */ \"../../frame.ts\");\n/* harmony import */ var _scene_selection__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! ../scene/selection */ \"../../scene/selection.ts\");\n/* harmony import */ var _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! ../actions/actionClipboard */ \"../../actions/actionClipboard.tsx\");\n/* harmony import */ var _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! ../actions/actionFrame */ \"../../actions/actionFrame.ts\");\n/* harmony import */ var _actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ../actions/actionCanvas */ \"../../actions/actionCanvas.tsx\");\n/* harmony import */ var _jotai__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ../jotai */ \"../../jotai.ts\");\n/* harmony import */ var _ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! ./ActiveConfirmDialog */ \"../../components/ActiveConfirmDialog.tsx\");\n/* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ../errors */ \"../../errors.ts\");\n/* harmony import */ var _snapping__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(/*! ../snapping */ \"../../snapping.ts\");\n/* harmony import */ var _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(/*! ../actions/actionBoundText */ \"../../actions/actionBoundText.tsx\");\n/* harmony import */ var _BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(/*! ./BraveMeasureTextError */ \"../../components/BraveMeasureTextError.tsx\");\n/* harmony import */ var _EyeDropper__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(/*! ./EyeDropper */ \"../../components/EyeDropper.tsx\");\n/* harmony import */ var _data_transform__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(/*! ../data/transform */ \"../../data/transform.ts\");\n/* harmony import */ var _Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(/*! ./Sidebar/Sidebar */ \"../../components/Sidebar/Sidebar.tsx\");\n/* harmony import */ var _canvases__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(/*! ./canvases */ \"../../components/canvases/index.tsx\");\n/* harmony import */ var _scene_Renderer__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(/*! ../scene/Renderer */ \"../../scene/Renderer.ts\");\n/* harmony import */ var _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(/*! ../scene/ShapeCache */ \"../../scene/ShapeCache.ts\");\n/* harmony import */ var _MermaidToExcalidraw__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(/*! ./MermaidToExcalidraw */ \"../../components/MermaidToExcalidraw.tsx\");\n/* harmony import */ var _LaserTool_LaserTool__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(/*! ./LaserTool/LaserTool */ \"../../components/LaserTool/LaserTool.tsx\");\n/* harmony import */ var _LaserTool_LaserPathManager__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(/*! ./LaserTool/LaserPathManager */ \"../../components/LaserTool/LaserPathManager.ts\");\n/* harmony import */ var _cursor__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(/*! ../cursor */ \"../../cursor.ts\");\n/* harmony import */ var _emitter__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(/*! ../emitter */ \"../../emitter.ts\");\nvar __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {\n function adopt(value) {\n return value instanceof P ? value : new P(function (resolve) {\n resolve(value);\n });\n }\n\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) {\n try {\n step(generator.next(value));\n } catch (e) {\n reject(e);\n }\n }\n\n function rejected(value) {\n try {\n step(generator[\"throw\"](value));\n } catch (e) {\n reject(e);\n }\n }\n\n function step(result) {\n result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n }\n\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst AppContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst AppPropsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst deviceContextInitialValue = {\n viewport: {\n isMobile: false,\n isLandscape: false\n },\n editor: {\n isMobile: false,\n canFitSidebar: false\n },\n isTouchScreen: false\n};\nconst DeviceContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(deviceContextInitialValue);\nDeviceContext.displayName = \"DeviceContext\";\nconst ExcalidrawContainerContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext({\n container: null,\n id: null\n});\nExcalidrawContainerContext.displayName = \"ExcalidrawContainerContext\";\nconst ExcalidrawElementsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext([]);\nExcalidrawElementsContext.displayName = \"ExcalidrawElementsContext\";\nconst ExcalidrawAppStateContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n width: 0,\n height: 0,\n offsetLeft: 0,\n offsetTop: 0\n}));\nExcalidrawAppStateContext.displayName = \"ExcalidrawAppStateContext\";\nconst ExcalidrawSetAppStateContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(() => {\n console.warn(\"unitialized ExcalidrawSetAppStateContext context!\");\n});\nExcalidrawSetAppStateContext.displayName = \"ExcalidrawSetAppStateContext\";\nconst ExcalidrawActionManagerContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nExcalidrawActionManagerContext.displayName = \"ExcalidrawActionManagerContext\";\nconst useApp = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(AppContext);\nconst useAppProps = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(AppPropsContext);\nconst useDevice = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(DeviceContext);\nconst useExcalidrawContainer = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawContainerContext);\nconst useExcalidrawElements = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawElementsContext);\nconst useExcalidrawAppState = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawAppStateContext);\nconst useExcalidrawSetAppState = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawSetAppStateContext);\nconst useExcalidrawActionManager = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawActionManagerContext);\nconst supportsResizeObserver = typeof window !== \"undefined\" && \"ResizeObserver\" in window;\nlet didTapTwice = false;\nlet tappedTwiceTimer = 0;\nlet isHoldingSpace = false;\nlet isPanning = false;\nlet isDraggingScrollBar = false;\nlet currentScrollBars = {\n horizontal: null,\n vertical: null\n};\nlet touchTimeout = 0;\nlet invalidateContextMenu = false;\n/**\n * Map of youtube embed video states\n */\n\nconst YOUTUBE_VIDEO_STATES = new Map();\nlet IS_PLAIN_PASTE = false;\nlet IS_PLAIN_PASTE_TIMER = 0;\nlet PLAIN_PASTE_TOAST_SHOWN = false;\nlet lastPointerUp = null;\nconst gesture = {\n pointers: new Map(),\n lastCenter: null,\n initialDistance: null,\n initialScale: null\n};\n\nclass App extends (react__WEBPACK_IMPORTED_MODULE_1___default().Component) {\n constructor(props) {\n super(props);\n this.interactiveCanvas = null;\n this.unmounted = false;\n this.device = deviceContextInitialValue;\n this.excalidrawContainerRef = react__WEBPACK_IMPORTED_MODULE_1___default().createRef();\n this.files = {};\n this.imageCache = new Map();\n this.iFrameRefs = new Map();\n this.lastPointerDownEvent = null;\n this.lastPointerUpEvent = null;\n this.lastViewportPosition = {\n x: 0,\n y: 0\n };\n this.laserPathManager = new _LaserTool_LaserPathManager__WEBPACK_IMPORTED_MODULE_69__.LaserPathManager(this);\n this.onChangeEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_71__.Emitter();\n this.onPointerDownEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_71__.Emitter();\n this.onPointerUpEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_71__.Emitter();\n\n this.updateEmbeddables = () => {\n const embeddableElements = new Map();\n let updated = false;\n this.scene.getNonDeletedElements().filter(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(element)) {\n embeddableElements.set(element.id, true);\n\n if (element.validated == null) {\n updated = true;\n const validated = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(element.link, this.props.validateEmbeddable);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n validated\n }, false);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element);\n }\n }\n\n return false;\n });\n\n if (updated) {\n this.scene.informMutation();\n } // GC\n\n\n this.iFrameRefs.forEach((ref, id) => {\n if (!embeddableElements.has(id)) {\n this.iFrameRefs.delete(id);\n }\n });\n };\n\n this.getFrameNameDOMId = frameElement => {\n return `${this.id}-frame-name-${frameElement.id}`;\n };\n\n this.frameNameBoundsCache = {\n get: frameElement => {\n let bounds = this.frameNameBoundsCache._cache.get(frameElement.id);\n\n if (!bounds || bounds.zoom !== this.state.zoom.value || bounds.versionNonce !== frameElement.versionNonce) {\n const frameNameDiv = document.getElementById(this.getFrameNameDOMId(frameElement));\n\n if (frameNameDiv) {\n const box = frameNameDiv.getBoundingClientRect();\n const boxSceneTopLeft = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: box.x,\n clientY: box.y\n }, this.state);\n const boxSceneBottomRight = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: box.right,\n clientY: box.bottom\n }, this.state);\n bounds = {\n x: boxSceneTopLeft.x,\n y: boxSceneTopLeft.y,\n width: boxSceneBottomRight.x - boxSceneTopLeft.x,\n height: boxSceneBottomRight.y - boxSceneTopLeft.y,\n angle: 0,\n zoom: this.state.zoom.value,\n versionNonce: frameElement.versionNonce\n };\n\n this.frameNameBoundsCache._cache.set(frameElement.id, bounds);\n\n return bounds;\n }\n\n return null;\n }\n\n return bounds;\n },\n\n /**\n * @private\n */\n _cache: new Map()\n };\n\n this.renderFrameNames = () => {\n if (!this.state.frameRendering.enabled || !this.state.frameRendering.name) {\n return null;\n }\n\n const isDarkTheme = this.state.theme === \"dark\";\n return this.scene.getNonDeletedFrames().map((f, index) => {\n if (!(0,_element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__.isElementInViewport)(f, this.canvas.width / window.devicePixelRatio, this.canvas.height / window.devicePixelRatio, {\n offsetLeft: this.state.offsetLeft,\n offsetTop: this.state.offsetTop,\n scrollX: this.state.scrollX,\n scrollY: this.state.scrollY,\n zoom: this.state.zoom\n })) {\n // if frame not visible, don't render its name\n return null;\n }\n\n const {\n x: x1,\n y: y1\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: f.x,\n sceneY: f.y\n }, this.state);\n const FRAME_NAME_EDIT_PADDING = 6;\n\n const reset = () => {\n var _a;\n\n if (((_a = f.name) === null || _a === void 0 ? void 0 : _a.trim()) === \"\") {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(f, {\n name: null\n });\n }\n\n this.setState({\n editingFrame: null\n });\n };\n\n let frameNameJSX;\n\n if (f.id === this.state.editingFrame) {\n const frameNameInEdit = f.name == null ? `Frame ${index + 1}` : f.name;\n frameNameJSX = (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"input\", {\n autoFocus: true,\n value: frameNameInEdit,\n onChange: e => {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(f, {\n name: e.target.value\n });\n },\n onBlur: () => reset(),\n onKeyDown: event => {\n // for some inexplicable reason, `onBlur` triggered on ESC\n // does not reset `state.editingFrame` despite being called,\n // and we need to reset it here as well\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ESCAPE || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ENTER) {\n reset();\n }\n },\n style: {\n background: this.state.viewBackgroundColor,\n filter: isDarkTheme ? _constants__WEBPACK_IMPORTED_MODULE_12__.THEME_FILTER : \"none\",\n zIndex: 2,\n border: \"none\",\n display: \"block\",\n padding: `${FRAME_NAME_EDIT_PADDING}px`,\n borderRadius: 4,\n boxShadow: \"inset 0 0 0 1px var(--color-primary)\",\n fontFamily: \"Assistant\",\n fontSize: \"14px\",\n transform: `translate(-${FRAME_NAME_EDIT_PADDING}px, ${FRAME_NAME_EDIT_PADDING}px)`,\n color: \"var(--color-gray-80)\",\n overflow: \"hidden\",\n maxWidth: `${document.body.clientWidth - x1 - FRAME_NAME_EDIT_PADDING}px`\n },\n size: frameNameInEdit.length + 1 || 1,\n dir: \"auto\",\n autoComplete: \"off\",\n autoCapitalize: \"off\",\n autoCorrect: \"off\"\n });\n } else {\n frameNameJSX = f.name == null || f.name.trim() === \"\" ? `Frame ${index + 1}` : f.name.trim();\n }\n\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n id: this.getFrameNameDOMId(f),\n style: {\n position: \"absolute\",\n // Positioning from bottom so that we don't to either\n // calculate text height or adjust using transform (which)\n // messes up input position when editing the frame name.\n // This makes the positioning deterministic and we can calculate\n // the same position when rendering to canvas / svg.\n bottom: `${this.state.height + _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameOffsetY - y1 + this.state.offsetTop}px`,\n left: `${x1 - this.state.offsetLeft}px`,\n zIndex: 2,\n fontSize: _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameFontSize,\n color: isDarkTheme ? _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameColorDarkTheme : _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameColorLightTheme,\n lineHeight: _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE.nameLineHeight,\n width: \"max-content\",\n maxWidth: `${f.width}px`,\n overflow: f.id === this.state.editingFrame ? \"visible\" : \"hidden\",\n whiteSpace: \"nowrap\",\n textOverflow: \"ellipsis\",\n cursor: _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE,\n pointerEvents: this.state.viewModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled\n },\n onPointerDown: event => this.handleCanvasPointerDown(event),\n onWheel: event => this.handleWheel(event),\n onContextMenu: this.handleCanvasContextMenu,\n onDoubleClick: () => {\n this.setState({\n editingFrame: f.id\n });\n }\n }, {\n children: frameNameJSX\n }), f.id);\n });\n };\n\n this.focusContainer = () => {\n var _a;\n\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.focus();\n };\n\n this.getSceneElementsIncludingDeleted = () => {\n return this.scene.getElementsIncludingDeleted();\n };\n\n this.getSceneElements = () => {\n return this.scene.getNonDeletedElements();\n };\n\n this.onInsertElements = elements => {\n this.addElementsFromPasteOrLibrary({\n elements,\n position: \"center\",\n files: null\n });\n };\n\n this.onExportImage = (type, elements, opts) => __awaiter(this, void 0, void 0, function* () {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"export\", type, \"ui\");\n const fileHandle = yield (0,_data__WEBPACK_IMPORTED_MODULE_13__.exportCanvas)(type, elements, this.state, this.files, {\n exportBackground: this.state.exportBackground,\n name: this.state.name,\n viewBackgroundColor: this.state.viewBackgroundColor,\n exportingFrame: opts.exportingFrame\n }).catch(_utils__WEBPACK_IMPORTED_MODULE_33__.muteFSAbortError).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: error.message\n });\n });\n\n if (this.state.exportEmbedScene && fileHandle && (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isImageFileHandle)(fileHandle)) {\n this.setState({\n fileHandle\n });\n }\n });\n\n this.openEyeDropper = ({\n type\n }) => {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_EyeDropper__WEBPACK_IMPORTED_MODULE_61__.activeEyeDropperAtom, {\n swapPreviewOnAlt: true,\n colorPickerType: type === \"stroke\" ? \"elementStroke\" : \"elementBackground\",\n onSelect: (color, event) => {\n const shouldUpdateStrokeColor = type === \"background\" && event.altKey || type === \"stroke\" && !event.altKey;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (!selectedElements.length || this.state.activeTool.type !== \"selection\") {\n if (shouldUpdateStrokeColor) {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemStrokeColor: color\n }),\n commitToHistory: true\n });\n } else {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemBackgroundColor: color\n }),\n commitToHistory: true\n });\n }\n } else {\n this.updateScene({\n elements: this.scene.getElementsIncludingDeleted().map(el => {\n if (this.state.selectedElementIds[el.id]) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(el, {\n [shouldUpdateStrokeColor ? \"strokeColor\" : \"backgroundColor\"]: color\n });\n }\n\n return el;\n })\n });\n }\n },\n keepOpenOnAlt: false\n });\n };\n\n this.syncActionResult = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(actionResult => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n\n if (this.unmounted || actionResult === false) {\n return;\n }\n\n let editingElement = null;\n\n if (actionResult.elements) {\n actionResult.elements.forEach(element => {\n var _a;\n\n if (((_a = this.state.editingElement) === null || _a === void 0 ? void 0 : _a.id) === element.id && this.state.editingElement !== element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n editingElement = element;\n }\n });\n this.scene.replaceAllElements(actionResult.elements);\n\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n }\n\n if (actionResult.files) {\n this.files = actionResult.replaceFiles ? actionResult.files : Object.assign(Object.assign({}, this.files), actionResult.files);\n this.addNewImagesToImageCache();\n }\n\n if (actionResult.appState || editingElement || this.state.contextMenu) {\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n\n let viewModeEnabled = ((_a = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _a === void 0 ? void 0 : _a.viewModeEnabled) || false;\n let zenModeEnabled = ((_b = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _b === void 0 ? void 0 : _b.zenModeEnabled) || false;\n let gridSize = ((_c = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _c === void 0 ? void 0 : _c.gridSize) || null;\n const theme = ((_d = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _d === void 0 ? void 0 : _d.theme) || this.props.theme || _constants__WEBPACK_IMPORTED_MODULE_12__.THEME.LIGHT;\n let name = (_f = (_e = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : this.state.name;\n const errorMessage = (_h = (_g = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _g === void 0 ? void 0 : _g.errorMessage) !== null && _h !== void 0 ? _h : this.state.errorMessage;\n\n if (typeof this.props.viewModeEnabled !== \"undefined\") {\n viewModeEnabled = this.props.viewModeEnabled;\n }\n\n if (typeof this.props.zenModeEnabled !== \"undefined\") {\n zenModeEnabled = this.props.zenModeEnabled;\n }\n\n if (typeof this.props.gridModeEnabled !== \"undefined\") {\n gridSize = this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null;\n }\n\n if (typeof this.props.name !== \"undefined\") {\n name = this.props.name;\n }\n\n editingElement = editingElement || ((_j = actionResult.appState) === null || _j === void 0 ? void 0 : _j.editingElement) || null;\n\n if (editingElement === null || editingElement === void 0 ? void 0 : editingElement.isDeleted) {\n editingElement = null;\n }\n\n this.setState(state => {\n // using Object.assign instead of spread to fool TS 4.2.2+ into\n // regarding the resulting type as not containing undefined\n // (which the following expression will never contain)\n return Object.assign(actionResult.appState || {}, {\n // NOTE this will prevent opening context menu using an action\n // or programmatically from the host, so it will need to be\n // rewritten later\n contextMenu: null,\n editingElement,\n viewModeEnabled,\n zenModeEnabled,\n gridSize,\n theme,\n name,\n errorMessage\n });\n }, () => {\n if (actionResult.syncHistory) {\n this.history.setCurrentState(this.state, this.scene.getElementsIncludingDeleted());\n }\n });\n }\n }); // Lifecycle\n\n this.onBlur = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isHoldingSpace = false;\n this.setState({\n isBindingEnabled: true\n });\n });\n\n this.onUnload = () => {\n this.onBlur();\n };\n\n this.disableEvent = event => {\n event.preventDefault();\n };\n\n this.resetHistory = () => {\n this.history.clear();\n };\n /**\n * Resets scene & history.\n * ! Do not use to clear scene user action !\n */\n\n\n this.resetScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(opts => {\n this.scene.replaceAllElements([]);\n this.setState(state => Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n isLoading: (opts === null || opts === void 0 ? void 0 : opts.resetLoadingState) ? false : state.isLoading,\n theme: this.state.theme\n }));\n this.resetHistory();\n });\n\n this.initializeScene = () => __awaiter(this, void 0, void 0, function* () {\n var _a;\n\n if (\"launchQueue\" in window && \"LaunchParams\" in window) {\n window.launchQueue.setConsumer(launchParams => __awaiter(this, void 0, void 0, function* () {\n if (!launchParams.files.length) {\n return;\n }\n\n const fileHandle = launchParams.files[0];\n const blob = yield fileHandle.getFile();\n this.loadFileToCanvas(new File([blob], blob.name || \"\", {\n type: blob.type\n }), fileHandle);\n }));\n }\n\n if (this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (!this.state.isLoading) {\n this.setState({\n isLoading: true\n });\n }\n\n let initialData = null;\n\n try {\n initialData = (yield this.props.initialData) || null;\n\n if (initialData === null || initialData === void 0 ? void 0 : initialData.libraryItems) {\n this.library.updateLibrary({\n libraryItems: initialData.libraryItems,\n merge: true\n }).catch(error => {\n console.error(error);\n });\n }\n } catch (error) {\n console.error(error);\n initialData = {\n appState: {\n errorMessage: error.message || \"Encountered an error during importing or restoring scene data\"\n }\n };\n }\n\n const scene = (0,_data_restore__WEBPACK_IMPORTED_MODULE_15__.restore)(initialData, null, null, {\n repairBindings: true\n });\n scene.appState = Object.assign(Object.assign({}, scene.appState), {\n theme: this.props.theme || scene.appState.theme,\n // we're falling back to current (pre-init) state when deciding\n // whether to open the library, to handle a case where we\n // update the state outside of initialData (e.g. when loading the app\n // with a library install link, which should auto-open the library)\n openSidebar: ((_a = scene.appState) === null || _a === void 0 ? void 0 : _a.openSidebar) || this.state.openSidebar,\n activeTool: scene.appState.activeTool.type === \"image\" ? Object.assign(Object.assign({}, scene.appState.activeTool), {\n type: \"selection\"\n }) : scene.appState.activeTool,\n isLoading: false,\n toast: this.state.toast\n });\n\n if (initialData === null || initialData === void 0 ? void 0 : initialData.scrollToContent) {\n scene.appState = Object.assign(Object.assign({}, scene.appState), (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(scene.elements, Object.assign(Object.assign({}, scene.appState), {\n width: this.state.width,\n height: this.state.height,\n offsetTop: this.state.offsetTop,\n offsetLeft: this.state.offsetLeft\n })));\n } // FontFaceSet loadingdone event we listen on may not always fire\n // (looking at you Safari), so on init we manually load fonts for current\n // text elements on canvas, and rerender them once done. This also\n // seems faster even in browsers that do fire the loadingdone event.\n\n\n this.fonts.loadFontsForElements(scene.elements);\n this.resetHistory();\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n commitToHistory: true\n }));\n });\n\n this.isMobileBreakpoint = (width, height) => {\n return width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_PORTRAIT || height < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_HEIGHT_LANDSCAPE && width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_LANDSCAPE;\n };\n\n this.refreshViewportBreakpoints = () => {\n const container = this.excalidrawContainerRef.current;\n\n if (!container) {\n return;\n }\n\n const {\n clientWidth: viewportWidth,\n clientHeight: viewportHeight\n } = document.body;\n const prevViewportState = this.device.viewport;\n const nextViewportState = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(prevViewportState, {\n isLandscape: viewportWidth > viewportHeight,\n isMobile: this.isMobileBreakpoint(viewportWidth, viewportHeight)\n });\n\n if (prevViewportState !== nextViewportState) {\n this.device = Object.assign(Object.assign({}, this.device), {\n viewport: nextViewportState\n });\n return true;\n }\n\n return false;\n };\n\n this.refreshEditorBreakpoints = () => {\n const container = this.excalidrawContainerRef.current;\n\n if (!container) {\n return;\n }\n\n const {\n width: editorWidth,\n height: editorHeight\n } = container.getBoundingClientRect();\n const sidebarBreakpoint = this.props.UIOptions.dockedSidebarBreakpoint != null ? this.props.UIOptions.dockedSidebarBreakpoint : _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_RIGHT_SIDEBAR_MIN_WIDTH;\n const prevEditorState = this.device.editor;\n const nextEditorState = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(prevEditorState, {\n isMobile: this.isMobileBreakpoint(editorWidth, editorHeight),\n canFitSidebar: editorWidth > sidebarBreakpoint\n });\n\n if (prevEditorState !== nextEditorState) {\n this.device = Object.assign(Object.assign({}, this.device), {\n editor: nextEditorState\n });\n return true;\n }\n\n return false;\n };\n\n this.onResize = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n this.scene.getElementsIncludingDeleted().forEach(element => _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element));\n this.refreshViewportBreakpoints();\n this.updateDOMRect();\n\n if (!supportsResizeObserver) {\n this.refreshEditorBreakpoints();\n }\n\n this.setState({});\n });\n\n this.renderInteractiveSceneCallback = ({\n atLeastOneVisibleElement,\n scrollBars,\n elements\n }) => {\n if (scrollBars) {\n currentScrollBars = scrollBars;\n }\n\n const scrolledOutside = // hide when editing text\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? false : !atLeastOneVisibleElement && elements.length > 0;\n\n if (this.state.scrolledOutside !== scrolledOutside) {\n this.setState({\n scrolledOutside\n });\n }\n\n this.scheduleImageRefresh();\n };\n\n this.onScroll = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n const {\n offsetTop,\n offsetLeft\n } = this.getCanvasOffsets();\n this.setState(state => {\n if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {\n return null;\n }\n\n return {\n offsetTop,\n offsetLeft\n };\n });\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.SCROLL_TIMEOUT); // Copy/paste\n\n this.onCut = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, \"keyboard\", event);\n event.preventDefault();\n event.stopPropagation();\n });\n this.onCopy = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, \"keyboard\", event);\n event.preventDefault();\n event.stopPropagation();\n });\n\n this.onTouchStart = event => {\n // fix for Apple Pencil Scribble\n // On Android, preventing the event would disable contextMenu on tap-hold\n if (!_constants__WEBPACK_IMPORTED_MODULE_12__.isAndroid) {\n event.preventDefault();\n }\n\n if (!didTapTwice) {\n didTapTwice = true;\n clearTimeout(tappedTwiceTimer);\n tappedTwiceTimer = window.setTimeout(App.resetTapTwice, _constants__WEBPACK_IMPORTED_MODULE_12__.TAP_TWICE_TIMEOUT);\n return;\n } // insert text only if we tapped twice with a single finger\n // event.touches.length === 1 will also prevent inserting text when user's zooming\n\n\n if (didTapTwice && event.touches.length === 1) {\n const touch = event.touches[0]; // @ts-ignore\n\n this.handleCanvasDoubleClick({\n clientX: touch.clientX,\n clientY: touch.clientY\n });\n didTapTwice = false;\n clearTimeout(tappedTwiceTimer);\n }\n\n if (_constants__WEBPACK_IMPORTED_MODULE_12__.isAndroid) {\n event.preventDefault();\n }\n\n if (event.touches.length === 2) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n };\n\n this.onTouchEnd = event => {\n this.resetContextMenuTimer();\n\n if (event.touches.length > 0) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n } else {\n gesture.pointers.clear();\n }\n };\n\n this.pasteFromClipboard = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => __awaiter(this, void 0, void 0, function* () {\n var _b, _c, _d;\n\n const isPlainPaste = !!IS_PLAIN_PASTE; // #686\n\n const target = document.activeElement;\n const isExcalidrawActive = (_b = this.excalidrawContainerRef.current) === null || _b === void 0 ? void 0 : _b.contains(target);\n\n if (event && !isExcalidrawActive) {\n return;\n }\n\n const elementUnderCursor = document.elementFromPoint(this.lastViewportPosition.x, this.lastViewportPosition.y);\n\n if (event && (!(elementUnderCursor instanceof HTMLCanvasElement) || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(target))) {\n return;\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state); // must be called in the same frame (thus before any awaits) as the paste\n // event else some browsers (FF...) will clear the clipboardData\n // (something something security)\n\n let file = (_c = event === null || event === void 0 ? void 0 : event.clipboardData) === null || _c === void 0 ? void 0 : _c.files[0];\n const data = yield (0,_clipboard__WEBPACK_IMPORTED_MODULE_11__.parseClipboard)(event, isPlainPaste);\n\n if (!file && !isPlainPaste) {\n if (data.mixedContent) {\n return this.addElementsFromMixedContentPaste(data.mixedContent, {\n isPlainPaste,\n sceneX,\n sceneY\n });\n } else if (data.text) {\n const string = data.text.trim();\n\n if (string.startsWith(\"<svg\") && string.endsWith(\"</svg>\")) {\n // ignore SVG validation/normalization which will be done during image\n // initialization\n file = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(string);\n }\n }\n } // prefer spreadsheet data over image file (MS Office/Libre Office)\n\n\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(file) && !data.spreadsheet) {\n if (!this.isToolSupported(\"image\")) {\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageToolNotSupported\")\n });\n return;\n }\n\n const imageElement = this.createImageElement({\n sceneX,\n sceneY\n });\n this.insertImageElement(imageElement, file);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n });\n return;\n }\n\n if (this.props.onPaste) {\n try {\n if ((yield this.props.onPaste(data, event)) === false) {\n return;\n }\n } catch (error) {\n console.error(error);\n }\n }\n\n if (data.errorMessage) {\n this.setState({\n errorMessage: data.errorMessage\n });\n } else if (data.spreadsheet && !isPlainPaste) {\n this.setState({\n pasteDialog: {\n data: data.spreadsheet,\n shown: true\n }\n });\n } else if (data.elements) {\n const elements = data.programmaticAPI ? (0,_data_transform__WEBPACK_IMPORTED_MODULE_62__.convertToExcalidrawElements)(data.elements) : data.elements; // TODO remove formatting from elements if isPlainPaste\n\n this.addElementsFromPasteOrLibrary({\n elements,\n files: data.files || null,\n position: \"cursor\",\n retainSeed: isPlainPaste\n });\n } else if (data.text) {\n const maybeUrl = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.extractSrc)(data.text);\n\n if (!isPlainPaste && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(maybeUrl, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(maybeUrl) || ((_d = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(maybeUrl)) === null || _d === void 0 ? void 0 : _d.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(maybeUrl)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n\n return;\n }\n\n this.addTextFromPaste(data.text, isPlainPaste);\n }\n\n this.setActiveTool({\n type: \"selection\"\n });\n event === null || event === void 0 ? void 0 : event.preventDefault();\n }));\n\n this.addElementsFromPasteOrLibrary = opts => {\n const elements = (0,_data_restore__WEBPACK_IMPORTED_MODULE_15__.restoreElements)(opts.elements, null, undefined);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(elements);\n const elementsCenterX = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minX, maxX) / 2;\n const elementsCenterY = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minY, maxY) / 2;\n const clientX = typeof opts.position === \"object\" ? opts.position.clientX : opts.position === \"cursor\" ? this.lastViewportPosition.x : this.state.width / 2 + this.state.offsetLeft;\n const clientY = typeof opts.position === \"object\" ? opts.position.clientY : opts.position === \"cursor\" ? this.lastViewportPosition.y : this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const dx = x - elementsCenterX;\n const dy = y - elementsCenterY;\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(dx, dy, this.state.gridSize);\n const newElements = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.duplicateElements)(elements.map(element => {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n x: element.x + gridX - minX,\n y: element.y + gridY - minY\n });\n }), {\n randomizeSeed: !opts.retainSeed\n });\n const nextElements = [...this.scene.getElementsIncludingDeleted(), ...newElements];\n this.scene.replaceAllElements(nextElements);\n newElements.forEach(newElement => {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(newElement) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(newElement)) {\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerElement)(newElement);\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.redrawTextBoundingBox)(newElement, container);\n }\n });\n\n if (opts.files) {\n this.files = Object.assign(Object.assign({}, this.files), opts.files);\n }\n\n this.history.resumeRecording();\n const nextElementsToSelect = (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.excludeElementsInFramesFromSelection)(newElements);\n this.setState(Object.assign(Object.assign(Object.assign({}, this.state), {\n // keep sidebar (presumably the library) open if it's docked and\n // can fit.\n //\n // Note, we should close the sidebar only if we're dropping items\n // from library, not when pasting from clipboard. Alas.\n openSidebar: this.state.openSidebar && this.device.editor.canFitSidebar && _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.get(_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_63__.isSidebarDockedAtom) ? this.state.openSidebar : null\n }), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: null,\n selectedElementIds: nextElementsToSelect.reduce((acc, element) => {\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(element)) {\n acc[element.id] = true;\n }\n\n return acc;\n }, {})\n }, this.scene.getNonDeletedElements(), this.state, this)), () => {\n if (opts.files) {\n this.addNewImagesToImageCache();\n }\n });\n this.setActiveTool({\n type: \"selection\"\n });\n\n if (opts.fitToContent) {\n this.scrollToContent(newElements, {\n fitToContent: true\n });\n }\n };\n\n this.setAppState = (state, callback) => {\n this.setState(state, callback);\n };\n\n this.removePointer = event => {\n if (touchTimeout) {\n this.resetContextMenuTimer();\n }\n\n gesture.pointers.delete(event.pointerId);\n };\n\n this.toggleLock = (source = \"ui\") => {\n if (!this.state.activeTool.locked) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", \"toggleLock\", `${source} (${this.device.editor.isMobile ? \"mobile\" : \"desktop\"})`);\n }\n\n this.setState(prevState => {\n return {\n activeTool: Object.assign(Object.assign(Object.assign({}, prevState.activeTool), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, prevState.activeTool.locked ? {\n type: \"selection\"\n } : prevState.activeTool)), {\n locked: !prevState.activeTool.locked\n })\n };\n });\n };\n\n this.updateFrameRendering = opts => {\n this.setState(prevState => {\n var _a, _b, _c, _d;\n\n const next = typeof opts === \"function\" ? opts(prevState.frameRendering) : opts;\n return {\n frameRendering: {\n enabled: (_a = next === null || next === void 0 ? void 0 : next.enabled) !== null && _a !== void 0 ? _a : prevState.frameRendering.enabled,\n clip: (_b = next === null || next === void 0 ? void 0 : next.clip) !== null && _b !== void 0 ? _b : prevState.frameRendering.clip,\n name: (_c = next === null || next === void 0 ? void 0 : next.name) !== null && _c !== void 0 ? _c : prevState.frameRendering.name,\n outline: (_d = next === null || next === void 0 ? void 0 : next.outline) !== null && _d !== void 0 ? _d : prevState.frameRendering.outline\n }\n };\n });\n };\n\n this.togglePenMode = force => {\n this.setState(prevState => {\n return {\n penMode: force !== null && force !== void 0 ? force : !prevState.penMode,\n penDetected: true\n };\n });\n };\n\n this.onHandToolToggle = () => {\n this.actionManager.executeAction(_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.actionToggleHandTool);\n };\n /**\n * Zooms on canvas viewport center\n */\n\n\n this.zoomCanvas = (\n /** decimal fraction between 0.1 (10% zoom) and 30 (3000% zoom) */\n value) => {\n this.setState(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.state.width / 2 + this.state.offsetLeft,\n viewportY: this.state.height / 2 + this.state.offsetTop,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(value)\n }, this.state)));\n };\n\n this.cancelInProgresAnimation = null;\n\n this.scrollToContent = (target = this.scene.getNonDeletedElements(), opts) => {\n var _a, _b;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this); // convert provided target into ExcalidrawElement[] if necessary\n\n const targetElements = Array.isArray(target) ? target : [target];\n let zoom = this.state.zoom;\n let scrollX = this.state.scrollX;\n let scrollY = this.state.scrollY;\n\n if ((opts === null || opts === void 0 ? void 0 : opts.fitToContent) || (opts === null || opts === void 0 ? void 0 : opts.fitToViewport)) {\n const {\n appState\n } = (0,_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.zoomToFit)({\n targetElements,\n appState: this.state,\n fitToViewport: !!(opts === null || opts === void 0 ? void 0 : opts.fitToViewport),\n viewportZoomFactor: opts === null || opts === void 0 ? void 0 : opts.viewportZoomFactor\n });\n zoom = appState.zoom;\n scrollX = appState.scrollX;\n scrollY = appState.scrollY;\n } else {\n // compute only the viewport location, without any zoom adjustment\n const scroll = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(targetElements, this.state);\n scrollX = scroll.scrollX;\n scrollY = scroll.scrollY;\n } // when animating, we use RequestAnimationFrame to prevent the animation\n // from slowing down other processes\n\n\n if (opts === null || opts === void 0 ? void 0 : opts.animate) {\n const origScrollX = this.state.scrollX;\n const origScrollY = this.state.scrollY;\n const origZoom = this.state.zoom.value;\n const cancel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeToValuesRAF)({\n fromValues: {\n scrollX: origScrollX,\n scrollY: origScrollY,\n zoom: origZoom\n },\n toValues: {\n scrollX,\n scrollY,\n zoom: zoom.value\n },\n interpolateValue: (from, to, progress, key) => {\n // for zoom, use different easing\n if (key === \"zoom\") {\n return from * Math.pow(to / from, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeOut)(progress));\n } // handle using default\n\n\n return undefined;\n },\n onStep: ({\n scrollX,\n scrollY,\n zoom\n }) => {\n this.setState({\n scrollX,\n scrollY,\n zoom: {\n value: zoom\n }\n });\n },\n onStart: () => {\n this.setState({\n shouldCacheIgnoreZoom: true\n });\n },\n onEnd: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n onCancel: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n duration: (_b = opts === null || opts === void 0 ? void 0 : opts.duration) !== null && _b !== void 0 ? _b : 500\n });\n\n this.cancelInProgresAnimation = () => {\n cancel();\n this.cancelInProgresAnimation = null;\n };\n } else {\n this.setState({\n scrollX,\n scrollY,\n zoom\n });\n }\n };\n /** use when changing scrollX/scrollY/zoom based on user interaction */\n\n\n this.translateCanvas = state => {\n var _a;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this);\n this.setState(state);\n };\n\n this.setToast = toast => {\n this.setState({\n toast\n });\n };\n\n this.restoreFileFromShare = () => __awaiter(this, void 0, void 0, function* () {\n try {\n const webShareTargetCache = yield caches.open(\"web-share-target\");\n const response = yield webShareTargetCache.match(\"shared-file\");\n\n if (response) {\n const blob = yield response.blob();\n const file = new File([blob], blob.name || \"\", {\n type: blob.type\n });\n this.loadFileToCanvas(file, null);\n yield webShareTargetCache.delete(\"shared-file\");\n window.history.replaceState(null, _constants__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, window.location.pathname);\n }\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n });\n /** adds supplied files to existing files in the appState */\n\n\n this.addFiles = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(files => {\n const filesMap = files.reduce((acc, fileData) => {\n acc.set(fileData.id, fileData);\n return acc;\n }, new Map());\n this.files = Object.assign(Object.assign({}, this.files), Object.fromEntries(filesMap));\n this.scene.getNonDeletedElements().forEach(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && filesMap.has(element.fileId)) {\n this.imageCache.delete(element.fileId);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element);\n }\n });\n this.scene.informMutation();\n this.addNewImagesToImageCache();\n });\n this.updateScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(sceneData => {\n if (sceneData.commitToHistory) {\n this.history.resumeRecording();\n }\n\n if (sceneData.appState) {\n this.setState(sceneData.appState);\n }\n\n if (sceneData.elements) {\n this.scene.replaceAllElements(sceneData.elements);\n }\n\n if (sceneData.collaborators) {\n this.setState({\n collaborators: sceneData.collaborators\n });\n }\n });\n\n this.onSceneUpdated = () => {\n this.setState({});\n };\n /**\n * @returns whether the menu was toggled on or off\n */\n\n\n this.toggleSidebar = ({\n name,\n tab,\n force\n }) => {\n var _a;\n\n let nextName;\n\n if (force === undefined) {\n nextName = ((_a = this.state.openSidebar) === null || _a === void 0 ? void 0 : _a.name) === name ? null : name;\n } else {\n nextName = force ? name : null;\n }\n\n this.setState({\n openSidebar: nextName ? {\n name: nextName,\n tab\n } : null\n });\n return !!nextName;\n };\n\n this.updateCurrentCursorPosition = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n this.lastViewportPosition.x = event.clientX;\n this.lastViewportPosition.y = event.clientY;\n }); // Input handling\n\n this.onKeyDown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // normalize `event.key` when CapsLock is pressed #2372\n if (\"Proxy\" in window && (!event.shiftKey && /^[A-Z]$/.test(event.key) || event.shiftKey && /^[a-z]$/.test(event.key))) {\n event = new Proxy(event, {\n get(ev, prop) {\n const value = ev[prop];\n\n if (typeof value === \"function\") {\n // fix for Proxies hijacking `this`\n return value.bind(ev);\n }\n\n return prop === \"key\" ? // CapsLock inverts capitalization based on ShiftKey, so invert\n // it back\n event.shiftKey ? ev.key.toUpperCase() : ev.key.toLowerCase() : value;\n }\n\n });\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.V) {\n IS_PLAIN_PASTE = event.shiftKey;\n clearTimeout(IS_PLAIN_PASTE_TIMER); // reset (100ms to be safe that we it runs after the ensuing\n // paste event). Though, technically unnecessary to reset since we\n // (re)set the flag before each paste event.\n\n IS_PLAIN_PASTE_TIMER = window.setTimeout(() => {\n IS_PLAIN_PASTE = false;\n }, 100);\n } // prevent browser zoom in input fields\n\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n if (event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.MINUS || event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.EQUAL) {\n event.preventDefault();\n return;\n }\n } // bail if\n\n\n if ( // inside an input\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target) && // unless pressing escape (finalize action)\n event.key !== _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ESCAPE || // or unless using arrows (to move between buttons)\n (0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key) && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isInputLike)(event.target)) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.QUESTION_MARK) {\n this.setState({\n openDialog: \"help\"\n });\n return;\n } else if (event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.E && event.shiftKey && event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n event.preventDefault();\n this.setState({\n openDialog: \"imageExport\"\n });\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_UP || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n let offset = (event.shiftKey ? this.state.width : this.state.height) / this.state.zoom.value;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n offset = -offset;\n }\n\n if (event.shiftKey) {\n this.translateCanvas(state => ({\n scrollX: state.scrollX + offset\n }));\n } else {\n this.translateCanvas(state => ({\n scrollY: state.scrollY + offset\n }));\n }\n }\n\n if (this.actionManager.handleKeyDown(event)) {\n return;\n }\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: false\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const step = this.state.gridSize && (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize) || (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_SHIFT_TRANSLATE_AMOUNT : _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT);\n let offsetX = 0;\n let offsetY = 0;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_LEFT) {\n offsetX = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_RIGHT) {\n offsetX = step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_UP) {\n offsetY = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_DOWN) {\n offsetY = step;\n }\n\n const selectedElements = this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n });\n selectedElements.forEach(element => {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: element.x + offsetX,\n y: element.y + offsetY\n });\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element, {\n simultaneouslyUpdated: selectedElements\n });\n });\n this.maybeSuggestBindingForAll(selectedElements);\n event.preventDefault();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ENTER) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n const selectedElement = selectedElements[0];\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElement)) {\n if (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElement, this.scene)\n });\n }\n }\n } else if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isValidTextContainer)(selectedElement)) {\n let container;\n\n if (!(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement)) {\n container = selectedElement;\n }\n\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(selectedElement, this.state);\n const sceneX = midPoint.x;\n const sceneY = midPoint.y;\n this.startTextEditing({\n sceneX,\n sceneY,\n container\n });\n event.preventDefault();\n return;\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(selectedElement)) {\n this.setState({\n editingFrame: selectedElement.id\n });\n }\n }\n } else if (!event.ctrlKey && !event.altKey && !event.metaKey && this.state.draggingElement === null) {\n const shape = (0,_shapes__WEBPACK_IMPORTED_MODULE_32__.findShapeByKey)(event.key);\n\n if (shape) {\n if (this.state.activeTool.type !== shape) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", shape, `keyboard (${this.device.editor.isMobile ? \"mobile\" : \"desktop\"})`);\n }\n\n this.setActiveTool({\n type: shape\n });\n event.stopPropagation();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.Q) {\n this.toggleLock(\"keyboard\");\n event.stopPropagation();\n }\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE && gesture.pointers.size === 0) {\n isHoldingSpace = true;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n event.preventDefault();\n }\n\n if ((event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (this.state.activeTool.type === \"selection\" && !selectedElements.length) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && ((0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(this.state.activeTool.type) || selectedElements.some(element => (0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(element.type)))) {\n this.setState({\n openPopup: \"elementBackground\"\n });\n event.stopPropagation();\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) {\n this.setState({\n openPopup: \"elementStroke\"\n });\n event.stopPropagation();\n }\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.K && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if (this.state.activeTool.type === \"laser\") {\n this.setActiveTool({\n type: \"selection\"\n });\n } else {\n this.setActiveTool({\n type: \"laser\"\n });\n }\n\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.BACKSPACE || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.DELETE)) {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__.activeConfirmDialogAtom, \"clearCanvas\");\n } // eye dropper\n // -----------------------------------------------------------------------\n\n\n const lowerCased = event.key.toLocaleLowerCase();\n const isPickingStroke = lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S && event.shiftKey;\n const isPickingBackground = event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.I || lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && event.shiftKey;\n\n if (isPickingStroke || isPickingBackground) {\n this.openEyeDropper({\n type: isPickingStroke ? \"stroke\" : \"background\"\n });\n } // -----------------------------------------------------------------------\n\n });\n this.onWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // prevent browser pinch zoom on DOM elements\n if (!(event.target instanceof HTMLCanvasElement) && event.ctrlKey) {\n event.preventDefault();\n }\n });\n this.onKeyUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE) {\n if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (this.state.activeTool.type === \"selection\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n isHoldingSpace = false;\n }\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: true\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements)(selectedElements) : (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(selectedElements);\n this.setState({\n suggestedBindings: []\n });\n }\n }); // We purposely widen the `tool` type so this helper can be called with\n // any tool without having to type check it\n\n this.isToolSupported = tool => {\n var _a;\n\n return ((_a = this.props.UIOptions.tools) === null || _a === void 0 ? void 0 : _a[tool]) !== false;\n };\n\n this.setActiveTool = tool => {\n var _a;\n\n if (!this.isToolSupported(tool.type)) {\n console.warn(`\"${tool.type}\" tool is disabled via \"UIOptions.canvasActions.tools.${tool.type}\"`);\n return;\n }\n\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, tool);\n\n if (nextActiveTool.type === \"hand\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (!isHoldingSpace) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_33__.isToolIcon)(document.activeElement)) {\n this.focusContainer();\n }\n\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElementType)(nextActiveTool.type)) {\n this.setState({\n suggestedBindings: []\n });\n }\n\n if (nextActiveTool.type === \"image\") {\n this.onImageAction({\n insertOnCanvasDirectly: (_a = tool.type === \"image\" && tool.insertOnCanvasDirectly) !== null && _a !== void 0 ? _a : false\n });\n }\n\n this.setState(prevState => {\n const commonResets = {\n snapLines: prevState.snapLines.length ? [] : prevState.snapLines,\n originSnapOffset: null,\n activeEmbeddable: null\n };\n\n if (nextActiveTool.type !== \"selection\") {\n return Object.assign(Object.assign(Object.assign({}, prevState), {\n activeTool: nextActiveTool,\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n selectedGroupIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n editingGroupId: null,\n multiElement: null\n }), commonResets);\n }\n\n return Object.assign(Object.assign(Object.assign({}, prevState), {\n activeTool: nextActiveTool\n }), commonResets);\n });\n };\n\n this.setOpenDialog = dialogType => {\n this.setState({\n openDialog: dialogType\n });\n };\n\n this.setCursor = cursor => {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, cursor);\n };\n\n this.resetCursor = () => {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n };\n /**\n * returns whether user is making a gesture with >= 2 fingers (points)\n * on o touch screen (not on a trackpad). Currently only relates to Darwin\n * (iOS/iPadOS,MacOS), but may work on other devices in the future if\n * GestureEvent is standardized.\n */\n\n\n this.isTouchScreenMultiTouchGesture = () => {\n // we don't want to deselect when using trackpad, and multi-point gestures\n // only work on touch screens, so checking for >= pointers means we're on a\n // touchscreen\n return gesture.pointers.size >= 2;\n }; // fires only on Safari\n\n\n this.onGestureStart = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // we only want to deselect on touch screens because user may have selected\n // elements by mistake while zooming\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n\n gesture.initialScale = this.state.zoom.value;\n }); // fires only on Safari\n\n this.onGestureChange = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // onGestureChange only has zoom factor but not the center.\n // If we're on iPad or iPhone, then we recognize multi-touch and will\n // zoom in at the right location in the touchmove handler\n // (handleCanvasPointerMove).\n //\n // On Macbook trackpad, we don't have those events so will zoom in at the\n // current location instead.\n //\n // As such, bail from this handler on touch devices.\n\n if (this.isTouchScreenMultiTouchGesture()) {\n return;\n }\n\n const initialScale = gesture.initialScale;\n\n if (initialScale) {\n this.setState(state => Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * event.scale)\n }, state)));\n }\n }); // fires only on Safari\n\n this.onGestureEnd = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // reselect elements only on touch screens (see onGestureStart)\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n }\n\n gesture.initialScale = null;\n });\n\n this.startTextEditing = ({\n sceneX,\n sceneY,\n insertAtParentCenter = true,\n container\n }) => {\n var _a, _b;\n\n let shouldBindToContainer = false;\n let parentCenterPosition = insertAtParentCenter && this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n\n if (container && parentCenterPosition) {\n const boundTextElementToContainer = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(container);\n\n if (!boundTextElementToContainer) {\n shouldBindToContainer = true;\n }\n }\n\n let existingTextElement = null;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElements[0])) {\n existingTextElement = selectedElements[0];\n } else if (container) {\n existingTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(selectedElements[0]);\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n\n const fontFamily = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.fontFamily) || this.state.currentItemFontFamily;\n const lineHeight = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.lineHeight) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(fontFamily);\n const fontSize = this.state.currentItemFontSize;\n\n if (!existingTextElement && shouldBindToContainer && container && !(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isArrowElement)(container)) {\n const fontString = {\n fontSize,\n fontFamily\n };\n const minWidth = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineWidth)((0,_utils__WEBPACK_IMPORTED_MODULE_33__.getFontString)(fontString), lineHeight);\n const minHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineHeight)(fontSize, lineHeight);\n const newHeight = Math.max(container.height, minHeight);\n const newWidth = Math.max(container.width, minWidth);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n height: newHeight,\n width: newWidth\n });\n sceneX = container.x + newWidth / 2;\n sceneY = container.y + newHeight / 2;\n\n if (parentCenterPosition) {\n parentCenterPosition = this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n }\n }\n\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: sceneX,\n y: sceneY\n });\n const element = existingTextElement ? existingTextElement : (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)({\n x: parentCenterPosition ? parentCenterPosition.elementCenterX : sceneX,\n y: parentCenterPosition ? parentCenterPosition.elementCenterY : sceneY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text: \"\",\n fontSize,\n fontFamily,\n textAlign: parentCenterPosition ? \"center\" : this.state.currentItemTextAlign,\n verticalAlign: parentCenterPosition ? _constants__WEBPACK_IMPORTED_MODULE_12__.VERTICAL_ALIGN.MIDDLE : _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n containerId: shouldBindToContainer ? container === null || container === void 0 ? void 0 : container.id : undefined,\n groupIds: (_a = container === null || container === void 0 ? void 0 : container.groupIds) !== null && _a !== void 0 ? _a : [],\n lineHeight,\n angle: (_b = container === null || container === void 0 ? void 0 : container.angle) !== null && _b !== void 0 ? _b : 0,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n\n if (!existingTextElement && shouldBindToContainer && container) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n boundElements: (container.boundElements || []).concat({\n type: \"text\",\n id: element.id\n })\n });\n }\n\n this.setState({\n editingElement: element\n });\n\n if (!existingTextElement) {\n if (container && shouldBindToContainer) {\n const containerIndex = this.scene.getElementIndex(container.id);\n this.scene.insertElementAtIndex(element, containerIndex + 1);\n } else {\n this.scene.addNewElement(element);\n }\n }\n\n this.setState({\n editingElement: element\n });\n this.handleTextWysiwyg(element, {\n isExistingElement: !!existingTextElement\n });\n };\n\n this.handleCanvasDoubleClick = event => {\n // case: double-clicking with arrow/line tool selected would both create\n // text and enter multiElement mode\n if (this.state.multiElement) {\n return;\n } // we should only be able to double click when mode is selection\n\n\n if (this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0])) {\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id)) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElements[0], this.scene)\n });\n return;\n } else if (this.state.editingLinearElement && this.state.editingLinearElement.elementId === selectedElements[0].id) {\n return;\n }\n }\n\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n let {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedGroupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIds)(this.state);\n\n if (selectedGroupIds.length > 0) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n const selectedGroupId = hitElement && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIdForElement)(hitElement, this.state.selectedGroupIds);\n\n if (selectedGroupId) {\n this.setState(prevState => Object.assign(Object.assign({}, prevState), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: selectedGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)));\n return;\n }\n }\n\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.viewModeEnabled) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) {\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"active\"\n }\n });\n return;\n }\n\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if (container) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(container) || !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTransparent)(container.backgroundColor) || (0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY])) {\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, this.state);\n sceneX = midPoint.x;\n sceneY = midPoint.y;\n }\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n }\n };\n\n this.getElementLinkAtPosition = (scenePointer, hitElement) => {\n // Reversing so we traverse the elements in decreasing order\n // of z-index\n const elements = this.scene.getNonDeletedElements().slice().reverse();\n let hitElementIndex = Infinity;\n return elements.find((element, index) => {\n if (hitElement && element.id === hitElement.id) {\n hitElementIndex = index;\n }\n\n return element.link && index <= hitElementIndex && (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(element, this.state, [scenePointer.x, scenePointer.y], this.device.editor.isMobile);\n });\n };\n\n this.redirectToLink = (event, isTouchScreen) => {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDownEvent.clientX, this.lastPointerDownEvent.clientY, this.lastPointerUpEvent.clientX, this.lastPointerUpEvent.clientY);\n\n if (!this.hitLinkElement || // For touch screen allow dragging threshold else strict check\n isTouchScreen && draggedDistance > _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD || !isTouchScreen && draggedDistance !== 0) {\n return;\n }\n\n const lastPointerDownCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerDownEvent, this.state);\n const lastPointerDownHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerDownCoords.x, lastPointerDownCoords.y], this.device.editor.isMobile);\n const lastPointerUpCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerUpEvent, this.state);\n const lastPointerUpHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerUpCoords.x, lastPointerUpCoords.y], this.device.editor.isMobile);\n\n if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {\n let url = this.hitLinkElement.link;\n\n if (url) {\n url = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(url);\n let customEvent;\n\n if (this.props.onLinkOpen) {\n customEvent = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.wrapEvent)(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.EXCALIDRAW_LINK, event.nativeEvent);\n this.props.onLinkOpen(Object.assign(Object.assign({}, this.hitLinkElement), {\n link: url\n }), customEvent);\n }\n\n if (!(customEvent === null || customEvent === void 0 ? void 0 : customEvent.defaultPrevented)) {\n const target = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.isLocalLink)(url) ? \"_self\" : \"_blank\";\n const newWindow = window.open(undefined, target); // https://mathiasbynens.github.io/rel-noopener/\n\n if (newWindow) {\n newWindow.opener = null;\n newWindow.location = url;\n }\n }\n }\n }\n };\n\n this.getTopLayerFrameAtSceneCoords = sceneCoords => {\n const frames = this.scene.getNonDeletedFrames().filter(frame => (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)(sceneCoords, frame));\n return frames.length ? frames[frames.length - 1] : null;\n };\n\n this.handleCanvasPointerMove = event => {\n var _a, _b;\n\n this.savePointer(event.clientX, event.clientY, this.state.cursorButton);\n\n if (gesture.pointers.has(event.pointerId)) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n }\n\n const initialScale = gesture.initialScale;\n\n if (gesture.pointers.size === 2 && gesture.lastCenter && initialScale && gesture.initialDistance) {\n const center = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n const deltaX = center.x - gesture.lastCenter.x;\n const deltaY = center.y - gesture.lastCenter.y;\n gesture.lastCenter = center;\n const distance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n const scaleFactor = this.state.activeTool.type === \"freedraw\" && this.state.penMode ? 1 : distance / gesture.initialDistance;\n const nextZoom = scaleFactor ? (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * scaleFactor) : this.state.zoom.value;\n this.setState(state => {\n const zoomState = (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: center.x,\n viewportY: center.y,\n nextZoom\n }, state);\n this.translateCanvas({\n zoom: zoomState.zoom,\n scrollX: zoomState.scrollX + deltaX / nextZoom,\n scrollY: zoomState.scrollY + deltaY / nextZoom,\n shouldCacheIgnoreZoom: true\n });\n });\n this.resetShouldCacheIgnoreZoomDebounced();\n } else {\n gesture.lastCenter = gesture.initialDistance = gesture.initialScale = null;\n }\n\n if (isHoldingSpace || isPanning || isDraggingScrollBar || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state)) {\n return;\n }\n\n const isPointerOverScrollBars = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop);\n const isOverScrollBar = isPointerOverScrollBars.isOverEither;\n\n if (!this.state.draggingElement && !this.state.multiElement) {\n if (isOverScrollBar) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const {\n x: scenePointerX,\n y: scenePointerY\n } = scenePointer;\n\n if (!this.state.draggingElement && (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.isActiveToolNonLinearSnappable)(this.state.activeTool.type)) {\n const {\n originOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.getSnapLinesAtPointer)(this.scene.getNonDeletedElements(), this.state, {\n x: scenePointerX,\n y: scenePointerY\n }, event);\n this.setState({\n snapLines,\n originSnapOffset: originOffset\n });\n } else if (!this.state.draggingElement) {\n this.setState({\n snapLines: []\n });\n }\n\n if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerMove(event, scenePointerX, scenePointerY, this.state);\n\n if (editingLinearElement && editingLinearElement !== this.state.editingLinearElement) {\n // Since we are reading from previous state which is not possible with\n // automatic batching in React 18 hence using flush sync to synchronously\n // update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n this.setState({\n editingLinearElement\n });\n });\n }\n\n if ((editingLinearElement === null || editingLinearElement === void 0 ? void 0 : editingLinearElement.lastUncommittedPoint) != null) {\n this.maybeSuggestBindingAtCursor(scenePointer);\n } else {\n // causes stack overflow if not sync\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n this.setState({\n suggestedBindings: []\n });\n });\n }\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElementType)(this.state.activeTool.type)) {\n // Hovering with a selected tool or creating new linear element via click\n // and point\n const {\n draggingElement\n } = this.state;\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [scenePointer], this.state.startBoundElement);\n } else {\n this.maybeSuggestBindingAtCursor(scenePointer);\n }\n }\n\n if (this.state.multiElement) {\n const {\n multiElement\n } = this.state;\n const {\n x: rx,\n y: ry\n } = multiElement;\n const {\n points,\n lastCommittedPoint\n } = multiElement;\n const lastPoint = points[points.length - 1];\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n\n if (lastPoint === lastCommittedPoint) {\n // if we haven't yet created a temp point and we're beyond commit-zone\n // threshold, add a point\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(scenePointerX - rx, scenePointerY - ry, lastPoint[0], lastPoint[1]) >= _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: [...points, [scenePointerX - rx, scenePointerY - ry]]\n });\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER); // in this branch, we're inside the commit zone, and no uncommitted\n // point exists. Thus do nothing (don't add/remove points).\n }\n } else if (points.length > 2 && lastCommittedPoint && (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(scenePointerX - rx, scenePointerY - ry, lastCommittedPoint[0], lastCommittedPoint[1]) < _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: points.slice(0, -1)\n });\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(scenePointerX, scenePointerY, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const [lastCommittedX, lastCommittedY] = (_a = multiElement === null || multiElement === void 0 ? void 0 : multiElement.lastCommittedPoint) !== null && _a !== void 0 ? _a : [0, 0];\n let dxFromLastCommitted = gridX - rx - lastCommittedX;\n let dyFromLastCommitted = gridY - ry - lastCommittedY;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event)) {\n ({\n width: dxFromLastCommitted,\n height: dyFromLastCommitted\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)( // actual coordinate of the last committed point\n lastCommittedX + rx, lastCommittedY + ry, // cursor-grid coordinate\n gridX, gridY));\n }\n\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.isPathALoop)(points, this.state.zoom.value)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } // update last uncommitted point\n\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: [...points.slice(0, -1), [lastCommittedX + dxFromLastCommitted, lastCommittedY + dyFromLastCommitted]]\n });\n }\n\n return;\n }\n\n const hasDeselectedButton = Boolean(event.buttons);\n\n if (hasDeselectedButton || this.state.activeTool.type !== \"selection\" && this.state.activeTool.type !== \"text\" && this.state.activeTool.type !== \"eraser\") {\n return;\n }\n\n const elements = this.scene.getNonDeletedElements();\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && !isOverScrollBar && !this.state.editingLinearElement) {\n const elementWithTransformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getElementWithTransformHandleType)(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType);\n\n if (elementWithTransformHandleType && elementWithTransformHandleType.transformHandleType) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCursorForResizingElement)(elementWithTransformHandleType));\n return;\n }\n } else if (selectedElements.length > 1 && !isOverScrollBar) {\n const transformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getTransformHandleTypeFromCoords)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType);\n\n if (transformHandleType) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCursorForResizingElement)({\n transformHandleType\n }));\n return;\n }\n }\n\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n this.hitLinkElement = this.getElementLinkAtPosition(scenePointer, hitElement);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n return;\n }\n\n if (this.hitLinkElement && !this.state.selectedElementIds[this.hitLinkElement.id]) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.showHyperlinkTooltip)(this.hitLinkElement, this.state);\n } else {\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.hideHyperlinkToolip)();\n\n if (hitElement && (hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) && this.state.selectedElementIds[hitElement.id] && !this.state.contextMenu && !this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: \"info\"\n });\n } else if (this.state.activeTool.type === \"text\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(hitElement) ? _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.TEXT : _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.CROSSHAIR);\n } else if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (isOverScrollBar) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n } else if (this.state.selectedLinearElement) {\n this.handleHoverSelectedLinearElement(this.state.selectedLinearElement, scenePointerX, scenePointerY);\n } else if ( // if using cmd/ctrl, we're not dragging\n !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((hitElement || this.isHittingCommonBoundingBoxOfSelectedElements(scenePointer, selectedElements)) && !(hitElement === null || hitElement === void 0 ? void 0 : hitElement.locked)) {\n if (hitElement && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, event, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"hover\"\n }\n });\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n\n if (((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"hover\") {\n this.setState({\n activeEmbeddable: null\n });\n }\n }\n }\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n };\n\n this.handleEraser = (event, pointerDownState, scenePointer) => {\n const updateElementIds = elements => {\n elements.forEach(element => {\n if (element.locked) {\n return;\n }\n\n idsToUpdate.push(element.id);\n\n if (event.altKey) {\n if (pointerDownState.elementIdsToErase[element.id] && pointerDownState.elementIdsToErase[element.id].erase) {\n pointerDownState.elementIdsToErase[element.id].erase = false;\n }\n } else if (!pointerDownState.elementIdsToErase[element.id]) {\n pointerDownState.elementIdsToErase[element.id] = {\n erase: true,\n opacity: element.opacity\n };\n }\n });\n };\n\n const idsToUpdate = [];\n const distance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y, scenePointer.x, scenePointer.y);\n const threshold = 10 / this.state.zoom.value;\n const point = Object.assign({}, pointerDownState.lastCoords);\n let samplingInterval = 0;\n\n while (samplingInterval <= distance) {\n const hitElements = this.getElementsAtPosition(point.x, point.y);\n updateElementIds(hitElements); // Exit since we reached current point\n\n if (samplingInterval === distance) {\n break;\n } // Calculate next point in the line at a distance of sampling interval\n\n\n samplingInterval = Math.min(samplingInterval + threshold, distance);\n const distanceRatio = samplingInterval / distance;\n const nextX = (1 - distanceRatio) * point.x + distanceRatio * scenePointer.x;\n const nextY = (1 - distanceRatio) * point.y + distanceRatio * scenePointer.y;\n point.x = nextX;\n point.y = nextY;\n }\n\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n const id = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && idsToUpdate.includes(ele.containerId) ? ele.containerId : ele.id;\n\n if (idsToUpdate.includes(id)) {\n if (event.altKey) {\n if (pointerDownState.elementIdsToErase[id] && pointerDownState.elementIdsToErase[id].erase === false) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[id].opacity\n });\n }\n } else {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_READY_TO_ERASE_OPACITY\n });\n }\n }\n\n return ele;\n });\n this.scene.replaceAllElements(elements);\n pointerDownState.lastCoords.x = scenePointer.x;\n pointerDownState.lastCoords.y = scenePointer.y;\n }; // set touch moving for mobile context menu\n\n\n this.handleTouchMove = event => {\n invalidateContextMenu = true;\n };\n\n this.handleCanvasPointerDown = event => {\n var _a, _b; // since contextMenu options are potentially evaluated on each render,\n // and an contextMenu action may depend on selection state, we must\n // close the contextMenu before we update the selection on pointerDown\n // (e.g. resetting selection)\n\n\n if (this.state.contextMenu) {\n this.setState({\n contextMenu: null\n });\n }\n\n if (this.state.snapLines) {\n this.setAppState({\n snapLines: []\n });\n }\n\n this.updateGestureOnPointerDown(event); // if dragging element is freedraw and another pointerdown event occurs\n // a second finger is on the screen\n // discard the freedraw element if it is very short because it is likely\n // just a spike, otherwise finalize the freedraw element when the second\n // finger is lifted\n\n if (event.pointerType === \"touch\" && this.state.draggingElement && this.state.draggingElement.type === \"freedraw\") {\n const element = this.state.draggingElement;\n this.updateScene(Object.assign(Object.assign({}, element.points.length < 10 ? {\n elements: this.scene.getElementsIncludingDeleted().filter(el => el.id !== element.id)\n } : {}), {\n appState: {\n draggingElement: null,\n editingElement: null,\n startBoundElement: null,\n suggestedBindings: [],\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.keys(this.state.selectedElementIds).filter(key => key !== element.id).reduce((obj, key) => {\n obj[key] = this.state.selectedElementIds[key];\n return obj;\n }, {}), this.state)\n }\n }));\n return;\n } // remove any active selection when we start to interact with canvas\n // (mainly, we care about removing selection outside the component which\n // would prevent our copy handling otherwise)\n\n\n const selection = document.getSelection();\n\n if (selection === null || selection === void 0 ? void 0 : selection.anchorNode) {\n selection.removeAllRanges();\n }\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices(event);\n this.maybeCleanupAfterMissingPointerUp(event); //fires only once, if pen is detected, penMode is enabled\n //the user can disable this by toggling the penMode button\n\n if (!this.state.penDetected && event.pointerType === \"pen\") {\n this.setState(prevState => {\n return {\n penMode: true,\n penDetected: true\n };\n });\n }\n\n if (!this.device.isTouchScreen && [\"pen\", \"touch\"].includes(event.pointerType)) {\n this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(this.device, {\n isTouchScreen: true\n });\n }\n\n if (isPanning) {\n return;\n }\n\n this.lastPointerDownEvent = event; // we must exit before we set `cursorButton` state and `savePointer`\n // else it will send pointer state & laser pointer events in collab when\n // panning\n\n if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) {\n return;\n }\n\n this.setState({\n lastPointerDownWith: event.pointerType,\n cursorButton: \"down\"\n });\n this.savePointer(event.clientX, event.clientY, \"down\"); // only handle left mouse button or touch\n\n if (event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.TOUCH) {\n return;\n } // don't select while panning\n\n\n if (gesture.pointers.size > 1) {\n return;\n } // State for the duration of a pointer interaction, which starts with a\n // pointerDown event, ends with a pointerUp event (or another pointerDown)\n\n\n const pointerDownState = this.initialPointerDownState(event);\n this.setState({\n selectedElementsAreBeingDragged: false\n });\n\n if (this.handleDraggingScrollBar(event, pointerDownState)) {\n return;\n }\n\n this.clearSelectionIfNotUsingSelection();\n this.updateBindingEnabledOnPointerMove(event);\n\n if (this.handleSelectionOnPointerDown(event, pointerDownState)) {\n return;\n }\n\n const allowOnPointerDown = !this.state.penMode || event.pointerType !== \"touch\" || this.state.activeTool.type === \"selection\" || this.state.activeTool.type === \"text\" || this.state.activeTool.type === \"image\";\n\n if (!allowOnPointerDown) {\n return;\n }\n\n if (this.state.activeTool.type === \"text\") {\n this.handleTextOnPointerDown(event, pointerDownState);\n return;\n } else if (this.state.activeTool.type === \"arrow\" || this.state.activeTool.type === \"line\") {\n this.handleLinearElementOnPointerDown(event, this.state.activeTool.type, pointerDownState);\n } else if (this.state.activeTool.type === \"image\") {\n // reset image preview on pointerdown\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.CROSSHAIR); // retrieve the latest element as the state may be stale\n\n const pendingImageElement = this.state.pendingImageElementId && this.scene.getElement(this.state.pendingImageElementId);\n\n if (!pendingImageElement) {\n return;\n }\n\n this.setState({\n draggingElement: pendingImageElement,\n editingElement: pendingImageElement,\n pendingImageElementId: null,\n multiElement: null\n });\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const frame = this.getTopLayerFrameAtSceneCoords({\n x,\n y\n });\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(pendingImageElement, {\n x,\n y,\n frameId: frame ? frame.id : null\n });\n } else if (this.state.activeTool.type === \"freedraw\") {\n this.handleFreeDrawElementOnPointerDown(event, this.state.activeTool.type, pointerDownState);\n } else if (this.state.activeTool.type === \"custom\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n } else if (this.state.activeTool.type === \"frame\") {\n this.createFrameElementOnPointerDown(pointerDownState);\n } else if (this.state.activeTool.type === \"laser\") {\n this.laserPathManager.startPath(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y);\n } else if (this.state.activeTool.type !== \"eraser\" && this.state.activeTool.type !== \"hand\") {\n this.createGenericElementOnPointerDown(this.state.activeTool.type, pointerDownState);\n }\n\n (_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.onPointerDown) === null || _b === void 0 ? void 0 : _b.call(_a, this.state.activeTool, pointerDownState);\n this.onPointerDownEmitter.trigger(this.state.activeTool, pointerDownState, event);\n const onPointerMove = this.onPointerMoveFromPointerDownHandler(pointerDownState);\n const onPointerUp = this.onPointerUpFromPointerDownHandler(pointerDownState);\n const onKeyDown = this.onKeyDownFromPointerDownHandler(pointerDownState);\n const onKeyUp = this.onKeyUpFromPointerDownHandler(pointerDownState);\n lastPointerUp = onPointerUp;\n\n if (!this.state.viewModeEnabled || this.state.activeTool.type === \"laser\") {\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, onKeyDown);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, onKeyUp);\n pointerDownState.eventListeners.onMove = onPointerMove;\n pointerDownState.eventListeners.onUp = onPointerUp;\n pointerDownState.eventListeners.onKeyUp = onKeyUp;\n pointerDownState.eventListeners.onKeyDown = onKeyDown;\n }\n };\n\n this.handleCanvasPointerUp = event => {\n var _a, _b;\n\n this.removePointer(event);\n this.lastPointerUpEvent = event;\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: event.clientX,\n clientY: event.clientY\n }, this.state);\n const clicklength = event.timeStamp - ((_b = (_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a.timeStamp) !== null && _b !== void 0 ? _b : 0);\n\n if (this.device.editor.isMobile && clicklength < 300) {\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, event, scenePointer.x, scenePointer.y)) {\n this.handleEmbeddableCenterClick(hitElement);\n return;\n }\n }\n\n if (this.device.isTouchScreen) {\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n this.hitLinkElement = this.getElementLinkAtPosition(scenePointer, hitElement);\n }\n\n if (this.hitLinkElement && !this.state.selectedElementIds[this.hitLinkElement.id]) {\n if (clicklength < 300 && this.hitLinkElement.type === \"embeddable\" && !(0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLinkIcon)(this.hitLinkElement, this.state, [scenePointer.x, scenePointer.y])) {\n this.handleEmbeddableCenterClick(this.hitLinkElement);\n } else {\n this.redirectToLink(event, this.device.isTouchScreen);\n }\n } else if (this.state.viewModeEnabled) {\n this.setState({\n activeEmbeddable: null,\n selectedElementIds: {}\n });\n }\n };\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices = event => {\n // deal with opening context menu on touch devices\n if (event.pointerType === \"touch\") {\n invalidateContextMenu = false;\n\n if (touchTimeout) {\n // If there's already a touchTimeout, this means that there's another\n // touch down and we are doing another touch, so we shouldn't open the\n // context menu.\n invalidateContextMenu = true;\n } else {\n // open the context menu with the first touch's clientX and clientY\n // if the touch is not moving\n touchTimeout = window.setTimeout(() => {\n touchTimeout = 0;\n\n if (!invalidateContextMenu) {\n this.handleCanvasContextMenu(event);\n }\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.TOUCH_CTX_MENU_TIMEOUT);\n }\n }\n };\n\n this.resetContextMenuTimer = () => {\n clearTimeout(touchTimeout);\n touchTimeout = 0;\n invalidateContextMenu = false;\n }; // Returns whether the event is a panning\n\n\n this.handleCanvasPanUsingWheelOrSpaceDrag = event => {\n if (!(gesture.pointers.size <= 1 && (event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.WHEEL || event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && isHoldingSpace || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state) || this.state.viewModeEnabled)) || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement)) {\n return false;\n }\n\n isPanning = true;\n event.preventDefault();\n let nextPastePrevented = false;\n const isLinux = /Linux/.test(window.navigator.platform);\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRABBING);\n let {\n clientX: lastX,\n clientY: lastY\n } = event;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const deltaX = lastX - event.clientX;\n const deltaY = lastY - event.clientY;\n lastX = event.clientX;\n lastY = event.clientY;\n /*\n * Prevent paste event if we move while middle clicking on Linux.\n * See issue #1383.\n */\n\n if (isLinux && !nextPastePrevented && (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1)) {\n nextPastePrevented = true;\n /* Prevent the next paste event */\n\n const preventNextPaste = event => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n event.stopPropagation();\n };\n /*\n * Reenable next paste in case of disabled middle click paste for\n * any reason:\n * - right click paste\n * - empty clipboard\n */\n\n\n const enableNextPaste = () => {\n setTimeout(() => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }, 100);\n };\n\n document.body.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }\n\n this.translateCanvas({\n scrollX: this.state.scrollX - deltaX / this.state.zoom.value,\n scrollY: this.state.scrollY - deltaY / this.state.zoom.value\n });\n });\n const teardown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(lastPointerUp = () => {\n lastPointerUp = null;\n isPanning = false;\n\n if (!isHoldingSpace) {\n if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n this.setState({\n cursorButton: \"up\"\n });\n this.savePointer(event.clientX, event.clientY, \"up\");\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, teardown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, teardown);\n onPointerMove.flush();\n });\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, teardown);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove, {\n passive: true\n });\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, teardown);\n return true;\n };\n\n this.clearSelectionIfNotUsingSelection = () => {\n if (this.state.activeTool.type !== \"selection\") {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n };\n /**\n * @returns whether the pointer event has been completely handled\n */\n\n\n this.handleSelectionOnPointerDown = (event, pointerDownState) => {\n var _a;\n\n if (this.state.activeTool.type === \"selection\") {\n const elements = this.scene.getNonDeletedElements();\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && !this.state.editingLinearElement) {\n const elementWithTransformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getElementWithTransformHandleType)(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);\n\n if (elementWithTransformHandleType != null) {\n this.setState({\n resizingElement: elementWithTransformHandleType.element\n });\n pointerDownState.resize.handleType = elementWithTransformHandleType.transformHandleType;\n }\n } else if (selectedElements.length > 1) {\n pointerDownState.resize.handleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getTransformHandleTypeFromCoords)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);\n }\n\n if (pointerDownState.resize.handleType) {\n pointerDownState.resize.isResizing = true;\n pointerDownState.resize.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getResizeOffsetXY)(pointerDownState.resize.handleType, selectedElements, pointerDownState.origin.x, pointerDownState.origin.y));\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0]) && selectedElements[0].points.length === 2) {\n pointerDownState.resize.arrowDirection = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getResizeArrowDirection)(pointerDownState.resize.handleType, selectedElements[0]);\n }\n } else {\n if (this.state.selectedLinearElement) {\n const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;\n const ret = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerDown(event, this.state, this.history, pointerDownState.origin, linearElementEditor);\n\n if (ret.hitElement) {\n pointerDownState.hit.element = ret.hitElement;\n }\n\n if (ret.linearElementEditor) {\n this.setState({\n selectedLinearElement: ret.linearElementEditor\n });\n\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: ret.linearElementEditor\n });\n }\n }\n\n if (ret.didAddPoint) {\n return true;\n }\n } // hitElement may already be set above, so check first\n\n\n pointerDownState.hit.element = (_a = pointerDownState.hit.element) !== null && _a !== void 0 ? _a : this.getElementAtPosition(pointerDownState.origin.x, pointerDownState.origin.y);\n\n if (pointerDownState.hit.element) {\n // Early return if pointer is hitting link icon\n const hitLinkElement = this.getElementLinkAtPosition({\n x: pointerDownState.origin.x,\n y: pointerDownState.origin.y\n }, pointerDownState.hit.element);\n\n if (hitLinkElement) {\n return false;\n }\n } // For overlapped elements one position may hit\n // multiple elements\n\n\n pointerDownState.hit.allHitElements = this.getElementsAtPosition(pointerDownState.origin.x, pointerDownState.origin.y);\n const hitElement = pointerDownState.hit.element;\n const someHitElementIsSelected = pointerDownState.hit.allHitElements.some(element => this.isASelectedElement(element));\n\n if ((hitElement === null || !someHitElementIsSelected) && !event.shiftKey && !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) {\n this.clearSelection(hitElement);\n }\n\n if (this.state.editingLinearElement) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [this.state.editingLinearElement.elementId]: true\n }, this.state)\n }); // If we click on something\n } else if (hitElement != null) {\n // on CMD/CTRL, drill down to hit element regardless of groups etc.\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if (!this.state.selectedElementIds[hitElement.id]) {\n pointerDownState.hit.wasAddedToSelection = true;\n }\n\n this.setState(prevState => Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.editGroupForSelectedElement)(prevState, hitElement)), {\n previousSelectedElementIds: this.state.selectedElementIds\n })); // mark as not completely handled so as to allow dragging etc.\n\n return false;\n } // deselect if item is selected\n // if shift is not clicked, this will always return true\n // otherwise, it will trigger selection based on current\n // state of the box\n\n\n if (!this.state.selectedElementIds[hitElement.id]) {\n // if we are currently editing a group, exiting editing mode and deselect the group.\n if (this.state.editingGroupId && !(0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, this.state.editingGroupId)) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n } // Add hit element to selection. At this point if we're not holding\n // SHIFT the previously selected element(s) were deselected above\n // (make sure you use setState updater to use latest state)\n // With shift-selection, we want to make sure that frames and their containing\n // elements are not selected at the same time.\n\n\n if (!someHitElementIsSelected && !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) {\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n });\n const previouslySelectedElements = [];\n Object.keys(prevState.selectedElementIds).forEach(id => {\n const element = this.scene.getElement(id);\n element && previouslySelectedElements.push(element);\n }); // if hitElement is frame, deselect all of its elements if they are selected\n\n if (hitElement.type === \"frame\") {\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getFrameChildren)(previouslySelectedElements, hitElement.id).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n } else if (hitElement.frameId) {\n // if hitElement is in a frame and its frame has been selected\n // disable selection for the given element\n if (nextSelectedElementIds[hitElement.frameId]) {\n delete nextSelectedElementIds[hitElement.id];\n }\n } else {\n // hitElement is neither a frame nor an element in a frame\n // but since hitElement could be in a group with some frames\n // this means selecting hitElement will have the frames selected as well\n // because we want to keep the invariant:\n // - frames and their elements are not selected at the same time\n // we deselect elements in those frames that were previously selected\n const groupIds = hitElement.groupIds;\n const framesInGroups = new Set(groupIds.flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).filter(element => element.type === \"frame\").map(frame => frame.id));\n\n if (framesInGroups.size > 0) {\n previouslySelectedElements.forEach(element => {\n if (element.frameId && framesInGroups.has(element.frameId)) {\n // deselect element and groups containing the element\n delete nextSelectedElementIds[element.id];\n element.groupIds.flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n }\n });\n }\n }\n\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n showHyperlinkPopup: hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) ? \"info\" : false\n });\n });\n pointerDownState.hit.wasAddedToSelection = true;\n }\n }\n }\n\n this.setState({\n previousSelectedElementIds: this.state.selectedElementIds\n });\n }\n }\n\n return false;\n };\n\n this.handleTextOnPointerDown = (event, pointerDownState) => {\n // if we're currently still editing text, clicking outside\n // should only finalize it, not create another (irrespective\n // of state.activeTool.locked)\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement)) {\n return;\n }\n\n let sceneX = pointerDownState.origin.x;\n let sceneY = pointerDownState.origin.y;\n const element = this.getElementAtPosition(sceneX, sceneY, {\n includeBoundTextElement: true\n }); // FIXME\n\n let container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(element)) {\n container = element;\n sceneX = element.x + element.width / 2;\n sceneY = element.y + element.height / 2;\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n\n if (!this.state.activeTool.locked) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n };\n\n this.handleFreeDrawElementOnPointerDown = (event, elementType, pointerDownState) => {\n // Begin a mark capture. This does not have to update state yet.\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, null);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFreeDrawElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: null,\n simulatePressure: event.pressure === 0.5,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n const pressures = element.simulatePressure ? element.pressures : [...element.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [[0, 0]],\n pressures\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }; //create rectangle element with youtube top left on nearest grid point width / hight 640/360\n\n\n this.insertEmbeddableElement = ({\n sceneX,\n sceneY,\n link\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(link);\n\n if (!embedLink) {\n return;\n }\n\n if (embedLink.warning) {\n this.setToast({\n message: embedLink.warning,\n closable: true\n });\n }\n\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)({\n type: \"embeddable\",\n x: gridX,\n y: gridY,\n strokeColor: \"transparent\",\n backgroundColor: \"transparent\",\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n roundness: this.getCurrentItemRoundness(\"embeddable\"),\n opacity: this.state.currentItemOpacity,\n locked: false,\n width: embedLink.aspectRatio.w,\n height: embedLink.aspectRatio.h,\n link,\n validated: null\n });\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), element]);\n return element;\n };\n\n this.createImageElement = ({\n sceneX,\n sceneY,\n addToFrameUnderCursor = true\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const topLayerFrame = addToFrameUnderCursor ? this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n }) : null;\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newImageElement)({\n type: \"image\",\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n roundness: null,\n opacity: this.state.currentItemOpacity,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n return element;\n };\n\n this.handleLinearElementOnPointerDown = (event, elementType, pointerDownState) => {\n if (this.state.multiElement) {\n const {\n multiElement\n } = this.state; // finalize if completing a loop\n\n if (multiElement.type === \"line\" && (0,_math__WEBPACK_IMPORTED_MODULE_28__.isPathALoop)(multiElement.points, this.state.zoom.value)) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n lastCommittedPoint: multiElement.points[multiElement.points.length - 1]\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n const {\n x: rx,\n y: ry,\n lastCommittedPoint\n } = multiElement; // clicking inside commit zone → finalize arrow\n\n if (multiElement.points.length > 1 && lastCommittedPoint && (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerDownState.origin.x - rx, pointerDownState.origin.y - ry, lastCommittedPoint[0], lastCommittedPoint[1]) < _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [multiElement.id]: true\n }), prevState)\n })); // clicking outside commit zone → update reference for last committed\n // point\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n lastCommittedPoint: multiElement.points[multiElement.points.length - 1]\n });\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.\n If so, we want it to be null for start and \"arrow\" for end. If the linear item is not\n an arrow, we want it to be null for both. Otherwise, we want it to use the\n values from appState. */\n\n const {\n currentItemStartArrowhead,\n currentItemEndArrowhead\n } = this.state;\n const [startArrowhead, endArrowhead] = elementType === \"arrow\" ? [currentItemStartArrowhead, currentItemEndArrowhead] : [null, null];\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newLinearElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.state.currentItemRoundness === \"round\" ? {\n type: _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null,\n startArrowhead,\n endArrowhead,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [...element.points, [0, 0]]\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }\n };\n\n this.createGenericElementOnPointerDown = (elementType, pointerDownState) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const baseElementAttributes = {\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.getCurrentItemRoundness(elementType),\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n };\n let element;\n\n if (elementType === \"embeddable\") {\n element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)(Object.assign({\n type: \"embeddable\",\n validated: null\n }, baseElementAttributes));\n } else {\n element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newElement)(Object.assign({\n type: elementType\n }, baseElementAttributes));\n }\n\n if (element.type === \"selection\") {\n this.setState({\n selectionElement: element,\n draggingElement: element\n });\n } else {\n this.scene.addNewElement(element);\n this.setState({\n multiElement: null,\n draggingElement: element,\n editingElement: element\n });\n }\n };\n\n this.createFrameElementOnPointerDown = pointerDownState => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const frame = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFrameElement)(Object.assign({\n x: gridX,\n y: gridY,\n opacity: this.state.currentItemOpacity,\n locked: false\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE));\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), frame]);\n this.setState({\n multiElement: null,\n draggingElement: frame,\n editingElement: frame\n });\n };\n\n this.restoreReadyToEraseElements = pointerDownState => {\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n if (pointerDownState.elementIdsToErase[ele.id] && pointerDownState.elementIdsToErase[ele.id].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.id].opacity\n });\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && pointerDownState.elementIdsToErase[ele.containerId] && pointerDownState.elementIdsToErase[ele.containerId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.containerId].opacity\n });\n } else if (ele.frameId && pointerDownState.elementIdsToErase[ele.frameId] && pointerDownState.elementIdsToErase[ele.frameId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.frameId].opacity\n });\n }\n\n return ele;\n });\n this.scene.replaceAllElements(elements);\n };\n\n this.eraseElements = pointerDownState => {\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n if (pointerDownState.elementIdsToErase[ele.id] && pointerDownState.elementIdsToErase[ele.id].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && pointerDownState.elementIdsToErase[ele.containerId] && pointerDownState.elementIdsToErase[ele.containerId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n } else if (ele.frameId && pointerDownState.elementIdsToErase[ele.frameId] && pointerDownState.elementIdsToErase[ele.frameId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n }\n\n return ele;\n });\n this.history.resumeRecording();\n this.scene.replaceAllElements(elements);\n };\n\n this.initializeImage = ({\n imageFile,\n imageElement: _imageElement,\n showCursorImagePreview = false\n }) => __awaiter(this, void 0, void 0, function* () {\n var _e, _f, _g, _h; // at this point this should be guaranteed image file, but we do this check\n // to satisfy TS down the line\n\n\n if (!(0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(imageFile)) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.unsupportedFileType\"));\n }\n\n const mimeType = imageFile.type;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, \"wait\");\n\n if (mimeType === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n try {\n imageFile = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.normalizeSVG)(yield imageFile.text()), imageFile.name);\n } catch (error) {\n console.warn(error);\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.svgImageInsertError\"));\n }\n } // generate image id (by default the file digest) before any\n // resizing/compression takes place to keep it more portable\n\n\n const fileId = yield ((_f = (_e = this.props).generateIdForFile) === null || _f === void 0 ? void 0 : _f.call(_e, imageFile)) || (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.generateIdFromFile)(imageFile);\n\n if (!fileId) {\n console.warn(\"Couldn't generate file id or the supplied `generateIdForFile` didn't resolve to one.\");\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\"));\n }\n\n const existingFileData = this.files[fileId];\n\n if (!(existingFileData === null || existingFileData === void 0 ? void 0 : existingFileData.dataURL)) {\n try {\n imageFile = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT\n });\n } catch (error) {\n console.error(\"error trying to resing image file on insertion\", error);\n }\n\n if (imageFile.size > _constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.fileTooBig\", {\n maxSize: `${Math.trunc(_constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES / 1024 / 1024)}MB`\n }));\n }\n }\n\n if (showCursorImagePreview) {\n const dataURL = (_g = this.files[fileId]) === null || _g === void 0 ? void 0 : _g.dataURL; // optimization so that we don't unnecessarily resize the original\n // full-size file for cursor preview\n // (it's much faster to convert the resized dataURL to File)\n\n const resizedFile = dataURL && (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.dataURLToFile)(dataURL);\n this.setImagePreviewCursor(resizedFile || imageFile);\n }\n\n const dataURL = ((_h = this.files[fileId]) === null || _h === void 0 ? void 0 : _h.dataURL) || (yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imageFile));\n const imageElement = (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(_imageElement, {\n fileId\n }, false);\n return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {\n var _j;\n\n try {\n this.files = Object.assign(Object.assign({}, this.files), {\n [fileId]: {\n mimeType,\n id: fileId,\n dataURL,\n created: Date.now(),\n lastRetrieved: Date.now()\n }\n });\n const cachedImageData = this.imageCache.get(fileId);\n\n if (!cachedImageData) {\n this.addNewImagesToImageCache();\n yield this.updateImageCache([imageElement]);\n }\n\n if ((cachedImageData === null || cachedImageData === void 0 ? void 0 : cachedImageData.image) instanceof Promise) {\n yield cachedImageData.image;\n }\n\n if (this.state.pendingImageElementId !== imageElement.id && ((_j = this.state.draggingElement) === null || _j === void 0 ? void 0 : _j.id) !== imageElement.id) {\n this.initializeImageDimensions(imageElement, true);\n }\n\n resolve(imageElement);\n } catch (error) {\n console.error(error);\n reject(new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\")));\n } finally {\n if (!showCursorImagePreview) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n }\n }\n }));\n });\n /**\n * inserts image into elements array and rerenders\n */\n\n\n this.insertImageElement = (imageElement, imageFile, showCursorImagePreview) => __awaiter(this, void 0, void 0, function* () {\n // we should be handling all cases upstream, but in case we forget to handle\n // a future case, let's throw here\n if (!this.isToolSupported(\"image\")) {\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageToolNotSupported\")\n });\n return;\n }\n\n this.scene.addNewElement(imageElement);\n\n try {\n return yield this.initializeImage({\n imageFile,\n imageElement,\n showCursorImagePreview\n });\n } catch (error) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n isDeleted: true\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n this.setState({\n errorMessage: error.message || (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\")\n });\n return null;\n }\n });\n\n this.setImagePreviewCursor = imageFile => __awaiter(this, void 0, void 0, function* () {\n // mustn't be larger than 128 px\n // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Basic_User_Interface/Using_URL_values_for_the_cursor_property\n const cursorImageSizePx = 96;\n const imagePreview = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: cursorImageSizePx\n });\n let previewDataURL = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imagePreview); // SVG cannot be resized via `resizeImageFile` so we resize by rendering to\n // a small canvas\n\n if (imageFile.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n const img = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.loadHTMLImageElement)(previewDataURL);\n let height = Math.min(img.height, cursorImageSizePx);\n let width = height * (img.width / img.height);\n\n if (width > cursorImageSizePx) {\n width = cursorImageSizePx;\n height = width * (img.height / img.width);\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.height = height;\n canvas.width = width;\n const context = canvas.getContext(\"2d\");\n context.drawImage(img, 0, 0, width, height);\n previewDataURL = canvas.toDataURL(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg);\n }\n\n if (this.state.pendingImageElementId) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, `url(${previewDataURL}) 4 4, auto`);\n }\n });\n\n this.onImageAction = ({\n insertOnCanvasDirectly\n }) => __awaiter(this, void 0, void 0, function* () {\n try {\n const clientX = this.state.width / 2 + this.state.offsetLeft;\n const clientY = this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const imageFile = yield (0,_data_filesystem__WEBPACK_IMPORTED_MODULE_42__.fileOpen)({\n description: \"Image\",\n extensions: Object.keys(_constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_MIME_TYPES)\n });\n const imageElement = this.createImageElement({\n sceneX: x,\n sceneY: y,\n addToFrameUnderCursor: false\n });\n\n if (insertOnCanvasDirectly) {\n this.insertImageElement(imageElement, imageFile);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } else {\n this.setState({\n pendingImageElementId: imageElement.id\n }, () => {\n this.insertImageElement(imageElement, imageFile,\n /* showCursorImagePreview */\n true);\n });\n }\n } catch (error) {\n if (error.name !== \"AbortError\") {\n console.error(error);\n } else {\n console.warn(error);\n }\n\n this.setState({\n pendingImageElementId: null,\n editingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n }\n });\n\n this.initializeImageDimensions = (imageElement, forceNaturalSize = false) => {\n var _a;\n\n const image = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(imageElement) && ((_a = this.imageCache.get(imageElement.fileId)) === null || _a === void 0 ? void 0 : _a.image);\n\n if (!image || image instanceof Promise) {\n if (imageElement.width < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value && imageElement.height < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value) {\n const placeholderSize = 100 / this.state.zoom.value;\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n x: imageElement.x - placeholderSize / 2,\n y: imageElement.y - placeholderSize / 2,\n width: placeholderSize,\n height: placeholderSize\n });\n }\n\n return;\n }\n\n if (forceNaturalSize || // if user-created bounding box is below threshold, assume the\n // intention was to click instead of drag, and use the image's\n // intrinsic size\n imageElement.width < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value && imageElement.height < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value) {\n const minHeight = Math.max(this.state.height - 120, 160); // max 65% of canvas height, clamped to <300px, vh - 120px>\n\n const maxHeight = Math.min(minHeight, Math.floor(this.state.height * 0.5) / this.state.zoom.value);\n const height = Math.min(image.naturalHeight, maxHeight);\n const width = height * (image.naturalWidth / image.naturalHeight); // add current imageElement width/height to account for previous centering\n // of the placeholder image\n\n const x = imageElement.x + imageElement.width / 2 - width / 2;\n const y = imageElement.y + imageElement.height / 2 - height / 2;\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n x,\n y,\n width,\n height\n });\n }\n };\n /** updates image cache, refreshing updated elements and/or setting status\n to error for images that fail during <img> element creation */\n\n\n this.updateImageCache = (elements, files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const {\n updatedFiles,\n erroredFiles\n } = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.updateImageCache)({\n imageCache: this.imageCache,\n fileIds: elements.map(element => element.fileId),\n files\n });\n\n if (updatedFiles.size || erroredFiles.size) {\n for (const element of elements) {\n if (updatedFiles.has(element.fileId)) {\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element);\n }\n }\n }\n\n if (erroredFiles.size) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().map(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && erroredFiles.has(element.fileId)) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n status: \"error\"\n });\n }\n\n return element;\n }));\n }\n\n return {\n updatedFiles,\n erroredFiles\n };\n });\n /** adds new images to imageCache and re-renders if needed */\n\n\n this.addNewImagesToImageCache = (imageElements = (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.getInitializedImageElements)(this.scene.getNonDeletedElements()), files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const uncachedImageElements = imageElements.filter(element => !element.isDeleted && !this.imageCache.has(element.fileId));\n\n if (uncachedImageElements.length) {\n const {\n updatedFiles\n } = yield this.updateImageCache(uncachedImageElements, files);\n\n if (updatedFiles.size) {\n this.scene.informMutation();\n }\n }\n });\n /** generally you should use `addNewImagesToImageCache()` directly if you need\n * to render new images. This is just a failsafe */\n\n\n this.scheduleImageRefresh = lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default()(() => {\n this.addNewImagesToImageCache();\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_RENDER_TIMEOUT);\n\n this.updateBindingEnabledOnPointerMove = event => {\n const shouldEnableBinding = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.shouldEnableBindingForPointerEvent)(event);\n\n if (this.state.isBindingEnabled !== shouldEnableBinding) {\n this.setState({\n isBindingEnabled: shouldEnableBinding\n });\n }\n };\n\n this.maybeSuggestBindingAtCursor = pointerCoords => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerCoords, this.scene);\n this.setState({\n suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : []\n });\n };\n\n this.maybeSuggestBindingsForLinearElementAtCoords = (linearElement,\n /** scene coords */\n pointerCoords, // During line creation the start binding hasn't been written yet\n // into `linearElement`\n oppositeBindingBoundElement) => {\n if (!pointerCoords.length) {\n return;\n }\n\n const suggestedBindings = pointerCoords.reduce((acc, coords) => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(coords, this.scene);\n\n if (hoveredBindableElement != null && !(0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isLinearElementSimpleAndAlreadyBound)(linearElement, oppositeBindingBoundElement === null || oppositeBindingBoundElement === void 0 ? void 0 : oppositeBindingBoundElement.id, hoveredBindableElement)) {\n acc.push(hoveredBindableElement);\n }\n\n return acc;\n }, []);\n this.setState({\n suggestedBindings\n });\n };\n\n this.handleInteractiveCanvasRef = canvas => {\n var _a, _b, _c; // canvas is null when unmounting\n\n\n if (canvas !== null) {\n this.interactiveCanvas = canvas; // -----------------------------------------------------------------------\n // NOTE wheel, touchstart, touchend events must be registered outside\n // of react because react binds them them passively (so we can't prevent\n // default on them)\n\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd); // -----------------------------------------------------------------------\n } else {\n (_a = this.interactiveCanvas) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n (_b = this.interactiveCanvas) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n (_c = this.interactiveCanvas) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd);\n }\n };\n\n this.handleAppOnDrop = event => __awaiter(this, void 0, void 0, function* () {\n var _k, _l, _m, _o; // must be retrieved first, in the same frame\n\n\n const {\n file,\n fileHandle\n } = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getFileFromEvent)(event);\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n try {\n // if image tool not supported, don't show an error here and let it fall\n // through so we still support importing scene data from images. If no\n // scene data encoded, we'll show an error then\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(file) && this.isToolSupported(\"image\")) {\n // first attempt to decode scene from the image if it's embedded\n // ---------------------------------------------------------------------\n if ((file === null || file === void 0 ? void 0 : file.type) === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.png || (file === null || file === void 0 ? void 0 : file.type) === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n try {\n const scene = yield (0,_data__WEBPACK_IMPORTED_MODULE_13__.loadFromBlob)(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n appState: Object.assign(Object.assign({}, scene.appState || this.state), {\n isLoading: false\n }),\n replaceFiles: true,\n commitToHistory: true\n }));\n return;\n } catch (error) {\n if (error.name !== \"EncodingError\") {\n throw error;\n }\n }\n } // if no scene is embedded or we fail for whatever reason, fall back\n // to importing as regular image\n // ---------------------------------------------------------------------\n\n\n const imageElement = this.createImageElement({\n sceneX,\n sceneY\n });\n this.insertImageElement(imageElement, file);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n });\n return;\n }\n } catch (error) {\n return this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n\n const libraryJSON = event.dataTransfer.getData(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib);\n\n if (libraryJSON && typeof libraryJSON === \"string\") {\n try {\n const libraryItems = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.parseLibraryJSON)(libraryJSON);\n this.addElementsFromPasteOrLibrary({\n elements: (0,_data_library__WEBPACK_IMPORTED_MODULE_14__.distributeLibraryItemsOnSquareGrid)(libraryItems),\n position: event,\n files: null\n });\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n\n return;\n }\n\n if (file) {\n // atetmpt to parse an excalidraw/excalidrawlib file\n yield this.loadFileToCanvas(file, fileHandle);\n }\n\n if ((_l = (_k = event.dataTransfer) === null || _k === void 0 ? void 0 : _k.types) === null || _l === void 0 ? void 0 : _l.includes(\"text/plain\")) {\n const text = (_m = event.dataTransfer) === null || _m === void 0 ? void 0 : _m.getData(\"text\");\n\n if (text && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(text, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(text) || ((_o = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(text)) === null || _o === void 0 ? void 0 : _o.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(text)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n }\n }\n });\n\n this.loadFileToCanvas = (file, fileHandle) => __awaiter(this, void 0, void 0, function* () {\n file = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.normalizeFile)(file);\n\n try {\n const ret = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.loadSceneOrLibraryFromBlob)(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);\n\n if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidraw) {\n this.setState({\n isLoading: true\n });\n this.syncActionResult(Object.assign(Object.assign({}, ret.data), {\n appState: Object.assign(Object.assign({}, ret.data.appState || this.state), {\n isLoading: false\n }),\n replaceFiles: true,\n commitToHistory: true\n }));\n } else if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib) {\n yield this.library.updateLibrary({\n libraryItems: file,\n merge: true,\n openLibraryMenu: true\n }).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.importLibraryError\")\n });\n });\n }\n } catch (error) {\n if (error instanceof _errors__WEBPACK_IMPORTED_MODULE_57__.ImageSceneDataError && error.code === \"IMAGE_NOT_CONTAINS_SCENE_DATA\" && !this.isToolSupported(\"image\")) {\n this.setState({\n isLoading: false,\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageToolNotSupported\")\n });\n return;\n }\n\n this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n });\n\n this.handleCanvasContextMenu = event => {\n event.preventDefault();\n\n if ((\"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"touch\" || \"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"pen\" && // always allow if user uses a pen secondary button\n event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.SECONDARY) && this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const element = this.getElementAtPosition(x, y, {\n preferSelected: true,\n includeLockedElements: true\n });\n const selectedElements = this.scene.getSelectedElements(this.state);\n const isHittignCommonBoundBox = this.isHittingCommonBoundingBoxOfSelectedElements({\n x,\n y\n }, selectedElements);\n const type = element || isHittignCommonBoundBox ? \"element\" : \"canvas\";\n const container = this.excalidrawContainerRef.current;\n const {\n top: offsetTop,\n left: offsetLeft\n } = container.getBoundingClientRect();\n const left = event.clientX - offsetLeft;\n const top = event.clientY - offsetTop;\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"contextMenu\", \"openContextMenu\", type);\n this.setState(Object.assign(Object.assign({}, element && !this.state.selectedElementIds[element.id] ? Object.assign(Object.assign(Object.assign({}, this.state), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: this.state.editingGroupId,\n selectedElementIds: {\n [element.id]: true\n }\n }, this.scene.getNonDeletedElements(), this.state, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(element) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(element, this.scene) : null\n }) : this.state), {\n showHyperlinkPopup: false\n }), () => {\n this.setState({\n contextMenu: {\n top,\n left,\n items: this.getContextMenuItems(type)\n }\n });\n });\n };\n\n this.maybeDragNewGenericElement = (pointerDownState, event) => {\n var _a, _b, _c, _d, _e;\n\n const draggingElement = this.state.draggingElement;\n const pointerCoords = pointerDownState.lastCoords;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"selection\" && this.state.activeTool.type !== \"eraser\") {\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.origin.x, pointerDownState.origin.y, pointerCoords.x, pointerCoords.y, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.x, pointerCoords.x), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.y, pointerCoords.y), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event));\n } else {\n let [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const image = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(draggingElement) && ((_a = this.imageCache.get(draggingElement.fileId)) === null || _a === void 0 ? void 0 : _a.image);\n const aspectRatio = image && !(image instanceof Promise) ? image.width / image.height : null;\n this.maybeCacheReferenceSnapPoints(event, [draggingElement]);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.snapNewElement)(draggingElement, this.state, event, {\n x: pointerDownState.originInGrid.x + ((_c = (_b = this.state.originSnapOffset) === null || _b === void 0 ? void 0 : _b.x) !== null && _c !== void 0 ? _c : 0),\n y: pointerDownState.originInGrid.y + ((_e = (_d = this.state.originSnapOffset) === null || _d === void 0 ? void 0 : _d.y) !== null && _e !== void 0 ? _e : 0)\n }, {\n x: gridX - pointerDownState.originInGrid.x,\n y: gridY - pointerDownState.originInGrid.y\n });\n gridX += snapOffset.x;\n gridY += snapOffset.y;\n this.setState({\n snapLines\n });\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.originInGrid.x, pointerDownState.originInGrid.y, gridX, gridY, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.x, gridX), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.y, gridY), (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), aspectRatio, this.state.originSnapOffset);\n this.maybeSuggestBindingForAll([draggingElement]); // highlight elements that are to be added to frames on frames creation\n\n if (this.state.activeTool.type === \"frame\") {\n this.setState({\n elementsToHighlight: (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), draggingElement, this.state)\n });\n }\n }\n };\n\n this.maybeHandleResize = (pointerDownState, event) => {\n const selectedElements = this.scene.getSelectedElements(this.state);\n const selectedFrames = selectedElements.filter(element => element.type === \"frame\");\n const transformHandleType = pointerDownState.resize.handleType;\n\n if (selectedFrames.length > 0 && transformHandleType === \"rotation\") {\n return false;\n }\n\n this.setState({\n // TODO: rename this state field to \"isScaling\" to distinguish\n // it from the generic \"isResizing\" which includes scaling and\n // rotating\n isResizing: transformHandleType && transformHandleType !== \"rotation\",\n isRotating: transformHandleType === \"rotation\",\n activeEmbeddable: null\n });\n const pointerCoords = pointerDownState.lastCoords;\n let [resizeX, resizeY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x - pointerDownState.resize.offset.x, pointerCoords.y - pointerDownState.resize.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const frameElementsOffsetsMap = new Map();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getFrameChildren)(this.scene.getNonDeletedElements(), frame.id);\n elementsInFrame.forEach(element => {\n frameElementsOffsetsMap.set(frame.id + element.id, {\n x: element.x - frame.x,\n y: element.y - frame.y\n });\n });\n }); // check needed for avoiding flickering when a key gets pressed\n // during dragging\n\n if (!this.state.selectedElementsAreBeingDragged) {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const dragOffset = {\n x: gridX - pointerDownState.originInGrid.x,\n y: gridY - pointerDownState.originInGrid.y\n };\n const originalElements = [...pointerDownState.originalElements.values()];\n this.maybeCacheReferenceSnapPoints(event, selectedElements);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.snapResizingElements)(selectedElements, (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(originalElements, this.state), this.state, event, dragOffset, transformHandleType);\n resizeX += snapOffset.x;\n resizeY += snapOffset.y;\n this.setState({\n snapLines\n });\n }\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.transformElements)(pointerDownState, transformHandleType, selectedElements, pointerDownState.resize.arrowDirection, (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(selectedElements[0]) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y, this.state)) {\n this.maybeSuggestBindingForAll(selectedElements);\n const elementsToHighlight = new Set();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getFrameChildren)(this.scene.getNonDeletedElements(), frame.id); // keep elements' positions relative to their frames on frames resizing\n\n if (transformHandleType) {\n if (transformHandleType.includes(\"w\")) {\n elementsInFrame.forEach(element => {\n var _a, _b;\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: frame.x + (((_a = frameElementsOffsetsMap.get(frame.id + element.id)) === null || _a === void 0 ? void 0 : _a.x) || 0),\n y: frame.y + (((_b = frameElementsOffsetsMap.get(frame.id + element.id)) === null || _b === void 0 ? void 0 : _b.y) || 0)\n });\n });\n }\n\n if (transformHandleType.includes(\"n\")) {\n elementsInFrame.forEach(element => {\n var _a, _b;\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: frame.x + (((_a = frameElementsOffsetsMap.get(frame.id + element.id)) === null || _a === void 0 ? void 0 : _a.x) || 0),\n y: frame.y + (((_b = frameElementsOffsetsMap.get(frame.id + element.id)) === null || _b === void 0 ? void 0 : _b.y) || 0)\n });\n });\n }\n }\n\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), frame, this.state).forEach(element => elementsToHighlight.add(element));\n });\n this.setState({\n elementsToHighlight: [...elementsToHighlight]\n });\n return true;\n }\n\n return false;\n };\n\n this.getContextMenuItems = type => {\n const options = [];\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsPng, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsSvg); // canvas contextMenu\n // -------------------------------------------------------------------------\n\n if (type === \"canvas\") {\n if (this.state.viewModeEnabled) {\n return [...options, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleGridMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n }\n\n return [_actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsPng, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsSvg, _actions__WEBPACK_IMPORTED_MODULE_5__.copyText, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSelectAll, _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_48__.actionUnlockAllElements, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleGridMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleObjectsSnapMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n } // element contextMenu\n // -------------------------------------------------------------------------\n\n\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.copyText);\n\n if (this.state.viewModeEnabled) {\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, ...options];\n }\n\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionSelectAllElementsInFrame, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionRemoveAllElementsFromFrame, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, ...options, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyStyles, _actions__WEBPACK_IMPORTED_MODULE_5__.actionPasteStyles, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionGroup, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUnbindText, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBindText, _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_59__.actionWrapTextInContainer, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUngroup, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionAddToLibrary, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendBackward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringForward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendToBack, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringToFront, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipHorizontal, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipVertical, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleLinearEditor, _actions__WEBPACK_IMPORTED_MODULE_5__.actionLink, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDuplicateSelection, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleElementLock, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDeleteSelected];\n };\n\n this.handleWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault();\n\n if (isPanning) {\n return;\n }\n\n const {\n deltaX,\n deltaY\n } = event; // note that event.ctrlKey is necessary to handle pinch zooming\n\n if (event.metaKey || event.ctrlKey) {\n const sign = Math.sign(deltaY);\n const MAX_STEP = _constants__WEBPACK_IMPORTED_MODULE_12__.ZOOM_STEP * 100;\n const absDelta = Math.abs(deltaY);\n let delta = deltaY;\n\n if (absDelta > MAX_STEP) {\n delta = MAX_STEP * sign;\n }\n\n let newZoom = this.state.zoom.value - delta / 100; // increase zoom steps the more zoomed-in we are (applies to >100% only)\n\n newZoom += Math.log10(Math.max(1, this.state.zoom.value)) * -sign * // reduced amplification for small deltas (small movements on a trackpad)\n Math.min(1, absDelta / 20);\n this.translateCanvas(state => Object.assign(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(newZoom)\n }, state)), {\n shouldCacheIgnoreZoom: true\n }));\n this.resetShouldCacheIgnoreZoomDebounced();\n return;\n } // scroll horizontally when shift pressed\n\n\n if (event.shiftKey) {\n this.translateCanvas(({\n zoom,\n scrollX\n }) => ({\n // on Mac, shift+wheel tends to result in deltaX\n scrollX: scrollX - (deltaY || deltaX) / zoom.value\n }));\n return;\n }\n\n this.translateCanvas(({\n zoom,\n scrollX,\n scrollY\n }) => ({\n scrollX: scrollX - deltaX / zoom.value,\n scrollY: scrollY - deltaY / zoom.value\n }));\n });\n\n this.savePointer = (x, y, button) => {\n var _a, _b;\n\n if (!x || !y) {\n return;\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: x,\n clientY: y\n }, this.state);\n\n if (isNaN(sceneX) || isNaN(sceneY)) {// sometimes the pointer goes off screen\n }\n\n const pointer = {\n x: sceneX,\n y: sceneY,\n tool: this.state.activeTool.type === \"laser\" ? \"laser\" : \"pointer\"\n };\n (_b = (_a = this.props).onPointerUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, {\n pointer,\n button,\n pointersMap: gesture.pointers\n });\n };\n\n this.resetShouldCacheIgnoreZoomDebounced = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n if (!this.unmounted) {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n }\n }, 300);\n\n this.updateDOMRect = cb => {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n width,\n height,\n left: offsetLeft,\n top: offsetTop\n } = excalidrawContainer.getBoundingClientRect();\n const {\n width: currentWidth,\n height: currentHeight,\n offsetTop: currentOffsetTop,\n offsetLeft: currentOffsetLeft\n } = this.state;\n\n if (width === currentWidth && height === currentHeight && offsetLeft === currentOffsetLeft && offsetTop === currentOffsetTop) {\n if (cb) {\n cb();\n }\n\n return;\n }\n\n this.setState({\n width,\n height,\n offsetLeft,\n offsetTop\n }, () => {\n cb && cb();\n });\n }\n };\n\n this.refresh = () => {\n this.setState(Object.assign({}, this.getCanvasOffsets()));\n };\n\n const defaultAppState = (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)();\n const {\n excalidrawAPI,\n viewModeEnabled = false,\n zenModeEnabled = false,\n gridModeEnabled = false,\n objectsSnapModeEnabled = false,\n theme = defaultAppState.theme,\n name = defaultAppState.name\n } = props;\n this.state = Object.assign(Object.assign(Object.assign(Object.assign({}, defaultAppState), {\n theme,\n isLoading: true\n }), this.getCanvasOffsets()), {\n viewModeEnabled,\n zenModeEnabled,\n objectsSnapModeEnabled,\n gridSize: gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null,\n name,\n width: window.innerWidth,\n height: window.innerHeight\n });\n this.id = (0,nanoid__WEBPACK_IMPORTED_MODULE_72__.nanoid)();\n this.library = new _data_library__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this);\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_30__[\"default\"]();\n this.canvas = document.createElement(\"canvas\");\n this.rc = roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_3__[\"default\"].canvas(this.canvas);\n this.renderer = new _scene_Renderer__WEBPACK_IMPORTED_MODULE_65__.Renderer(this.scene);\n\n if (excalidrawAPI) {\n const api = {\n updateScene: this.updateScene,\n updateLibrary: this.library.updateLibrary,\n addFiles: this.addFiles,\n resetScene: this.resetScene,\n getSceneElementsIncludingDeleted: this.getSceneElementsIncludingDeleted,\n history: {\n clear: this.resetHistory\n },\n scrollToContent: this.scrollToContent,\n getSceneElements: this.getSceneElements,\n getAppState: () => this.state,\n getFiles: () => this.files,\n refresh: this.refresh,\n setToast: this.setToast,\n id: this.id,\n setActiveTool: this.setActiveTool,\n setCursor: this.setCursor,\n resetCursor: this.resetCursor,\n updateFrameRendering: this.updateFrameRendering,\n toggleSidebar: this.toggleSidebar,\n onChange: cb => this.onChangeEmitter.on(cb),\n onPointerDown: cb => this.onPointerDownEmitter.on(cb),\n onPointerUp: cb => this.onPointerUpEmitter.on(cb)\n };\n\n if (typeof excalidrawAPI === \"function\") {\n excalidrawAPI(api);\n } else {\n console.error(\"excalidrawAPI should be a function!\");\n }\n }\n\n this.excalidrawContainerValue = {\n container: this.excalidrawContainerRef.current,\n id: this.id\n };\n this.fonts = new _scene_Fonts__WEBPACK_IMPORTED_MODULE_49__.Fonts({\n scene: this.scene,\n onSceneUpdated: this.onSceneUpdated\n });\n this.history = new _history__WEBPACK_IMPORTED_MODULE_24__[\"default\"]();\n this.actionManager = new _actions_manager__WEBPACK_IMPORTED_MODULE_7__.ActionManager(this.syncActionResult, () => this.state, () => this.scene.getElementsIncludingDeleted(), this);\n this.actionManager.registerAll(_actions_register__WEBPACK_IMPORTED_MODULE_8__.actions);\n this.actionManager.registerAction((0,_actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__.createUndoAction)(this.history));\n this.actionManager.registerAction((0,_actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__.createRedoAction)(this.history));\n }\n\n onWindowMessage(event) {\n if (event.origin !== \"https://player.vimeo.com\" && event.origin !== \"https://www.youtube.com\") {\n return;\n }\n\n let data = null;\n\n try {\n data = JSON.parse(event.data);\n } catch (e) {}\n\n if (!data) {\n return;\n }\n\n switch (event.origin) {\n case \"https://player.vimeo.com\":\n //Allowing for multiple instances of Excalidraw running in the window\n if (data.method === \"paused\") {\n let source = null;\n const iframes = document.body.querySelectorAll(\"iframe.excalidraw__embeddable\");\n\n if (!iframes) {\n break;\n }\n\n for (const iframe of iframes) {\n if (iframe.contentWindow === event.source) {\n source = iframe.contentWindow;\n }\n }\n\n source === null || source === void 0 ? void 0 : source.postMessage(JSON.stringify({\n method: data.value ? \"play\" : \"pause\",\n value: true\n }), \"*\");\n }\n\n break;\n\n case \"https://www.youtube.com\":\n if (data.event === \"infoDelivery\" && data.info && data.id && typeof data.info.playerState === \"number\") {\n const id = data.id;\n const playerState = data.info.playerState;\n\n if (Object.values(_constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES).includes(playerState)) {\n YOUTUBE_VIDEO_STATES.set(id, playerState);\n }\n }\n\n break;\n }\n }\n\n updateEmbeddableRef(id, ref) {\n if (ref) {\n this.iFrameRefs.set(id, ref);\n }\n }\n\n getHTMLIFrameElement(id) {\n return this.iFrameRefs.get(id);\n }\n\n handleEmbeddableCenterClick(element) {\n var _a, _b, _c, _d;\n\n if (((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) === element && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"active\") {\n return;\n } // The delay serves two purposes\n // 1. To prevent first click propagating to iframe on mobile,\n // else the click will immediately start and stop the video\n // 2. If the user double clicks the frame center to activate it\n // without the delay youtube will immediately open the video\n // in fullscreen mode\n\n\n setTimeout(() => {\n this.setState({\n activeEmbeddable: {\n element,\n state: \"active\"\n },\n selectedElementIds: {\n [element.id]: true\n },\n draggingElement: null,\n selectionElement: null\n });\n }, 100);\n const iframe = this.getHTMLIFrameElement(element.id);\n\n if (!(iframe === null || iframe === void 0 ? void 0 : iframe.contentWindow)) {\n return;\n }\n\n if (iframe.src.includes(\"youtube\")) {\n const state = YOUTUBE_VIDEO_STATES.get(element.id);\n\n if (!state) {\n YOUTUBE_VIDEO_STATES.set(element.id, _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.UNSTARTED);\n iframe.contentWindow.postMessage(JSON.stringify({\n event: \"listening\",\n id: element.id\n }), \"*\");\n }\n\n switch (state) {\n case _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.PLAYING:\n case _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.BUFFERING:\n (_c = iframe.contentWindow) === null || _c === void 0 ? void 0 : _c.postMessage(JSON.stringify({\n event: \"command\",\n func: \"pauseVideo\",\n args: \"\"\n }), \"*\");\n break;\n\n default:\n (_d = iframe.contentWindow) === null || _d === void 0 ? void 0 : _d.postMessage(JSON.stringify({\n event: \"command\",\n func: \"playVideo\",\n args: \"\"\n }), \"*\");\n }\n }\n\n if (iframe.src.includes(\"player.vimeo.com\")) {\n iframe.contentWindow.postMessage(JSON.stringify({\n method: \"paused\" //video play/pause in onWindowMessage handler\n\n }), \"*\");\n }\n }\n\n isEmbeddableCenter(el, event, sceneX, sceneY) {\n var _a, _b;\n\n return el && !event.altKey && !event.shiftKey && !event.metaKey && !event.ctrlKey && (((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) !== el || ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"hover\" || !this.state.activeEmbeddable) && sceneX >= el.x + el.width / 3 && sceneX <= el.x + 2 * el.width / 3 && sceneY >= el.y + el.height / 3 && sceneY <= el.y + 2 * el.height / 3;\n }\n\n renderEmbeddables() {\n const scale = this.state.zoom.value;\n const normalizedWidth = this.state.width;\n const normalizedHeight = this.state.height;\n const embeddableElements = this.scene.getNonDeletedElements().filter(el => (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(el) && !!el.validated);\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {\n children: embeddableElements.map(el => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: el.x,\n sceneY: el.y\n }, this.state);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)((0,_data_url__WEBPACK_IMPORTED_MODULE_46__.toValidURL)(el.link || \"\"));\n const isVisible = (0,_element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__.isElementInViewport)(el, normalizedWidth, normalizedHeight, this.state);\n const isActive = ((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) === el && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"active\";\n const isHovered = ((_c = this.state.activeEmbeddable) === null || _c === void 0 ? void 0 : _c.element) === el && ((_d = this.state.activeEmbeddable) === null || _d === void 0 ? void 0 : _d.state) === \"hover\";\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: (0,clsx__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\"excalidraw__embeddable-container\", {\n \"is-hovered\": isHovered\n }),\n style: {\n transform: isVisible ? `translate(${x - this.state.offsetLeft}px, ${y - this.state.offsetTop}px) scale(${scale})` : \"none\",\n display: isVisible ? \"block\" : \"none\",\n opacity: el.opacity / 100,\n [\"--embeddable-radius\"]: `${(0,_math__WEBPACK_IMPORTED_MODULE_28__.getCornerRadius)(Math.min(el.width, el.height), el)}px`\n }\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(\"div\", Object.assign({\n //this is a hack that addresses isse with embedded excalidraw.com embeddable\n //https://github.com/excalidraw/excalidraw/pull/6691#issuecomment-1607383938\n\n /*ref={(ref) => {\n if (!this.excalidrawContainerRef.current) {\n return;\n }\n const container = this.excalidrawContainerRef.current;\n const sh = container.scrollHeight;\n const ch = container.clientHeight;\n if (sh !== ch) {\n container.style.height = `${sh}px`;\n setTimeout(() => {\n container.style.height = `100%`;\n });\n }\n }}*/\n className: \"excalidraw__embeddable-container__inner\",\n style: {\n width: isVisible ? `${el.width}px` : 0,\n height: isVisible ? `${el.height}px` : 0,\n transform: isVisible ? `rotate(${el.angle}rad)` : \"none\",\n pointerEvents: isActive ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled\n }\n }, {\n children: [isHovered && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: \"excalidraw__embeddable-hint\"\n }, {\n children: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"buttons.embeddableInteractionButton\")\n })), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: \"excalidraw__embeddable__outer\",\n style: {\n padding: `${el.strokeWidth}px`\n }\n }, {\n children: (_g = (_f = (_e = this.props).renderEmbeddable) === null || _f === void 0 ? void 0 : _f.call(_e, el, this.state)) !== null && _g !== void 0 ? _g : (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"iframe\", {\n ref: ref => this.updateEmbeddableRef(el.id, ref),\n className: \"excalidraw__embeddable\",\n srcDoc: (embedLink === null || embedLink === void 0 ? void 0 : embedLink.type) === \"document\" ? embedLink.srcdoc(this.state.theme) : undefined,\n src: (embedLink === null || embedLink === void 0 ? void 0 : embedLink.type) !== \"document\" ? (_h = embedLink === null || embedLink === void 0 ? void 0 : embedLink.link) !== null && _h !== void 0 ? _h : \"\" : undefined,\n // https://stackoverflow.com/q/18470015\n scrolling: \"no\",\n referrerPolicy: \"no-referrer-when-downgrade\",\n title: \"Excalidraw Embedded Content\",\n allow: \"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\",\n allowFullScreen: true,\n sandbox: `${((_j = embedLink === null || embedLink === void 0 ? void 0 : embedLink.sandbox) === null || _j === void 0 ? void 0 : _j.allowSameOrigin) ? \"allow-same-origin\" : \"\"} allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads`\n })\n }))]\n }))\n }), el.id);\n })\n });\n }\n\n render() {\n var _a, _b, _c;\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n const {\n renderTopRightUI,\n renderCustomStats\n } = this.props;\n const versionNonce = this.scene.getVersionNonce();\n const {\n canvasElements,\n visibleElements\n } = this.renderer.getRenderableElements({\n versionNonce,\n zoom: this.state.zoom,\n offsetLeft: this.state.offsetLeft,\n offsetTop: this.state.offsetTop,\n scrollX: this.state.scrollX,\n scrollY: this.state.scrollY,\n height: this.state.height,\n width: this.state.width,\n editingElement: this.state.editingElement,\n pendingImageElementId: this.state.pendingImageElementId\n });\n const shouldBlockPointerEvents = !(this.state.editingElement && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(this.state.editingElement)) && (this.state.selectionElement || this.state.draggingElement || this.state.resizingElement || this.state.activeTool.type === \"laser\" && // technically we can just test on this once we make it more safe\n this.state.cursorButton === \"down\" || this.state.editingElement && !(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement));\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: (0,clsx__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\"excalidraw excalidraw-container\", {\n \"excalidraw--view-mode\": this.state.viewModeEnabled,\n \"excalidraw--mobile\": this.device.editor.isMobile\n }),\n style: {\n [\"--ui-pointerEvents\"]: shouldBlockPointerEvents ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled\n },\n ref: this.excalidrawContainerRef,\n onDrop: this.handleAppOnDrop,\n tabIndex: 0,\n onKeyDown: this.props.handleKeyboardGlobally ? undefined : this.onKeyDown\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AppContext.Provider, Object.assign({\n value: this\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AppPropsContext.Provider, Object.assign({\n value: this.props\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawContainerContext.Provider, Object.assign({\n value: this.excalidrawContainerValue\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(DeviceContext.Provider, Object.assign({\n value: this.device\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawSetAppStateContext.Provider, Object.assign({\n value: this.setAppState\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawAppStateContext.Provider, Object.assign({\n value: this.state\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(ExcalidrawElementsContext.Provider, Object.assign({\n value: this.scene.getNonDeletedElements()\n }, {\n children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(ExcalidrawActionManagerContext.Provider, Object.assign({\n value: this.actionManager\n }, {\n children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_LayerUI__WEBPACK_IMPORTED_MODULE_36__[\"default\"], Object.assign({\n canvas: this.canvas,\n appState: this.state,\n files: this.files,\n setAppState: this.setAppState,\n actionManager: this.actionManager,\n elements: this.scene.getNonDeletedElements(),\n onLockToggle: this.toggleLock,\n onPenModeToggle: this.togglePenMode,\n onHandToolToggle: this.onHandToolToggle,\n langCode: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.getLanguage)().code,\n renderTopRightUI: renderTopRightUI,\n renderCustomStats: renderCustomStats,\n showExitZenModeBtn: typeof ((_a = this.props) === null || _a === void 0 ? void 0 : _a.zenModeEnabled) === \"undefined\" && this.state.zenModeEnabled,\n UIOptions: this.props.UIOptions,\n onExportImage: this.onExportImage,\n renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === \"selection\" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,\n app: this,\n isCollaborating: this.props.isCollaborating\n }, {\n children: [this.props.children, this.state.openDialog === \"mermaid\" && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_MermaidToExcalidraw__WEBPACK_IMPORTED_MODULE_67__[\"default\"], {})]\n })), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-textEditorContainer\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-contextMenuContainer\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-eye-dropper-container\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_LaserTool_LaserTool__WEBPACK_IMPORTED_MODULE_68__.LaserToolOverlay, {\n manager: this.laserPathManager\n }), selectedElements.length === 1 && !this.state.contextMenu && this.state.showHyperlinkPopup && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.Hyperlink, {\n element: selectedElements[0],\n setAppState: this.setAppState,\n onLinkOpen: this.props.onLinkOpen,\n setToast: this.setToast\n }, selectedElements[0].id), this.state.toast !== null && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_Toast__WEBPACK_IMPORTED_MODULE_37__.Toast, {\n message: this.state.toast.message,\n onClose: () => this.setToast(null),\n duration: this.state.toast.duration,\n closable: this.state.toast.closable\n }), this.state.contextMenu && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_ContextMenu__WEBPACK_IMPORTED_MODULE_35__.ContextMenu, {\n items: this.state.contextMenu.items,\n top: this.state.contextMenu.top,\n left: this.state.contextMenu.left,\n actionManager: this.actionManager,\n onClose: callback => {\n this.setState({\n contextMenu: null\n }, () => {\n this.focusContainer();\n callback === null || callback === void 0 ? void 0 : callback();\n });\n }\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_64__.StaticCanvas, {\n canvas: this.canvas,\n rc: this.rc,\n elements: canvasElements,\n visibleElements: visibleElements,\n versionNonce: versionNonce,\n selectionNonce: (_b = this.state.selectionElement) === null || _b === void 0 ? void 0 : _b.versionNonce,\n scale: window.devicePixelRatio,\n appState: this.state,\n renderConfig: {\n imageCache: this.imageCache,\n isExporting: false,\n renderGrid: true\n }\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_64__.InteractiveCanvas, {\n containerRef: this.excalidrawContainerRef,\n canvas: this.interactiveCanvas,\n elements: canvasElements,\n visibleElements: visibleElements,\n selectedElements: selectedElements,\n versionNonce: versionNonce,\n selectionNonce: (_c = this.state.selectionElement) === null || _c === void 0 ? void 0 : _c.versionNonce,\n scale: window.devicePixelRatio,\n appState: this.state,\n renderInteractiveSceneCallback: this.renderInteractiveSceneCallback,\n handleCanvasRef: this.handleInteractiveCanvasRef,\n onContextMenu: this.handleCanvasContextMenu,\n onPointerMove: this.handleCanvasPointerMove,\n onPointerUp: this.handleCanvasPointerUp,\n onPointerCancel: this.removePointer,\n onTouchMove: this.handleTouchMove,\n onPointerDown: this.handleCanvasPointerDown,\n onDoubleClick: this.handleCanvasDoubleClick\n }), this.renderFrameNames()]\n })), this.renderEmbeddables()]\n }))\n }))\n }))\n }))\n }))\n }))\n }))\n }));\n }\n\n componentDidMount() {\n var _a;\n\n return __awaiter(this, void 0, void 0, function* () {\n this.unmounted = false;\n this.excalidrawContainerValue.container = this.excalidrawContainerRef.current;\n\n if (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n const setState = this.setState.bind(this);\n Object.defineProperties(window.h, {\n state: {\n configurable: true,\n get: () => {\n return this.state;\n }\n },\n setState: {\n configurable: true,\n value: (...args) => {\n return this.setState(...args);\n }\n },\n app: {\n configurable: true,\n value: this\n },\n history: {\n configurable: true,\n value: this.history\n }\n });\n }\n\n this.scene.addCallback(this.onSceneUpdated);\n this.addEventListeners();\n\n if (this.props.autoFocus && this.excalidrawContainerRef.current) {\n this.focusContainer();\n }\n\n if ( // bounding rects don't work in tests so updating\n // the state on init would result in making the test enviro run\n // in mobile breakpoint (0 width/height), making everything fail\n !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTestEnv)()) {\n this.refreshViewportBreakpoints();\n this.refreshEditorBreakpoints();\n }\n\n if (supportsResizeObserver && this.excalidrawContainerRef.current) {\n this.resizeObserver = new ResizeObserver(() => {\n this.refreshEditorBreakpoints();\n this.updateDOMRect();\n });\n (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(this.excalidrawContainerRef.current);\n }\n\n const searchParams = new URLSearchParams(window.location.search.slice(1));\n\n if (searchParams.has(\"web-share-target\")) {\n // Obtain a file that was shared via the Web Share Target API.\n this.restoreFileFromShare();\n } else {\n this.updateDOMRect(this.initializeScene);\n } // note that this check seems to always pass in localhost\n\n\n if ((0,_constants__WEBPACK_IMPORTED_MODULE_12__.isBrave)() && !(0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isMeasureTextSupported)()) {\n this.setState({\n errorMessage: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_60__[\"default\"], {})\n });\n }\n });\n }\n\n componentWillUnmount() {\n var _a;\n\n this.renderer.destroy();\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_30__[\"default\"]();\n this.renderer = new _scene_Renderer__WEBPACK_IMPORTED_MODULE_65__.Renderer(this.scene);\n this.files = {};\n this.imageCache.clear();\n (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();\n this.unmounted = true;\n this.removeEventListeners();\n this.scene.destroy();\n this.library.destroy();\n this.laserPathManager.destroy();\n this.onChangeEmitter.destroy();\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache.destroy();\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.destroy();\n clearTimeout(touchTimeout);\n _scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected.clearCache();\n _groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements.clearCache();\n touchTimeout = 0;\n }\n\n removeEventListeners() {\n var _a, _b, _c, _d;\n\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel);\n (_b = this.nearestScrollableContainer) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MESSAGE, this.onWindowMessage, false);\n }\n\n addEventListeners() {\n var _a, _b, _c, _d, _e;\n\n this.removeEventListeners();\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MESSAGE, this.onWindowMessage, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer); // #3553\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel, {\n passive: false\n });\n\n if (this.props.handleKeyboardGlobally) {\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp, {\n passive: true\n });\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition); // rerender text elements on font load to fix #637 && #1553\n\n (_c = (_b = document.fonts) === null || _b === void 0 ? void 0 : _b.addEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, \"loadingdone\", event => {\n const loadedFontFaces = event.fontfaces;\n this.fonts.onFontsLoaded(loadedFontFaces);\n }); // Safari-only desktop pinch zoom\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n\n if (this.props.detectScroll) {\n this.nearestScrollableContainer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getNearestScrollableContainer)(this.excalidrawContainerRef.current);\n this.nearestScrollableContainer.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n }\n\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_e = this.excalidrawContainerRef.current) === null || _e === void 0 ? void 0 : _e.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n }\n\n componentDidUpdate(prevProps, prevState) {\n var _a, _b, _c, _d, _e, _f;\n\n this.updateEmbeddables();\n\n if (!this.state.showWelcomeScreen && !this.scene.getElementsIncludingDeleted().length) {\n this.setState({\n showWelcomeScreen: true\n });\n }\n\n if (prevProps.UIOptions.dockedSidebarBreakpoint !== this.props.UIOptions.dockedSidebarBreakpoint) {\n this.refreshEditorBreakpoints();\n }\n\n if (prevState.scrollX !== this.state.scrollX || prevState.scrollY !== this.state.scrollY) {\n (_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.onScrollChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.state.scrollX, this.state.scrollY);\n }\n\n if (Object.keys(this.state.selectedElementIds).length && (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n\n if (this.state.activeTool.type === \"eraser\" && prevState.theme !== this.state.theme) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setEraserCursor)(this.interactiveCanvas, this.state.theme);\n } // Hide hyperlink popup if shown when element type is not selection\n\n\n if (prevState.activeTool.type === \"selection\" && this.state.activeTool.type !== \"selection\" && this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: false\n });\n }\n\n if (prevProps.langCode !== this.props.langCode) {\n this.updateLanguage();\n }\n\n if (prevProps.viewModeEnabled !== this.props.viewModeEnabled) {\n this.setState({\n viewModeEnabled: !!this.props.viewModeEnabled\n });\n }\n\n if (prevState.viewModeEnabled !== this.state.viewModeEnabled) {\n this.addEventListeners();\n this.deselectElements();\n }\n\n if (prevProps.zenModeEnabled !== this.props.zenModeEnabled) {\n this.setState({\n zenModeEnabled: !!this.props.zenModeEnabled\n });\n }\n\n if (prevProps.theme !== this.props.theme && this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {\n this.setState({\n gridSize: this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null\n });\n }\n\n if (this.props.name && prevProps.name !== this.props.name) {\n this.setState({\n name: this.props.name\n });\n }\n\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.classList.toggle(\"theme--dark\", this.state.theme === \"dark\");\n\n if (this.state.editingLinearElement && !this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {\n // defer so that the commitToHistory flag isn't reset via current update\n setTimeout(() => {\n // execute only if the condition still holds when the deferred callback\n // executes (it can be scheduled multiple times depending on how\n // many times the component renders)\n this.state.editingLinearElement && this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } // failsafe in case the state is being updated in incorrect order resulting\n // in the editingElement being now a deleted element\n\n\n if ((_d = this.state.editingElement) === null || _d === void 0 ? void 0 : _d.isDeleted) {\n this.setState({\n editingElement: null\n });\n }\n\n if (this.state.selectedLinearElement && !this.state.selectedElementIds[this.state.selectedLinearElement.elementId]) {\n // To make sure `selectedLinearElement` is in sync with `selectedElementIds`, however this shouldn't be needed once\n // we have a single API to update `selectedElementIds`\n this.setState({\n selectedLinearElement: null\n });\n }\n\n const {\n multiElement\n } = prevState;\n\n if (prevState.activeTool !== this.state.activeTool && multiElement != null && (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(multiElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(multiElement, this.state, this.scene, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)(_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1)));\n }\n\n this.history.record(this.state, this.scene.getElementsIncludingDeleted()); // Do not notify consumers if we're still loading the scene. Among other\n // potential issues, this fixes a case where the tab isn't focused during\n // init, which would trigger onChange with empty elements, which would then\n // override whatever is in localStorage currently.\n\n if (!this.state.isLoading) {\n (_f = (_e = this.props).onChange) === null || _f === void 0 ? void 0 : _f.call(_e, this.scene.getElementsIncludingDeleted(), this.state, this.files);\n this.onChangeEmitter.trigger(this.scene.getElementsIncludingDeleted(), this.state, this.files);\n }\n }\n\n static resetTapTwice() {\n didTapTwice = false;\n } // TODO rewrite this to paste both text & images at the same time if\n // pasted data contains both\n\n\n addElementsFromMixedContentPaste(mixedContent, {\n isPlainPaste,\n sceneX,\n sceneY\n }) {\n return __awaiter(this, void 0, void 0, function* () {\n if (!isPlainPaste && mixedContent.some(node => node.type === \"imageUrl\") && this.isToolSupported(\"image\")) {\n const imageURLs = mixedContent.filter(node => node.type === \"imageUrl\").map(node => node.value);\n const responses = yield Promise.all(imageURLs.map(url => __awaiter(this, void 0, void 0, function* () {\n try {\n return {\n file: yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.ImageURLToFile)(url)\n };\n } catch (error) {\n return {\n errorMessage: error.message\n };\n }\n })));\n let y = sceneY;\n let firstImageYOffsetDone = false;\n const nextSelectedIds = {};\n\n for (const response of responses) {\n if (response.file) {\n const imageElement = this.createImageElement({\n sceneX,\n sceneY: y\n });\n const initializedImageElement = yield this.insertImageElement(imageElement, response.file);\n\n if (initializedImageElement) {\n // vertically center first image in the batch\n if (!firstImageYOffsetDone) {\n firstImageYOffsetDone = true;\n y -= initializedImageElement.height / 2;\n } // hack to reset the `y` coord because we vertically center during\n // insertImageElement\n\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(initializedImageElement, {\n y\n }, false);\n y = imageElement.y + imageElement.height + 25;\n nextSelectedIds[imageElement.id] = true;\n }\n }\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedIds, this.state)\n });\n const error = responses.find(response => !!response.errorMessage);\n\n if (error && error.errorMessage) {\n this.setState({\n errorMessage: error.errorMessage\n });\n }\n } else {\n const textNodes = mixedContent.filter(node => node.type === \"text\");\n\n if (textNodes.length) {\n this.addTextFromPaste(textNodes.map(node => node.value).join(\"\\n\\n\"), isPlainPaste);\n }\n }\n });\n }\n\n addTextFromPaste(text, isPlainPaste = false) {\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state);\n const textElementProps = {\n x,\n y,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roundness: null,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text,\n fontSize: this.state.currentItemFontSize,\n fontFamily: this.state.currentItemFontFamily,\n textAlign: this.state.currentItemTextAlign,\n verticalAlign: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n locked: false\n };\n const LINE_GAP = 10;\n let currentY = y;\n const lines = isPlainPaste ? [text] : text.split(\"\\n\");\n const textElements = lines.reduce((acc, line, idx) => {\n var _a;\n\n const text = line.trim();\n const lineHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(textElementProps.fontFamily);\n\n if (text.length) {\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x,\n y: currentY\n });\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)(Object.assign(Object.assign({}, textElementProps), {\n x,\n y: currentY,\n text,\n lineHeight,\n frameId: topLayerFrame ? topLayerFrame.id : null\n }));\n acc.push(element);\n currentY += element.height + LINE_GAP;\n } else {\n const prevLine = (_a = lines[idx - 1]) === null || _a === void 0 ? void 0 : _a.trim(); // add paragraph only if previous line was not empty, IOW don't add\n // more than one empty line\n\n if (prevLine) {\n currentY += (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getLineHeightInPx)(textElementProps.fontSize, lineHeight) + LINE_GAP;\n }\n }\n\n return acc;\n }, []);\n\n if (textElements.length === 0) {\n return;\n }\n\n const frameId = textElements[0].frameId;\n\n if (frameId) {\n this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));\n } else {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), ...textElements]);\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.fromEntries(textElements.map(el => [el.id, true])), this.state)\n });\n\n if (!isPlainPaste && textElements.length > 1 && PLAIN_PASTE_TOAST_SHOWN === false && !this.device.editor.isMobile) {\n this.setToast({\n message: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"toast.pasteAsSingleElement\", {\n shortcut: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getShortcutKey)(\"CtrlOrCmd+Shift+V\")\n }),\n duration: 5000\n });\n PLAIN_PASTE_TOAST_SHOWN = true;\n }\n\n this.history.resumeRecording();\n }\n\n handleTextWysiwyg(element, {\n isExistingElement = false\n }) {\n const updateElement = (text, originalText, isDeleted) => {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted().map(_element => {\n if (_element.id === element.id && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(_element)) {\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.updateTextElement)(_element, {\n text,\n isDeleted,\n originalText\n });\n }\n\n return _element;\n })]);\n };\n\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.textWysiwyg)({\n id: element.id,\n canvas: this.canvas,\n getViewportCoords: (x, y) => {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: x,\n sceneY: y\n }, this.state);\n return [viewportX - this.state.offsetLeft, viewportY - this.state.offsetTop];\n },\n onChange: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(text => {\n updateElement(text, text, false);\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element);\n }\n }),\n onSubmit: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(({\n text,\n viaKeyboard,\n originalText\n }) => {\n const isDeleted = !text.trim();\n updateElement(text, originalText, isDeleted); // select the created text element only if submitting via keyboard\n // (when submitting via click it should act as signal to deselect)\n\n if (!isDeleted && viaKeyboard) {\n const elementIdToSelect = element.containerId ? element.containerId : element.id;\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [elementIdToSelect]: true\n }), prevState)\n }));\n }\n\n if (isDeleted) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDeletion)(this.scene.getNonDeletedElements(), [element]);\n }\n\n if (!isDeleted || isExistingElement) {\n this.history.resumeRecording();\n }\n\n this.setState({\n draggingElement: null,\n editingElement: null\n });\n\n if (this.state.activeTool.locked) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n this.focusContainer();\n }),\n element,\n excalidrawContainer: this.excalidrawContainerRef.current,\n app: this\n }); // deselect all other elements when inserting text\n\n this.deselectElements(); // do an initial update to re-initialize element position since we were\n // modifying element's x/y for sake of editor (case: syncing to remote)\n\n updateElement(element.text, element.originalText, false);\n }\n\n deselectElements() {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n getTextElementAtPosition(x, y) {\n const element = this.getElementAtPosition(x, y, {\n includeBoundTextElement: true\n });\n\n if (element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && !element.isDeleted) {\n return element;\n }\n\n return null;\n }\n\n getElementAtPosition(x, y, opts) {\n const allHitElements = this.getElementsAtPosition(x, y, opts === null || opts === void 0 ? void 0 : opts.includeBoundTextElement, opts === null || opts === void 0 ? void 0 : opts.includeLockedElements);\n\n if (allHitElements.length > 1) {\n if (opts === null || opts === void 0 ? void 0 : opts.preferSelected) {\n for (let index = allHitElements.length - 1; index > -1; index--) {\n if (this.state.selectedElementIds[allHitElements[index].id]) {\n return allHitElements[index];\n }\n }\n }\n\n const elementWithHighestZIndex = allHitElements[allHitElements.length - 1]; // If we're hitting element with highest z-index only on its bounding box\n // while also hitting other element figure, the latter should be considered.\n\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(elementWithHighestZIndex, this.state, this.frameNameBoundsCache, x, y) ? allHitElements[allHitElements.length - 2] : elementWithHighestZIndex;\n }\n\n if (allHitElements.length === 1) {\n return allHitElements[0];\n }\n\n return null;\n }\n\n getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {\n const elements = includeBoundTextElement && includeLockedElements ? this.scene.getNonDeletedElements() : this.scene.getNonDeletedElements().filter(element => (includeLockedElements || !element.locked) && (includeBoundTextElement || !((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && element.containerId)));\n return (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsAtPosition)(elements, element => (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(element, this.state, this.frameNameBoundsCache, x, y)).filter(element => {\n // hitting a frame's element from outside the frame is not considered a hit\n const containingFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(element);\n return containingFrame && this.state.frameRendering.enabled && this.state.frameRendering.clip ? (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)({\n x,\n y\n }, containingFrame) : true;\n });\n }\n\n handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {\n const element = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getElement(linearElementEditor.elementId);\n const boundTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(element);\n\n if (!element) {\n return;\n }\n\n if (this.state.selectedLinearElement) {\n let hoverPointIndex = -1;\n let segmentMidPointHoveredCoords = null;\n\n if ((0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(element, this.state, this.frameNameBoundsCache, [scenePointerX, scenePointerY])) {\n hoverPointIndex = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointIndexUnderCursor(element, this.state.zoom, scenePointerX, scenePointerY);\n segmentMidPointHoveredCoords = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, {\n x: scenePointerX,\n y: scenePointerY\n }, this.state);\n\n if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n } else if ((0,_element_transformHandles__WEBPACK_IMPORTED_MODULE_47__.shouldShowBoundingBox)([element], this.state) && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n } else if (boundTextElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(boundTextElement, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n\n if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n hoverPointIndex\n })\n });\n }\n\n if (!_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.arePointsEqual(this.state.selectedLinearElement.segmentMidPointHoveredCoords, segmentMidPointHoveredCoords)) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n segmentMidPointHoveredCoords\n })\n });\n }\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n\n maybeCleanupAfterMissingPointerUp(event) {\n if (lastPointerUp !== null) {\n // Unfortunately, sometimes we don't get a pointerup after a pointerdown,\n // this can happen when a contextual menu or alert is triggered. In order to avoid\n // being in a weird state, we clean up on the next pointerdown\n lastPointerUp(event);\n }\n }\n\n updateGestureOnPointerDown(event) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n\n if (gesture.pointers.size === 2) {\n gesture.lastCenter = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n gesture.initialScale = this.state.zoom.value;\n gesture.initialDistance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n }\n }\n\n initialPointerDownState(event) {\n const origin = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedElements = this.scene.getSelectedElements(this.state);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return {\n origin,\n withCmdOrCtrl: event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD],\n originInGrid: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(origin.x, origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize)),\n scrollbars: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop),\n // we need to duplicate because we'll be updating this state\n lastCoords: Object.assign({}, origin),\n originalElements: this.scene.getNonDeletedElements().reduce((acc, element) => {\n acc.set(element.id, (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.deepCopyElement)(element));\n return acc;\n }, new Map()),\n resize: {\n handleType: false,\n isResizing: false,\n offset: {\n x: 0,\n y: 0\n },\n arrowDirection: \"origin\",\n center: {\n x: (maxX + minX) / 2,\n y: (maxY + minY) / 2\n }\n },\n hit: {\n element: null,\n allHitElements: [],\n wasAddedToSelection: false,\n hasBeenDuplicated: false,\n hasHitCommonBoundingBoxOfSelectedElements: this.isHittingCommonBoundingBoxOfSelectedElements(origin, selectedElements)\n },\n drag: {\n hasOccurred: false,\n offset: null\n },\n eventListeners: {\n onMove: null,\n onUp: null,\n onKeyUp: null,\n onKeyDown: null\n },\n boxSelection: {\n hasOccurred: false\n },\n elementIdsToErase: {}\n };\n } // Returns whether the event is a dragging a scrollbar\n\n\n handleDraggingScrollBar(event, pointerDownState) {\n if (!(pointerDownState.scrollbars.isOverEither && !this.state.multiElement)) {\n return false;\n }\n\n isDraggingScrollBar = true;\n pointerDownState.lastCoords.x = event.clientX;\n pointerDownState.lastCoords.y = event.clientY;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n this.handlePointerMoveOverScrollbars(event, pointerDownState);\n });\n const onPointerUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isDraggingScrollBar = false;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.setCursorForShape)(this.interactiveCanvas, this.state);\n lastPointerUp = null;\n this.setState({\n cursorButton: \"up\"\n });\n this.savePointer(event.clientX, event.clientY, \"up\");\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n onPointerMove.flush();\n });\n lastPointerUp = onPointerUp;\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n return true;\n }\n\n isASelectedElement(hitElement) {\n return hitElement != null && this.state.selectedElementIds[hitElement.id];\n }\n\n isHittingCommonBoundingBoxOfSelectedElements(point, selectedElements) {\n if (selectedElements.length < 2) {\n return false;\n } // How many pixels off the shape boundary we still consider a hit\n\n\n const threshold = 10 / this.state.zoom.value;\n const [x1, y1, x2, y2] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return point.x > x1 - threshold && point.x < x2 + threshold && point.y > y1 - threshold && point.y < y2 + threshold;\n }\n\n getCurrentItemRoundness(elementType) {\n return this.state.currentItemRoundness === \"round\" ? {\n type: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isUsingAdaptiveRadius)(elementType) ? _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.ADAPTIVE_RADIUS : _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null;\n }\n\n maybeCacheReferenceSnapPoints(event, selectedElements, recomputeAnyways = false) {\n if ((0,_snapping__WEBPACK_IMPORTED_MODULE_58__.isSnappingEnabled)({\n event,\n appState: this.state,\n selectedElements\n }) && (recomputeAnyways || !_snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.getReferenceSnapPoints())) {\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.setReferenceSnapPoints((0,_snapping__WEBPACK_IMPORTED_MODULE_58__.getReferenceSnapPoints)(this.scene.getNonDeletedElements(), selectedElements, this.state));\n }\n }\n\n maybeCacheVisibleGaps(event, selectedElements, recomputeAnyways = false) {\n if ((0,_snapping__WEBPACK_IMPORTED_MODULE_58__.isSnappingEnabled)({\n event,\n appState: this.state,\n selectedElements\n }) && (recomputeAnyways || !_snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.getVisibleGaps())) {\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.setVisibleGaps((0,_snapping__WEBPACK_IMPORTED_MODULE_58__.getVisibleGaps)(this.scene.getNonDeletedElements(), selectedElements, this.state));\n }\n }\n\n onKeyDownFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onKeyUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // Prevents focus from escaping excalidraw tab\n event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ALT && event.preventDefault();\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onPointerMoveFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n var _a, _b; // We need to initialize dragOffsetXY only after we've updated\n // `state.selectedElementIds` on pointerDown. Doing it here in pointerMove\n // event handler should hopefully ensure we're already working with\n // the updated state.\n\n\n if (pointerDownState.drag.offset === null) {\n pointerDownState.drag.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getDragOffsetXY)(this.scene.getSelectedElements(this.state), pointerDownState.origin.x, pointerDownState.origin.y));\n }\n\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n if (this.handlePointerMoveOverScrollbars(event, pointerDownState)) {\n return;\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.handleEraser(event, pointerDownState, pointerCoords);\n return;\n }\n\n if (this.state.activeTool.type === \"laser\") {\n this.laserPathManager.addPointToPath(pointerCoords.x, pointerCoords.y);\n }\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize); // for arrows/lines, don't start dragging until a given threshold\n // to ensure we don't create a 2-point arrow by mistake when\n // user clicks mouse in a way that it moves a tiny bit (thus\n // triggering pointermove)\n\n if (!pointerDownState.drag.hasOccurred && (this.state.activeTool.type === \"arrow\" || this.state.activeTool.type === \"line\")) {\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerCoords.x, pointerCoords.y, pointerDownState.origin.x, pointerDownState.origin.y) < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD) {\n return;\n }\n }\n\n if (pointerDownState.resize.isResizing) {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return true;\n }\n }\n\n if (this.state.selectedLinearElement) {\n const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;\n\n if (_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.shouldAddMidpoint(this.state.selectedLinearElement, pointerCoords, this.state)) {\n const ret = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.addMidpoint(this.state.selectedLinearElement, pointerCoords, this.state, !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]);\n\n if (!ret) {\n return;\n } // Since we are reading from previous state which is not possible with\n // automatic batching in React 18 hence using flush sync to synchronously\n // update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.\n\n\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n if (this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n pointerDownState: ret.pointerDownState,\n selectedPointsIndices: ret.selectedPointsIndices\n })\n });\n }\n\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: Object.assign(Object.assign({}, this.state.editingLinearElement), {\n pointerDownState: ret.pointerDownState,\n selectedPointsIndices: ret.selectedPointsIndices\n })\n });\n }\n });\n return;\n } else if (linearElementEditor.pointerDownState.segmentMidpoint.value !== null && !linearElementEditor.pointerDownState.segmentMidpoint.added) {\n return;\n }\n\n const didDrag = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointDragging(event, this.state, pointerCoords.x, pointerCoords.y, (element, pointsSceneCoords) => {\n this.maybeSuggestBindingsForLinearElementAtCoords(element, pointsSceneCoords);\n }, linearElementEditor);\n\n if (didDrag) {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n pointerDownState.drag.hasOccurred = true;\n\n if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {\n this.setState({\n editingLinearElement: Object.assign(Object.assign({}, this.state.editingLinearElement), {\n isDragging: true\n })\n });\n }\n\n if (!this.state.selectedLinearElement.isDragging) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n isDragging: true\n })\n });\n }\n\n return;\n }\n }\n\n const hasHitASelectedElement = pointerDownState.hit.allHitElements.some(element => this.isASelectedElement(element));\n const isSelectingPointsInLineEditor = this.state.editingLinearElement && event.shiftKey && this.state.editingLinearElement.elementId === ((_a = pointerDownState.hit.element) === null || _a === void 0 ? void 0 : _a.id);\n\n if ((hasHitASelectedElement || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) && !isSelectingPointsInLineEditor) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.every(element => element.locked)) {\n return;\n }\n\n const selectedElementsHasAFrame = selectedElements.find(e => (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(e));\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(pointerCoords);\n this.setState({\n frameToHighlight: topLayerFrame && !selectedElementsHasAFrame ? topLayerFrame : null\n }); // Marking that click was used for dragging to check\n // if elements should be deselected on pointerup\n\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n }); // prevent dragging even if we're no longer holding cmd/ctrl otherwise\n // it would have weird results (stuff jumping all over the screen)\n // Checking for editingElement to avoid jump while editing on mobile #6503\n\n if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl && !this.state.editingElement && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) !== \"active\") {\n const dragOffset = {\n x: pointerCoords.x - pointerDownState.origin.x,\n y: pointerCoords.y - pointerDownState.origin.y\n };\n const originalElements = [...pointerDownState.originalElements.values()]; // We only drag in one direction if shift is pressed\n\n const lockDirection = event.shiftKey;\n\n if (lockDirection) {\n const distanceX = Math.abs(dragOffset.x);\n const distanceY = Math.abs(dragOffset.y);\n const lockX = lockDirection && distanceX < distanceY;\n const lockY = lockDirection && distanceX > distanceY;\n\n if (lockX) {\n dragOffset.x = 0;\n }\n\n if (lockY) {\n dragOffset.y = 0;\n }\n } // Snap cache *must* be synchronously popuplated before initial drag,\n // otherwise the first drag even will not snap, causing a jump before\n // it snaps to its position if previously snapped already.\n\n\n this.maybeCacheVisibleGaps(event, selectedElements);\n this.maybeCacheReferenceSnapPoints(event, selectedElements);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_58__.snapDraggedElements)((0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(originalElements, this.state), dragOffset, this.state, event);\n this.setState({\n snapLines\n }); // when we're editing the name of a frame, we want the user to be\n // able to select and interact with the text input\n\n !this.state.editingFrame && (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragSelectedElements)(pointerDownState, selectedElements, dragOffset, this.state, this.scene, snapOffset, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n this.maybeSuggestBindingForAll(selectedElements); // We duplicate the selected element if alt is pressed on pointer move\n\n if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {\n // Move the currently selected elements to the top of the z index stack, and\n // put the duplicates where the selected elements used to be.\n // (the origin point where the dragging started)\n pointerDownState.hit.hasBeenDuplicated = true;\n const nextElements = [];\n const elementsToAppend = [];\n const groupIdMap = new Map();\n const oldIdToDuplicatedId = new Map();\n const hitElement = pointerDownState.hit.element;\n const selectedElementIds = new Set(this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n }).map(element => element.id));\n const elements = this.scene.getElementsIncludingDeleted();\n\n for (const element of elements) {\n if (selectedElementIds.has(element.id) || // case: the state.selectedElementIds might not have been\n // updated yet by the time this mousemove event is fired\n element.id === (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && pointerDownState.hit.wasAddedToSelection) {\n const duplicatedElement = (0,_element__WEBPACK_IMPORTED_MODULE_16__.duplicateElement)(this.state.editingGroupId, groupIdMap, element);\n const origElement = pointerDownState.originalElements.get(element.id);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(duplicatedElement, {\n x: origElement.x,\n y: origElement.y\n }); // put duplicated element to pointerDownState.originalElements\n // so that we can snap to the duplicated element without releasing\n\n pointerDownState.originalElements.set(duplicatedElement.id, duplicatedElement);\n nextElements.push(duplicatedElement);\n elementsToAppend.push(element);\n oldIdToDuplicatedId.set(element.id, duplicatedElement.id);\n } else {\n nextElements.push(element);\n }\n }\n\n const nextSceneElements = [...nextElements, ...elementsToAppend];\n (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.bindTextToShapeAfterDuplication)(nextElements, elementsToAppend, oldIdToDuplicatedId);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, \"duplicatesServeAsOld\");\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.bindElementsToFramesAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);\n this.scene.replaceAllElements(nextSceneElements);\n this.maybeCacheVisibleGaps(event, selectedElements, true);\n this.maybeCacheReferenceSnapPoints(event, selectedElements, true);\n }\n\n return;\n }\n } // It is very important to read this.state within each move event,\n // otherwise we would read a stale one!\n\n\n const draggingElement = this.state.draggingElement;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"freedraw\") {\n const points = draggingElement.points;\n const dx = pointerCoords.x - draggingElement.x;\n const dy = pointerCoords.y - draggingElement.y;\n const lastPoint = points.length > 0 && points[points.length - 1];\n const discardPoint = lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;\n\n if (!discardPoint) {\n const pressures = draggingElement.simulatePressure ? draggingElement.pressures : [...draggingElement.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures\n });\n }\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n });\n const points = draggingElement.points;\n let dx = gridX - draggingElement.x;\n let dy = gridY - draggingElement.y;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event) && points.length === 2) {\n ({\n width: dx,\n height: dy\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)(draggingElement.x, draggingElement.y, pointerCoords.x, pointerCoords.y));\n }\n\n if (points.length === 1) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]]\n });\n } else if (points.length === 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points.slice(0, -1), [dx, dy]]\n });\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n // When creating a linear element by dragging\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [pointerCoords], this.state.startBoundElement);\n }\n } else {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n this.maybeDragNewGenericElement(pointerDownState, event);\n }\n\n if (this.state.activeTool.type === \"selection\") {\n pointerDownState.boxSelection.hasOccurred = true;\n const elements = this.scene.getNonDeletedElements(); // box-select line editor points\n\n if (this.state.editingLinearElement) {\n _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handleBoxSelection(event, this.state, this.setState.bind(this)); // regular box-select\n } else {\n let shouldReuseSelection = true;\n\n if (!event.shiftKey && (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(elements, this.state)) {\n if (pointerDownState.withCmdOrCtrl && pointerDownState.hit.element) {\n this.setState(prevState => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)(Object.assign(Object.assign({}, prevState), {\n selectedElementIds: {\n [pointerDownState.hit.element.id]: true\n }\n }), this.scene.getNonDeletedElements(), prevState, this));\n } else {\n shouldReuseSelection = false;\n }\n }\n\n const elementsWithinSelection = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsWithinSelection)(elements, draggingElement);\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, shouldReuseSelection && prevState.selectedElementIds), elementsWithinSelection.reduce((acc, element) => {\n acc[element.id] = true;\n return acc;\n }, {}));\n\n if (pointerDownState.hit.element) {\n // if using ctrl/cmd, select the hitElement only if we\n // haven't box-selected anything else\n if (!elementsWithinSelection.length) {\n nextSelectedElementIds[pointerDownState.hit.element.id] = true;\n } else {\n delete nextSelectedElementIds[pointerDownState.hit.element.id];\n }\n }\n\n prevState = !shouldReuseSelection ? Object.assign(Object.assign({}, prevState), {\n selectedGroupIds: {},\n editingGroupId: null\n }) : prevState;\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // select linear element only when we haven't box-selected anything else\n selectedLinearElement: elementsWithinSelection.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(elementsWithinSelection[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(elementsWithinSelection[0], this.scene) : null,\n showHyperlinkPopup: elementsWithinSelection.length === 1 && (elementsWithinSelection[0].link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(elementsWithinSelection[0])) ? \"info\" : false\n });\n });\n }\n }\n });\n } // Returns whether the pointer move happened over either scrollbar\n\n\n handlePointerMoveOverScrollbars(event, pointerDownState) {\n if (pointerDownState.scrollbars.isOverHorizontal) {\n const x = event.clientX;\n const dx = x - pointerDownState.lastCoords.x;\n this.translateCanvas({\n scrollX: this.state.scrollX - dx / this.state.zoom.value\n });\n pointerDownState.lastCoords.x = x;\n return true;\n }\n\n if (pointerDownState.scrollbars.isOverVertical) {\n const y = event.clientY;\n const dy = y - pointerDownState.lastCoords.y;\n this.translateCanvas({\n scrollY: this.state.scrollY - dy / this.state.zoom.value\n });\n pointerDownState.lastCoords.y = y;\n return true;\n }\n\n return false;\n }\n\n onPointerUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(childEvent => {\n var _a, _b, _c, _d, _e, _f;\n\n if (pointerDownState.eventListeners.onMove) {\n pointerDownState.eventListeners.onMove.flush();\n }\n\n const {\n draggingElement,\n resizingElement,\n multiElement,\n activeTool,\n isResizing,\n isRotating\n } = this.state;\n this.setState({\n isResizing: false,\n isRotating: false,\n resizingElement: null,\n selectionElement: null,\n frameToHighlight: null,\n elementsToHighlight: null,\n cursorButton: \"up\",\n // text elements are reset on finalize, and resetting on pointerup\n // may cause issues with double taps\n editingElement: multiElement || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? this.state.editingElement : null,\n snapLines: [],\n originSnapOffset: null\n });\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.setReferenceSnapPoints(null);\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.setVisibleGaps(null);\n this.savePointer(childEvent.clientX, childEvent.clientY, \"up\");\n this.setState({\n selectedElementsAreBeingDragged: false\n }); // Handle end of dragging a point of a linear element, might close a loop\n // and sets binding element\n\n if (this.state.editingLinearElement) {\n if (!pointerDownState.boxSelection.hasOccurred && ((_b = (_a = pointerDownState.hit) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.id) !== this.state.editingLinearElement.elementId) {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n } else {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state);\n\n if (editingLinearElement !== this.state.editingLinearElement) {\n this.setState({\n editingLinearElement,\n suggestedBindings: []\n });\n }\n }\n } else if (this.state.selectedLinearElement) {\n if (((_d = (_c = pointerDownState.hit) === null || _c === void 0 ? void 0 : _c.element) === null || _d === void 0 ? void 0 : _d.id) !== this.state.selectedLinearElement.elementId) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement to null if there is more than one element selected since we don't want to show linear element handles\n\n if (selectedELements.length > 1) {\n this.setState({\n selectedLinearElement: null\n });\n }\n } else {\n const linearElementEditor = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state);\n const {\n startBindingElement,\n endBindingElement\n } = linearElementEditor;\n const element = this.scene.getElement(linearElementEditor.elementId);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindLinearElement)(element, startBindingElement, endBindingElement);\n }\n\n if (linearElementEditor !== this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, linearElementEditor), {\n selectedPointsIndices: null\n }),\n suggestedBindings: []\n });\n }\n }\n }\n\n lastPointerUp = null;\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, pointerDownState.eventListeners.onMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, pointerDownState.eventListeners.onUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, pointerDownState.eventListeners.onKeyDown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, pointerDownState.eventListeners.onKeyUp);\n\n if (this.state.pendingImageElementId) {\n this.setState({\n pendingImageElementId: null\n });\n }\n\n this.onPointerUpEmitter.trigger(this.state.activeTool, pointerDownState, childEvent);\n\n if ((draggingElement === null || draggingElement === void 0 ? void 0 : draggingElement.type) === \"freedraw\") {\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n const points = draggingElement.points;\n let dx = pointerCoords.x - draggingElement.x;\n let dy = pointerCoords.y - draggingElement.y; // Allows dots to avoid being flagged as infinitely small\n\n if (dx === points[0][0] && dy === points[0][1]) {\n dy += 0.0001;\n dx += 0.0001;\n }\n\n const pressures = draggingElement.simulatePressure ? [] : [...draggingElement.pressures, childEvent.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures,\n lastCommittedPoint: [dx, dy]\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement)) {\n const imageElement = draggingElement;\n\n try {\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } catch (error) {\n console.error(error);\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== imageElement.id));\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n }\n\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n if (draggingElement.points.length > 1) {\n this.history.resumeRecording();\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n\n if (!pointerDownState.drag.hasOccurred && draggingElement && !multiElement) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...draggingElement.points, [pointerCoords.x - draggingElement.x, pointerCoords.y - draggingElement.y]]\n });\n this.setState({\n multiElement: draggingElement,\n editingElement: this.state.draggingElement\n });\n } else if (pointerDownState.drag.hasOccurred && !multiElement) {\n if ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(draggingElement, this.state, this.scene, pointerCoords);\n }\n\n this.setState({\n suggestedBindings: [],\n startBoundElement: null\n });\n\n if (!activeTool.locked) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n this.setState(prevState => ({\n draggingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n }),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(draggingElement, this.scene)\n }));\n } else {\n this.setState(prevState => ({\n draggingElement: null\n }));\n }\n }\n\n return;\n }\n\n if (activeTool.type !== \"selection\" && draggingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(draggingElement)) {\n // remove invisible element which was added in onPointerDown\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== draggingElement.id));\n this.setState({\n draggingElement: null\n });\n return;\n }\n\n if (draggingElement) {\n if (pointerDownState.drag.hasOccurred) {\n const sceneCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state); // when editing the points of a linear element, we check if the\n // linear element still is in the frame afterwards\n // if not, the linear element will be removed from its frame (if any)\n\n if (this.state.selectedLinearElement && this.state.selectedLinearElement.isDragging) {\n const linearElement = this.scene.getElement(this.state.selectedLinearElement.elementId);\n\n if (linearElement === null || linearElement === void 0 ? void 0 : linearElement.frameId) {\n const frame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(linearElement);\n\n if (frame && linearElement) {\n if (!(0,_frame__WEBPACK_IMPORTED_MODULE_50__.elementOverlapsWithFrame)(linearElement, frame)) {\n // remove the linear element from all groups\n // before removing it from the frame as well\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(linearElement, {\n groupIds: []\n });\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.removeElementsFromFrame)(this.scene.getElementsIncludingDeleted(), [linearElement], this.state));\n }\n }\n }\n } else {\n // update the relationships between selected elements and frames\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(sceneCoords);\n const selectedElements = this.scene.getSelectedElements(this.state);\n let nextElements = this.scene.getElementsIncludingDeleted();\n\n const updateGroupIdsAfterEditingGroup = elements => {\n if (elements.length > 0) {\n for (const element of elements) {\n const index = element.groupIds.indexOf(this.state.editingGroupId);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: element.groupIds.slice(0, index)\n }, false);\n }\n\n nextElements.forEach(element => {\n if (element.groupIds.length && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(nextElements, element.groupIds[element.groupIds.length - 1]).length < 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: []\n }, false);\n }\n });\n this.setState({\n editingGroupId: null\n });\n }\n };\n\n if (topLayerFrame && !this.state.selectedElementIds[topLayerFrame.id]) {\n const elementsToAdd = selectedElements.filter(element => element.frameId !== topLayerFrame.id && (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n\n if (this.state.editingGroupId) {\n updateGroupIdsAfterEditingGroup(elementsToAdd);\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(nextElements, elementsToAdd, topLayerFrame);\n } else if (!topLayerFrame) {\n if (this.state.editingGroupId) {\n const elementsToRemove = selectedElements.filter(element => element.frameId && !(0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n updateGroupIdsAfterEditingGroup(elementsToRemove);\n }\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(nextElements, this.state, this);\n this.scene.replaceAllElements(nextElements);\n }\n }\n\n if (draggingElement.type === \"frame\") {\n const elementsInsideFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInNewFrame)(this.scene.getElementsIncludingDeleted(), draggingElement);\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(this.scene.getElementsIncludingDeleted(), elementsInsideFrame, draggingElement));\n }\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getNormalizedDimensions)(draggingElement));\n }\n\n if (resizingElement) {\n this.history.resumeRecording();\n }\n\n if (resizingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(resizingElement)) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== resizingElement.id));\n } // handle frame membership for resizing frames and/or selected elements\n\n\n if (pointerDownState.resize.isResizing) {\n let nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(this.scene.getElementsIncludingDeleted(), this.state, this);\n const selectedFrames = this.scene.getSelectedElements(this.state).filter(element => element.type === \"frame\");\n\n for (const frame of selectedFrames) {\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.replaceAllElementsInFrame)(nextElements, (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getElementsIncludingDeleted(), frame, this.state), frame, this.state);\n }\n\n this.scene.replaceAllElements(nextElements);\n } // Code below handles selection when element(s) weren't\n // drag or added to selection on pointer down phase.\n\n\n const hitElement = pointerDownState.hit.element;\n\n if (((_e = this.state.selectedLinearElement) === null || _e === void 0 ? void 0 : _e.elementId) !== (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement)) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement when no other element selected except\n // the one we've hit\n\n if (selectedELements.length === 1) {\n this.setState({\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene)\n });\n }\n }\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDownEvent.clientX, this.lastPointerDownEvent.clientY, this.lastPointerUpEvent.clientX, this.lastPointerUpEvent.clientY);\n\n if (draggedDistance === 0) {\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastPointerUpEvent.clientX,\n clientY: this.lastPointerUpEvent.clientY\n }, this.state);\n const hitElements = this.getElementsAtPosition(scenePointer.x, scenePointer.y);\n hitElements.forEach(hitElement => pointerDownState.elementIdsToErase[hitElement.id] = {\n erase: true,\n opacity: hitElement.opacity\n });\n }\n\n this.eraseElements(pointerDownState);\n return;\n } else if (Object.keys(pointerDownState.elementIdsToErase).length) {\n this.restoreReadyToEraseElements(pointerDownState);\n }\n\n if (hitElement && !pointerDownState.drag.hasOccurred && !pointerDownState.hit.wasAddedToSelection && ( // if we're editing a line, pointerup shouldn't switch selection if\n // box selected\n !this.state.editingLinearElement || !pointerDownState.boxSelection.hasOccurred)) {\n // when inside line editor, shift selects points instead\n if (childEvent.shiftKey && !this.state.editingLinearElement) {\n if (this.state.selectedElementIds[hitElement.id]) {\n if ((0,_groups__WEBPACK_IMPORTED_MODULE_23__.isSelectedViaGroup)(this.state, hitElement)) {\n this.setState(_prevState => {\n const nextSelectedElementIds = Object.assign({}, _prevState.selectedElementIds); // We want to unselect all groups hitElement is part of\n // as well as all elements that are part of the groups\n // hitElement is part of\n\n for (const groupedElement of hitElement.groupIds.flatMap(groupId => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), groupId))) {\n delete nextSelectedElementIds[groupedElement.id];\n }\n\n return {\n selectedGroupIds: Object.assign(Object.assign({}, _prevState.selectedElementIds), hitElement.groupIds.map(gId => ({\n [gId]: false\n })).reduce((prev, acc) => Object.assign(Object.assign({}, prev), acc), {})),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, _prevState)\n };\n }); // if not gragging a linear element point (outside editor)\n } else if (!((_f = this.state.selectedLinearElement) === null || _f === void 0 ? void 0 : _f.isDragging)) {\n // remove element from selection while\n // keeping prev elements selected\n this.setState(prevState => {\n const newSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete newSelectedElementIds[hitElement.id];\n const newSelectedElements = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(this.scene.getNonDeletedElements(), {\n selectedElementIds: newSelectedElementIds\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: newSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // set selectedLinearElement only if thats the only element selected\n selectedLinearElement: newSelectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(newSelectedElements[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(newSelectedElements[0], this.scene) : prevState.selectedLinearElement\n });\n });\n }\n } else if (hitElement.frameId && this.state.selectedElementIds[hitElement.frameId]) {\n // when hitElement is part of a selected frame, deselect the frame\n // to avoid frame and containing elements selected simultaneously\n this.setState(prevState => {\n var _a, _b;\n\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n }); // deselect the frame\n\n delete nextSelectedElementIds[hitElement.frameId]; // deselect groups containing the frame\n\n ((_b = (_a = this.scene.getElement(hitElement.frameId)) === null || _a === void 0 ? void 0 : _a.groupIds) !== null && _b !== void 0 ? _b : []).flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n showHyperlinkPopup: hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) ? \"info\" : false\n });\n });\n } else {\n // add element to selection while keeping prev elements selected\n this.setState(_prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, _prevState.selectedElementIds), {\n [hitElement.id]: true\n }), _prevState)\n }));\n }\n } else {\n this.setState(prevState => {\n var _a;\n\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement) && // Don't set `selectedLinearElement` if its same as the hitElement, this is mainly to prevent resetting the `hoverPointIndex` to -1.\n // Future we should update the API to take care of setting the correct `hoverPointIndex` when initialized\n ((_a = prevState.selectedLinearElement) === null || _a === void 0 ? void 0 : _a.elementId) !== hitElement.id ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene) : prevState.selectedLinearElement\n });\n });\n }\n }\n\n if (!pointerDownState.drag.hasOccurred && !this.state.isResizing && (hitElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(hitElement, this.state, this.frameNameBoundsCache, pointerDownState.origin.x, pointerDownState.origin.y) || !hitElement && pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements)) {\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: null\n });\n } else {\n // Deselect selected elements\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\" && draggingElement && draggingElement.type !== \"selection\") {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n showHyperlinkPopup: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(draggingElement) && !draggingElement.link ? \"editor\" : prevState.showHyperlinkPopup\n }));\n }\n\n if (activeTool.type !== \"selection\" || (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(this.scene.getNonDeletedElements(), this.state)) {\n this.history.resumeRecording();\n }\n\n if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {\n ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? _element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements : _element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(this.scene.getSelectedElements(this.state));\n }\n\n if (activeTool.type === \"laser\") {\n this.laserPathManager.endPath();\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_70__.resetCursor)(this.interactiveCanvas);\n this.setState({\n draggingElement: null,\n suggestedBindings: [],\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n } else {\n this.setState({\n draggingElement: null,\n suggestedBindings: []\n });\n }\n\n if (hitElement && this.lastPointerUpEvent && this.lastPointerDownEvent && this.lastPointerUpEvent.timeStamp - this.lastPointerDownEvent.timeStamp < 300 && gesture.pointers.size <= 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, this.lastPointerUpEvent, pointerDownState.origin.x, pointerDownState.origin.y)) {\n this.handleEmbeddableCenterClick(hitElement);\n }\n });\n }\n\n maybeSuggestBindingForAll(selectedElements) {\n if (selectedElements.length > 50) {\n return;\n }\n\n const suggestedBindings = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getEligibleElementsForBinding)(selectedElements);\n this.setState({\n suggestedBindings\n });\n }\n\n clearSelection(hitElement) {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n activeEmbeddable: null,\n selectedGroupIds: {},\n // Continue editing the same group if the user selected a different\n // element from it\n editingGroupId: prevState.editingGroupId && hitElement != null && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, prevState.editingGroupId) ? prevState.editingGroupId : null\n }));\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null,\n previousSelectedElementIds: this.state.selectedElementIds\n });\n }\n\n getTextWysiwygSnappedToCenterPosition(x, y, appState, container) {\n if (container) {\n let elementCenterX = container.x + container.width / 2;\n let elementCenterY = container.y + container.height / 2;\n const elementCenter = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, appState);\n\n if (elementCenter) {\n elementCenterX = elementCenter.x;\n elementCenterY = elementCenter.y;\n }\n\n const distanceToCenter = Math.hypot(x - elementCenterX, y - elementCenterY);\n const isSnappedToCenter = distanceToCenter < _constants__WEBPACK_IMPORTED_MODULE_12__.TEXT_TO_CENTER_SNAP_THRESHOLD;\n\n if (isSnappedToCenter) {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: elementCenterX,\n sceneY: elementCenterY\n }, appState);\n return {\n viewportX,\n viewportY,\n elementCenterX,\n elementCenterY\n };\n }\n }\n }\n\n getCanvasOffsets() {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n left,\n top\n } = excalidrawContainer.getBoundingClientRect();\n return {\n offsetLeft: left,\n offsetTop: top\n };\n }\n\n return {\n offsetLeft: 0,\n offsetTop: 0\n };\n }\n\n updateLanguage() {\n return __awaiter(this, void 0, void 0, function* () {\n const currentLang = _i18n__WEBPACK_IMPORTED_MODULE_25__.languages.find(lang => lang.code === this.props.langCode) || _i18n__WEBPACK_IMPORTED_MODULE_25__.defaultLang;\n yield (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.setLanguage)(currentLang);\n this.setAppState({});\n });\n }\n\n}\n\nApp.defaultProps = {\n // needed for tests to pass since we directly render App in many tests\n UIOptions: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_UI_OPTIONS\n};\n\nif (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n window.h = window.h || {};\n Object.defineProperties(window.h, {\n elements: {\n configurable: true,\n\n get() {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.getElementsIncludingDeleted();\n },\n\n set(elements) {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.replaceAllElements(elements);\n }\n\n }\n });\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QywrQ0FBVztBQUNsRyxZQUFZLG1EQUFXO0FBQ3ZCLHlCQUF5QjtBQUN6QixLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGFBQWEsMkRBQWtCO0FBQy9COztBQUVBLElBQUksYUFBb0IsS0FBSyxpREFBUSxJQUFJLGFBQW9CO0FBQzdEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDs7QUFFQSxpRUFBZSxHQUFHIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2NvbXBvbmVudHMvQXBwLnRzeD82N2FlIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX2F3YWl0ZXIgPSB0aGlzICYmIHRoaXMuX19hd2FpdGVyIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcbiAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkge1xuICAgICAgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7XG4gICAgfVxuXG4gICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xuICB9KTtcbn07XG5cbmltcG9ydCB7IGpzeCBhcyBfanN4LCBqc3hzIGFzIF9qc3hzLCBGcmFnbWVudCBhcyBfRnJhZ21lbnQgfSBmcm9tIFwicmVhY3QvanN4LXJ1bnRpbWVcIjtcbmltcG9ydCBSZWFjdCwgeyB1c2VDb250ZXh0IH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBmbHVzaFN5bmMgfSBmcm9tIFwicmVhY3QtZG9tXCI7XG5pbXBvcnQgcm91Z2ggZnJvbSBcInJvdWdoanMvYmluL3JvdWdoXCI7XG5pbXBvcnQgY2xzeCBmcm9tIFwiY2xzeFwiO1xuaW1wb3J0IHsgbmFub2lkIH0gZnJvbSBcIm5hbm9pZFwiO1xuaW1wb3J0IHsgYWN0aW9uQWRkVG9MaWJyYXJ5LCBhY3Rpb25CcmluZ0ZvcndhcmQsIGFjdGlvbkJyaW5nVG9Gcm9udCwgYWN0aW9uQ29weSwgYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcsIGNvcHlUZXh0LCBhY3Rpb25Db3B5U3R5bGVzLCBhY3Rpb25DdXQsIGFjdGlvbkRlbGV0ZVNlbGVjdGVkLCBhY3Rpb25EdXBsaWNhdGVTZWxlY3Rpb24sIGFjdGlvbkZpbmFsaXplLCBhY3Rpb25GbGlwSG9yaXpvbnRhbCwgYWN0aW9uRmxpcFZlcnRpY2FsLCBhY3Rpb25Hcm91cCwgYWN0aW9uUGFzdGVTdHlsZXMsIGFjdGlvblNlbGVjdEFsbCwgYWN0aW9uU2VuZEJhY2t3YXJkLCBhY3Rpb25TZW5kVG9CYWNrLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHMsIGFjdGlvblRvZ2dsZVplbk1vZGUsIGFjdGlvblVuYmluZFRleHQsIGFjdGlvbkJpbmRUZXh0LCBhY3Rpb25Vbmdyb3VwLCBhY3Rpb25MaW5rLCBhY3Rpb25Ub2dnbGVFbGVtZW50TG9jaywgYWN0aW9uVG9nZ2xlTGluZWFyRWRpdG9yLCBhY3Rpb25Ub2dnbGVPYmplY3RzU25hcE1vZGUgfSBmcm9tIFwiLi4vYWN0aW9uc1wiO1xuaW1wb3J0IHsgY3JlYXRlUmVkb0FjdGlvbiwgY3JlYXRlVW5kb0FjdGlvbiB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkhpc3RvcnlcIjtcbmltcG9ydCB7IEFjdGlvbk1hbmFnZXIgfSBmcm9tIFwiLi4vYWN0aW9ucy9tYW5hZ2VyXCI7XG5pbXBvcnQgeyBhY3Rpb25zIH0gZnJvbSBcIi4uL2FjdGlvbnMvcmVnaXN0ZXJcIjtcbmltcG9ydCB7IHRyYWNrRXZlbnQgfSBmcm9tIFwiLi4vYW5hbHl0aWNzXCI7XG5pbXBvcnQgeyBnZXREZWZhdWx0QXBwU3RhdGUsIGlzRXJhc2VyQWN0aXZlLCBpc0hhbmRUb29sQWN0aXZlIH0gZnJvbSBcIi4uL2FwcFN0YXRlXCI7XG5pbXBvcnQgeyBwYXJzZUNsaXBib2FyZCB9IGZyb20gXCIuLi9jbGlwYm9hcmRcIjtcbmltcG9ydCB7IEFQUF9OQU1FLCBDVVJTT1JfVFlQRSwgREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hULCBERUZBVUxUX1VJX09QVElPTlMsIERFRkFVTFRfVkVSVElDQUxfQUxJR04sIERSQUdHSU5HX1RIUkVTSE9MRCwgRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZLCBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQsIEVMRU1FTlRfVFJBTlNMQVRFX0FNT1VOVCwgRU5WLCBFVkVOVCwgRlJBTUVfU1RZTEUsIEdSSURfU0laRSwgSU1BR0VfTUlNRV9UWVBFUywgSU1BR0VfUkVOREVSX1RJTUVPVVQsIGlzQW5kcm9pZCwgaXNCcmF2ZSwgTElORV9DT05GSVJNX1RIUkVTSE9MRCwgTUFYX0FMTE9XRURfRklMRV9CWVRFUywgTUlNRV9UWVBFUywgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9QT1JUUkFJVCwgTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEgsIFBPSU5URVJfQlVUVE9OLCBST1VORE5FU1MsIFNDUk9MTF9USU1FT1VULCBUQVBfVFdJQ0VfVElNRU9VVCwgVEVYVF9UT19DRU5URVJfU05BUF9USFJFU0hPTEQsIFRIRU1FLCBUSEVNRV9GSUxURVIsIFRPVUNIX0NUWF9NRU5VX1RJTUVPVVQsIFZFUlRJQ0FMX0FMSUdOLCBZT1VUVUJFX1NUQVRFUywgWk9PTV9TVEVQLCBQT0lOVEVSX0VWRU5UUyB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGV4cG9ydENhbnZhcywgbG9hZEZyb21CbG9iIH0gZnJvbSBcIi4uL2RhdGFcIjtcbmltcG9ydCBMaWJyYXJ5LCB7IGRpc3RyaWJ1dGVMaWJyYXJ5SXRlbXNPblNxdWFyZUdyaWQgfSBmcm9tIFwiLi4vZGF0YS9saWJyYXJ5XCI7XG5pbXBvcnQgeyByZXN0b3JlLCByZXN0b3JlRWxlbWVudHMgfSBmcm9tIFwiLi4vZGF0YS9yZXN0b3JlXCI7XG5pbXBvcnQgeyBkcmFnTmV3RWxlbWVudCwgZHJhZ1NlbGVjdGVkRWxlbWVudHMsIGR1cGxpY2F0ZUVsZW1lbnQsIGdldENvbW1vbkJvdW5kcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50LCBnZXREcmFnT2Zmc2V0WFksIGdldEVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSwgZ2V0Tm9ybWFsaXplZERpbWVuc2lvbnMsIGdldFJlc2l6ZUFycm93RGlyZWN0aW9uLCBnZXRSZXNpemVPZmZzZXRYWSwgZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplLCBnZXRUcmFuc2Zvcm1IYW5kbGVUeXBlRnJvbUNvb3JkcywgaGl0VGVzdCwgaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50LCBpc0ludmlzaWJseVNtYWxsRWxlbWVudCwgaXNOb25EZWxldGVkRWxlbWVudCwgaXNUZXh0RWxlbWVudCwgbmV3RWxlbWVudCwgbmV3TGluZWFyRWxlbWVudCwgbmV3VGV4dEVsZW1lbnQsIG5ld0ltYWdlRWxlbWVudCwgdGV4dFd5c2l3eWcsIHRyYW5zZm9ybUVsZW1lbnRzLCB1cGRhdGVUZXh0RWxlbWVudCwgcmVkcmF3VGV4dEJvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnRcIjtcbmltcG9ydCB7IGJpbmRPclVuYmluZExpbmVhckVsZW1lbnQsIGJpbmRPclVuYmluZFNlbGVjdGVkRWxlbWVudHMsIGZpeEJpbmRpbmdzQWZ0ZXJEZWxldGlvbiwgZml4QmluZGluZ3NBZnRlckR1cGxpY2F0aW9uLCBnZXRFbGlnaWJsZUVsZW1lbnRzRm9yQmluZGluZywgZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nLCBpc0JpbmRpbmdFbmFibGVkLCBpc0xpbmVhckVsZW1lbnRTaW1wbGVBbmRBbHJlYWR5Qm91bmQsIG1heWJlQmluZExpbmVhckVsZW1lbnQsIHNob3VsZEVuYWJsZUJpbmRpbmdGb3JQb2ludGVyRXZlbnQsIHVuYmluZExpbmVhckVsZW1lbnRzLCB1cGRhdGVCb3VuZEVsZW1lbnRzIH0gZnJvbSBcIi4uL2VsZW1lbnQvYmluZGluZ1wiO1xuaW1wb3J0IHsgTGluZWFyRWxlbWVudEVkaXRvciB9IGZyb20gXCIuLi9lbGVtZW50L2xpbmVhckVsZW1lbnRFZGl0b3JcIjtcbmltcG9ydCB7IG11dGF0ZUVsZW1lbnQsIG5ld0VsZW1lbnRXaXRoIH0gZnJvbSBcIi4uL2VsZW1lbnQvbXV0YXRlRWxlbWVudFwiO1xuaW1wb3J0IHsgZGVlcENvcHlFbGVtZW50LCBkdXBsaWNhdGVFbGVtZW50cywgbmV3RnJhbWVFbGVtZW50LCBuZXdGcmVlRHJhd0VsZW1lbnQsIG5ld0VtYmVkZGFibGVFbGVtZW50IH0gZnJvbSBcIi4uL2VsZW1lbnQvbmV3RWxlbWVudFwiO1xuaW1wb3J0IHsgaGFzQm91bmRUZXh0RWxlbWVudCwgaXNBcnJvd0VsZW1lbnQsIGlzQmluZGluZ0VsZW1lbnQsIGlzQmluZGluZ0VsZW1lbnRUeXBlLCBpc0JvdW5kVG9Db250YWluZXIsIGlzRnJhbWVFbGVtZW50LCBpc0ltYWdlRWxlbWVudCwgaXNFbWJlZGRhYmxlRWxlbWVudCwgaXNJbml0aWFsaXplZEltYWdlRWxlbWVudCwgaXNMaW5lYXJFbGVtZW50LCBpc0xpbmVhckVsZW1lbnRUeXBlLCBpc1VzaW5nQWRhcHRpdmVSYWRpdXMgfSBmcm9tIFwiLi4vZWxlbWVudC90eXBlQ2hlY2tzXCI7XG5pbXBvcnQgeyBnZXRDZW50ZXIsIGdldERpc3RhbmNlIH0gZnJvbSBcIi4uL2dlc3R1cmVcIjtcbmltcG9ydCB7IGVkaXRHcm91cEZvclNlbGVjdGVkRWxlbWVudCwgZ2V0RWxlbWVudHNJbkdyb3VwLCBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50LCBnZXRTZWxlY3RlZEdyb3VwSWRzLCBpc0VsZW1lbnRJbkdyb3VwLCBpc1NlbGVjdGVkVmlhR3JvdXAsIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMgfSBmcm9tIFwiLi4vZ3JvdXBzXCI7XG5pbXBvcnQgSGlzdG9yeSBmcm9tIFwiLi4vaGlzdG9yeVwiO1xuaW1wb3J0IHsgZGVmYXVsdExhbmcsIGdldExhbmd1YWdlLCBsYW5ndWFnZXMsIHNldExhbmd1YWdlLCB0IH0gZnJvbSBcIi4uL2kxOG5cIjtcbmltcG9ydCB7IENPREVTLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyLCBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvLCBzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZSwgaXNBcnJvd0tleSwgS0VZUyB9IGZyb20gXCIuLi9rZXlzXCI7XG5pbXBvcnQgeyBpc0VsZW1lbnRJblZpZXdwb3J0IH0gZnJvbSBcIi4uL2VsZW1lbnQvc2l6ZUhlbHBlcnNcIjtcbmltcG9ydCB7IGRpc3RhbmNlMmQsIGdldENvcm5lclJhZGl1cywgZ2V0R3JpZFBvaW50LCBpc1BhdGhBTG9vcCB9IGZyb20gXCIuLi9tYXRoXCI7XG5pbXBvcnQgeyBjYWxjdWxhdGVTY3JvbGxDZW50ZXIsIGdldEVsZW1lbnRzQXRQb3NpdGlvbiwgZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24sIGdldE5vcm1hbGl6ZWRab29tLCBnZXRTZWxlY3RlZEVsZW1lbnRzLCBoYXNCYWNrZ3JvdW5kLCBpc092ZXJTY3JvbGxCYXJzLCBpc1NvbWVFbGVtZW50U2VsZWN0ZWQgfSBmcm9tIFwiLi4vc2NlbmVcIjtcbmltcG9ydCBTY2VuZSBmcm9tIFwiLi4vc2NlbmUvU2NlbmVcIjtcbmltcG9ydCB7IGdldFN0YXRlRm9yWm9vbSB9IGZyb20gXCIuLi9zY2VuZS96b29tXCI7XG5pbXBvcnQgeyBmaW5kU2hhcGVCeUtleSB9IGZyb20gXCIuLi9zaGFwZXNcIjtcbmltcG9ydCB7IGRlYm91bmNlLCBkaXN0YW5jZSwgZ2V0Rm9udFN0cmluZywgZ2V0TmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIsIGlzSW5wdXRMaWtlLCBpc1Rvb2xJY29uLCBpc1dyaXRhYmxlRWxlbWVudCwgc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzLCB0dXBsZVRvQ29vcnMsIHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcywgd2l0aEJhdGNoZWRVcGRhdGVzLCB3cmFwRXZlbnQsIHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZCwgdXBkYXRlT2JqZWN0LCB1cGRhdGVBY3RpdmVUb29sLCBnZXRTaG9ydGN1dEtleSwgaXNUcmFuc3BhcmVudCwgZWFzZVRvVmFsdWVzUkFGLCBtdXRlRlNBYm9ydEVycm9yLCBpc1Rlc3RFbnYsIGVhc2VPdXQgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IsIGV4dHJhY3RTcmMsIGdldEVtYmVkTGluayB9IGZyb20gXCIuLi9lbGVtZW50L2VtYmVkZGFibGVcIjtcbmltcG9ydCB7IENvbnRleHRNZW51LCBDT05URVhUX01FTlVfU0VQQVJBVE9SIH0gZnJvbSBcIi4vQ29udGV4dE1lbnVcIjtcbmltcG9ydCBMYXllclVJIGZyb20gXCIuL0xheWVyVUlcIjtcbmltcG9ydCB7IFRvYXN0IH0gZnJvbSBcIi4vVG9hc3RcIjtcbmltcG9ydCB7IGFjdGlvblRvZ2dsZVZpZXdNb2RlIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uVG9nZ2xlVmlld01vZGVcIjtcbmltcG9ydCB7IGRhdGFVUkxUb0ZpbGUsIGdlbmVyYXRlSWRGcm9tRmlsZSwgZ2V0RGF0YVVSTCwgZ2V0RmlsZUZyb21FdmVudCwgSW1hZ2VVUkxUb0ZpbGUsIGlzSW1hZ2VGaWxlSGFuZGxlLCBpc1N1cHBvcnRlZEltYWdlRmlsZSwgbG9hZFNjZW5lT3JMaWJyYXJ5RnJvbUJsb2IsIG5vcm1hbGl6ZUZpbGUsIHBhcnNlTGlicmFyeUpTT04sIHJlc2l6ZUltYWdlRmlsZSwgU1ZHU3RyaW5nVG9GaWxlIH0gZnJvbSBcIi4uL2RhdGEvYmxvYlwiO1xuaW1wb3J0IHsgZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzLCBsb2FkSFRNTEltYWdlRWxlbWVudCwgbm9ybWFsaXplU1ZHLCB1cGRhdGVJbWFnZUNhY2hlIGFzIF91cGRhdGVJbWFnZUNhY2hlIH0gZnJvbSBcIi4uL2VsZW1lbnQvaW1hZ2VcIjtcbmltcG9ydCB0aHJvdHRsZSBmcm9tIFwibG9kYXNoLnRocm90dGxlXCI7XG5pbXBvcnQgeyBmaWxlT3BlbiB9IGZyb20gXCIuLi9kYXRhL2ZpbGVzeXN0ZW1cIjtcbmltcG9ydCB7IGJpbmRUZXh0VG9TaGFwZUFmdGVyRHVwbGljYXRpb24sIGdldEFwcHJveE1pbkxpbmVIZWlnaHQsIGdldEFwcHJveE1pbkxpbmVXaWR0aCwgZ2V0Qm91bmRUZXh0RWxlbWVudCwgZ2V0Q29udGFpbmVyQ2VudGVyLCBnZXRDb250YWluZXJFbGVtZW50LCBnZXREZWZhdWx0TGluZUhlaWdodCwgZ2V0TGluZUhlaWdodEluUHgsIGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24sIGlzTWVhc3VyZVRleHRTdXBwb3J0ZWQsIGlzVmFsaWRUZXh0Q29udGFpbmVyIH0gZnJvbSBcIi4uL2VsZW1lbnQvdGV4dEVsZW1lbnRcIjtcbmltcG9ydCB7IGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnQvY29sbGlzaW9uXCI7XG5pbXBvcnQgeyBzaG93SHlwZXJsaW5rVG9vbHRpcCwgaGlkZUh5cGVybGlua1Rvb2xpcCwgSHlwZXJsaW5rLCBpc1BvaW50SGl0dGluZ0xpbmssIGlzUG9pbnRIaXR0aW5nTGlua0ljb24gfSBmcm9tIFwiLi4vZWxlbWVudC9IeXBlcmxpbmtcIjtcbmltcG9ydCB7IGlzTG9jYWxMaW5rLCBub3JtYWxpemVMaW5rLCB0b1ZhbGlkVVJMIH0gZnJvbSBcIi4uL2RhdGEvdXJsXCI7XG5pbXBvcnQgeyBzaG91bGRTaG93Qm91bmRpbmdCb3ggfSBmcm9tIFwiLi4vZWxlbWVudC90cmFuc2Zvcm1IYW5kbGVzXCI7XG5pbXBvcnQgeyBhY3Rpb25VbmxvY2tBbGxFbGVtZW50cyB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkVsZW1lbnRMb2NrXCI7XG5pbXBvcnQgeyBGb250cyB9IGZyb20gXCIuLi9zY2VuZS9Gb250c1wiO1xuaW1wb3J0IHsgZ2V0RnJhbWVDaGlsZHJlbiwgaXNDdXJzb3JJbkZyYW1lLCBiaW5kRWxlbWVudHNUb0ZyYW1lc0FmdGVyRHVwbGljYXRpb24sIGFkZEVsZW1lbnRzVG9GcmFtZSwgcmVwbGFjZUFsbEVsZW1lbnRzSW5GcmFtZSwgcmVtb3ZlRWxlbWVudHNGcm9tRnJhbWUsIGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lLCBnZXRFbGVtZW50c0luTmV3RnJhbWUsIGdldENvbnRhaW5pbmdGcmFtZSwgZWxlbWVudE92ZXJsYXBzV2l0aEZyYW1lLCB1cGRhdGVGcmFtZU1lbWJlcnNoaXBPZlNlbGVjdGVkRWxlbWVudHMsIGlzRWxlbWVudEluRnJhbWUgfSBmcm9tIFwiLi4vZnJhbWVcIjtcbmltcG9ydCB7IGV4Y2x1ZGVFbGVtZW50c0luRnJhbWVzRnJvbVNlbGVjdGlvbiwgbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMgfSBmcm9tIFwiLi4vc2NlbmUvc2VsZWN0aW9uXCI7XG5pbXBvcnQgeyBhY3Rpb25QYXN0ZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkNsaXBib2FyZFwiO1xuaW1wb3J0IHsgYWN0aW9uUmVtb3ZlQWxsRWxlbWVudHNGcm9tRnJhbWUsIGFjdGlvblNlbGVjdEFsbEVsZW1lbnRzSW5GcmFtZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkZyYW1lXCI7XG5pbXBvcnQgeyBhY3Rpb25Ub2dnbGVIYW5kVG9vbCwgem9vbVRvRml0IH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uQ2FudmFzXCI7XG5pbXBvcnQgeyBqb3RhaVN0b3JlIH0gZnJvbSBcIi4uL2pvdGFpXCI7XG5pbXBvcnQgeyBhY3RpdmVDb25maXJtRGlhbG9nQXRvbSB9IGZyb20gXCIuL0FjdGl2ZUNvbmZpcm1EaWFsb2dcIjtcbmltcG9ydCB7IEltYWdlU2NlbmVEYXRhRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBnZXRTbmFwTGluZXNBdFBvaW50ZXIsIHNuYXBEcmFnZ2VkRWxlbWVudHMsIGlzQWN0aXZlVG9vbE5vbkxpbmVhclNuYXBwYWJsZSwgc25hcE5ld0VsZW1lbnQsIHNuYXBSZXNpemluZ0VsZW1lbnRzLCBpc1NuYXBwaW5nRW5hYmxlZCwgZ2V0VmlzaWJsZUdhcHMsIGdldFJlZmVyZW5jZVNuYXBQb2ludHMsIFNuYXBDYWNoZSB9IGZyb20gXCIuLi9zbmFwcGluZ1wiO1xuaW1wb3J0IHsgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkJvdW5kVGV4dFwiO1xuaW1wb3J0IEJyYXZlTWVhc3VyZVRleHRFcnJvciBmcm9tIFwiLi9CcmF2ZU1lYXN1cmVUZXh0RXJyb3JcIjtcbmltcG9ydCB7IGFjdGl2ZUV5ZURyb3BwZXJBdG9tIH0gZnJvbSBcIi4vRXllRHJvcHBlclwiO1xuaW1wb3J0IHsgY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzIH0gZnJvbSBcIi4uL2RhdGEvdHJhbnNmb3JtXCI7XG5pbXBvcnQgeyBpc1NpZGViYXJEb2NrZWRBdG9tIH0gZnJvbSBcIi4vU2lkZWJhci9TaWRlYmFyXCI7XG5pbXBvcnQgeyBTdGF0aWNDYW52YXMsIEludGVyYWN0aXZlQ2FudmFzIH0gZnJvbSBcIi4vY2FudmFzZXNcIjtcbmltcG9ydCB7IFJlbmRlcmVyIH0gZnJvbSBcIi4uL3NjZW5lL1JlbmRlcmVyXCI7XG5pbXBvcnQgeyBTaGFwZUNhY2hlIH0gZnJvbSBcIi4uL3NjZW5lL1NoYXBlQ2FjaGVcIjtcbmltcG9ydCBNZXJtYWlkVG9FeGNhbGlkcmF3IGZyb20gXCIuL01lcm1haWRUb0V4Y2FsaWRyYXdcIjtcbmltcG9ydCB7IExhc2VyVG9vbE92ZXJsYXkgfSBmcm9tIFwiLi9MYXNlclRvb2wvTGFzZXJUb29sXCI7XG5pbXBvcnQgeyBMYXNlclBhdGhNYW5hZ2VyIH0gZnJvbSBcIi4vTGFzZXJUb29sL0xhc2VyUGF0aE1hbmFnZXJcIjtcbmltcG9ydCB7IHNldEVyYXNlckN1cnNvciwgc2V0Q3Vyc29yLCByZXNldEN1cnNvciwgc2V0Q3Vyc29yRm9yU2hhcGUgfSBmcm9tIFwiLi4vY3Vyc29yXCI7XG5pbXBvcnQgeyBFbWl0dGVyIH0gZnJvbSBcIi4uL2VtaXR0ZXJcIjtcbmNvbnN0IEFwcENvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuY29uc3QgQXBwUHJvcHNDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChudWxsKTtcbmNvbnN0IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWUgPSB7XG4gIHZpZXdwb3J0OiB7XG4gICAgaXNNb2JpbGU6IGZhbHNlLFxuICAgIGlzTGFuZHNjYXBlOiBmYWxzZVxuICB9LFxuICBlZGl0b3I6IHtcbiAgICBpc01vYmlsZTogZmFsc2UsXG4gICAgY2FuRml0U2lkZWJhcjogZmFsc2VcbiAgfSxcbiAgaXNUb3VjaFNjcmVlbjogZmFsc2Vcbn07XG5jb25zdCBEZXZpY2VDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChkZXZpY2VDb250ZXh0SW5pdGlhbFZhbHVlKTtcbkRldmljZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkRldmljZUNvbnRleHRcIjtcbmV4cG9ydCBjb25zdCBFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoe1xuICBjb250YWluZXI6IG51bGwsXG4gIGlkOiBudWxsXG59KTtcbkV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoW10pO1xuRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXREZWZhdWx0QXBwU3RhdGUoKSksIHtcbiAgd2lkdGg6IDAsXG4gIGhlaWdodDogMCxcbiAgb2Zmc2V0TGVmdDogMCxcbiAgb2Zmc2V0VG9wOiAwXG59KSk7XG5FeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dCgoKSA9PiB7XG4gIGNvbnNvbGUud2FybihcInVuaXRpYWxpemVkIEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQgY29udGV4dCFcIik7XG59KTtcbkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQobnVsbCk7XG5FeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dFwiO1xuZXhwb3J0IGNvbnN0IHVzZUFwcCA9ICgpID0+IHVzZUNvbnRleHQoQXBwQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlQXBwUHJvcHMgPSAoKSA9PiB1c2VDb250ZXh0KEFwcFByb3BzQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRGV2aWNlID0gKCkgPT4gdXNlQ29udGV4dChEZXZpY2VDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3Q29udGFpbmVyID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0VsZW1lbnRzID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3QXBwU3RhdGUgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdTZXRBcHBTdGF0ZSA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXIgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCk7XG5jb25zdCBzdXBwb3J0c1Jlc2l6ZU9ic2VydmVyID0gdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiAmJiBcIlJlc2l6ZU9ic2VydmVyXCIgaW4gd2luZG93O1xubGV0IGRpZFRhcFR3aWNlID0gZmFsc2U7XG5sZXQgdGFwcGVkVHdpY2VUaW1lciA9IDA7XG5sZXQgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbmxldCBpc1Bhbm5pbmcgPSBmYWxzZTtcbmxldCBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gZmFsc2U7XG5sZXQgY3VycmVudFNjcm9sbEJhcnMgPSB7XG4gIGhvcml6b250YWw6IG51bGwsXG4gIHZlcnRpY2FsOiBudWxsXG59O1xubGV0IHRvdWNoVGltZW91dCA9IDA7XG5sZXQgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG4vKipcbiAqIE1hcCBvZiB5b3V0dWJlIGVtYmVkIHZpZGVvIHN0YXRlc1xuICovXG5cbmNvbnN0IFlPVVRVQkVfVklERU9fU1RBVEVTID0gbmV3IE1hcCgpO1xubGV0IElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG5sZXQgSVNfUExBSU5fUEFTVEVfVElNRVIgPSAwO1xubGV0IFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gZmFsc2U7XG5sZXQgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG5jb25zdCBnZXN0dXJlID0ge1xuICBwb2ludGVyczogbmV3IE1hcCgpLFxuICBsYXN0Q2VudGVyOiBudWxsLFxuICBpbml0aWFsRGlzdGFuY2U6IG51bGwsXG4gIGluaXRpYWxTY2FsZTogbnVsbFxufTtcblxuY2xhc3MgQXBwIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyA9IG51bGw7XG4gICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICB0aGlzLmRldmljZSA9IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWU7XG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmID0gUmVhY3QuY3JlYXRlUmVmKCk7XG4gICAgdGhpcy5maWxlcyA9IHt9O1xuICAgIHRoaXMuaW1hZ2VDYWNoZSA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmlGcmFtZVJlZnMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCA9IG51bGw7XG4gICAgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQgPSBudWxsO1xuICAgIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24gPSB7XG4gICAgICB4OiAwLFxuICAgICAgeTogMFxuICAgIH07XG4gICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyID0gbmV3IExhc2VyUGF0aE1hbmFnZXIodGhpcyk7XG4gICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyVXBFbWl0dGVyID0gbmV3IEVtaXR0ZXIoKTtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBlbWJlZGRhYmxlRWxlbWVudHMgPSBuZXcgTWFwKCk7XG4gICAgICBsZXQgdXBkYXRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgZW1iZWRkYWJsZUVsZW1lbnRzLnNldChlbGVtZW50LmlkLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50LnZhbGlkYXRlZCA9PSBudWxsKSB7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlZCA9IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IoZWxlbWVudC5saW5rLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSk7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgdmFsaWRhdGVkXG4gICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWQpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgfSAvLyBHQ1xuXG5cbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5mb3JFYWNoKChyZWYsIGlkKSA9PiB7XG4gICAgICAgIGlmICghZW1iZWRkYWJsZUVsZW1lbnRzLmhhcyhpZCkpIHtcbiAgICAgICAgICB0aGlzLmlGcmFtZVJlZnMuZGVsZXRlKGlkKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQgPSBmcmFtZUVsZW1lbnQgPT4ge1xuICAgICAgcmV0dXJuIGAke3RoaXMuaWR9LWZyYW1lLW5hbWUtJHtmcmFtZUVsZW1lbnQuaWR9YDtcbiAgICB9O1xuXG4gICAgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSA9IHtcbiAgICAgIGdldDogZnJhbWVFbGVtZW50ID0+IHtcbiAgICAgICAgbGV0IGJvdW5kcyA9IHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLmdldChmcmFtZUVsZW1lbnQuaWQpO1xuXG4gICAgICAgIGlmICghYm91bmRzIHx8IGJvdW5kcy56b29tICE9PSB0aGlzLnN0YXRlLnpvb20udmFsdWUgfHwgYm91bmRzLnZlcnNpb25Ob25jZSAhPT0gZnJhbWVFbGVtZW50LnZlcnNpb25Ob25jZSkge1xuICAgICAgICAgIGNvbnN0IGZyYW1lTmFtZURpdiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQoZnJhbWVFbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoZnJhbWVOYW1lRGl2KSB7XG4gICAgICAgICAgICBjb25zdCBib3ggPSBmcmFtZU5hbWVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBjb25zdCBib3hTY2VuZVRvcExlZnQgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgICBjbGllbnRYOiBib3gueCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LnlcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3QgYm94U2NlbmVCb3R0b21SaWdodCA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICAgIGNsaWVudFg6IGJveC5yaWdodCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LmJvdHRvbVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBib3VuZHMgPSB7XG4gICAgICAgICAgICAgIHg6IGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICB5OiBib3hTY2VuZVRvcExlZnQueSxcbiAgICAgICAgICAgICAgd2lkdGg6IGJveFNjZW5lQm90dG9tUmlnaHQueCAtIGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICBoZWlnaHQ6IGJveFNjZW5lQm90dG9tUmlnaHQueSAtIGJveFNjZW5lVG9wTGVmdC55LFxuICAgICAgICAgICAgICBhbmdsZTogMCxcbiAgICAgICAgICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLnZhbHVlLFxuICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IGZyYW1lRWxlbWVudC52ZXJzaW9uTm9uY2VcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLnNldChmcmFtZUVsZW1lbnQuaWQsIGJvdW5kcyk7XG5cbiAgICAgICAgICAgIHJldHVybiBib3VuZHM7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYm91bmRzO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICovXG4gICAgICBfY2FjaGU6IG5ldyBNYXAoKVxuICAgIH07XG5cbiAgICB0aGlzLnJlbmRlckZyYW1lTmFtZXMgPSAoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCB8fCAhdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc0RhcmtUaGVtZSA9IHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiO1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLm1hcCgoZiwgaW5kZXgpID0+IHtcbiAgICAgICAgaWYgKCFpc0VsZW1lbnRJblZpZXdwb3J0KGYsIHRoaXMuY2FudmFzLndpZHRoIC8gd2luZG93LmRldmljZVBpeGVsUmF0aW8sIHRoaXMuY2FudmFzLmhlaWdodCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLCB7XG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb21cbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAvLyBpZiBmcmFtZSBub3QgdmlzaWJsZSwgZG9uJ3QgcmVuZGVyIGl0cyBuYW1lXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogeDEsXG4gICAgICAgICAgeTogeTFcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBmLngsXG4gICAgICAgICAgc2NlbmVZOiBmLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IEZSQU1FX05BTUVfRURJVF9QQURESU5HID0gNjtcblxuICAgICAgICBjb25zdCByZXNldCA9ICgpID0+IHtcbiAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICBpZiAoKChfYSA9IGYubmFtZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRyaW0oKSkgPT09IFwiXCIpIHtcbiAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZiwge1xuICAgICAgICAgICAgICBuYW1lOiBudWxsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIGxldCBmcmFtZU5hbWVKU1g7XG5cbiAgICAgICAgaWYgKGYuaWQgPT09IHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lKSB7XG4gICAgICAgICAgY29uc3QgZnJhbWVOYW1lSW5FZGl0ID0gZi5uYW1lID09IG51bGwgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZTtcbiAgICAgICAgICBmcmFtZU5hbWVKU1ggPSBfanN4KFwiaW5wdXRcIiwge1xuICAgICAgICAgICAgYXV0b0ZvY3VzOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IGZyYW1lTmFtZUluRWRpdCxcbiAgICAgICAgICAgIG9uQ2hhbmdlOiBlID0+IHtcbiAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChmLCB7XG4gICAgICAgICAgICAgICAgbmFtZTogZS50YXJnZXQudmFsdWVcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25CbHVyOiAoKSA9PiByZXNldCgpLFxuICAgICAgICAgICAgb25LZXlEb3duOiBldmVudCA9PiB7XG4gICAgICAgICAgICAgIC8vIGZvciBzb21lIGluZXhwbGljYWJsZSByZWFzb24sIGBvbkJsdXJgIHRyaWdnZXJlZCBvbiBFU0NcbiAgICAgICAgICAgICAgLy8gZG9lcyBub3QgcmVzZXQgYHN0YXRlLmVkaXRpbmdGcmFtZWAgZGVzcGl0ZSBiZWluZyBjYWxsZWQsXG4gICAgICAgICAgICAgIC8vIGFuZCB3ZSBuZWVkIHRvIHJlc2V0IGl0IGhlcmUgYXMgd2VsbFxuICAgICAgICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkVTQ0FQRSB8fCBldmVudC5rZXkgPT09IEtFWVMuRU5URVIpIHtcbiAgICAgICAgICAgICAgICByZXNldCgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgYmFja2dyb3VuZDogdGhpcy5zdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yLFxuICAgICAgICAgICAgICBmaWx0ZXI6IGlzRGFya1RoZW1lID8gVEhFTUVfRklMVEVSIDogXCJub25lXCIsXG4gICAgICAgICAgICAgIHpJbmRleDogMixcbiAgICAgICAgICAgICAgYm9yZGVyOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgZGlzcGxheTogXCJibG9ja1wiLFxuICAgICAgICAgICAgICBwYWRkaW5nOiBgJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weGAsXG4gICAgICAgICAgICAgIGJvcmRlclJhZGl1czogNCxcbiAgICAgICAgICAgICAgYm94U2hhZG93OiBcImluc2V0IDAgMCAwIDFweCB2YXIoLS1jb2xvci1wcmltYXJ5KVwiLFxuICAgICAgICAgICAgICBmb250RmFtaWx5OiBcIkFzc2lzdGFudFwiLFxuICAgICAgICAgICAgICBmb250U2l6ZTogXCIxNHB4XCIsXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogYHRyYW5zbGF0ZSgtJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weCwgJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weClgLFxuICAgICAgICAgICAgICBjb2xvcjogXCJ2YXIoLS1jb2xvci1ncmF5LTgwKVwiLFxuICAgICAgICAgICAgICBvdmVyZmxvdzogXCJoaWRkZW5cIixcbiAgICAgICAgICAgICAgbWF4V2lkdGg6IGAke2RvY3VtZW50LmJvZHkuY2xpZW50V2lkdGggLSB4MSAtIEZSQU1FX05BTUVfRURJVF9QQURESU5HfXB4YFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNpemU6IGZyYW1lTmFtZUluRWRpdC5sZW5ndGggKyAxIHx8IDEsXG4gICAgICAgICAgICBkaXI6IFwiYXV0b1wiLFxuICAgICAgICAgICAgYXV0b0NvbXBsZXRlOiBcIm9mZlwiLFxuICAgICAgICAgICAgYXV0b0NhcGl0YWxpemU6IFwib2ZmXCIsXG4gICAgICAgICAgICBhdXRvQ29ycmVjdDogXCJvZmZcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IGYubmFtZSA9PSBudWxsIHx8IGYubmFtZS50cmltKCkgPT09IFwiXCIgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZS50cmltKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBpZDogdGhpcy5nZXRGcmFtZU5hbWVET01JZChmKSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgcG9zaXRpb246IFwiYWJzb2x1dGVcIixcbiAgICAgICAgICAgIC8vIFBvc2l0aW9uaW5nIGZyb20gYm90dG9tIHNvIHRoYXQgd2UgZG9uJ3QgdG8gZWl0aGVyXG4gICAgICAgICAgICAvLyBjYWxjdWxhdGUgdGV4dCBoZWlnaHQgb3IgYWRqdXN0IHVzaW5nIHRyYW5zZm9ybSAod2hpY2gpXG4gICAgICAgICAgICAvLyBtZXNzZXMgdXAgaW5wdXQgcG9zaXRpb24gd2hlbiBlZGl0aW5nIHRoZSBmcmFtZSBuYW1lLlxuICAgICAgICAgICAgLy8gVGhpcyBtYWtlcyB0aGUgcG9zaXRpb25pbmcgZGV0ZXJtaW5pc3RpYyBhbmQgd2UgY2FuIGNhbGN1bGF0ZVxuICAgICAgICAgICAgLy8gdGhlIHNhbWUgcG9zaXRpb24gd2hlbiByZW5kZXJpbmcgdG8gY2FudmFzIC8gc3ZnLlxuICAgICAgICAgICAgYm90dG9tOiBgJHt0aGlzLnN0YXRlLmhlaWdodCArIEZSQU1FX1NUWUxFLm5hbWVPZmZzZXRZIC0geTEgKyB0aGlzLnN0YXRlLm9mZnNldFRvcH1weGAsXG4gICAgICAgICAgICBsZWZ0OiBgJHt4MSAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdH1weGAsXG4gICAgICAgICAgICB6SW5kZXg6IDIsXG4gICAgICAgICAgICBmb250U2l6ZTogRlJBTUVfU1RZTEUubmFtZUZvbnRTaXplLFxuICAgICAgICAgICAgY29sb3I6IGlzRGFya1RoZW1lID8gRlJBTUVfU1RZTEUubmFtZUNvbG9yRGFya1RoZW1lIDogRlJBTUVfU1RZTEUubmFtZUNvbG9yTGlnaHRUaGVtZSxcbiAgICAgICAgICAgIGxpbmVIZWlnaHQ6IEZSQU1FX1NUWUxFLm5hbWVMaW5lSGVpZ2h0LFxuICAgICAgICAgICAgd2lkdGg6IFwibWF4LWNvbnRlbnRcIixcbiAgICAgICAgICAgIG1heFdpZHRoOiBgJHtmLndpZHRofXB4YCxcbiAgICAgICAgICAgIG92ZXJmbG93OiBmLmlkID09PSB0aGlzLnN0YXRlLmVkaXRpbmdGcmFtZSA/IFwidmlzaWJsZVwiIDogXCJoaWRkZW5cIixcbiAgICAgICAgICAgIHdoaXRlU3BhY2U6IFwibm93cmFwXCIsXG4gICAgICAgICAgICB0ZXh0T3ZlcmZsb3c6IFwiZWxsaXBzaXNcIixcbiAgICAgICAgICAgIGN1cnNvcjogQ1VSU09SX1RZUEUuTU9WRSxcbiAgICAgICAgICAgIHBvaW50ZXJFdmVudHM6IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkID8gUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5lbmFibGVkXG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblBvaW50ZXJEb3duOiBldmVudCA9PiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJEb3duKGV2ZW50KSxcbiAgICAgICAgICBvbldoZWVsOiBldmVudCA9PiB0aGlzLmhhbmRsZVdoZWVsKGV2ZW50KSxcbiAgICAgICAgICBvbkNvbnRleHRNZW51OiB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51LFxuICAgICAgICAgIG9uRG91YmxlQ2xpY2s6ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nRnJhbWU6IGYuaWRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBmcmFtZU5hbWVKU1hcbiAgICAgICAgfSksIGYuaWQpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZm9jdXNDb250YWluZXIgPSAoKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZm9jdXMoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5nZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCA9ICgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuICAgIH07XG5cbiAgICB0aGlzLmdldFNjZW5lRWxlbWVudHMgPSAoKSA9PiB7XG4gICAgICByZXR1cm4gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5vbkluc2VydEVsZW1lbnRzID0gZWxlbWVudHMgPT4ge1xuICAgICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSh7XG4gICAgICAgIGVsZW1lbnRzLFxuICAgICAgICBwb3NpdGlvbjogXCJjZW50ZXJcIixcbiAgICAgICAgZmlsZXM6IG51bGxcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLm9uRXhwb3J0SW1hZ2UgPSAodHlwZSwgZWxlbWVudHMsIG9wdHMpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRyYWNrRXZlbnQoXCJleHBvcnRcIiwgdHlwZSwgXCJ1aVwiKTtcbiAgICAgIGNvbnN0IGZpbGVIYW5kbGUgPSB5aWVsZCBleHBvcnRDYW52YXModHlwZSwgZWxlbWVudHMsIHRoaXMuc3RhdGUsIHRoaXMuZmlsZXMsIHtcbiAgICAgICAgZXhwb3J0QmFja2dyb3VuZDogdGhpcy5zdGF0ZS5leHBvcnRCYWNrZ3JvdW5kLFxuICAgICAgICBuYW1lOiB0aGlzLnN0YXRlLm5hbWUsXG4gICAgICAgIHZpZXdCYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUudmlld0JhY2tncm91bmRDb2xvcixcbiAgICAgICAgZXhwb3J0aW5nRnJhbWU6IG9wdHMuZXhwb3J0aW5nRnJhbWVcbiAgICAgIH0pLmNhdGNoKG11dGVGU0Fib3J0RXJyb3IpLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5leHBvcnRFbWJlZFNjZW5lICYmIGZpbGVIYW5kbGUgJiYgaXNJbWFnZUZpbGVIYW5kbGUoZmlsZUhhbmRsZSkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZmlsZUhhbmRsZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub3BlbkV5ZURyb3BwZXIgPSAoe1xuICAgICAgdHlwZVxuICAgIH0pID0+IHtcbiAgICAgIGpvdGFpU3RvcmUuc2V0KGFjdGl2ZUV5ZURyb3BwZXJBdG9tLCB7XG4gICAgICAgIHN3YXBQcmV2aWV3T25BbHQ6IHRydWUsXG4gICAgICAgIGNvbG9yUGlja2VyVHlwZTogdHlwZSA9PT0gXCJzdHJva2VcIiA/IFwiZWxlbWVudFN0cm9rZVwiIDogXCJlbGVtZW50QmFja2dyb3VuZFwiLFxuICAgICAgICBvblNlbGVjdDogKGNvbG9yLCBldmVudCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHNob3VsZFVwZGF0ZVN0cm9rZUNvbG9yID0gdHlwZSA9PT0gXCJiYWNrZ3JvdW5kXCIgJiYgZXZlbnQuYWx0S2V5IHx8IHR5cGUgPT09IFwic3Ryb2tlXCIgJiYgIWV2ZW50LmFsdEtleTtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgICAgaWYgKCFzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICAgICAgaWYgKHNob3VsZFVwZGF0ZVN0cm9rZUNvbG9yKSB7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCh7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGN1cnJlbnRJdGVtU3Ryb2tlQ29sb3I6IGNvbG9yXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KHtcbiAgICAgICAgICAgICAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAgICAgICAgICAgY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3I6IGNvbG9yXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVNjZW5lKHtcbiAgICAgICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbZWwuaWRdKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWwsIHtcbiAgICAgICAgICAgICAgICAgICAgW3Nob3VsZFVwZGF0ZVN0cm9rZUNvbG9yID8gXCJzdHJva2VDb2xvclwiIDogXCJiYWNrZ3JvdW5kQ29sb3JcIl06IGNvbG9yXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gZWw7XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGtlZXBPcGVuT25BbHQ6IGZhbHNlXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0ID0gd2l0aEJhdGNoZWRVcGRhdGVzKGFjdGlvblJlc3VsdCA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZiwgX2csIF9oLCBfajtcblxuICAgICAgaWYgKHRoaXMudW5tb3VudGVkIHx8IGFjdGlvblJlc3VsdCA9PT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsZXQgZWRpdGluZ0VsZW1lbnQgPSBudWxsO1xuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmVsZW1lbnRzKSB7XG4gICAgICAgIGFjdGlvblJlc3VsdC5lbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgIGlmICgoKF9hID0gdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmlkKSA9PT0gZWxlbWVudC5pZCAmJiB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICE9PSBlbGVtZW50ICYmIGlzTm9uRGVsZXRlZEVsZW1lbnQoZWxlbWVudCkpIHtcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50ID0gZWxlbWVudDtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhhY3Rpb25SZXN1bHQuZWxlbWVudHMpO1xuXG4gICAgICAgIGlmIChhY3Rpb25SZXN1bHQuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3Rpb25SZXN1bHQuZmlsZXMpIHtcbiAgICAgICAgdGhpcy5maWxlcyA9IGFjdGlvblJlc3VsdC5yZXBsYWNlRmlsZXMgPyBhY3Rpb25SZXN1bHQuZmlsZXMgOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZmlsZXMpLCBhY3Rpb25SZXN1bHQuZmlsZXMpO1xuICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmFwcFN0YXRlIHx8IGVkaXRpbmdFbGVtZW50IHx8IHRoaXMuc3RhdGUuY29udGV4dE1lbnUpIHtcbiAgICAgICAgaWYgKGFjdGlvblJlc3VsdC5jb21taXRUb0hpc3RvcnkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdmlld01vZGVFbmFibGVkID0gKChfYSA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnZpZXdNb2RlRW5hYmxlZCkgfHwgZmFsc2U7XG4gICAgICAgIGxldCB6ZW5Nb2RlRW5hYmxlZCA9ICgoX2IgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi56ZW5Nb2RlRW5hYmxlZCkgfHwgZmFsc2U7XG4gICAgICAgIGxldCBncmlkU2l6ZSA9ICgoX2MgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5ncmlkU2l6ZSkgfHwgbnVsbDtcbiAgICAgICAgY29uc3QgdGhlbWUgPSAoKF9kID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QudGhlbWUpIHx8IHRoaXMucHJvcHMudGhlbWUgfHwgVEhFTUUuTElHSFQ7XG4gICAgICAgIGxldCBuYW1lID0gKF9mID0gKF9lID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2UubmFtZSkgIT09IG51bGwgJiYgX2YgIT09IHZvaWQgMCA/IF9mIDogdGhpcy5zdGF0ZS5uYW1lO1xuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSAoX2ggPSAoX2cgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9nID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZy5lcnJvck1lc3NhZ2UpICE9PSBudWxsICYmIF9oICE9PSB2b2lkIDAgPyBfaCA6IHRoaXMuc3RhdGUuZXJyb3JNZXNzYWdlO1xuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICB2aWV3TW9kZUVuYWJsZWQgPSB0aGlzLnByb3BzLnZpZXdNb2RlRW5hYmxlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIHplbk1vZGVFbmFibGVkID0gdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICBncmlkU2l6ZSA9IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkID8gR1JJRF9TSVpFIDogbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy5uYW1lICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgbmFtZSA9IHRoaXMucHJvcHMubmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGVkaXRpbmdFbGVtZW50ID0gZWRpdGluZ0VsZW1lbnQgfHwgKChfaiA9IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2ogPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9qLmVkaXRpbmdFbGVtZW50KSB8fCBudWxsO1xuXG4gICAgICAgIGlmIChlZGl0aW5nRWxlbWVudCA9PT0gbnVsbCB8fCBlZGl0aW5nRWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZWRpdGluZ0VsZW1lbnQuaXNEZWxldGVkKSB7XG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSA9PiB7XG4gICAgICAgICAgLy8gdXNpbmcgT2JqZWN0LmFzc2lnbiBpbnN0ZWFkIG9mIHNwcmVhZCB0byBmb29sIFRTIDQuMi4yKyBpbnRvXG4gICAgICAgICAgLy8gcmVnYXJkaW5nIHRoZSByZXN1bHRpbmcgdHlwZSBhcyBub3QgY29udGFpbmluZyB1bmRlZmluZWRcbiAgICAgICAgICAvLyAod2hpY2ggdGhlIGZvbGxvd2luZyBleHByZXNzaW9uIHdpbGwgbmV2ZXIgY29udGFpbilcbiAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihhY3Rpb25SZXN1bHQuYXBwU3RhdGUgfHwge30sIHtcbiAgICAgICAgICAgIC8vIE5PVEUgdGhpcyB3aWxsIHByZXZlbnQgb3BlbmluZyBjb250ZXh0IG1lbnUgdXNpbmcgYW4gYWN0aW9uXG4gICAgICAgICAgICAvLyBvciBwcm9ncmFtbWF0aWNhbGx5IGZyb20gdGhlIGhvc3QsIHNvIGl0IHdpbGwgbmVlZCB0byBiZVxuICAgICAgICAgICAgLy8gcmV3cml0dGVuIGxhdGVyXG4gICAgICAgICAgICBjb250ZXh0TWVudTogbnVsbCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50LFxuICAgICAgICAgICAgdmlld01vZGVFbmFibGVkLFxuICAgICAgICAgICAgemVuTW9kZUVuYWJsZWQsXG4gICAgICAgICAgICBncmlkU2l6ZSxcbiAgICAgICAgICAgIHRoZW1lLFxuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgaWYgKGFjdGlvblJlc3VsdC5zeW5jSGlzdG9yeSkge1xuICAgICAgICAgICAgdGhpcy5oaXN0b3J5LnNldEN1cnJlbnRTdGF0ZSh0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pOyAvLyBMaWZlY3ljbGVcblxuICAgIHRoaXMub25CbHVyID0gd2l0aEJhdGNoZWRVcGRhdGVzKCgpID0+IHtcbiAgICAgIGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogdHJ1ZVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLm9uVW5sb2FkID0gKCkgPT4ge1xuICAgICAgdGhpcy5vbkJsdXIoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5kaXNhYmxlRXZlbnQgPSBldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0SGlzdG9yeSA9ICgpID0+IHtcbiAgICAgIHRoaXMuaGlzdG9yeS5jbGVhcigpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmVzZXRzIHNjZW5lICYgaGlzdG9yeS5cbiAgICAgKiAhIERvIG5vdCB1c2UgdG8gY2xlYXIgc2NlbmUgdXNlciBhY3Rpb24gIVxuICAgICAqL1xuXG5cbiAgICB0aGlzLnJlc2V0U2NlbmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMob3B0cyA9PiB7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbXSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZ2V0RGVmYXVsdEFwcFN0YXRlKCkpLCB7XG4gICAgICAgIGlzTG9hZGluZzogKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yZXNldExvYWRpbmdTdGF0ZSkgPyBmYWxzZSA6IHN0YXRlLmlzTG9hZGluZyxcbiAgICAgICAgdGhlbWU6IHRoaXMuc3RhdGUudGhlbWVcbiAgICAgIH0pKTtcbiAgICAgIHRoaXMucmVzZXRIaXN0b3J5KCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmluaXRpYWxpemVTY2VuZSA9ICgpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgaWYgKFwibGF1bmNoUXVldWVcIiBpbiB3aW5kb3cgJiYgXCJMYXVuY2hQYXJhbXNcIiBpbiB3aW5kb3cpIHtcbiAgICAgICAgd2luZG93LmxhdW5jaFF1ZXVlLnNldENvbnN1bWVyKGxhdW5jaFBhcmFtcyA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgICAgaWYgKCFsYXVuY2hQYXJhbXMuZmlsZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgZmlsZUhhbmRsZSA9IGxhdW5jaFBhcmFtcy5maWxlc1swXTtcbiAgICAgICAgICBjb25zdCBibG9iID0geWllbGQgZmlsZUhhbmRsZS5nZXRGaWxlKCk7XG4gICAgICAgICAgdGhpcy5sb2FkRmlsZVRvQ2FudmFzKG5ldyBGaWxlKFtibG9iXSwgYmxvYi5uYW1lIHx8IFwiXCIsIHtcbiAgICAgICAgICAgIHR5cGU6IGJsb2IudHlwZVxuICAgICAgICAgIH0pLCBmaWxlSGFuZGxlKTtcbiAgICAgICAgfSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5wcm9wcy50aGVtZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmlzTG9hZGluZykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0xvYWRpbmc6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGxldCBpbml0aWFsRGF0YSA9IG51bGw7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGluaXRpYWxEYXRhID0gKHlpZWxkIHRoaXMucHJvcHMuaW5pdGlhbERhdGEpIHx8IG51bGw7XG5cbiAgICAgICAgaWYgKGluaXRpYWxEYXRhID09PSBudWxsIHx8IGluaXRpYWxEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpbml0aWFsRGF0YS5saWJyYXJ5SXRlbXMpIHtcbiAgICAgICAgICB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSh7XG4gICAgICAgICAgICBsaWJyYXJ5SXRlbXM6IGluaXRpYWxEYXRhLmxpYnJhcnlJdGVtcyxcbiAgICAgICAgICAgIG1lcmdlOiB0cnVlXG4gICAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICBpbml0aWFsRGF0YSA9IHtcbiAgICAgICAgICBhcHBTdGF0ZToge1xuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlIHx8IFwiRW5jb3VudGVyZWQgYW4gZXJyb3IgZHVyaW5nIGltcG9ydGluZyBvciByZXN0b3Jpbmcgc2NlbmUgZGF0YVwiXG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzY2VuZSA9IHJlc3RvcmUoaW5pdGlhbERhdGEsIG51bGwsIG51bGwsIHtcbiAgICAgICAgcmVwYWlyQmluZGluZ3M6IHRydWVcbiAgICAgIH0pO1xuICAgICAgc2NlbmUuYXBwU3RhdGUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlKSwge1xuICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZSB8fCBzY2VuZS5hcHBTdGF0ZS50aGVtZSxcbiAgICAgICAgLy8gd2UncmUgZmFsbGluZyBiYWNrIHRvIGN1cnJlbnQgKHByZS1pbml0KSBzdGF0ZSB3aGVuIGRlY2lkaW5nXG4gICAgICAgIC8vIHdoZXRoZXIgdG8gb3BlbiB0aGUgbGlicmFyeSwgdG8gaGFuZGxlIGEgY2FzZSB3aGVyZSB3ZVxuICAgICAgICAvLyB1cGRhdGUgdGhlIHN0YXRlIG91dHNpZGUgb2YgaW5pdGlhbERhdGEgKGUuZy4gd2hlbiBsb2FkaW5nIHRoZSBhcHBcbiAgICAgICAgLy8gd2l0aCBhIGxpYnJhcnkgaW5zdGFsbCBsaW5rLCB3aGljaCBzaG91bGQgYXV0by1vcGVuIHRoZSBsaWJyYXJ5KVxuICAgICAgICBvcGVuU2lkZWJhcjogKChfYSA9IHNjZW5lLmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eub3BlblNpZGViYXIpIHx8IHRoaXMuc3RhdGUub3BlblNpZGViYXIsXG4gICAgICAgIGFjdGl2ZVRvb2w6IHNjZW5lLmFwcFN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiID8gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sKSwge1xuICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgfSkgOiBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sLFxuICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICB0b2FzdDogdGhpcy5zdGF0ZS50b2FzdFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEuc2Nyb2xsVG9Db250ZW50KSB7XG4gICAgICAgIHNjZW5lLmFwcFN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIGNhbGN1bGF0ZVNjcm9sbENlbnRlcihzY2VuZS5lbGVtZW50cywgT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIHtcbiAgICAgICAgICB3aWR0aDogdGhpcy5zdGF0ZS53aWR0aCxcbiAgICAgICAgICBoZWlnaHQ6IHRoaXMuc3RhdGUuaGVpZ2h0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0XG4gICAgICAgIH0pKSk7XG4gICAgICB9IC8vIEZvbnRGYWNlU2V0IGxvYWRpbmdkb25lIGV2ZW50IHdlIGxpc3RlbiBvbiBtYXkgbm90IGFsd2F5cyBmaXJlXG4gICAgICAvLyAobG9va2luZyBhdCB5b3UgU2FmYXJpKSwgc28gb24gaW5pdCB3ZSBtYW51YWxseSBsb2FkIGZvbnRzIGZvciBjdXJyZW50XG4gICAgICAvLyB0ZXh0IGVsZW1lbnRzIG9uIGNhbnZhcywgYW5kIHJlcmVuZGVyIHRoZW0gb25jZSBkb25lLiBUaGlzIGFsc29cbiAgICAgIC8vIHNlZW1zIGZhc3RlciBldmVuIGluIGJyb3dzZXJzIHRoYXQgZG8gZmlyZSB0aGUgbG9hZGluZ2RvbmUgZXZlbnQuXG5cblxuICAgICAgdGhpcy5mb250cy5sb2FkRm9udHNGb3JFbGVtZW50cyhzY2VuZS5lbGVtZW50cyk7XG4gICAgICB0aGlzLnJlc2V0SGlzdG9yeSgpO1xuICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUpLCB7XG4gICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5pc01vYmlsZUJyZWFrcG9pbnQgPSAod2lkdGgsIGhlaWdodCkgPT4ge1xuICAgICAgcmV0dXJuIHdpZHRoIDwgTVFfTUFYX1dJRFRIX1BPUlRSQUlUIHx8IGhlaWdodCA8IE1RX01BWF9IRUlHSFRfTEFORFNDQVBFICYmIHdpZHRoIDwgTVFfTUFYX1dJRFRIX0xBTkRTQ0FQRTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZWZyZXNoVmlld3BvcnRCcmVha3BvaW50cyA9ICgpID0+IHtcbiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAoIWNvbnRhaW5lcikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgY2xpZW50V2lkdGg6IHZpZXdwb3J0V2lkdGgsXG4gICAgICAgIGNsaWVudEhlaWdodDogdmlld3BvcnRIZWlnaHRcbiAgICAgIH0gPSBkb2N1bWVudC5ib2R5O1xuICAgICAgY29uc3QgcHJldlZpZXdwb3J0U3RhdGUgPSB0aGlzLmRldmljZS52aWV3cG9ydDtcbiAgICAgIGNvbnN0IG5leHRWaWV3cG9ydFN0YXRlID0gdXBkYXRlT2JqZWN0KHByZXZWaWV3cG9ydFN0YXRlLCB7XG4gICAgICAgIGlzTGFuZHNjYXBlOiB2aWV3cG9ydFdpZHRoID4gdmlld3BvcnRIZWlnaHQsXG4gICAgICAgIGlzTW9iaWxlOiB0aGlzLmlzTW9iaWxlQnJlYWtwb2ludCh2aWV3cG9ydFdpZHRoLCB2aWV3cG9ydEhlaWdodClcbiAgICAgIH0pO1xuXG4gICAgICBpZiAocHJldlZpZXdwb3J0U3RhdGUgIT09IG5leHRWaWV3cG9ydFN0YXRlKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmRldmljZSksIHtcbiAgICAgICAgICB2aWV3cG9ydDogbmV4dFZpZXdwb3J0U3RhdGVcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMucmVmcmVzaEVkaXRvckJyZWFrcG9pbnRzID0gKCkgPT4ge1xuICAgICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG5cbiAgICAgIGlmICghY29udGFpbmVyKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICB3aWR0aDogZWRpdG9yV2lkdGgsXG4gICAgICAgIGhlaWdodDogZWRpdG9ySGVpZ2h0XG4gICAgICB9ID0gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgY29uc3Qgc2lkZWJhckJyZWFrcG9pbnQgPSB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCAhPSBudWxsID8gdGhpcy5wcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgOiBNUV9SSUdIVF9TSURFQkFSX01JTl9XSURUSDtcbiAgICAgIGNvbnN0IHByZXZFZGl0b3JTdGF0ZSA9IHRoaXMuZGV2aWNlLmVkaXRvcjtcbiAgICAgIGNvbnN0IG5leHRFZGl0b3JTdGF0ZSA9IHVwZGF0ZU9iamVjdChwcmV2RWRpdG9yU3RhdGUsIHtcbiAgICAgICAgaXNNb2JpbGU6IHRoaXMuaXNNb2JpbGVCcmVha3BvaW50KGVkaXRvcldpZHRoLCBlZGl0b3JIZWlnaHQpLFxuICAgICAgICBjYW5GaXRTaWRlYmFyOiBlZGl0b3JXaWR0aCA+IHNpZGViYXJCcmVha3BvaW50XG4gICAgICB9KTtcblxuICAgICAgaWYgKHByZXZFZGl0b3JTdGF0ZSAhPT0gbmV4dEVkaXRvclN0YXRlKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmRldmljZSksIHtcbiAgICAgICAgICBlZGl0b3I6IG5leHRFZGl0b3JTdGF0ZVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgdGhpcy5vblJlc2l6ZSA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZvckVhY2goZWxlbWVudCA9PiBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KSk7XG4gICAgICB0aGlzLnJlZnJlc2hWaWV3cG9ydEJyZWFrcG9pbnRzKCk7XG4gICAgICB0aGlzLnVwZGF0ZURPTVJlY3QoKTtcblxuICAgICAgaWYgKCFzdXBwb3J0c1Jlc2l6ZU9ic2VydmVyKSB7XG4gICAgICAgIHRoaXMucmVmcmVzaEVkaXRvckJyZWFrcG9pbnRzKCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe30pO1xuICAgIH0pO1xuXG4gICAgdGhpcy5yZW5kZXJJbnRlcmFjdGl2ZVNjZW5lQ2FsbGJhY2sgPSAoe1xuICAgICAgYXRMZWFzdE9uZVZpc2libGVFbGVtZW50LFxuICAgICAgc2Nyb2xsQmFycyxcbiAgICAgIGVsZW1lbnRzXG4gICAgfSkgPT4ge1xuICAgICAgaWYgKHNjcm9sbEJhcnMpIHtcbiAgICAgICAgY3VycmVudFNjcm9sbEJhcnMgPSBzY3JvbGxCYXJzO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzY3JvbGxlZE91dHNpZGUgPSAvLyBoaWRlIHdoZW4gZWRpdGluZyB0ZXh0XG4gICAgICBpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID8gZmFsc2UgOiAhYXRMZWFzdE9uZVZpc2libGVFbGVtZW50ICYmIGVsZW1lbnRzLmxlbmd0aCA+IDA7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNjcm9sbGVkT3V0c2lkZSAhPT0gc2Nyb2xsZWRPdXRzaWRlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNjcm9sbGVkT3V0c2lkZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zY2hlZHVsZUltYWdlUmVmcmVzaCgpO1xuICAgIH07XG5cbiAgICB0aGlzLm9uU2Nyb2xsID0gZGVib3VuY2UoKCkgPT4ge1xuICAgICAgY29uc3Qge1xuICAgICAgICBvZmZzZXRUb3AsXG4gICAgICAgIG9mZnNldExlZnRcbiAgICAgIH0gPSB0aGlzLmdldENhbnZhc09mZnNldHMoKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICBpZiAoc3RhdGUub2Zmc2V0TGVmdCA9PT0gb2Zmc2V0TGVmdCAmJiBzdGF0ZS5vZmZzZXRUb3AgPT09IG9mZnNldFRvcCkge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBvZmZzZXRUb3AsXG4gICAgICAgICAgb2Zmc2V0TGVmdFxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfSwgU0NST0xMX1RJTUVPVVQpOyAvLyBDb3B5L3Bhc3RlXG5cbiAgICB0aGlzLm9uQ3V0ID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaXNFeGNhbGlkcmF3QWN0aXZlID0gKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jb250YWlucyhkb2N1bWVudC5hY3RpdmVFbGVtZW50KTtcblxuICAgICAgaWYgKCFpc0V4Y2FsaWRyYXdBY3RpdmUgfHwgaXNXcml0YWJsZUVsZW1lbnQoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkN1dCwgXCJrZXlib2FyZFwiLCBldmVudCk7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfSk7XG4gICAgdGhpcy5vbkNvcHkgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBpc0V4Y2FsaWRyYXdBY3RpdmUgPSAoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNvbnRhaW5zKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpO1xuXG4gICAgICBpZiAoIWlzRXhjYWxpZHJhd0FjdGl2ZSB8fCBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uQ29weSwgXCJrZXlib2FyZFwiLCBldmVudCk7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLm9uVG91Y2hTdGFydCA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIGZpeCBmb3IgQXBwbGUgUGVuY2lsIFNjcmliYmxlXG4gICAgICAvLyBPbiBBbmRyb2lkLCBwcmV2ZW50aW5nIHRoZSBldmVudCB3b3VsZCBkaXNhYmxlIGNvbnRleHRNZW51IG9uIHRhcC1ob2xkXG4gICAgICBpZiAoIWlzQW5kcm9pZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWRpZFRhcFR3aWNlKSB7XG4gICAgICAgIGRpZFRhcFR3aWNlID0gdHJ1ZTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRhcHBlZFR3aWNlVGltZXIpO1xuICAgICAgICB0YXBwZWRUd2ljZVRpbWVyID0gd2luZG93LnNldFRpbWVvdXQoQXBwLnJlc2V0VGFwVHdpY2UsIFRBUF9UV0lDRV9USU1FT1VUKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBpbnNlcnQgdGV4dCBvbmx5IGlmIHdlIHRhcHBlZCB0d2ljZSB3aXRoIGEgc2luZ2xlIGZpbmdlclxuICAgICAgLy8gZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDEgd2lsbCBhbHNvIHByZXZlbnQgaW5zZXJ0aW5nIHRleHQgd2hlbiB1c2VyJ3Mgem9vbWluZ1xuXG5cbiAgICAgIGlmIChkaWRUYXBUd2ljZSAmJiBldmVudC50b3VjaGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBjb25zdCB0b3VjaCA9IGV2ZW50LnRvdWNoZXNbMF07IC8vIEB0cy1pZ25vcmVcblxuICAgICAgICB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrKHtcbiAgICAgICAgICBjbGllbnRYOiB0b3VjaC5jbGllbnRYLFxuICAgICAgICAgIGNsaWVudFk6IHRvdWNoLmNsaWVudFlcbiAgICAgICAgfSk7XG4gICAgICAgIGRpZFRhcFR3aWNlID0gZmFsc2U7XG4gICAgICAgIGNsZWFyVGltZW91dCh0YXBwZWRUd2ljZVRpbWVyKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzQW5kcm9pZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5vblRvdWNoRW5kID0gZXZlbnQgPT4ge1xuICAgICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIoKTtcblxuICAgICAgaWYgKGV2ZW50LnRvdWNoZXMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczoge30sXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh0aGlzLnN0YXRlLnByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzLCB0aGlzLnN0YXRlKVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUucG9pbnRlcnMuY2xlYXIoKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5wYXN0ZUZyb21DbGlwYm9hcmQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdmFyIF9iLCBfYywgX2Q7XG5cbiAgICAgIGNvbnN0IGlzUGxhaW5QYXN0ZSA9ICEhSVNfUExBSU5fUEFTVEU7IC8vICM2ODZcblxuICAgICAgY29uc3QgdGFyZ2V0ID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcbiAgICAgIGNvbnN0IGlzRXhjYWxpZHJhd0FjdGl2ZSA9IChfYiA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY29udGFpbnModGFyZ2V0KTtcblxuICAgICAgaWYgKGV2ZW50ICYmICFpc0V4Y2FsaWRyYXdBY3RpdmUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50VW5kZXJDdXJzb3IgPSBkb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCwgdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55KTtcblxuICAgICAgaWYgKGV2ZW50ICYmICghKGVsZW1lbnRVbmRlckN1cnNvciBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50KSB8fCBpc1dyaXRhYmxlRWxlbWVudCh0YXJnZXQpKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeDogc2NlbmVYLFxuICAgICAgICB5OiBzY2VuZVlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgIGNsaWVudFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueVxuICAgICAgfSwgdGhpcy5zdGF0ZSk7IC8vIG11c3QgYmUgY2FsbGVkIGluIHRoZSBzYW1lIGZyYW1lICh0aHVzIGJlZm9yZSBhbnkgYXdhaXRzKSBhcyB0aGUgcGFzdGVcbiAgICAgIC8vIGV2ZW50IGVsc2Ugc29tZSBicm93c2VycyAoRkYuLi4pIHdpbGwgY2xlYXIgdGhlIGNsaXBib2FyZERhdGFcbiAgICAgIC8vIChzb21ldGhpbmcgc29tZXRoaW5nIHNlY3VyaXR5KVxuXG4gICAgICBsZXQgZmlsZSA9IChfYyA9IGV2ZW50ID09PSBudWxsIHx8IGV2ZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBldmVudC5jbGlwYm9hcmREYXRhKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZmlsZXNbMF07XG4gICAgICBjb25zdCBkYXRhID0geWllbGQgcGFyc2VDbGlwYm9hcmQoZXZlbnQsIGlzUGxhaW5QYXN0ZSk7XG5cbiAgICAgIGlmICghZmlsZSAmJiAhaXNQbGFpblBhc3RlKSB7XG4gICAgICAgIGlmIChkYXRhLm1peGVkQ29udGVudCkge1xuICAgICAgICAgIHJldHVybiB0aGlzLmFkZEVsZW1lbnRzRnJvbU1peGVkQ29udGVudFBhc3RlKGRhdGEubWl4ZWRDb250ZW50LCB7XG4gICAgICAgICAgICBpc1BsYWluUGFzdGUsXG4gICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICBzY2VuZVlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLnRleHQpIHtcbiAgICAgICAgICBjb25zdCBzdHJpbmcgPSBkYXRhLnRleHQudHJpbSgpO1xuXG4gICAgICAgICAgaWYgKHN0cmluZy5zdGFydHNXaXRoKFwiPHN2Z1wiKSAmJiBzdHJpbmcuZW5kc1dpdGgoXCI8L3N2Zz5cIikpIHtcbiAgICAgICAgICAgIC8vIGlnbm9yZSBTVkcgdmFsaWRhdGlvbi9ub3JtYWxpemF0aW9uIHdoaWNoIHdpbGwgYmUgZG9uZSBkdXJpbmcgaW1hZ2VcbiAgICAgICAgICAgIC8vIGluaXRpYWxpemF0aW9uXG4gICAgICAgICAgICBmaWxlID0gU1ZHU3RyaW5nVG9GaWxlKHN0cmluZyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IC8vIHByZWZlciBzcHJlYWRzaGVldCBkYXRhIG92ZXIgaW1hZ2UgZmlsZSAoTVMgT2ZmaWNlL0xpYnJlIE9mZmljZSlcblxuXG4gICAgICBpZiAoaXNTdXBwb3J0ZWRJbWFnZUZpbGUoZmlsZSkgJiYgIWRhdGEuc3ByZWFkc2hlZXQpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzVG9vbFN1cHBvcnRlZChcImltYWdlXCIpKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6IHQoXCJlcnJvcnMuaW1hZ2VUb29sTm90U3VwcG9ydGVkXCIpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQoe1xuICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICBzY2VuZVlcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgZmlsZSk7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlRGltZW5zaW9ucyhpbWFnZUVsZW1lbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgIFtpbWFnZUVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMucHJvcHMub25QYXN0ZSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmICgoeWllbGQgdGhpcy5wcm9wcy5vblBhc3RlKGRhdGEsIGV2ZW50KSkgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChkYXRhLmVycm9yTWVzc2FnZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGRhdGEuZXJyb3JNZXNzYWdlXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLnNwcmVhZHNoZWV0ICYmICFpc1BsYWluUGFzdGUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcGFzdGVEaWFsb2c6IHtcbiAgICAgICAgICAgIGRhdGE6IGRhdGEuc3ByZWFkc2hlZXQsXG4gICAgICAgICAgICBzaG93bjogdHJ1ZVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZWxlbWVudHMpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSBkYXRhLnByb2dyYW1tYXRpY0FQSSA/IGNvbnZlcnRUb0V4Y2FsaWRyYXdFbGVtZW50cyhkYXRhLmVsZW1lbnRzKSA6IGRhdGEuZWxlbWVudHM7IC8vIFRPRE8gcmVtb3ZlIGZvcm1hdHRpbmcgZnJvbSBlbGVtZW50cyBpZiBpc1BsYWluUGFzdGVcblxuICAgICAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5KHtcbiAgICAgICAgICBlbGVtZW50cyxcbiAgICAgICAgICBmaWxlczogZGF0YS5maWxlcyB8fCBudWxsLFxuICAgICAgICAgIHBvc2l0aW9uOiBcImN1cnNvclwiLFxuICAgICAgICAgIHJldGFpblNlZWQ6IGlzUGxhaW5QYXN0ZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS50ZXh0KSB7XG4gICAgICAgIGNvbnN0IG1heWJlVXJsID0gZXh0cmFjdFNyYyhkYXRhLnRleHQpO1xuXG4gICAgICAgIGlmICghaXNQbGFpblBhc3RlICYmIGVtYmVkZGFibGVVUkxWYWxpZGF0b3IobWF5YmVVcmwsIHRoaXMucHJvcHMudmFsaWRhdGVFbWJlZGRhYmxlKSAmJiAoL14oaHR0cHxodHRwcyk6XFwvXFwvW15cXHMvJC4/I10uW15cXHNdKiQvLnRlc3QobWF5YmVVcmwpIHx8ICgoX2QgPSBnZXRFbWJlZExpbmsobWF5YmVVcmwpKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QudHlwZSkgPT09IFwidmlkZW9cIikpIHtcbiAgICAgICAgICBjb25zdCBlbWJlZGRhYmxlID0gdGhpcy5pbnNlcnRFbWJlZGRhYmxlRWxlbWVudCh7XG4gICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgICBsaW5rOiBub3JtYWxpemVMaW5rKG1heWJlVXJsKVxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKGVtYmVkZGFibGUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICAgICAgICBbZW1iZWRkYWJsZS5pZF06IHRydWVcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5hZGRUZXh0RnJvbVBhc3RlKGRhdGEudGV4dCwgaXNQbGFpblBhc3RlKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgfSk7XG4gICAgICBldmVudCA9PT0gbnVsbCB8fCBldmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9KSk7XG5cbiAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5ID0gb3B0cyA9PiB7XG4gICAgICBjb25zdCBlbGVtZW50cyA9IHJlc3RvcmVFbGVtZW50cyhvcHRzLmVsZW1lbnRzLCBudWxsLCB1bmRlZmluZWQpO1xuICAgICAgY29uc3QgW21pblgsIG1pblksIG1heFgsIG1heFldID0gZ2V0Q29tbW9uQm91bmRzKGVsZW1lbnRzKTtcbiAgICAgIGNvbnN0IGVsZW1lbnRzQ2VudGVyWCA9IGRpc3RhbmNlKG1pblgsIG1heFgpIC8gMjtcbiAgICAgIGNvbnN0IGVsZW1lbnRzQ2VudGVyWSA9IGRpc3RhbmNlKG1pblksIG1heFkpIC8gMjtcbiAgICAgIGNvbnN0IGNsaWVudFggPSB0eXBlb2Ygb3B0cy5wb3NpdGlvbiA9PT0gXCJvYmplY3RcIiA/IG9wdHMucG9zaXRpb24uY2xpZW50WCA6IG9wdHMucG9zaXRpb24gPT09IFwiY3Vyc29yXCIgPyB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnggOiB0aGlzLnN0YXRlLndpZHRoIC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0TGVmdDtcbiAgICAgIGNvbnN0IGNsaWVudFkgPSB0eXBlb2Ygb3B0cy5wb3NpdGlvbiA9PT0gXCJvYmplY3RcIiA/IG9wdHMucG9zaXRpb24uY2xpZW50WSA6IG9wdHMucG9zaXRpb24gPT09IFwiY3Vyc29yXCIgPyB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnkgOiB0aGlzLnN0YXRlLmhlaWdodCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldFRvcDtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgIGNsaWVudFgsXG4gICAgICAgIGNsaWVudFlcbiAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgZHggPSB4IC0gZWxlbWVudHNDZW50ZXJYO1xuICAgICAgY29uc3QgZHkgPSB5IC0gZWxlbWVudHNDZW50ZXJZO1xuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoZHgsIGR5LCB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IG5ld0VsZW1lbnRzID0gZHVwbGljYXRlRWxlbWVudHMoZWxlbWVudHMubWFwKGVsZW1lbnQgPT4ge1xuICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlbWVudCwge1xuICAgICAgICAgIHg6IGVsZW1lbnQueCArIGdyaWRYIC0gbWluWCxcbiAgICAgICAgICB5OiBlbGVtZW50LnkgKyBncmlkWSAtIG1pbllcbiAgICAgICAgfSk7XG4gICAgICB9KSwge1xuICAgICAgICByYW5kb21pemVTZWVkOiAhb3B0cy5yZXRhaW5TZWVkXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IG5leHRFbGVtZW50cyA9IFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCAuLi5uZXdFbGVtZW50c107XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0RWxlbWVudHMpO1xuICAgICAgbmV3RWxlbWVudHMuZm9yRWFjaChuZXdFbGVtZW50ID0+IHtcbiAgICAgICAgaWYgKGlzVGV4dEVsZW1lbnQobmV3RWxlbWVudCkgJiYgaXNCb3VuZFRvQ29udGFpbmVyKG5ld0VsZW1lbnQpKSB7XG4gICAgICAgICAgY29uc3QgY29udGFpbmVyID0gZ2V0Q29udGFpbmVyRWxlbWVudChuZXdFbGVtZW50KTtcbiAgICAgICAgICByZWRyYXdUZXh0Qm91bmRpbmdCb3gobmV3RWxlbWVudCwgY29udGFpbmVyKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIGlmIChvcHRzLmZpbGVzKSB7XG4gICAgICAgIHRoaXMuZmlsZXMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZmlsZXMpLCBvcHRzLmZpbGVzKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgY29uc3QgbmV4dEVsZW1lbnRzVG9TZWxlY3QgPSBleGNsdWRlRWxlbWVudHNJbkZyYW1lc0Zyb21TZWxlY3Rpb24obmV3RWxlbWVudHMpO1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgLy8ga2VlcCBzaWRlYmFyIChwcmVzdW1hYmx5IHRoZSBsaWJyYXJ5KSBvcGVuIGlmIGl0J3MgZG9ja2VkIGFuZFxuICAgICAgICAvLyBjYW4gZml0LlxuICAgICAgICAvL1xuICAgICAgICAvLyBOb3RlLCB3ZSBzaG91bGQgY2xvc2UgdGhlIHNpZGViYXIgb25seSBpZiB3ZSdyZSBkcm9wcGluZyBpdGVtc1xuICAgICAgICAvLyBmcm9tIGxpYnJhcnksIG5vdCB3aGVuIHBhc3RpbmcgZnJvbSBjbGlwYm9hcmQuIEFsYXMuXG4gICAgICAgIG9wZW5TaWRlYmFyOiB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyICYmIHRoaXMuZGV2aWNlLmVkaXRvci5jYW5GaXRTaWRlYmFyICYmIGpvdGFpU3RvcmUuZ2V0KGlzU2lkZWJhckRvY2tlZEF0b20pID8gdGhpcy5zdGF0ZS5vcGVuU2lkZWJhciA6IG51bGxcbiAgICAgIH0pLCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dEVsZW1lbnRzVG9TZWxlY3QucmVkdWNlKChhY2MsIGVsZW1lbnQpID0+IHtcbiAgICAgICAgICBpZiAoIWlzQm91bmRUb0NvbnRhaW5lcihlbGVtZW50KSkge1xuICAgICAgICAgICAgYWNjW2VsZW1lbnQuaWRdID0gdHJ1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICB9LCB7fSlcbiAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHRoaXMpKSwgKCkgPT4ge1xuICAgICAgICBpZiAob3B0cy5maWxlcykge1xuICAgICAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgfSk7XG5cbiAgICAgIGlmIChvcHRzLmZpdFRvQ29udGVudCkge1xuICAgICAgICB0aGlzLnNjcm9sbFRvQ29udGVudChuZXdFbGVtZW50cywge1xuICAgICAgICAgIGZpdFRvQ29udGVudDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5zZXRBcHBTdGF0ZSA9IChzdGF0ZSwgY2FsbGJhY2spID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUsIGNhbGxiYWNrKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZW1vdmVQb2ludGVyID0gZXZlbnQgPT4ge1xuICAgICAgaWYgKHRvdWNoVGltZW91dCkge1xuICAgICAgICB0aGlzLnJlc2V0Q29udGV4dE1lbnVUaW1lcigpO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLnBvaW50ZXJzLmRlbGV0ZShldmVudC5wb2ludGVySWQpO1xuICAgIH07XG5cbiAgICB0aGlzLnRvZ2dsZUxvY2sgPSAoc291cmNlID0gXCJ1aVwiKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgdHJhY2tFdmVudChcInRvb2xiYXJcIiwgXCJ0b2dnbGVMb2NrXCIsIGAke3NvdXJjZX0gKCR7dGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlID8gXCJtb2JpbGVcIiA6IFwiZGVza3RvcFwifSlgKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuYWN0aXZlVG9vbCksIHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwgcHJldlN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkID8ge1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0gOiBwcmV2U3RhdGUuYWN0aXZlVG9vbCkpLCB7XG4gICAgICAgICAgICBsb2NrZWQ6ICFwcmV2U3RhdGUuYWN0aXZlVG9vbC5sb2NrZWRcbiAgICAgICAgICB9KVxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMudXBkYXRlRnJhbWVSZW5kZXJpbmcgPSBvcHRzID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kO1xuXG4gICAgICAgIGNvbnN0IG5leHQgPSB0eXBlb2Ygb3B0cyA9PT0gXCJmdW5jdGlvblwiID8gb3B0cyhwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcpIDogb3B0cztcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBmcmFtZVJlbmRlcmluZzoge1xuICAgICAgICAgICAgZW5hYmxlZDogKF9hID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0LmVuYWJsZWQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5lbmFibGVkLFxuICAgICAgICAgICAgY2xpcDogKF9iID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0LmNsaXApICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5jbGlwLFxuICAgICAgICAgICAgbmFtZTogKF9jID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0Lm5hbWUpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lLFxuICAgICAgICAgICAgb3V0bGluZTogKF9kID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0Lm91dGxpbmUpICE9PSBudWxsICYmIF9kICE9PSB2b2lkIDAgPyBfZCA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5vdXRsaW5lXG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMudG9nZ2xlUGVuTW9kZSA9IGZvcmNlID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBwZW5Nb2RlOiBmb3JjZSAhPT0gbnVsbCAmJiBmb3JjZSAhPT0gdm9pZCAwID8gZm9yY2UgOiAhcHJldlN0YXRlLnBlbk1vZGUsXG4gICAgICAgICAgcGVuRGV0ZWN0ZWQ6IHRydWVcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLm9uSGFuZFRvb2xUb2dnbGUgPSAoKSA9PiB7XG4gICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25Ub2dnbGVIYW5kVG9vbCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBab29tcyBvbiBjYW52YXMgdmlld3BvcnQgY2VudGVyXG4gICAgICovXG5cblxuICAgIHRoaXMuem9vbUNhbnZhcyA9IChcbiAgICAvKiogZGVjaW1hbCBmcmFjdGlvbiBiZXR3ZWVuIDAuMSAoMTAlIHpvb20pIGFuZCAzMCAoMzAwMCUgem9vbSkgKi9cbiAgICB2YWx1ZSkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKHt9LCBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICB2aWV3cG9ydFg6IHRoaXMuc3RhdGUud2lkdGggLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICB2aWV3cG9ydFk6IHRoaXMuc3RhdGUuaGVpZ2h0IC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20odmFsdWUpXG4gICAgICB9LCB0aGlzLnN0YXRlKSkpO1xuICAgIH07XG5cbiAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9IG51bGw7XG5cbiAgICB0aGlzLnNjcm9sbFRvQ29udGVudCA9ICh0YXJnZXQgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBvcHRzKSA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAoX2EgPSB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwodGhpcyk7IC8vIGNvbnZlcnQgcHJvdmlkZWQgdGFyZ2V0IGludG8gRXhjYWxpZHJhd0VsZW1lbnRbXSBpZiBuZWNlc3NhcnlcblxuICAgICAgY29uc3QgdGFyZ2V0RWxlbWVudHMgPSBBcnJheS5pc0FycmF5KHRhcmdldCkgPyB0YXJnZXQgOiBbdGFyZ2V0XTtcbiAgICAgIGxldCB6b29tID0gdGhpcy5zdGF0ZS56b29tO1xuICAgICAgbGV0IHNjcm9sbFggPSB0aGlzLnN0YXRlLnNjcm9sbFg7XG4gICAgICBsZXQgc2Nyb2xsWSA9IHRoaXMuc3RhdGUuc2Nyb2xsWTtcblxuICAgICAgaWYgKChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZml0VG9Db250ZW50KSB8fCAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvVmlld3BvcnQpKSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBhcHBTdGF0ZVxuICAgICAgICB9ID0gem9vbVRvRml0KHtcbiAgICAgICAgICB0YXJnZXRFbGVtZW50cyxcbiAgICAgICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgICAgICBmaXRUb1ZpZXdwb3J0OiAhIShvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZml0VG9WaWV3cG9ydCksXG4gICAgICAgICAgdmlld3BvcnRab29tRmFjdG9yOiBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMudmlld3BvcnRab29tRmFjdG9yXG4gICAgICAgIH0pO1xuICAgICAgICB6b29tID0gYXBwU3RhdGUuem9vbTtcbiAgICAgICAgc2Nyb2xsWCA9IGFwcFN0YXRlLnNjcm9sbFg7XG4gICAgICAgIHNjcm9sbFkgPSBhcHBTdGF0ZS5zY3JvbGxZO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gY29tcHV0ZSBvbmx5IHRoZSB2aWV3cG9ydCBsb2NhdGlvbiwgd2l0aG91dCBhbnkgem9vbSBhZGp1c3RtZW50XG4gICAgICAgIGNvbnN0IHNjcm9sbCA9IGNhbGN1bGF0ZVNjcm9sbENlbnRlcih0YXJnZXRFbGVtZW50cywgdGhpcy5zdGF0ZSk7XG4gICAgICAgIHNjcm9sbFggPSBzY3JvbGwuc2Nyb2xsWDtcbiAgICAgICAgc2Nyb2xsWSA9IHNjcm9sbC5zY3JvbGxZO1xuICAgICAgfSAvLyB3aGVuIGFuaW1hdGluZywgd2UgdXNlIFJlcXVlc3RBbmltYXRpb25GcmFtZSB0byBwcmV2ZW50IHRoZSBhbmltYXRpb25cbiAgICAgIC8vIGZyb20gc2xvd2luZyBkb3duIG90aGVyIHByb2Nlc3Nlc1xuXG5cbiAgICAgIGlmIChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuYW5pbWF0ZSkge1xuICAgICAgICBjb25zdCBvcmlnU2Nyb2xsWCA9IHRoaXMuc3RhdGUuc2Nyb2xsWDtcbiAgICAgICAgY29uc3Qgb3JpZ1Njcm9sbFkgPSB0aGlzLnN0YXRlLnNjcm9sbFk7XG4gICAgICAgIGNvbnN0IG9yaWdab29tID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgICBjb25zdCBjYW5jZWwgPSBlYXNlVG9WYWx1ZXNSQUYoe1xuICAgICAgICAgIGZyb21WYWx1ZXM6IHtcbiAgICAgICAgICAgIHNjcm9sbFg6IG9yaWdTY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWTogb3JpZ1Njcm9sbFksXG4gICAgICAgICAgICB6b29tOiBvcmlnWm9vbVxuICAgICAgICAgIH0sXG4gICAgICAgICAgdG9WYWx1ZXM6IHtcbiAgICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgem9vbTogem9vbS52YWx1ZVxuICAgICAgICAgIH0sXG4gICAgICAgICAgaW50ZXJwb2xhdGVWYWx1ZTogKGZyb20sIHRvLCBwcm9ncmVzcywga2V5KSA9PiB7XG4gICAgICAgICAgICAvLyBmb3Igem9vbSwgdXNlIGRpZmZlcmVudCBlYXNpbmdcbiAgICAgICAgICAgIGlmIChrZXkgPT09IFwiem9vbVwiKSB7XG4gICAgICAgICAgICAgIHJldHVybiBmcm9tICogTWF0aC5wb3codG8gLyBmcm9tLCBlYXNlT3V0KHByb2dyZXNzKSk7XG4gICAgICAgICAgICB9IC8vIGhhbmRsZSB1c2luZyBkZWZhdWx0XG5cblxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uU3RlcDogKHtcbiAgICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgem9vbVxuICAgICAgICAgIH0pID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgICB6b29tOiB7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHpvb21cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblN0YXJ0OiAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uRW5kOiAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvbkNhbmNlbDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgZHVyYXRpb246IChfYiA9IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5kdXJhdGlvbikgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogNTAwXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uID0gKCkgPT4ge1xuICAgICAgICAgIGNhbmNlbCgpO1xuICAgICAgICAgIHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uID0gbnVsbDtcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICB6b29tXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG4gICAgLyoqIHVzZSB3aGVuIGNoYW5naW5nIHNjcm9sbFgvc2Nyb2xsWS96b29tIGJhc2VkIG9uIHVzZXIgaW50ZXJhY3Rpb24gKi9cblxuXG4gICAgdGhpcy50cmFuc2xhdGVDYW52YXMgPSBzdGF0ZSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIChfYSA9IHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY2FsbCh0aGlzKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUpO1xuICAgIH07XG5cbiAgICB0aGlzLnNldFRvYXN0ID0gdG9hc3QgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHRvYXN0XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXN0b3JlRmlsZUZyb21TaGFyZSA9ICgpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHdlYlNoYXJlVGFyZ2V0Q2FjaGUgPSB5aWVsZCBjYWNoZXMub3BlbihcIndlYi1zaGFyZS10YXJnZXRcIik7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0geWllbGQgd2ViU2hhcmVUYXJnZXRDYWNoZS5tYXRjaChcInNoYXJlZC1maWxlXCIpO1xuXG4gICAgICAgIGlmIChyZXNwb25zZSkge1xuICAgICAgICAgIGNvbnN0IGJsb2IgPSB5aWVsZCByZXNwb25zZS5ibG9iKCk7XG4gICAgICAgICAgY29uc3QgZmlsZSA9IG5ldyBGaWxlKFtibG9iXSwgYmxvYi5uYW1lIHx8IFwiXCIsIHtcbiAgICAgICAgICAgIHR5cGU6IGJsb2IudHlwZVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhmaWxlLCBudWxsKTtcbiAgICAgICAgICB5aWVsZCB3ZWJTaGFyZVRhcmdldENhY2hlLmRlbGV0ZShcInNoYXJlZC1maWxlXCIpO1xuICAgICAgICAgIHdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZShudWxsLCBBUFBfTkFNRSwgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIC8qKiBhZGRzIHN1cHBsaWVkIGZpbGVzIHRvIGV4aXN0aW5nIGZpbGVzIGluIHRoZSBhcHBTdGF0ZSAqL1xuXG5cbiAgICB0aGlzLmFkZEZpbGVzID0gd2l0aEJhdGNoZWRVcGRhdGVzKGZpbGVzID0+IHtcbiAgICAgIGNvbnN0IGZpbGVzTWFwID0gZmlsZXMucmVkdWNlKChhY2MsIGZpbGVEYXRhKSA9PiB7XG4gICAgICAgIGFjYy5zZXQoZmlsZURhdGEuaWQsIGZpbGVEYXRhKTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIG5ldyBNYXAoKSk7XG4gICAgICB0aGlzLmZpbGVzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgT2JqZWN0LmZyb21FbnRyaWVzKGZpbGVzTWFwKSk7XG4gICAgICB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGVsZW1lbnQpICYmIGZpbGVzTWFwLmhhcyhlbGVtZW50LmZpbGVJZCkpIHtcbiAgICAgICAgICB0aGlzLmltYWdlQ2FjaGUuZGVsZXRlKGVsZW1lbnQuZmlsZUlkKTtcbiAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLmluZm9ybU11dGF0aW9uKCk7XG4gICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgIH0pO1xuICAgIHRoaXMudXBkYXRlU2NlbmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoc2NlbmVEYXRhID0+IHtcbiAgICAgIGlmIChzY2VuZURhdGEuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNjZW5lRGF0YS5hcHBTdGF0ZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHNjZW5lRGF0YS5hcHBTdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuZWxlbWVudHMpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoc2NlbmVEYXRhLmVsZW1lbnRzKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNjZW5lRGF0YS5jb2xsYWJvcmF0b3JzKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbGxhYm9yYXRvcnM6IHNjZW5lRGF0YS5jb2xsYWJvcmF0b3JzXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5vblNjZW5lVXBkYXRlZCA9ICgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe30pO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybnMgd2hldGhlciB0aGUgbWVudSB3YXMgdG9nZ2xlZCBvbiBvciBvZmZcbiAgICAgKi9cblxuXG4gICAgdGhpcy50b2dnbGVTaWRlYmFyID0gKHtcbiAgICAgIG5hbWUsXG4gICAgICB0YWIsXG4gICAgICBmb3JjZVxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgbGV0IG5leHROYW1lO1xuXG4gICAgICBpZiAoZm9yY2UgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBuZXh0TmFtZSA9ICgoX2EgPSB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EubmFtZSkgPT09IG5hbWUgPyBudWxsIDogbmFtZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5leHROYW1lID0gZm9yY2UgPyBuYW1lIDogbnVsbDtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG9wZW5TaWRlYmFyOiBuZXh0TmFtZSA/IHtcbiAgICAgICAgICBuYW1lOiBuZXh0TmFtZSxcbiAgICAgICAgICB0YWJcbiAgICAgICAgfSA6IG51bGxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuICEhbmV4dE5hbWU7XG4gICAgfTtcblxuICAgIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnkgPSBldmVudC5jbGllbnRZO1xuICAgIH0pOyAvLyBJbnB1dCBoYW5kbGluZ1xuXG4gICAgdGhpcy5vbktleURvd24gPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgLy8gbm9ybWFsaXplIGBldmVudC5rZXlgIHdoZW4gQ2Fwc0xvY2sgaXMgcHJlc3NlZCAjMjM3MlxuICAgICAgaWYgKFwiUHJveHlcIiBpbiB3aW5kb3cgJiYgKCFldmVudC5zaGlmdEtleSAmJiAvXltBLVpdJC8udGVzdChldmVudC5rZXkpIHx8IGV2ZW50LnNoaWZ0S2V5ICYmIC9eW2Etel0kLy50ZXN0KGV2ZW50LmtleSkpKSB7XG4gICAgICAgIGV2ZW50ID0gbmV3IFByb3h5KGV2ZW50LCB7XG4gICAgICAgICAgZ2V0KGV2LCBwcm9wKSB7XG4gICAgICAgICAgICBjb25zdCB2YWx1ZSA9IGV2W3Byb3BdO1xuXG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgLy8gZml4IGZvciBQcm94aWVzIGhpamFja2luZyBgdGhpc2BcbiAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlLmJpbmQoZXYpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcHJvcCA9PT0gXCJrZXlcIiA/IC8vIENhcHNMb2NrIGludmVydHMgY2FwaXRhbGl6YXRpb24gYmFzZWQgb24gU2hpZnRLZXksIHNvIGludmVydFxuICAgICAgICAgICAgLy8gaXQgYmFja1xuICAgICAgICAgICAgZXZlbnQuc2hpZnRLZXkgPyBldi5rZXkudG9VcHBlckNhc2UoKSA6IGV2LmtleS50b0xvd2VyQ2FzZSgpIDogdmFsdWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgZXZlbnQua2V5LnRvTG93ZXJDYXNlKCkgPT09IEtFWVMuVikge1xuICAgICAgICBJU19QTEFJTl9QQVNURSA9IGV2ZW50LnNoaWZ0S2V5O1xuICAgICAgICBjbGVhclRpbWVvdXQoSVNfUExBSU5fUEFTVEVfVElNRVIpOyAvLyByZXNldCAoMTAwbXMgdG8gYmUgc2FmZSB0aGF0IHdlIGl0IHJ1bnMgYWZ0ZXIgdGhlIGVuc3VpbmdcbiAgICAgICAgLy8gcGFzdGUgZXZlbnQpLiBUaG91Z2gsIHRlY2huaWNhbGx5IHVubmVjZXNzYXJ5IHRvIHJlc2V0IHNpbmNlIHdlXG4gICAgICAgIC8vIChyZSlzZXQgdGhlIGZsYWcgYmVmb3JlIGVhY2ggcGFzdGUgZXZlbnQuXG5cbiAgICAgICAgSVNfUExBSU5fUEFTVEVfVElNRVIgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgSVNfUExBSU5fUEFTVEUgPSBmYWxzZTtcbiAgICAgICAgfSwgMTAwKTtcbiAgICAgIH0gLy8gcHJldmVudCBicm93c2VyIHpvb20gaW4gaW5wdXQgZmllbGRzXG5cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIGlzV3JpdGFibGVFbGVtZW50KGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgaWYgKGV2ZW50LmNvZGUgPT09IENPREVTLk1JTlVTIHx8IGV2ZW50LmNvZGUgPT09IENPREVTLkVRVUFMKSB7XG4gICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gLy8gYmFpbCBpZlxuXG5cbiAgICAgIGlmICggLy8gaW5zaWRlIGFuIGlucHV0XG4gICAgICBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpICYmIC8vIHVubGVzcyBwcmVzc2luZyBlc2NhcGUgKGZpbmFsaXplIGFjdGlvbilcbiAgICAgIGV2ZW50LmtleSAhPT0gS0VZUy5FU0NBUEUgfHwgLy8gb3IgdW5sZXNzIHVzaW5nIGFycm93cyAodG8gbW92ZSBiZXR3ZWVuIGJ1dHRvbnMpXG4gICAgICBpc0Fycm93S2V5KGV2ZW50LmtleSkgJiYgaXNJbnB1dExpa2UoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuUVVFU1RJT05fTUFSSykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBvcGVuRGlhbG9nOiBcImhlbHBcIlxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkudG9Mb3dlckNhc2UoKSA9PT0gS0VZUy5FICYmIGV2ZW50LnNoaWZ0S2V5ICYmIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIG9wZW5EaWFsb2c6IFwiaW1hZ2VFeHBvcnRcIlxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfVVAgfHwgZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfRE9XTikge1xuICAgICAgICBsZXQgb2Zmc2V0ID0gKGV2ZW50LnNoaWZ0S2V5ID8gdGhpcy5zdGF0ZS53aWR0aCA6IHRoaXMuc3RhdGUuaGVpZ2h0KSAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfRE9XTikge1xuICAgICAgICAgIG9mZnNldCA9IC1vZmZzZXQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2Nyb2xsWDogc3RhdGUuc2Nyb2xsWCArIG9mZnNldFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2Nyb2xsWTogc3RhdGUuc2Nyb2xsWSArIG9mZnNldFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5hY3Rpb25NYW5hZ2VyLmhhbmRsZUtleURvd24oZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIHRoaXMuc3RhdGUuaXNCaW5kaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzQXJyb3dLZXkoZXZlbnQua2V5KSkge1xuICAgICAgICBjb25zdCBzdGVwID0gdGhpcy5zdGF0ZS5ncmlkU2l6ZSAmJiAoZXZlbnQuc2hpZnRLZXkgPyBFTEVNRU5UX1RSQU5TTEFURV9BTU9VTlQgOiB0aGlzLnN0YXRlLmdyaWRTaXplKSB8fCAoZXZlbnQuc2hpZnRLZXkgPyBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQgOiBFTEVNRU5UX1RSQU5TTEFURV9BTU9VTlQpO1xuICAgICAgICBsZXQgb2Zmc2V0WCA9IDA7XG4gICAgICAgIGxldCBvZmZzZXRZID0gMDtcblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX0xFRlQpIHtcbiAgICAgICAgICBvZmZzZXRYID0gLXN0ZXA7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX1JJR0hUKSB7XG4gICAgICAgICAgb2Zmc2V0WCA9IHN0ZXA7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX1VQKSB7XG4gICAgICAgICAgb2Zmc2V0WSA9IC1zdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19ET1dOKSB7XG4gICAgICAgICAgb2Zmc2V0WSA9IHN0ZXA7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzLFxuICAgICAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlLFxuICAgICAgICAgIGluY2x1ZGVFbGVtZW50c0luRnJhbWVzOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICBzZWxlY3RlZEVsZW1lbnRzLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICB4OiBlbGVtZW50LnggKyBvZmZzZXRYLFxuICAgICAgICAgICAgeTogZWxlbWVudC55ICsgb2Zmc2V0WVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHVwZGF0ZUJvdW5kRWxlbWVudHMoZWxlbWVudCwge1xuICAgICAgICAgICAgc2ltdWx0YW5lb3VzbHlVcGRhdGVkOiBzZWxlY3RlZEVsZW1lbnRzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5FTlRFUikge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudCA9IHNlbGVjdGVkRWxlbWVudHNbMF07XG5cbiAgICAgICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgICAgIGlmIChpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgIT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3Ioc2VsZWN0ZWRFbGVtZW50LCB0aGlzLnNjZW5lKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkgfHwgaXNWYWxpZFRleHRDb250YWluZXIoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgbGV0IGNvbnRhaW5lcjtcblxuICAgICAgICAgICAgaWYgKCFpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgY29udGFpbmVyID0gc2VsZWN0ZWRFbGVtZW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBtaWRQb2ludCA9IGdldENvbnRhaW5lckNlbnRlcihzZWxlY3RlZEVsZW1lbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3Qgc2NlbmVYID0gbWlkUG9pbnQueDtcbiAgICAgICAgICAgIGNvbnN0IHNjZW5lWSA9IG1pZFBvaW50Lnk7XG4gICAgICAgICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICAgIHNjZW5lWSxcbiAgICAgICAgICAgICAgY29udGFpbmVyXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSBlbHNlIGlmIChpc0ZyYW1lRWxlbWVudChzZWxlY3RlZEVsZW1lbnQpKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0ZyYW1lOiBzZWxlY3RlZEVsZW1lbnQuaWRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICghZXZlbnQuY3RybEtleSAmJiAhZXZlbnQuYWx0S2V5ICYmICFldmVudC5tZXRhS2V5ICYmIHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50ID09PSBudWxsKSB7XG4gICAgICAgIGNvbnN0IHNoYXBlID0gZmluZFNoYXBlQnlLZXkoZXZlbnQua2V5KTtcblxuICAgICAgICBpZiAoc2hhcGUpIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IHNoYXBlKSB7XG4gICAgICAgICAgICB0cmFja0V2ZW50KFwidG9vbGJhclwiLCBzaGFwZSwgYGtleWJvYXJkICgke3RoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSA/IFwibW9iaWxlXCIgOiBcImRlc2t0b3BcIn0pYCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgICAgIHR5cGU6IHNoYXBlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlEpIHtcbiAgICAgICAgICB0aGlzLnRvZ2dsZUxvY2soXCJrZXlib2FyZFwiKTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlNQQUNFICYmIGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMCkge1xuICAgICAgICBpc0hvbGRpbmdTcGFjZSA9IHRydWU7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCKTtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKChldmVudC5rZXkgPT09IEtFWVMuRyB8fCBldmVudC5rZXkgPT09IEtFWVMuUykgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgIXNlbGVjdGVkRWxlbWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5HICYmIChoYXNCYWNrZ3JvdW5kKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSB8fCBzZWxlY3RlZEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiBoYXNCYWNrZ3JvdW5kKGVsZW1lbnQudHlwZSkpKSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgb3BlblBvcHVwOiBcImVsZW1lbnRCYWNrZ3JvdW5kXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuUykge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgb3BlblBvcHVwOiBcImVsZW1lbnRTdHJva2VcIlxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuSyAmJiAhZXZlbnQuYWx0S2V5ICYmICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIikge1xuICAgICAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgICAgIHR5cGU6IFwibGFzZXJcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgKGV2ZW50LmtleSA9PT0gS0VZUy5CQUNLU1BBQ0UgfHwgZXZlbnQua2V5ID09PSBLRVlTLkRFTEVURSkpIHtcbiAgICAgICAgam90YWlTdG9yZS5zZXQoYWN0aXZlQ29uZmlybURpYWxvZ0F0b20sIFwiY2xlYXJDYW52YXNcIik7XG4gICAgICB9IC8vIGV5ZSBkcm9wcGVyXG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbiAgICAgIGNvbnN0IGxvd2VyQ2FzZWQgPSBldmVudC5rZXkudG9Mb2NhbGVMb3dlckNhc2UoKTtcbiAgICAgIGNvbnN0IGlzUGlja2luZ1N0cm9rZSA9IGxvd2VyQ2FzZWQgPT09IEtFWVMuUyAmJiBldmVudC5zaGlmdEtleTtcbiAgICAgIGNvbnN0IGlzUGlja2luZ0JhY2tncm91bmQgPSBldmVudC5rZXkgPT09IEtFWVMuSSB8fCBsb3dlckNhc2VkID09PSBLRVlTLkcgJiYgZXZlbnQuc2hpZnRLZXk7XG5cbiAgICAgIGlmIChpc1BpY2tpbmdTdHJva2UgfHwgaXNQaWNraW5nQmFja2dyb3VuZCkge1xuICAgICAgICB0aGlzLm9wZW5FeWVEcm9wcGVyKHtcbiAgICAgICAgICB0eXBlOiBpc1BpY2tpbmdTdHJva2UgPyBcInN0cm9rZVwiIDogXCJiYWNrZ3JvdW5kXCJcbiAgICAgICAgfSk7XG4gICAgICB9IC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICB9KTtcbiAgICB0aGlzLm9uV2hlZWwgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgLy8gcHJldmVudCBicm93c2VyIHBpbmNoIHpvb20gb24gRE9NIGVsZW1lbnRzXG4gICAgICBpZiAoIShldmVudC50YXJnZXQgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCkgJiYgZXZlbnQuY3RybEtleSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMub25LZXlVcCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlNQQUNFKSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiAhdGhpcy5zdGF0ZS5pc0JpbmRpbmdFbmFibGVkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGlzQmluZGluZ0VuYWJsZWQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0Fycm93S2V5KGV2ZW50LmtleSkpIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgICAgaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSA/IGJpbmRPclVuYmluZFNlbGVjdGVkRWxlbWVudHMoc2VsZWN0ZWRFbGVtZW50cykgOiB1bmJpbmRMaW5lYXJFbGVtZW50cyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pOyAvLyBXZSBwdXJwb3NlbHkgd2lkZW4gdGhlIGB0b29sYCB0eXBlIHNvIHRoaXMgaGVscGVyIGNhbiBiZSBjYWxsZWQgd2l0aFxuICAgIC8vIGFueSB0b29sIHdpdGhvdXQgaGF2aW5nIHRvIHR5cGUgY2hlY2sgaXRcblxuICAgIHRoaXMuaXNUb29sU3VwcG9ydGVkID0gdG9vbCA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIHJldHVybiAoKF9hID0gdGhpcy5wcm9wcy5VSU9wdGlvbnMudG9vbHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVt0b29sXSkgIT09IGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLnNldEFjdGl2ZVRvb2wgPSB0b29sID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgaWYgKCF0aGlzLmlzVG9vbFN1cHBvcnRlZCh0b29sLnR5cGUpKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgXCIke3Rvb2wudHlwZX1cIiB0b29sIGlzIGRpc2FibGVkIHZpYSBcIlVJT3B0aW9ucy5jYW52YXNBY3Rpb25zLnRvb2xzLiR7dG9vbC50eXBlfVwiYCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbmV4dEFjdGl2ZVRvb2wgPSB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHRvb2wpO1xuXG4gICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSA9PT0gXCJoYW5kXCIpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgfSBlbHNlIGlmICghaXNIb2xkaW5nU3BhY2UpIHtcbiAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc1Rvb2xJY29uKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpKSB7XG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc0xpbmVhckVsZW1lbnRUeXBlKG5leHRBY3RpdmVUb29sLnR5cGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICB0aGlzLm9uSW1hZ2VBY3Rpb24oe1xuICAgICAgICAgIGluc2VydE9uQ2FudmFzRGlyZWN0bHk6IChfYSA9IHRvb2wudHlwZSA9PT0gXCJpbWFnZVwiICYmIHRvb2wuaW5zZXJ0T25DYW52YXNEaXJlY3RseSkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgY29uc3QgY29tbW9uUmVzZXRzID0ge1xuICAgICAgICAgIHNuYXBMaW5lczogcHJldlN0YXRlLnNuYXBMaW5lcy5sZW5ndGggPyBbXSA6IHByZXZTdGF0ZS5zbmFwTGluZXMsXG4gICAgICAgICAgb3JpZ2luU25hcE9mZnNldDogbnVsbCxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHtcbiAgICAgICAgICAgIGFjdGl2ZVRvb2w6IG5leHRBY3RpdmVUb29sLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgcHJldlN0YXRlKSxcbiAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCBwcmV2U3RhdGUpLFxuICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgICBtdWx0aUVsZW1lbnQ6IG51bGxcbiAgICAgICAgICB9KSwgY29tbW9uUmVzZXRzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IG5leHRBY3RpdmVUb29sXG4gICAgICAgIH0pLCBjb21tb25SZXNldHMpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc2V0T3BlbkRpYWxvZyA9IGRpYWxvZ1R5cGUgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG9wZW5EaWFsb2c6IGRpYWxvZ1R5cGVcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnNldEN1cnNvciA9IGN1cnNvciA9PiB7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgY3Vyc29yKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldEN1cnNvciA9ICgpID0+IHtcbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogcmV0dXJucyB3aGV0aGVyIHVzZXIgaXMgbWFraW5nIGEgZ2VzdHVyZSB3aXRoID49IDIgZmluZ2VycyAocG9pbnRzKVxuICAgICAqIG9uIG8gdG91Y2ggc2NyZWVuIChub3Qgb24gYSB0cmFja3BhZCkuIEN1cnJlbnRseSBvbmx5IHJlbGF0ZXMgdG8gRGFyd2luXG4gICAgICogKGlPUy9pUGFkT1MsTWFjT1MpLCBidXQgbWF5IHdvcmsgb24gb3RoZXIgZGV2aWNlcyBpbiB0aGUgZnV0dXJlIGlmXG4gICAgICogR2VzdHVyZUV2ZW50IGlzIHN0YW5kYXJkaXplZC5cbiAgICAgKi9cblxuXG4gICAgdGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUgPSAoKSA9PiB7XG4gICAgICAvLyB3ZSBkb24ndCB3YW50IHRvIGRlc2VsZWN0IHdoZW4gdXNpbmcgdHJhY2twYWQsIGFuZCBtdWx0aS1wb2ludCBnZXN0dXJlc1xuICAgICAgLy8gb25seSB3b3JrIG9uIHRvdWNoIHNjcmVlbnMsIHNvIGNoZWNraW5nIGZvciA+PSBwb2ludGVycyBtZWFucyB3ZSdyZSBvbiBhXG4gICAgICAvLyB0b3VjaHNjcmVlblxuICAgICAgcmV0dXJuIGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA+PSAyO1xuICAgIH07IC8vIGZpcmVzIG9ubHkgb24gU2FmYXJpXG5cblxuICAgIHRoaXMub25HZXN0dXJlU3RhcnQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gd2Ugb25seSB3YW50IHRvIGRlc2VsZWN0IG9uIHRvdWNoIHNjcmVlbnMgYmVjYXVzZSB1c2VyIG1heSBoYXZlIHNlbGVjdGVkXG4gICAgICAvLyBlbGVtZW50cyBieSBtaXN0YWtlIHdoaWxlIHpvb21pbmdcblxuICAgICAgaWYgKHRoaXMuaXNUb3VjaFNjcmVlbk11bHRpVG91Y2hHZXN0dXJlKCkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgfSk7IC8vIGZpcmVzIG9ubHkgb24gU2FmYXJpXG5cbiAgICB0aGlzLm9uR2VzdHVyZUNoYW5nZSA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyBvbkdlc3R1cmVDaGFuZ2Ugb25seSBoYXMgem9vbSBmYWN0b3IgYnV0IG5vdCB0aGUgY2VudGVyLlxuICAgICAgLy8gSWYgd2UncmUgb24gaVBhZCBvciBpUGhvbmUsIHRoZW4gd2UgcmVjb2duaXplIG11bHRpLXRvdWNoIGFuZCB3aWxsXG4gICAgICAvLyB6b29tIGluIGF0IHRoZSByaWdodCBsb2NhdGlvbiBpbiB0aGUgdG91Y2htb3ZlIGhhbmRsZXJcbiAgICAgIC8vIChoYW5kbGVDYW52YXNQb2ludGVyTW92ZSkuXG4gICAgICAvL1xuICAgICAgLy8gT24gTWFjYm9vayB0cmFja3BhZCwgd2UgZG9uJ3QgaGF2ZSB0aG9zZSBldmVudHMgc28gd2lsbCB6b29tIGluIGF0IHRoZVxuICAgICAgLy8gY3VycmVudCBsb2NhdGlvbiBpbnN0ZWFkLlxuICAgICAgLy9cbiAgICAgIC8vIEFzIHN1Y2gsIGJhaWwgZnJvbSB0aGlzIGhhbmRsZXIgb24gdG91Y2ggZGV2aWNlcy5cblxuICAgICAgaWYgKHRoaXMuaXNUb3VjaFNjcmVlbk11bHRpVG91Y2hHZXN0dXJlKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbml0aWFsU2NhbGUgPSBnZXN0dXJlLmluaXRpYWxTY2FsZTtcblxuICAgICAgaWYgKGluaXRpYWxTY2FsZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IE9iamVjdC5hc3NpZ24oe30sIGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgdmlld3BvcnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgICAgdmlld3BvcnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnksXG4gICAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKGluaXRpYWxTY2FsZSAqIGV2ZW50LnNjYWxlKVxuICAgICAgICB9LCBzdGF0ZSkpKTtcbiAgICAgIH1cbiAgICB9KTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuICAgIHRoaXMub25HZXN0dXJlRW5kID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIHJlc2VsZWN0IGVsZW1lbnRzIG9ubHkgb24gdG91Y2ggc2NyZWVucyAoc2VlIG9uR2VzdHVyZVN0YXJ0KVxuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczoge30sXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh0aGlzLnN0YXRlLnByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzLCB0aGlzLnN0YXRlKVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSBudWxsO1xuICAgIH0pO1xuXG4gICAgdGhpcy5zdGFydFRleHRFZGl0aW5nID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWSxcbiAgICAgIGluc2VydEF0UGFyZW50Q2VudGVyID0gdHJ1ZSxcbiAgICAgIGNvbnRhaW5lclxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgIGxldCBzaG91bGRCaW5kVG9Db250YWluZXIgPSBmYWxzZTtcbiAgICAgIGxldCBwYXJlbnRDZW50ZXJQb3NpdGlvbiA9IGluc2VydEF0UGFyZW50Q2VudGVyICYmIHRoaXMuZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwgdGhpcy5zdGF0ZSwgY29udGFpbmVyKTtcblxuICAgICAgaWYgKGNvbnRhaW5lciAmJiBwYXJlbnRDZW50ZXJQb3NpdGlvbikge1xuICAgICAgICBjb25zdCBib3VuZFRleHRFbGVtZW50VG9Db250YWluZXIgPSBnZXRCb3VuZFRleHRFbGVtZW50KGNvbnRhaW5lcik7XG5cbiAgICAgICAgaWYgKCFib3VuZFRleHRFbGVtZW50VG9Db250YWluZXIpIHtcbiAgICAgICAgICBzaG91bGRCaW5kVG9Db250YWluZXIgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxldCBleGlzdGluZ1RleHRFbGVtZW50ID0gbnVsbDtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBpZiAoaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnRzWzBdKSkge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBzZWxlY3RlZEVsZW1lbnRzWzBdO1xuICAgICAgICB9IGVsc2UgaWYgKGNvbnRhaW5lcikge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBnZXRCb3VuZFRleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSB0aGlzLmdldFRleHRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSB0aGlzLmdldFRleHRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZvbnRGYW1pbHkgPSAoZXhpc3RpbmdUZXh0RWxlbWVudCA9PT0gbnVsbCB8fCBleGlzdGluZ1RleHRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBleGlzdGluZ1RleHRFbGVtZW50LmZvbnRGYW1pbHkpIHx8IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250RmFtaWx5O1xuICAgICAgY29uc3QgbGluZUhlaWdodCA9IChleGlzdGluZ1RleHRFbGVtZW50ID09PSBudWxsIHx8IGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nVGV4dEVsZW1lbnQubGluZUhlaWdodCkgfHwgZ2V0RGVmYXVsdExpbmVIZWlnaHQoZm9udEZhbWlseSk7XG4gICAgICBjb25zdCBmb250U2l6ZSA9IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250U2l6ZTtcblxuICAgICAgaWYgKCFleGlzdGluZ1RleHRFbGVtZW50ICYmIHNob3VsZEJpbmRUb0NvbnRhaW5lciAmJiBjb250YWluZXIgJiYgIWlzQXJyb3dFbGVtZW50KGNvbnRhaW5lcikpIHtcbiAgICAgICAgY29uc3QgZm9udFN0cmluZyA9IHtcbiAgICAgICAgICBmb250U2l6ZSxcbiAgICAgICAgICBmb250RmFtaWx5XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IG1pbldpZHRoID0gZ2V0QXBwcm94TWluTGluZVdpZHRoKGdldEZvbnRTdHJpbmcoZm9udFN0cmluZyksIGxpbmVIZWlnaHQpO1xuICAgICAgICBjb25zdCBtaW5IZWlnaHQgPSBnZXRBcHByb3hNaW5MaW5lSGVpZ2h0KGZvbnRTaXplLCBsaW5lSGVpZ2h0KTtcbiAgICAgICAgY29uc3QgbmV3SGVpZ2h0ID0gTWF0aC5tYXgoY29udGFpbmVyLmhlaWdodCwgbWluSGVpZ2h0KTtcbiAgICAgICAgY29uc3QgbmV3V2lkdGggPSBNYXRoLm1heChjb250YWluZXIud2lkdGgsIG1pbldpZHRoKTtcbiAgICAgICAgbXV0YXRlRWxlbWVudChjb250YWluZXIsIHtcbiAgICAgICAgICBoZWlnaHQ6IG5ld0hlaWdodCxcbiAgICAgICAgICB3aWR0aDogbmV3V2lkdGhcbiAgICAgICAgfSk7XG4gICAgICAgIHNjZW5lWCA9IGNvbnRhaW5lci54ICsgbmV3V2lkdGggLyAyO1xuICAgICAgICBzY2VuZVkgPSBjb250YWluZXIueSArIG5ld0hlaWdodCAvIDI7XG5cbiAgICAgICAgaWYgKHBhcmVudENlbnRlclBvc2l0aW9uKSB7XG4gICAgICAgICAgcGFyZW50Q2VudGVyUG9zaXRpb24gPSB0aGlzLmdldFRleHRXeXNpd3lnU25hcHBlZFRvQ2VudGVyUG9zaXRpb24oc2NlbmVYLCBzY2VuZVksIHRoaXMuc3RhdGUsIGNvbnRhaW5lcik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSk7XG4gICAgICBjb25zdCBlbGVtZW50ID0gZXhpc3RpbmdUZXh0RWxlbWVudCA/IGV4aXN0aW5nVGV4dEVsZW1lbnQgOiBuZXdUZXh0RWxlbWVudCh7XG4gICAgICAgIHg6IHBhcmVudENlbnRlclBvc2l0aW9uID8gcGFyZW50Q2VudGVyUG9zaXRpb24uZWxlbWVudENlbnRlclggOiBzY2VuZVgsXG4gICAgICAgIHk6IHBhcmVudENlbnRlclBvc2l0aW9uID8gcGFyZW50Q2VudGVyUG9zaXRpb24uZWxlbWVudENlbnRlclkgOiBzY2VuZVksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICB0ZXh0OiBcIlwiLFxuICAgICAgICBmb250U2l6ZSxcbiAgICAgICAgZm9udEZhbWlseSxcbiAgICAgICAgdGV4dEFsaWduOiBwYXJlbnRDZW50ZXJQb3NpdGlvbiA/IFwiY2VudGVyXCIgOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtVGV4dEFsaWduLFxuICAgICAgICB2ZXJ0aWNhbEFsaWduOiBwYXJlbnRDZW50ZXJQb3NpdGlvbiA/IFZFUlRJQ0FMX0FMSUdOLk1JRERMRSA6IERFRkFVTFRfVkVSVElDQUxfQUxJR04sXG4gICAgICAgIGNvbnRhaW5lcklkOiBzaG91bGRCaW5kVG9Db250YWluZXIgPyBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuaWQgOiB1bmRlZmluZWQsXG4gICAgICAgIGdyb3VwSWRzOiAoX2EgPSBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuZ3JvdXBJZHMpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IFtdLFxuICAgICAgICBsaW5lSGVpZ2h0LFxuICAgICAgICBhbmdsZTogKF9iID0gY29udGFpbmVyID09PSBudWxsIHx8IGNvbnRhaW5lciA9PT0gdm9pZCAwID8gdm9pZCAwIDogY29udGFpbmVyLmFuZ2xlKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyICYmIGNvbnRhaW5lcikge1xuICAgICAgICBtdXRhdGVFbGVtZW50KGNvbnRhaW5lciwge1xuICAgICAgICAgIGJvdW5kRWxlbWVudHM6IChjb250YWluZXIuYm91bmRFbGVtZW50cyB8fCBbXSkuY29uY2F0KHtcbiAgICAgICAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgICAgICAgaWQ6IGVsZW1lbnQuaWRcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBlbGVtZW50XG4gICAgICB9KTtcblxuICAgICAgaWYgKCFleGlzdGluZ1RleHRFbGVtZW50KSB7XG4gICAgICAgIGlmIChjb250YWluZXIgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyKSB7XG4gICAgICAgICAgY29uc3QgY29udGFpbmVySW5kZXggPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRJbmRleChjb250YWluZXIuaWQpO1xuICAgICAgICAgIHRoaXMuc2NlbmUuaW5zZXJ0RWxlbWVudEF0SW5kZXgoZWxlbWVudCwgY29udGFpbmVySW5kZXggKyAxKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBlbGVtZW50XG4gICAgICB9KTtcbiAgICAgIHRoaXMuaGFuZGxlVGV4dFd5c2l3eWcoZWxlbWVudCwge1xuICAgICAgICBpc0V4aXN0aW5nRWxlbWVudDogISFleGlzdGluZ1RleHRFbGVtZW50XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNEb3VibGVDbGljayA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIGNhc2U6IGRvdWJsZS1jbGlja2luZyB3aXRoIGFycm93L2xpbmUgdG9vbCBzZWxlY3RlZCB3b3VsZCBib3RoIGNyZWF0ZVxuICAgICAgLy8gdGV4dCBhbmQgZW50ZXIgbXVsdGlFbGVtZW50IG1vZGVcbiAgICAgIGlmICh0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHdlIHNob3VsZCBvbmx5IGJlIGFibGUgdG8gZG91YmxlIGNsaWNrIHdoZW4gbW9kZSBpcyBzZWxlY3Rpb25cblxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNMaW5lYXJFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pKSB7XG4gICAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiAoIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgIT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpKSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKHNlbGVjdGVkRWxlbWVudHNbMF0sIHRoaXMuc2NlbmUpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgPT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICBsZXQge1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBzZWxlY3RlZEdyb3VwSWRzID0gZ2V0U2VsZWN0ZWRHcm91cElkcyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkR3JvdXBJZHMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkR3JvdXBJZCA9IGhpdEVsZW1lbnQgJiYgZ2V0U2VsZWN0ZWRHcm91cElkRm9yRWxlbWVudChoaXRFbGVtZW50LCB0aGlzLnN0YXRlLnNlbGVjdGVkR3JvdXBJZHMpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEdyb3VwSWQpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHNlbGVjdGVkR3JvdXBJZCxcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuXG4gICAgICBpZiAoIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICF0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG5cbiAgICAgICAgaWYgKGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IHtcbiAgICAgICAgICAgICAgZWxlbWVudDogaGl0RWxlbWVudCxcbiAgICAgICAgICAgICAgc3RhdGU6IFwiYWN0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjb250YWluZXIgPSBnZXRUZXh0QmluZGFibGVDb250YWluZXJBdFBvc2l0aW9uKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgICBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgaWYgKGhhc0JvdW5kVGV4dEVsZW1lbnQoY29udGFpbmVyKSB8fCAhaXNUcmFuc3BhcmVudChjb250YWluZXIuYmFja2dyb3VuZENvbG9yKSB8fCBpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveChjb250YWluZXIsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIFtzY2VuZVgsIHNjZW5lWV0pKSB7XG4gICAgICAgICAgICBjb25zdCBtaWRQb2ludCA9IGdldENvbnRhaW5lckNlbnRlcihjb250YWluZXIsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgc2NlbmVYID0gbWlkUG9pbnQueDtcbiAgICAgICAgICAgIHNjZW5lWSA9IG1pZFBvaW50Lnk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zdGFydFRleHRFZGl0aW5nKHtcbiAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgc2NlbmVZLFxuICAgICAgICAgIGluc2VydEF0UGFyZW50Q2VudGVyOiAhZXZlbnQuYWx0S2V5LFxuICAgICAgICAgIGNvbnRhaW5lclxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24gPSAoc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KSA9PiB7XG4gICAgICAvLyBSZXZlcnNpbmcgc28gd2UgdHJhdmVyc2UgdGhlIGVsZW1lbnRzIGluIGRlY3JlYXNpbmcgb3JkZXJcbiAgICAgIC8vIG9mIHotaW5kZXhcbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5zbGljZSgpLnJldmVyc2UoKTtcbiAgICAgIGxldCBoaXRFbGVtZW50SW5kZXggPSBJbmZpbml0eTtcbiAgICAgIHJldHVybiBlbGVtZW50cy5maW5kKChlbGVtZW50LCBpbmRleCkgPT4ge1xuICAgICAgICBpZiAoaGl0RWxlbWVudCAmJiBlbGVtZW50LmlkID09PSBoaXRFbGVtZW50LmlkKSB7XG4gICAgICAgICAgaGl0RWxlbWVudEluZGV4ID0gaW5kZXg7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlbWVudC5saW5rICYmIGluZGV4IDw9IGhpdEVsZW1lbnRJbmRleCAmJiBpc1BvaW50SGl0dGluZ0xpbmsoZWxlbWVudCwgdGhpcy5zdGF0ZSwgW3NjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueV0sIHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZWRpcmVjdFRvTGluayA9IChldmVudCwgaXNUb3VjaFNjcmVlbikgPT4ge1xuICAgICAgY29uc3QgZHJhZ2dlZERpc3RhbmNlID0gZGlzdGFuY2UyZCh0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50LmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQuY2xpZW50WSwgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WSk7XG5cbiAgICAgIGlmICghdGhpcy5oaXRMaW5rRWxlbWVudCB8fCAvLyBGb3IgdG91Y2ggc2NyZWVuIGFsbG93IGRyYWdnaW5nIHRocmVzaG9sZCBlbHNlIHN0cmljdCBjaGVja1xuICAgICAgaXNUb3VjaFNjcmVlbiAmJiBkcmFnZ2VkRGlzdGFuY2UgPiBEUkFHR0lOR19USFJFU0hPTEQgfHwgIWlzVG91Y2hTY3JlZW4gJiYgZHJhZ2dlZERpc3RhbmNlICE9PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbGFzdFBvaW50ZXJEb3duQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJEb3duSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlckRvd25Db29yZHMueCwgbGFzdFBvaW50ZXJEb3duQ29vcmRzLnldLCB0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJVcENvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh0aGlzLmxhc3RQb2ludGVyVXBFdmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlclVwQ29vcmRzLngsIGxhc3RQb2ludGVyVXBDb29yZHMueV0sIHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSk7XG5cbiAgICAgIGlmIChsYXN0UG9pbnRlckRvd25IaXR0aW5nTGlua0ljb24gJiYgbGFzdFBvaW50ZXJVcEhpdHRpbmdMaW5rSWNvbikge1xuICAgICAgICBsZXQgdXJsID0gdGhpcy5oaXRMaW5rRWxlbWVudC5saW5rO1xuXG4gICAgICAgIGlmICh1cmwpIHtcbiAgICAgICAgICB1cmwgPSBub3JtYWxpemVMaW5rKHVybCk7XG4gICAgICAgICAgbGV0IGN1c3RvbUV2ZW50O1xuXG4gICAgICAgICAgaWYgKHRoaXMucHJvcHMub25MaW5rT3Blbikge1xuICAgICAgICAgICAgY3VzdG9tRXZlbnQgPSB3cmFwRXZlbnQoRVZFTlQuRVhDQUxJRFJBV19MSU5LLCBldmVudC5uYXRpdmVFdmVudCk7XG4gICAgICAgICAgICB0aGlzLnByb3BzLm9uTGlua09wZW4oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmhpdExpbmtFbGVtZW50KSwge1xuICAgICAgICAgICAgICBsaW5rOiB1cmxcbiAgICAgICAgICAgIH0pLCBjdXN0b21FdmVudCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCEoY3VzdG9tRXZlbnQgPT09IG51bGwgfHwgY3VzdG9tRXZlbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGN1c3RvbUV2ZW50LmRlZmF1bHRQcmV2ZW50ZWQpKSB7XG4gICAgICAgICAgICBjb25zdCB0YXJnZXQgPSBpc0xvY2FsTGluayh1cmwpID8gXCJfc2VsZlwiIDogXCJfYmxhbmtcIjtcbiAgICAgICAgICAgIGNvbnN0IG5ld1dpbmRvdyA9IHdpbmRvdy5vcGVuKHVuZGVmaW5lZCwgdGFyZ2V0KTsgLy8gaHR0cHM6Ly9tYXRoaWFzYnluZW5zLmdpdGh1Yi5pby9yZWwtbm9vcGVuZXIvXG5cbiAgICAgICAgICAgIGlmIChuZXdXaW5kb3cpIHtcbiAgICAgICAgICAgICAgbmV3V2luZG93Lm9wZW5lciA9IG51bGw7XG4gICAgICAgICAgICAgIG5ld1dpbmRvdy5sb2NhdGlvbiA9IHVybDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3JkcyA9IHNjZW5lQ29vcmRzID0+IHtcbiAgICAgIGNvbnN0IGZyYW1lcyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLmZpbHRlcihmcmFtZSA9PiBpc0N1cnNvckluRnJhbWUoc2NlbmVDb29yZHMsIGZyYW1lKSk7XG4gICAgICByZXR1cm4gZnJhbWVzLmxlbmd0aCA/IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gOiBudWxsO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlID0gZXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCB0aGlzLnN0YXRlLmN1cnNvckJ1dHRvbik7XG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLmhhcyhldmVudC5wb2ludGVySWQpKSB7XG4gICAgICAgIGdlc3R1cmUucG9pbnRlcnMuc2V0KGV2ZW50LnBvaW50ZXJJZCwge1xuICAgICAgICAgIHg6IGV2ZW50LmNsaWVudFgsXG4gICAgICAgICAgeTogZXZlbnQuY2xpZW50WVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaW5pdGlhbFNjYWxlID0gZ2VzdHVyZS5pbml0aWFsU2NhbGU7XG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLnNpemUgPT09IDIgJiYgZ2VzdHVyZS5sYXN0Q2VudGVyICYmIGluaXRpYWxTY2FsZSAmJiBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSkge1xuICAgICAgICBjb25zdCBjZW50ZXIgPSBnZXRDZW50ZXIoZ2VzdHVyZS5wb2ludGVycyk7XG4gICAgICAgIGNvbnN0IGRlbHRhWCA9IGNlbnRlci54IC0gZ2VzdHVyZS5sYXN0Q2VudGVyLng7XG4gICAgICAgIGNvbnN0IGRlbHRhWSA9IGNlbnRlci55IC0gZ2VzdHVyZS5sYXN0Q2VudGVyLnk7XG4gICAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGNlbnRlcjtcbiAgICAgICAgY29uc3QgZGlzdGFuY2UgPSBnZXREaXN0YW5jZShBcnJheS5mcm9tKGdlc3R1cmUucG9pbnRlcnMudmFsdWVzKCkpKTtcbiAgICAgICAgY29uc3Qgc2NhbGVGYWN0b3IgPSB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmVlZHJhd1wiICYmIHRoaXMuc3RhdGUucGVuTW9kZSA/IDEgOiBkaXN0YW5jZSAvIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlO1xuICAgICAgICBjb25zdCBuZXh0Wm9vbSA9IHNjYWxlRmFjdG9yID8gZ2V0Tm9ybWFsaXplZFpvb20oaW5pdGlhbFNjYWxlICogc2NhbGVGYWN0b3IpIDogdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IHtcbiAgICAgICAgICBjb25zdCB6b29tU3RhdGUgPSBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICAgICAgdmlld3BvcnRYOiBjZW50ZXIueCxcbiAgICAgICAgICAgIHZpZXdwb3J0WTogY2VudGVyLnksXG4gICAgICAgICAgICBuZXh0Wm9vbVxuICAgICAgICAgIH0sIHN0YXRlKTtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyh7XG4gICAgICAgICAgICB6b29tOiB6b29tU3RhdGUuem9vbSxcbiAgICAgICAgICAgIHNjcm9sbFg6IHpvb21TdGF0ZS5zY3JvbGxYICsgZGVsdGFYIC8gbmV4dFpvb20sXG4gICAgICAgICAgICBzY3JvbGxZOiB6b29tU3RhdGUuc2Nyb2xsWSArIGRlbHRhWSAvIG5leHRab29tLFxuICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBnZXN0dXJlLmxhc3RDZW50ZXIgPSBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSA9IGdlc3R1cmUuaW5pdGlhbFNjYWxlID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzSG9sZGluZ1NwYWNlIHx8IGlzUGFubmluZyB8fCBpc0RyYWdnaW5nU2Nyb2xsQmFyIHx8IGlzSGFuZFRvb2xBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc1BvaW50ZXJPdmVyU2Nyb2xsQmFycyA9IGlzT3ZlclNjcm9sbEJhcnMoY3VycmVudFNjcm9sbEJhcnMsIGV2ZW50LmNsaWVudFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIGV2ZW50LmNsaWVudFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcCk7XG4gICAgICBjb25zdCBpc092ZXJTY3JvbGxCYXIgPSBpc1BvaW50ZXJPdmVyU2Nyb2xsQmFycy5pc092ZXJFaXRoZXI7XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIGlmIChpc092ZXJTY3JvbGxCYXIpIHtcbiAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3Qge1xuICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICB9ID0gc2NlbmVQb2ludGVyO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50ICYmIGlzQWN0aXZlVG9vbE5vbkxpbmVhclNuYXBwYWJsZSh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG9yaWdpbk9mZnNldCxcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSA9IGdldFNuYXBMaW5lc0F0UG9pbnRlcih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgeDogc2NlbmVQb2ludGVyWCxcbiAgICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICAgIH0sIGV2ZW50KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzLFxuICAgICAgICAgIG9yaWdpblNuYXBPZmZzZXQ6IG9yaWdpbk9mZnNldFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoIXRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNuYXBMaW5lczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgY29uc3QgZWRpdGluZ0xpbmVhckVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJNb3ZlKGV2ZW50LCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZWRpdGluZ0xpbmVhckVsZW1lbnQgIT09IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSBudWxsIHx8IGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlZGl0aW5nTGluZWFyRWxlbWVudC5sYXN0VW5jb21taXR0ZWRQb2ludCkgIT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0F0Q3Vyc29yKHNjZW5lUG9pbnRlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gY2F1c2VzIHN0YWNrIG92ZXJmbG93IGlmIG5vdCBzeW5jXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50VHlwZSh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgLy8gSG92ZXJpbmcgd2l0aCBhIHNlbGVjdGVkIHRvb2wgb3IgY3JlYXRpbmcgbmV3IGxpbmVhciBlbGVtZW50IHZpYSBjbGlja1xuICAgICAgICAvLyBhbmQgcG9pbnRcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBpZiAoaXNCaW5kaW5nRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ3NGb3JMaW5lYXJFbGVtZW50QXRDb29yZHMoZHJhZ2dpbmdFbGVtZW50LCBbc2NlbmVQb2ludGVyXSwgdGhpcy5zdGF0ZS5zdGFydEJvdW5kRWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3Ioc2NlbmVQb2ludGVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG11bHRpRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHJ4LFxuICAgICAgICAgIHk6IHJ5XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBwb2ludHMsXG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IGxhc3RQb2ludCA9IHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV07XG4gICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChsYXN0UG9pbnQgPT09IGxhc3RDb21taXR0ZWRQb2ludCkge1xuICAgICAgICAgIC8vIGlmIHdlIGhhdmVuJ3QgeWV0IGNyZWF0ZWQgYSB0ZW1wIHBvaW50IGFuZCB3ZSdyZSBiZXlvbmQgY29tbWl0LXpvbmVcbiAgICAgICAgICAvLyB0aHJlc2hvbGQsIGFkZCBhIHBvaW50XG4gICAgICAgICAgaWYgKGRpc3RhbmNlMmQoc2NlbmVQb2ludGVyWCAtIHJ4LCBzY2VuZVBvaW50ZXJZIC0gcnksIGxhc3RQb2ludFswXSwgbGFzdFBvaW50WzFdKSA+PSBMSU5FX0NPTkZJUk1fVEhSRVNIT0xEKSB7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeV1dXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpOyAvLyBpbiB0aGlzIGJyYW5jaCwgd2UncmUgaW5zaWRlIHRoZSBjb21taXQgem9uZSwgYW5kIG5vIHVuY29tbWl0dGVkXG4gICAgICAgICAgICAvLyBwb2ludCBleGlzdHMuIFRodXMgZG8gbm90aGluZyAoZG9uJ3QgYWRkL3JlbW92ZSBwb2ludHMpLlxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID4gMiAmJiBsYXN0Q29tbWl0dGVkUG9pbnQgJiYgZGlzdGFuY2UyZChzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeSwgbGFzdENvbW1pdHRlZFBvaW50WzBdLCBsYXN0Q29tbWl0dGVkUG9pbnRbMV0pIDwgTElORV9DT05GSVJNX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBwb2ludHMuc2xpY2UoMCwgLTEpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgICAgY29uc3QgW2xhc3RDb21taXR0ZWRYLCBsYXN0Q29tbWl0dGVkWV0gPSAoX2EgPSBtdWx0aUVsZW1lbnQgPT09IG51bGwgfHwgbXVsdGlFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBtdWx0aUVsZW1lbnQubGFzdENvbW1pdHRlZFBvaW50KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBbMCwgMF07XG4gICAgICAgICAgbGV0IGR4RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWCAtIHJ4IC0gbGFzdENvbW1pdHRlZFg7XG4gICAgICAgICAgbGV0IGR5RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWSAtIHJ5IC0gbGFzdENvbW1pdHRlZFk7XG5cbiAgICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpKSB7XG4gICAgICAgICAgICAoe1xuICAgICAgICAgICAgICB3aWR0aDogZHhGcm9tTGFzdENvbW1pdHRlZCxcbiAgICAgICAgICAgICAgaGVpZ2h0OiBkeUZyb21MYXN0Q29tbWl0dGVkXG4gICAgICAgICAgICB9ID0gZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplKCAvLyBhY3R1YWwgY29vcmRpbmF0ZSBvZiB0aGUgbGFzdCBjb21taXR0ZWQgcG9pbnRcbiAgICAgICAgICAgIGxhc3RDb21taXR0ZWRYICsgcngsIGxhc3RDb21taXR0ZWRZICsgcnksIC8vIGN1cnNvci1ncmlkIGNvb3JkaW5hdGVcbiAgICAgICAgICAgIGdyaWRYLCBncmlkWSkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChpc1BhdGhBTG9vcChwb2ludHMsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpIHtcbiAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICB9IC8vIHVwZGF0ZSBsYXN0IHVuY29tbWl0dGVkIHBvaW50XG5cblxuICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMuc2xpY2UoMCwgLTEpLCBbbGFzdENvbW1pdHRlZFggKyBkeEZyb21MYXN0Q29tbWl0dGVkLCBsYXN0Q29tbWl0dGVkWSArIGR5RnJvbUxhc3RDb21taXR0ZWRdXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNEZXNlbGVjdGVkQnV0dG9uID0gQm9vbGVhbihldmVudC5idXR0b25zKTtcblxuICAgICAgaWYgKGhhc0Rlc2VsZWN0ZWRCdXR0b24gfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwidGV4dFwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICFpc092ZXJTY3JvbGxCYXIgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlKGVsZW1lbnRzLCB0aGlzLnN0YXRlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICBpZiAoZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlICYmIGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS50cmFuc2Zvcm1IYW5kbGVUeXBlKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIGdldEN1cnNvckZvclJlc2l6aW5nRWxlbWVudChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiAxICYmICFpc092ZXJTY3JvbGxCYXIpIHtcbiAgICAgICAgY29uc3QgdHJhbnNmb3JtSGFuZGxlVHlwZSA9IGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzKGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG5cbiAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50KHtcbiAgICAgICAgICAgIHRyYW5zZm9ybUhhbmRsZVR5cGVcbiAgICAgICAgICB9KSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICB0aGlzLmhpdExpbmtFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KTtcblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGl0TGlua0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuaGl0TGlua0VsZW1lbnQuaWRdKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgc2hvd0h5cGVybGlua1Rvb2x0aXAodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoaWRlSHlwZXJsaW5rVG9vbGlwKCk7XG5cbiAgICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgKGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpKSAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSAmJiAhdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiAhdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXApIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogXCJpbmZvXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgaXNUZXh0RWxlbWVudChoaXRFbGVtZW50KSA/IENVUlNPUl9UWVBFLlRFWFQgOiBDVVJTT1JfVFlQRS5DUk9TU0hBSVIpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICB9IGVsc2UgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlSG92ZXJTZWxlY3RlZExpbmVhckVsZW1lbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpO1xuICAgICAgICB9IGVsc2UgaWYgKCAvLyBpZiB1c2luZyBjbWQvY3RybCwgd2UncmUgbm90IGRyYWdnaW5nXG4gICAgICAgICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICAgIGlmICgoaGl0RWxlbWVudCB8fCB0aGlzLmlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHNjZW5lUG9pbnRlciwgc2VsZWN0ZWRFbGVtZW50cykpICYmICEoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmxvY2tlZCkpIHtcbiAgICAgICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgZXZlbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICAgICAgZWxlbWVudDogaGl0RWxlbWVudCxcbiAgICAgICAgICAgICAgICAgIHN0YXRlOiBcImhvdmVyXCJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuXG4gICAgICAgICAgICAgIGlmICgoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImhvdmVyXCIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQVVUTyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVFcmFzZXIgPSAoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUsIHNjZW5lUG9pbnRlcikgPT4ge1xuICAgICAgY29uc3QgdXBkYXRlRWxlbWVudElkcyA9IGVsZW1lbnRzID0+IHtcbiAgICAgICAgZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoZWxlbWVudC5sb2NrZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZHNUb1VwZGF0ZS5wdXNoKGVsZW1lbnQuaWQpO1xuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSkge1xuICAgICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlbWVudC5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXS5lcmFzZSkge1xuICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdLmVyYXNlID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmICghcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSA9IHtcbiAgICAgICAgICAgICAgZXJhc2U6IHRydWUsXG4gICAgICAgICAgICAgIG9wYWNpdHk6IGVsZW1lbnQub3BhY2l0eVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfTtcblxuICAgICAgY29uc3QgaWRzVG9VcGRhdGUgPSBbXTtcbiAgICAgIGNvbnN0IGRpc3RhbmNlID0gZGlzdGFuY2UyZChwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnksIHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICBjb25zdCB0aHJlc2hvbGQgPSAxMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgIGNvbnN0IHBvaW50ID0gT2JqZWN0LmFzc2lnbih7fSwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzKTtcbiAgICAgIGxldCBzYW1wbGluZ0ludGVydmFsID0gMDtcblxuICAgICAgd2hpbGUgKHNhbXBsaW5nSW50ZXJ2YWwgPD0gZGlzdGFuY2UpIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbihwb2ludC54LCBwb2ludC55KTtcbiAgICAgICAgdXBkYXRlRWxlbWVudElkcyhoaXRFbGVtZW50cyk7IC8vIEV4aXQgc2luY2Ugd2UgcmVhY2hlZCBjdXJyZW50IHBvaW50XG5cbiAgICAgICAgaWYgKHNhbXBsaW5nSW50ZXJ2YWwgPT09IGRpc3RhbmNlKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gLy8gQ2FsY3VsYXRlIG5leHQgcG9pbnQgaW4gdGhlIGxpbmUgYXQgYSBkaXN0YW5jZSBvZiBzYW1wbGluZyBpbnRlcnZhbFxuXG5cbiAgICAgICAgc2FtcGxpbmdJbnRlcnZhbCA9IE1hdGgubWluKHNhbXBsaW5nSW50ZXJ2YWwgKyB0aHJlc2hvbGQsIGRpc3RhbmNlKTtcbiAgICAgICAgY29uc3QgZGlzdGFuY2VSYXRpbyA9IHNhbXBsaW5nSW50ZXJ2YWwgLyBkaXN0YW5jZTtcbiAgICAgICAgY29uc3QgbmV4dFggPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueCArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueDtcbiAgICAgICAgY29uc3QgbmV4dFkgPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueSArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueTtcbiAgICAgICAgcG9pbnQueCA9IG5leHRYO1xuICAgICAgICBwb2ludC55ID0gbmV4dFk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWxlID0+IHtcbiAgICAgICAgY29uc3QgaWQgPSBpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBpZHNUb1VwZGF0ZS5pbmNsdWRlcyhlbGUuY29udGFpbmVySWQpID8gZWxlLmNvbnRhaW5lcklkIDogZWxlLmlkO1xuXG4gICAgICAgIGlmIChpZHNUb1VwZGF0ZS5pbmNsdWRlcyhpZCkpIHtcbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0uZXJhc2UgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXS5vcGFjaXR5XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICAgIG9wYWNpdHk6IEVMRU1FTlRfUkVBRFlfVE9fRVJBU0VfT1BBQ0lUWVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBzY2VuZVBvaW50ZXIueDtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gc2NlbmVQb2ludGVyLnk7XG4gICAgfTsgLy8gc2V0IHRvdWNoIG1vdmluZyBmb3IgbW9iaWxlIGNvbnRleHQgbWVudVxuXG5cbiAgICB0aGlzLmhhbmRsZVRvdWNoTW92ZSA9IGV2ZW50ID0+IHtcbiAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IHRydWU7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24gPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBzaW5jZSBjb250ZXh0TWVudSBvcHRpb25zIGFyZSBwb3RlbnRpYWxseSBldmFsdWF0ZWQgb24gZWFjaCByZW5kZXIsXG4gICAgICAvLyBhbmQgYW4gY29udGV4dE1lbnUgYWN0aW9uIG1heSBkZXBlbmQgb24gc2VsZWN0aW9uIHN0YXRlLCB3ZSBtdXN0XG4gICAgICAvLyBjbG9zZSB0aGUgY29udGV4dE1lbnUgYmVmb3JlIHdlIHVwZGF0ZSB0aGUgc2VsZWN0aW9uIG9uIHBvaW50ZXJEb3duXG4gICAgICAvLyAoZS5nLiByZXNldHRpbmcgc2VsZWN0aW9uKVxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zbmFwTGluZXMpIHtcbiAgICAgICAgdGhpcy5zZXRBcHBTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy51cGRhdGVHZXN0dXJlT25Qb2ludGVyRG93bihldmVudCk7IC8vIGlmIGRyYWdnaW5nIGVsZW1lbnQgaXMgZnJlZWRyYXcgYW5kIGFub3RoZXIgcG9pbnRlcmRvd24gZXZlbnQgb2NjdXJzXG4gICAgICAvLyBhIHNlY29uZCBmaW5nZXIgaXMgb24gdGhlIHNjcmVlblxuICAgICAgLy8gZGlzY2FyZCB0aGUgZnJlZWRyYXcgZWxlbWVudCBpZiBpdCBpcyB2ZXJ5IHNob3J0IGJlY2F1c2UgaXQgaXMgbGlrZWx5XG4gICAgICAvLyBqdXN0IGEgc3Bpa2UsIG90aGVyd2lzZSBmaW5hbGl6ZSB0aGUgZnJlZWRyYXcgZWxlbWVudCB3aGVuIHRoZSBzZWNvbmRcbiAgICAgIC8vIGZpbmdlciBpcyBsaWZ0ZWRcblxuICAgICAgaWYgKGV2ZW50LnBvaW50ZXJUeXBlID09PSBcInRvdWNoXCIgJiYgdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudDtcbiAgICAgICAgdGhpcy51cGRhdGVTY2VuZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGVsZW1lbnQucG9pbnRzLmxlbmd0aCA8IDEwID8ge1xuICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbHRlcihlbCA9PiBlbC5pZCAhPT0gZWxlbWVudC5pZClcbiAgICAgICAgfSA6IHt9KSwge1xuICAgICAgICAgIGFwcFN0YXRlOiB7XG4gICAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgIHN0YXJ0Qm91bmRFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3Qua2V5cyh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcykuZmlsdGVyKGtleSA9PiBrZXkgIT09IGVsZW1lbnQuaWQpLnJlZHVjZSgob2JqLCBrZXkpID0+IHtcbiAgICAgICAgICAgICAgb2JqW2tleV0gPSB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1trZXldO1xuICAgICAgICAgICAgICByZXR1cm4gb2JqO1xuICAgICAgICAgICAgfSwge30pLCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSkpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHJlbW92ZSBhbnkgYWN0aXZlIHNlbGVjdGlvbiB3aGVuIHdlIHN0YXJ0IHRvIGludGVyYWN0IHdpdGggY2FudmFzXG4gICAgICAvLyAobWFpbmx5LCB3ZSBjYXJlIGFib3V0IHJlbW92aW5nIHNlbGVjdGlvbiBvdXRzaWRlIHRoZSBjb21wb25lbnQgd2hpY2hcbiAgICAgIC8vICB3b3VsZCBwcmV2ZW50IG91ciBjb3B5IGhhbmRsaW5nIG90aGVyd2lzZSlcblxuXG4gICAgICBjb25zdCBzZWxlY3Rpb24gPSBkb2N1bWVudC5nZXRTZWxlY3Rpb24oKTtcblxuICAgICAgaWYgKHNlbGVjdGlvbiA9PT0gbnVsbCB8fCBzZWxlY3Rpb24gPT09IHZvaWQgMCA/IHZvaWQgMCA6IHNlbGVjdGlvbi5hbmNob3JOb2RlKSB7XG4gICAgICAgIHNlbGVjdGlvbi5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tYXliZU9wZW5Db250ZXh0TWVudUFmdGVyUG9pbnRlckRvd25PblRvdWNoRGV2aWNlcyhldmVudCk7XG4gICAgICB0aGlzLm1heWJlQ2xlYW51cEFmdGVyTWlzc2luZ1BvaW50ZXJVcChldmVudCk7IC8vZmlyZXMgb25seSBvbmNlLCBpZiBwZW4gaXMgZGV0ZWN0ZWQsIHBlbk1vZGUgaXMgZW5hYmxlZFxuICAgICAgLy90aGUgdXNlciBjYW4gZGlzYWJsZSB0aGlzIGJ5IHRvZ2dsaW5nIHRoZSBwZW5Nb2RlIGJ1dHRvblxuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUucGVuRGV0ZWN0ZWQgJiYgZXZlbnQucG9pbnRlclR5cGUgPT09IFwicGVuXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBwZW5Nb2RlOiB0cnVlLFxuICAgICAgICAgICAgcGVuRGV0ZWN0ZWQ6IHRydWVcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuICYmIFtcInBlblwiLCBcInRvdWNoXCJdLmluY2x1ZGVzKGV2ZW50LnBvaW50ZXJUeXBlKSkge1xuICAgICAgICB0aGlzLmRldmljZSA9IHVwZGF0ZU9iamVjdCh0aGlzLmRldmljZSwge1xuICAgICAgICAgIGlzVG91Y2hTY3JlZW46IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc1Bhbm5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50ID0gZXZlbnQ7IC8vIHdlIG11c3QgZXhpdCBiZWZvcmUgd2Ugc2V0IGBjdXJzb3JCdXR0b25gIHN0YXRlIGFuZCBgc2F2ZVBvaW50ZXJgXG4gICAgICAvLyBlbHNlIGl0IHdpbGwgc2VuZCBwb2ludGVyIHN0YXRlICYgbGFzZXIgcG9pbnRlciBldmVudHMgaW4gY29sbGFiIHdoZW5cbiAgICAgIC8vIHBhbm5pbmdcblxuICAgICAgaWYgKHRoaXMuaGFuZGxlQ2FudmFzUGFuVXNpbmdXaGVlbE9yU3BhY2VEcmFnKGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBsYXN0UG9pbnRlckRvd25XaXRoOiBldmVudC5wb2ludGVyVHlwZSxcbiAgICAgICAgY3Vyc29yQnV0dG9uOiBcImRvd25cIlxuICAgICAgfSk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIFwiZG93blwiKTsgLy8gb25seSBoYW5kbGUgbGVmdCBtb3VzZSBidXR0b24gb3IgdG91Y2hcblxuICAgICAgaWYgKGV2ZW50LmJ1dHRvbiAhPT0gUE9JTlRFUl9CVVRUT04uTUFJTiAmJiBldmVudC5idXR0b24gIT09IFBPSU5URVJfQlVUVE9OLlRPVUNIKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gZG9uJ3Qgc2VsZWN0IHdoaWxlIHBhbm5pbmdcblxuXG4gICAgICBpZiAoZ2VzdHVyZS5wb2ludGVycy5zaXplID4gMSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIFN0YXRlIGZvciB0aGUgZHVyYXRpb24gb2YgYSBwb2ludGVyIGludGVyYWN0aW9uLCB3aGljaCBzdGFydHMgd2l0aCBhXG4gICAgICAvLyBwb2ludGVyRG93biBldmVudCwgZW5kcyB3aXRoIGEgcG9pbnRlclVwIGV2ZW50IChvciBhbm90aGVyIHBvaW50ZXJEb3duKVxuXG5cbiAgICAgIGNvbnN0IHBvaW50ZXJEb3duU3RhdGUgPSB0aGlzLmluaXRpYWxQb2ludGVyRG93blN0YXRlKGV2ZW50KTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkOiBmYWxzZVxuICAgICAgfSk7XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZURyYWdnaW5nU2Nyb2xsQmFyKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuY2xlYXJTZWxlY3Rpb25JZk5vdFVzaW5nU2VsZWN0aW9uKCk7XG4gICAgICB0aGlzLnVwZGF0ZUJpbmRpbmdFbmFibGVkT25Qb2ludGVyTW92ZShldmVudCk7XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZVNlbGVjdGlvbk9uUG9pbnRlckRvd24oZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgYWxsb3dPblBvaW50ZXJEb3duID0gIXRoaXMuc3RhdGUucGVuTW9kZSB8fCBldmVudC5wb2ludGVyVHlwZSAhPT0gXCJ0b3VjaFwiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInRleHRcIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiO1xuXG4gICAgICBpZiAoIWFsbG93T25Qb2ludGVyRG93bikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVUZXh0T25Qb2ludGVyRG93bihldmVudCwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiYXJyb3dcIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsaW5lXCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVMaW5lYXJFbGVtZW50T25Qb2ludGVyRG93bihldmVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiKSB7XG4gICAgICAgIC8vIHJlc2V0IGltYWdlIHByZXZpZXcgb24gcG9pbnRlcmRvd25cbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkNST1NTSEFJUik7IC8vIHJldHJpZXZlIHRoZSBsYXRlc3QgZWxlbWVudCBhcyB0aGUgc3RhdGUgbWF5IGJlIHN0YWxlXG5cbiAgICAgICAgY29uc3QgcGVuZGluZ0ltYWdlRWxlbWVudCA9IHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkICYmIHRoaXMuc2NlbmUuZ2V0RWxlbWVudCh0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCk7XG5cbiAgICAgICAgaWYgKCFwZW5kaW5nSW1hZ2VFbGVtZW50KSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBwZW5kaW5nSW1hZ2VFbGVtZW50LFxuICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBwZW5kaW5nSW1hZ2VFbGVtZW50LFxuICAgICAgICAgIHBlbmRpbmdJbWFnZUVsZW1lbnRJZDogbnVsbCxcbiAgICAgICAgICBtdWx0aUVsZW1lbnQ6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0pO1xuICAgICAgICBtdXRhdGVFbGVtZW50KHBlbmRpbmdJbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHksXG4gICAgICAgICAgZnJhbWVJZDogZnJhbWUgPyBmcmFtZS5pZCA6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVGcmVlRHJhd0VsZW1lbnRPblBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImN1c3RvbVwiKSB7XG4gICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgIHRoaXMuY3JlYXRlRnJhbWVFbGVtZW50T25Qb2ludGVyRG93bihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIikge1xuICAgICAgICB0aGlzLmxhc2VyUGF0aE1hbmFnZXIuc3RhcnRQYXRoKHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54LCBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImhhbmRcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUdlbmVyaWNFbGVtZW50T25Qb2ludGVyRG93bih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vblBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIudHJpZ2dlcih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wsIHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB0aGlzLm9uUG9pbnRlck1vdmVGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgY29uc3Qgb25Qb2ludGVyVXAgPSB0aGlzLm9uUG9pbnRlclVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5RG93biA9IHRoaXMub25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5VXAgPSB0aGlzLm9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgbGFzdFBvaW50ZXJVcCA9IG9uUG9pbnRlclVwO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgb25Qb2ludGVyVXApO1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlET1dOLCBvbktleURvd24pO1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgb25LZXlVcCk7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25Nb3ZlID0gb25Qb2ludGVyTW92ZTtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vblVwID0gb25Qb2ludGVyVXA7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlVcCA9IG9uS2V5VXA7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlEb3duID0gb25LZXlEb3duO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJVcCA9IGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgIHRoaXMucmVtb3ZlUG9pbnRlcihldmVudCk7XG4gICAgICB0aGlzLmxhc3RQb2ludGVyVXBFdmVudCA9IGV2ZW50O1xuICAgICAgY29uc3Qgc2NlbmVQb2ludGVyID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgY2xpZW50WDogZXZlbnQuY2xpZW50WCxcbiAgICAgICAgY2xpZW50WTogZXZlbnQuY2xpZW50WVxuICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBjbGlja2xlbmd0aCA9IGV2ZW50LnRpbWVTdGFtcCAtICgoX2IgPSAoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudGltZVN0YW1wKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwKTtcblxuICAgICAgaWYgKHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSAmJiBjbGlja2xlbmd0aCA8IDMwMCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpO1xuXG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpICYmIHRoaXMuaXNFbWJlZGRhYmxlQ2VudGVyKGhpdEVsZW1lbnQsIGV2ZW50LCBzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpKSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2soaGl0RWxlbWVudCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICAgIHRoaXMuaGl0TGlua0VsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbihzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5oaXRMaW5rRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5oaXRMaW5rRWxlbWVudC5pZF0pIHtcbiAgICAgICAgaWYgKGNsaWNrbGVuZ3RoIDwgMzAwICYmIHRoaXMuaGl0TGlua0VsZW1lbnQudHlwZSA9PT0gXCJlbWJlZGRhYmxlXCIgJiYgIWlzUG9pbnRIaXR0aW5nTGlua0ljb24odGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSwgW3NjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueV0pKSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2sodGhpcy5oaXRMaW5rRWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5yZWRpcmVjdFRvTGluayhldmVudCwgdGhpcy5kZXZpY2UuaXNUb3VjaFNjcmVlbik7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbCxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHt9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLm1heWJlT3BlbkNvbnRleHRNZW51QWZ0ZXJQb2ludGVyRG93bk9uVG91Y2hEZXZpY2VzID0gZXZlbnQgPT4ge1xuICAgICAgLy8gZGVhbCB3aXRoIG9wZW5pbmcgY29udGV4dCBtZW51IG9uIHRvdWNoIGRldmljZXNcbiAgICAgIGlmIChldmVudC5wb2ludGVyVHlwZSA9PT0gXCJ0b3VjaFwiKSB7XG4gICAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IGZhbHNlO1xuXG4gICAgICAgIGlmICh0b3VjaFRpbWVvdXQpIHtcbiAgICAgICAgICAvLyBJZiB0aGVyZSdzIGFscmVhZHkgYSB0b3VjaFRpbWVvdXQsIHRoaXMgbWVhbnMgdGhhdCB0aGVyZSdzIGFub3RoZXJcbiAgICAgICAgICAvLyB0b3VjaCBkb3duIGFuZCB3ZSBhcmUgZG9pbmcgYW5vdGhlciB0b3VjaCwgc28gd2Ugc2hvdWxkbid0IG9wZW4gdGhlXG4gICAgICAgICAgLy8gY29udGV4dCBtZW51LlxuICAgICAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gb3BlbiB0aGUgY29udGV4dCBtZW51IHdpdGggdGhlIGZpcnN0IHRvdWNoJ3MgY2xpZW50WCBhbmQgY2xpZW50WVxuICAgICAgICAgIC8vIGlmIHRoZSB0b3VjaCBpcyBub3QgbW92aW5nXG4gICAgICAgICAgdG91Y2hUaW1lb3V0ID0gd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgdG91Y2hUaW1lb3V0ID0gMDtcblxuICAgICAgICAgICAgaWYgKCFpbnZhbGlkYXRlQ29udGV4dE1lbnUpIHtcbiAgICAgICAgICAgICAgdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudShldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSwgVE9VQ0hfQ1RYX01FTlVfVElNRU9VVCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIgPSAoKSA9PiB7XG4gICAgICBjbGVhclRpbWVvdXQodG91Y2hUaW1lb3V0KTtcbiAgICAgIHRvdWNoVGltZW91dCA9IDA7XG4gICAgICBpbnZhbGlkYXRlQ29udGV4dE1lbnUgPSBmYWxzZTtcbiAgICB9OyAvLyBSZXR1cm5zIHdoZXRoZXIgdGhlIGV2ZW50IGlzIGEgcGFubmluZ1xuXG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc1BhblVzaW5nV2hlZWxPclNwYWNlRHJhZyA9IGV2ZW50ID0+IHtcbiAgICAgIGlmICghKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA8PSAxICYmIChldmVudC5idXR0b24gPT09IFBPSU5URVJfQlVUVE9OLldIRUVMIHx8IGV2ZW50LmJ1dHRvbiA9PT0gUE9JTlRFUl9CVVRUT04uTUFJTiAmJiBpc0hvbGRpbmdTcGFjZSB8fCBpc0hhbmRUb29sQWN0aXZlKHRoaXMuc3RhdGUpIHx8IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSkgfHwgaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlzUGFubmluZyA9IHRydWU7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgbGV0IG5leHRQYXN0ZVByZXZlbnRlZCA9IGZhbHNlO1xuICAgICAgY29uc3QgaXNMaW51eCA9IC9MaW51eC8udGVzdCh3aW5kb3cubmF2aWdhdG9yLnBsYXRmb3JtKTtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCQklORyk7XG4gICAgICBsZXQge1xuICAgICAgICBjbGllbnRYOiBsYXN0WCxcbiAgICAgICAgY2xpZW50WTogbGFzdFlcbiAgICAgIH0gPSBldmVudDtcbiAgICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQoZXZlbnQgPT4ge1xuICAgICAgICBjb25zdCBkZWx0YVggPSBsYXN0WCAtIGV2ZW50LmNsaWVudFg7XG4gICAgICAgIGNvbnN0IGRlbHRhWSA9IGxhc3RZIC0gZXZlbnQuY2xpZW50WTtcbiAgICAgICAgbGFzdFggPSBldmVudC5jbGllbnRYO1xuICAgICAgICBsYXN0WSA9IGV2ZW50LmNsaWVudFk7XG4gICAgICAgIC8qXG4gICAgICAgICAqIFByZXZlbnQgcGFzdGUgZXZlbnQgaWYgd2UgbW92ZSB3aGlsZSBtaWRkbGUgY2xpY2tpbmcgb24gTGludXguXG4gICAgICAgICAqIFNlZSBpc3N1ZSAjMTM4My5cbiAgICAgICAgICovXG5cbiAgICAgICAgaWYgKGlzTGludXggJiYgIW5leHRQYXN0ZVByZXZlbnRlZCAmJiAoTWF0aC5hYnMoZGVsdGFYKSA+IDEgfHwgTWF0aC5hYnMoZGVsdGFZKSA+IDEpKSB7XG4gICAgICAgICAgbmV4dFBhc3RlUHJldmVudGVkID0gdHJ1ZTtcbiAgICAgICAgICAvKiBQcmV2ZW50IHRoZSBuZXh0IHBhc3RlIGV2ZW50ICovXG5cbiAgICAgICAgICBjb25zdCBwcmV2ZW50TmV4dFBhc3RlID0gZXZlbnQgPT4ge1xuICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCBwcmV2ZW50TmV4dFBhc3RlKTtcbiAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgIH07XG4gICAgICAgICAgLypcbiAgICAgICAgICAgKiBSZWVuYWJsZSBuZXh0IHBhc3RlIGluIGNhc2Ugb2YgZGlzYWJsZWQgbWlkZGxlIGNsaWNrIHBhc3RlIGZvclxuICAgICAgICAgICAqIGFueSByZWFzb246XG4gICAgICAgICAgICogLSByaWdodCBjbGljayBwYXN0ZVxuICAgICAgICAgICAqIC0gZW1wdHkgY2xpcGJvYXJkXG4gICAgICAgICAgICovXG5cblxuICAgICAgICAgIGNvbnN0IGVuYWJsZU5leHRQYXN0ZSA9ICgpID0+IHtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHByZXZlbnROZXh0UGFzdGUpO1xuICAgICAgICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBlbmFibGVOZXh0UGFzdGUpO1xuICAgICAgICAgICAgfSwgMTAwKTtcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCBwcmV2ZW50TmV4dFBhc3RlKTtcbiAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBlbmFibGVOZXh0UGFzdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoe1xuICAgICAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCAtIGRlbHRhWCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSxcbiAgICAgICAgICBzY3JvbGxZOiB0aGlzLnN0YXRlLnNjcm9sbFkgLSBkZWx0YVkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHRlYXJkb3duID0gd2l0aEJhdGNoZWRVcGRhdGVzKGxhc3RQb2ludGVyVXAgPSAoKSA9PiB7XG4gICAgICAgIGxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgICAgICBpc1Bhbm5pbmcgPSBmYWxzZTtcblxuICAgICAgICBpZiAoIWlzSG9sZGluZ1NwYWNlKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGN1cnNvckJ1dHRvbjogXCJ1cFwiXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRlYXJkb3duKTtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGVhcmRvd24pO1xuICAgICAgICBvblBvaW50ZXJNb3ZlLmZsdXNoKCk7XG4gICAgICB9KTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkJMVVIsIHRlYXJkb3duKTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSwge1xuICAgICAgICBwYXNzaXZlOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRlYXJkb3duKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH07XG5cbiAgICB0aGlzLmNsZWFyU2VsZWN0aW9uSWZOb3RVc2luZ1NlbGVjdGlvbiA9ICgpID0+IHtcbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybnMgd2hldGhlciB0aGUgcG9pbnRlciBldmVudCBoYXMgYmVlbiBjb21wbGV0ZWx5IGhhbmRsZWRcbiAgICAgKi9cblxuXG4gICAgdGhpcy5oYW5kbGVTZWxlY3Rpb25PblBvaW50ZXJEb3duID0gKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCk7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlKGVsZW1lbnRzLCB0aGlzLnN0YXRlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHJlc2l6aW5nRWxlbWVudDogZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLmVsZW1lbnRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSA9IGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS50cmFuc2Zvcm1IYW5kbGVUeXBlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlID0gZ2V0VHJhbnNmb3JtSGFuZGxlVHlwZUZyb21Db29yZHMoZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaXNSZXNpemluZyA9IHRydWU7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUub2Zmc2V0ID0gdHVwbGVUb0Nvb3JzKGdldFJlc2l6ZU9mZnNldFhZKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHMsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpKTtcblxuICAgICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkgJiYgc2VsZWN0ZWRFbGVtZW50c1swXS5wb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5hcnJvd0RpcmVjdGlvbiA9IGdldFJlc2l6ZUFycm93RGlyZWN0aW9uKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHNbMF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgIGNvbnN0IGxpbmVhckVsZW1lbnRFZGl0b3IgPSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50O1xuICAgICAgICAgICAgY29uc3QgcmV0ID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludGVyRG93bihldmVudCwgdGhpcy5zdGF0ZSwgdGhpcy5oaXN0b3J5LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbiwgbGluZWFyRWxlbWVudEVkaXRvcik7XG5cbiAgICAgICAgICAgIGlmIChyZXQuaGl0RWxlbWVudCkge1xuICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50ID0gcmV0LmhpdEVsZW1lbnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChyZXQubGluZWFyRWxlbWVudEVkaXRvcikge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IHJldC5saW5lYXJFbGVtZW50RWRpdG9yXG4gICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogcmV0LmxpbmVhckVsZW1lbnRFZGl0b3JcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAocmV0LmRpZEFkZFBvaW50KSB7XG4gICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gaGl0RWxlbWVudCBtYXkgYWxyZWFkeSBiZSBzZXQgYWJvdmUsIHNvIGNoZWNrIGZpcnN0XG5cblxuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQgPSAoX2EgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpO1xuXG4gICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpIHtcbiAgICAgICAgICAgIC8vIEVhcmx5IHJldHVybiBpZiBwb2ludGVyIGlzIGhpdHRpbmcgbGluayBpY29uXG4gICAgICAgICAgICBjb25zdCBoaXRMaW5rRWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudExpbmtBdFBvc2l0aW9uKHtcbiAgICAgICAgICAgICAgeDogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCxcbiAgICAgICAgICAgICAgeTogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueVxuICAgICAgICAgICAgfSwgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCk7XG5cbiAgICAgICAgICAgIGlmIChoaXRMaW5rRWxlbWVudCkge1xuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBGb3Igb3ZlcmxhcHBlZCBlbGVtZW50cyBvbmUgcG9zaXRpb24gbWF5IGhpdFxuICAgICAgICAgIC8vIG11bHRpcGxlIGVsZW1lbnRzXG5cblxuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzID0gdGhpcy5nZXRFbGVtZW50c0F0UG9zaXRpb24ocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSk7XG4gICAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQ7XG4gICAgICAgICAgY29uc3Qgc29tZUhpdEVsZW1lbnRJc1NlbGVjdGVkID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuYWxsSGl0RWxlbWVudHMuc29tZShlbGVtZW50ID0+IHRoaXMuaXNBU2VsZWN0ZWRFbGVtZW50KGVsZW1lbnQpKTtcblxuICAgICAgICAgIGlmICgoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCAhc29tZUhpdEVsZW1lbnRJc1NlbGVjdGVkKSAmJiAhZXZlbnQuc2hpZnRLZXkgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgICAgICAgICB0aGlzLmNsZWFyU2VsZWN0aW9uKGhpdEVsZW1lbnQpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICAgICAgW3RoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkXTogdHJ1ZVxuICAgICAgICAgICAgICB9LCB0aGlzLnN0YXRlKVxuICAgICAgICAgICAgfSk7IC8vIElmIHdlIGNsaWNrIG9uIHNvbWV0aGluZ1xuICAgICAgICAgIH0gZWxzZSBpZiAoaGl0RWxlbWVudCAhPSBudWxsKSB7XG4gICAgICAgICAgICAvLyBvbiBDTUQvQ1RSTCwgZHJpbGwgZG93biB0byBoaXQgZWxlbWVudCByZWdhcmRsZXNzIG9mIGdyb3VwcyBldGMuXG4gICAgICAgICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0Lndhc0FkZGVkVG9TZWxlY3Rpb24gPSB0cnVlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBlZGl0R3JvdXBGb3JTZWxlY3RlZEVsZW1lbnQocHJldlN0YXRlLCBoaXRFbGVtZW50KSksIHtcbiAgICAgICAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczogdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgfSkpOyAvLyBtYXJrIGFzIG5vdCBjb21wbGV0ZWx5IGhhbmRsZWQgc28gYXMgdG8gYWxsb3cgZHJhZ2dpbmcgZXRjLlxuXG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH0gLy8gZGVzZWxlY3QgaWYgaXRlbSBpcyBzZWxlY3RlZFxuICAgICAgICAgICAgLy8gaWYgc2hpZnQgaXMgbm90IGNsaWNrZWQsIHRoaXMgd2lsbCBhbHdheXMgcmV0dXJuIHRydWVcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSwgaXQgd2lsbCB0cmlnZ2VyIHNlbGVjdGlvbiBiYXNlZCBvbiBjdXJyZW50XG4gICAgICAgICAgICAvLyBzdGF0ZSBvZiB0aGUgYm94XG5cblxuICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgICAvLyBpZiB3ZSBhcmUgY3VycmVudGx5IGVkaXRpbmcgYSBncm91cCwgZXhpdGluZyBlZGl0aW5nIG1vZGUgYW5kIGRlc2VsZWN0IHRoZSBncm91cC5cbiAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQgJiYgIWlzRWxlbWVudEluR3JvdXAoaGl0RWxlbWVudCwgdGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSAvLyBBZGQgaGl0IGVsZW1lbnQgdG8gc2VsZWN0aW9uLiBBdCB0aGlzIHBvaW50IGlmIHdlJ3JlIG5vdCBob2xkaW5nXG4gICAgICAgICAgICAgIC8vIFNISUZUIHRoZSBwcmV2aW91c2x5IHNlbGVjdGVkIGVsZW1lbnQocykgd2VyZSBkZXNlbGVjdGVkIGFib3ZlXG4gICAgICAgICAgICAgIC8vIChtYWtlIHN1cmUgeW91IHVzZSBzZXRTdGF0ZSB1cGRhdGVyIHRvIHVzZSBsYXRlc3Qgc3RhdGUpXG4gICAgICAgICAgICAgIC8vIFdpdGggc2hpZnQtc2VsZWN0aW9uLCB3ZSB3YW50IHRvIG1ha2Ugc3VyZSB0aGF0IGZyYW1lcyBhbmQgdGhlaXIgY29udGFpbmluZ1xuICAgICAgICAgICAgICAvLyBlbGVtZW50cyBhcmUgbm90IHNlbGVjdGVkIGF0IHRoZSBzYW1lIHRpbWUuXG5cblxuICAgICAgICAgICAgICBpZiAoIXNvbWVIaXRFbGVtZW50SXNTZWxlY3RlZCAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgY29uc3QgcHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMgPSBbXTtcbiAgICAgICAgICAgICAgICAgIE9iamVjdC5rZXlzKHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLmZvckVhY2goaWQgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KGlkKTtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudCAmJiBwcmV2aW91c2x5U2VsZWN0ZWRFbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgICAgfSk7IC8vIGlmIGhpdEVsZW1lbnQgaXMgZnJhbWUsIGRlc2VsZWN0IGFsbCBvZiBpdHMgZWxlbWVudHMgaWYgdGhleSBhcmUgc2VsZWN0ZWRcblxuICAgICAgICAgICAgICAgICAgaWYgKGhpdEVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGdldEZyYW1lQ2hpbGRyZW4ocHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMsIGhpdEVsZW1lbnQuaWQpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChoaXRFbGVtZW50LmZyYW1lSWQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gaWYgaGl0RWxlbWVudCBpcyBpbiBhIGZyYW1lIGFuZCBpdHMgZnJhbWUgaGFzIGJlZW4gc2VsZWN0ZWRcbiAgICAgICAgICAgICAgICAgICAgLy8gZGlzYWJsZSBzZWxlY3Rpb24gZm9yIHRoZSBnaXZlbiBlbGVtZW50XG4gICAgICAgICAgICAgICAgICAgIGlmIChuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuZnJhbWVJZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gaGl0RWxlbWVudCBpcyBuZWl0aGVyIGEgZnJhbWUgbm9yIGFuIGVsZW1lbnQgaW4gYSBmcmFtZVxuICAgICAgICAgICAgICAgICAgICAvLyBidXQgc2luY2UgaGl0RWxlbWVudCBjb3VsZCBiZSBpbiBhIGdyb3VwIHdpdGggc29tZSBmcmFtZXNcbiAgICAgICAgICAgICAgICAgICAgLy8gdGhpcyBtZWFucyBzZWxlY3RpbmcgaGl0RWxlbWVudCB3aWxsIGhhdmUgdGhlIGZyYW1lcyBzZWxlY3RlZCBhcyB3ZWxsXG4gICAgICAgICAgICAgICAgICAgIC8vIGJlY2F1c2Ugd2Ugd2FudCB0byBrZWVwIHRoZSBpbnZhcmlhbnQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIC0gZnJhbWVzIGFuZCB0aGVpciBlbGVtZW50cyBhcmUgbm90IHNlbGVjdGVkIGF0IHRoZSBzYW1lIHRpbWVcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgZGVzZWxlY3QgZWxlbWVudHMgaW4gdGhvc2UgZnJhbWVzIHRoYXQgd2VyZSBwcmV2aW91c2x5IHNlbGVjdGVkXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGdyb3VwSWRzID0gaGl0RWxlbWVudC5ncm91cElkcztcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZnJhbWVzSW5Hcm91cHMgPSBuZXcgU2V0KGdyb3VwSWRzLmZsYXRNYXAoZ2lkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBnaWQpKS5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIikubWFwKGZyYW1lID0+IGZyYW1lLmlkKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGZyYW1lc0luR3JvdXBzLnNpemUgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LmZyYW1lSWQgJiYgZnJhbWVzSW5Hcm91cHMuaGFzKGVsZW1lbnQuZnJhbWVJZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGVzZWxlY3QgZWxlbWVudCBhbmQgZ3JvdXBzIGNvbnRhaW5pbmcgdGhlIGVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZ3JvdXBJZHMuZmxhdE1hcChnaWQgPT4gZ2V0RWxlbWVudHNJbkdyb3VwKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGdpZCkpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogaGl0RWxlbWVudC5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZVRleHRPblBvaW50ZXJEb3duID0gKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICAvLyBpZiB3ZSdyZSBjdXJyZW50bHkgc3RpbGwgZWRpdGluZyB0ZXh0LCBjbGlja2luZyBvdXRzaWRlXG4gICAgICAvLyBzaG91bGQgb25seSBmaW5hbGl6ZSBpdCwgbm90IGNyZWF0ZSBhbm90aGVyIChpcnJlc3BlY3RpdmVcbiAgICAgIC8vIG9mIHN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKVxuICAgICAgaWYgKGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsZXQgc2NlbmVYID0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueDtcbiAgICAgIGxldCBzY2VuZVkgPSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55O1xuICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVYLCBzY2VuZVksIHtcbiAgICAgICAgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQ6IHRydWVcbiAgICAgIH0pOyAvLyBGSVhNRVxuXG4gICAgICBsZXQgY29udGFpbmVyID0gZ2V0VGV4dEJpbmRhYmxlQ29udGFpbmVyQXRQb3NpdGlvbih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCBzY2VuZVgsIHNjZW5lWSk7XG5cbiAgICAgIGlmIChoYXNCb3VuZFRleHRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgIGNvbnRhaW5lciA9IGVsZW1lbnQ7XG4gICAgICAgIHNjZW5lWCA9IGVsZW1lbnQueCArIGVsZW1lbnQud2lkdGggLyAyO1xuICAgICAgICBzY2VuZVkgPSBlbGVtZW50LnkgKyBlbGVtZW50LmhlaWdodCAvIDI7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc3RhcnRUZXh0RWRpdGluZyh7XG4gICAgICAgIHNjZW5lWCxcbiAgICAgICAgc2NlbmVZLFxuICAgICAgICBpbnNlcnRBdFBhcmVudENlbnRlcjogIWV2ZW50LmFsdEtleSxcbiAgICAgICAgY29udGFpbmVyXG4gICAgICB9KTtcbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlRnJlZURyYXdFbGVtZW50T25Qb2ludGVyRG93biA9IChldmVudCwgZWxlbWVudFR5cGUsIHBvaW50ZXJEb3duU3RhdGUpID0+IHtcbiAgICAgIC8vIEJlZ2luIGEgbWFyayBjYXB0dXJlLiBUaGlzIGRvZXMgbm90IGhhdmUgdG8gdXBkYXRlIHN0YXRlIHlldC5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIG51bGwpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0ZyZWVEcmF3RWxlbWVudCh7XG4gICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlLFxuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICByb3VuZG5lc3M6IG51bGwsXG4gICAgICAgIHNpbXVsYXRlUHJlc3N1cmU6IGV2ZW50LnByZXNzdXJlID09PSAwLjUsXG4gICAgICAgIGxvY2tlZDogZmFsc2UsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTtcbiAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRFbGVtZW50SWRzLCBwcmV2U3RhdGUpXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGVsZW1lbnQuc2ltdWxhdGVQcmVzc3VyZSA/IGVsZW1lbnQucHJlc3N1cmVzIDogWy4uLmVsZW1lbnQucHJlc3N1cmVzLCBldmVudC5wcmVzc3VyZV07XG4gICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgcG9pbnRzOiBbWzAsIDBdXSxcbiAgICAgICAgcHJlc3N1cmVzXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGJvdW5kRWxlbWVudCA9IGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZyhwb2ludGVyRG93blN0YXRlLm9yaWdpbiwgdGhpcy5zY2VuZSk7XG4gICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBlbGVtZW50LFxuICAgICAgICBlZGl0aW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IGJvdW5kRWxlbWVudCxcbiAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICB9KTtcbiAgICB9OyAvL2NyZWF0ZSByZWN0YW5nbGUgZWxlbWVudCB3aXRoIHlvdXR1YmUgdG9wIGxlZnQgb24gbmVhcmVzdCBncmlkIHBvaW50IHdpZHRoIC8gaGlnaHQgNjQwLzM2MFxuXG5cbiAgICB0aGlzLmluc2VydEVtYmVkZGFibGVFbGVtZW50ID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWSxcbiAgICAgIGxpbmtcbiAgICB9KSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHNjZW5lWCwgc2NlbmVZLCAoKF9hID0gdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hW0tFWVMuQ1RSTF9PUl9DTURdKSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IGVtYmVkTGluayA9IGdldEVtYmVkTGluayhsaW5rKTtcblxuICAgICAgaWYgKCFlbWJlZExpbmspIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZW1iZWRMaW5rLndhcm5pbmcpIHtcbiAgICAgICAgdGhpcy5zZXRUb2FzdCh7XG4gICAgICAgICAgbWVzc2FnZTogZW1iZWRMaW5rLndhcm5pbmcsXG4gICAgICAgICAgY2xvc2FibGU6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdFbWJlZGRhYmxlRWxlbWVudCh7XG4gICAgICAgIHR5cGU6IFwiZW1iZWRkYWJsZVwiLFxuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiBcInRyYW5zcGFyZW50XCIsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogXCJ0cmFuc3BhcmVudFwiLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgcm91bmRuZXNzOiB0aGlzLmdldEN1cnJlbnRJdGVtUm91bmRuZXNzKFwiZW1iZWRkYWJsZVwiKSxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIGxvY2tlZDogZmFsc2UsXG4gICAgICAgIHdpZHRoOiBlbWJlZExpbmsuYXNwZWN0UmF0aW8udyxcbiAgICAgICAgaGVpZ2h0OiBlbWJlZExpbmsuYXNwZWN0UmF0aW8uaCxcbiAgICAgICAgbGluayxcbiAgICAgICAgdmFsaWRhdGVkOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBlbGVtZW50XSk7XG4gICAgICByZXR1cm4gZWxlbWVudDtcbiAgICB9O1xuXG4gICAgdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZLFxuICAgICAgYWRkVG9GcmFtZVVuZGVyQ3Vyc29yID0gdHJ1ZVxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVYLCBzY2VuZVksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IGFkZFRvRnJhbWVVbmRlckN1cnNvciA/IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pIDogbnVsbDtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdJbWFnZUVsZW1lbnQoe1xuICAgICAgICB0eXBlOiBcImltYWdlXCIsXG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgICAgbG9ja2VkOiBmYWxzZSxcbiAgICAgICAgZnJhbWVJZDogdG9wTGF5ZXJGcmFtZSA/IHRvcExheWVyRnJhbWUuaWQgOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiBlbGVtZW50O1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUxpbmVhckVsZW1lbnRPblBvaW50ZXJEb3duID0gKGV2ZW50LCBlbGVtZW50VHlwZSwgcG9pbnRlckRvd25TdGF0ZSkgPT4ge1xuICAgICAgaWYgKHRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBtdWx0aUVsZW1lbnRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7IC8vIGZpbmFsaXplIGlmIGNvbXBsZXRpbmcgYSBsb29wXG5cbiAgICAgICAgaWYgKG11bHRpRWxlbWVudC50eXBlID09PSBcImxpbmVcIiAmJiBpc1BhdGhBTG9vcChtdWx0aUVsZW1lbnQucG9pbnRzLCB0aGlzLnN0YXRlLnpvb20udmFsdWUpKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICAgIGxhc3RDb21taXR0ZWRQb2ludDogbXVsdGlFbGVtZW50LnBvaW50c1ttdWx0aUVsZW1lbnQucG9pbnRzLmxlbmd0aCAtIDFdXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiByeCxcbiAgICAgICAgICB5OiByeSxcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnRcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDsgLy8gY2xpY2tpbmcgaW5zaWRlIGNvbW1pdCB6b25lIOKGkiBmaW5hbGl6ZSBhcnJvd1xuXG4gICAgICAgIGlmIChtdWx0aUVsZW1lbnQucG9pbnRzLmxlbmd0aCA+IDEgJiYgbGFzdENvbW1pdHRlZFBvaW50ICYmIGRpc3RhbmNlMmQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCAtIHJ4LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55IC0gcnksIGxhc3RDb21taXR0ZWRQb2ludFswXSwgbGFzdENvbW1pdHRlZFBvaW50WzFdKSA8IExJTkVfQ09ORklSTV9USFJFU0hPTEQpIHtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgIFttdWx0aUVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgfSksIHByZXZTdGF0ZSlcbiAgICAgICAgfSkpOyAvLyBjbGlja2luZyBvdXRzaWRlIGNvbW1pdCB6b25lIOKGkiB1cGRhdGUgcmVmZXJlbmNlIGZvciBsYXN0IGNvbW1pdHRlZFxuICAgICAgICAvLyBwb2ludFxuXG4gICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50OiBtdWx0aUVsZW1lbnQucG9pbnRzW211bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoIC0gMV1cbiAgICAgICAgfSk7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgICAgeTogZ3JpZFlcbiAgICAgICAgfSk7XG4gICAgICAgIC8qIElmIGFycm93IGlzIHByZS1hcnJvd2hlYWRzLCBpdCB3aWxsIGhhdmUgdW5kZWZpbmVkIGZvciBib3RoIHN0YXJ0IGFuZCBlbmQgYXJyb3doZWFkcy5cbiAgICAgICAgSWYgc28sIHdlIHdhbnQgaXQgdG8gYmUgbnVsbCBmb3Igc3RhcnQgYW5kIFwiYXJyb3dcIiBmb3IgZW5kLiBJZiB0aGUgbGluZWFyIGl0ZW0gaXMgbm90XG4gICAgICAgIGFuIGFycm93LCB3ZSB3YW50IGl0IHRvIGJlIG51bGwgZm9yIGJvdGguIE90aGVyd2lzZSwgd2Ugd2FudCBpdCB0byB1c2UgdGhlXG4gICAgICAgIHZhbHVlcyBmcm9tIGFwcFN0YXRlLiAqL1xuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBjdXJyZW50SXRlbVN0YXJ0QXJyb3doZWFkLFxuICAgICAgICAgIGN1cnJlbnRJdGVtRW5kQXJyb3doZWFkXG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICBjb25zdCBbc3RhcnRBcnJvd2hlYWQsIGVuZEFycm93aGVhZF0gPSBlbGVtZW50VHlwZSA9PT0gXCJhcnJvd1wiID8gW2N1cnJlbnRJdGVtU3RhcnRBcnJvd2hlYWQsIGN1cnJlbnRJdGVtRW5kQXJyb3doZWFkXSA6IFtudWxsLCBudWxsXTtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0xpbmVhckVsZW1lbnQoe1xuICAgICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlLFxuICAgICAgICAgIHg6IGdyaWRYLFxuICAgICAgICAgIHk6IGdyaWRZLFxuICAgICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICAgIHJvdW5kbmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdW5kbmVzcyA9PT0gXCJyb3VuZFwiID8ge1xuICAgICAgICAgICAgdHlwZTogUk9VTkRORVNTLlBST1BPUlRJT05BTF9SQURJVVNcbiAgICAgICAgICB9IDogbnVsbCxcbiAgICAgICAgICBzdGFydEFycm93aGVhZCxcbiAgICAgICAgICBlbmRBcnJvd2hlYWQsXG4gICAgICAgICAgbG9ja2VkOiBmYWxzZSxcbiAgICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7XG4gICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMobmV4dFNlbGVjdGVkRWxlbWVudElkcywgcHJldlN0YXRlKVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICBwb2ludHM6IFsuLi5lbGVtZW50LnBvaW50cywgWzAsIDBdXVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgYm91bmRFbGVtZW50ID0gZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLCB0aGlzLnNjZW5lKTtcbiAgICAgICAgdGhpcy5zY2VuZS5hZGROZXdFbGVtZW50KGVsZW1lbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IGJvdW5kRWxlbWVudCxcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlR2VuZXJpY0VsZW1lbnRPblBvaW50ZXJEb3duID0gKGVsZW1lbnRUeXBlLCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgYmFzZUVsZW1lbnRBdHRyaWJ1dGVzID0ge1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICByb3VuZG5lc3M6IHRoaXMuZ2V0Q3VycmVudEl0ZW1Sb3VuZG5lc3MoZWxlbWVudFR5cGUpLFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH07XG4gICAgICBsZXQgZWxlbWVudDtcblxuICAgICAgaWYgKGVsZW1lbnRUeXBlID09PSBcImVtYmVkZGFibGVcIikge1xuICAgICAgICBlbGVtZW50ID0gbmV3RW1iZWRkYWJsZUVsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdHlwZTogXCJlbWJlZGRhYmxlXCIsXG4gICAgICAgICAgdmFsaWRhdGVkOiBudWxsXG4gICAgICAgIH0sIGJhc2VFbGVtZW50QXR0cmlidXRlcykpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWxlbWVudCA9IG5ld0VsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdHlwZTogZWxlbWVudFR5cGVcbiAgICAgICAgfSwgYmFzZUVsZW1lbnRBdHRyaWJ1dGVzKSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbGVtZW50LnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0aW9uRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIG11bHRpRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlRnJhbWVFbGVtZW50T25Qb2ludGVyRG93biA9IHBvaW50ZXJEb3duU3RhdGUgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCAoKF9hID0gdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hW0tFWVMuQ1RSTF9PUl9DTURdKSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IGZyYW1lID0gbmV3RnJhbWVFbGVtZW50KE9iamVjdC5hc3NpZ24oe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlXG4gICAgICB9LCBGUkFNRV9TVFlMRSkpO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoWy4uLnRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGZyYW1lXSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgbXVsdGlFbGVtZW50OiBudWxsLFxuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGZyYW1lLFxuICAgICAgICBlZGl0aW5nRWxlbWVudDogZnJhbWVcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc3RvcmVSZWFkeVRvRXJhc2VFbGVtZW50cyA9IHBvaW50ZXJEb3duU3RhdGUgPT4ge1xuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGUgPT4ge1xuICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmlkXS5vcGFjaXR5XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNCb3VuZFRvQ29udGFpbmVyKGVsZSkgJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXS5vcGFjaXR5XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZWxlLmZyYW1lSWQgJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuZnJhbWVJZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuZnJhbWVJZF0uZXJhc2UpIHtcbiAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXS5vcGFjaXR5XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgfTtcblxuICAgIHRoaXMuZXJhc2VFbGVtZW50cyA9IHBvaW50ZXJEb3duU3RhdGUgPT4ge1xuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGUgPT4ge1xuICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGlzQm91bmRUb0NvbnRhaW5lcihlbGUpICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5jb250YWluZXJJZF0uZXJhc2UpIHtcbiAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICBpc0RlbGV0ZWQ6IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChlbGUuZnJhbWVJZCAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgIH07XG5cbiAgICB0aGlzLmluaXRpYWxpemVJbWFnZSA9ICh7XG4gICAgICBpbWFnZUZpbGUsXG4gICAgICBpbWFnZUVsZW1lbnQ6IF9pbWFnZUVsZW1lbnQsXG4gICAgICBzaG93Q3Vyc29ySW1hZ2VQcmV2aWV3ID0gZmFsc2VcbiAgICB9KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB2YXIgX2UsIF9mLCBfZywgX2g7IC8vIGF0IHRoaXMgcG9pbnQgdGhpcyBzaG91bGQgYmUgZ3VhcmFudGVlZCBpbWFnZSBmaWxlLCBidXQgd2UgZG8gdGhpcyBjaGVja1xuICAgICAgLy8gdG8gc2F0aXNmeSBUUyBkb3duIHRoZSBsaW5lXG5cblxuICAgICAgaWYgKCFpc1N1cHBvcnRlZEltYWdlRmlsZShpbWFnZUZpbGUpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcih0KFwiZXJyb3JzLnVuc3VwcG9ydGVkRmlsZVR5cGVcIikpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtaW1lVHlwZSA9IGltYWdlRmlsZS50eXBlO1xuICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIFwid2FpdFwiKTtcblxuICAgICAgaWYgKG1pbWVUeXBlID09PSBNSU1FX1RZUEVTLnN2Zykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGltYWdlRmlsZSA9IFNWR1N0cmluZ1RvRmlsZSh5aWVsZCBub3JtYWxpemVTVkcoeWllbGQgaW1hZ2VGaWxlLnRleHQoKSksIGltYWdlRmlsZS5uYW1lKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oZXJyb3IpO1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0KFwiZXJyb3JzLnN2Z0ltYWdlSW5zZXJ0RXJyb3JcIikpO1xuICAgICAgICB9XG4gICAgICB9IC8vIGdlbmVyYXRlIGltYWdlIGlkIChieSBkZWZhdWx0IHRoZSBmaWxlIGRpZ2VzdCkgYmVmb3JlIGFueVxuICAgICAgLy8gcmVzaXppbmcvY29tcHJlc3Npb24gdGFrZXMgcGxhY2UgdG8ga2VlcCBpdCBtb3JlIHBvcnRhYmxlXG5cblxuICAgICAgY29uc3QgZmlsZUlkID0geWllbGQgKChfZiA9IChfZSA9IHRoaXMucHJvcHMpLmdlbmVyYXRlSWRGb3JGaWxlKSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuY2FsbChfZSwgaW1hZ2VGaWxlKSkgfHwgZ2VuZXJhdGVJZEZyb21GaWxlKGltYWdlRmlsZSk7XG5cbiAgICAgIGlmICghZmlsZUlkKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIkNvdWxkbid0IGdlbmVyYXRlIGZpbGUgaWQgb3IgdGhlIHN1cHBsaWVkIGBnZW5lcmF0ZUlkRm9yRmlsZWAgZGlkbid0IHJlc29sdmUgdG8gb25lLlwiKTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMuaW1hZ2VJbnNlcnRFcnJvclwiKSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGV4aXN0aW5nRmlsZURhdGEgPSB0aGlzLmZpbGVzW2ZpbGVJZF07XG5cbiAgICAgIGlmICghKGV4aXN0aW5nRmlsZURhdGEgPT09IG51bGwgfHwgZXhpc3RpbmdGaWxlRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhpc3RpbmdGaWxlRGF0YS5kYXRhVVJMKSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGltYWdlRmlsZSA9IHlpZWxkIHJlc2l6ZUltYWdlRmlsZShpbWFnZUZpbGUsIHtcbiAgICAgICAgICAgIG1heFdpZHRoT3JIZWlnaHQ6IERFRkFVTFRfTUFYX0lNQUdFX1dJRFRIX09SX0hFSUdIVFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJlcnJvciB0cnlpbmcgdG8gcmVzaW5nIGltYWdlIGZpbGUgb24gaW5zZXJ0aW9uXCIsIGVycm9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpbWFnZUZpbGUuc2l6ZSA+IE1BWF9BTExPV0VEX0ZJTEVfQllURVMpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodChcImVycm9ycy5maWxlVG9vQmlnXCIsIHtcbiAgICAgICAgICAgIG1heFNpemU6IGAke01hdGgudHJ1bmMoTUFYX0FMTE9XRURfRklMRV9CWVRFUyAvIDEwMjQgLyAxMDI0KX1NQmBcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHNob3dDdXJzb3JJbWFnZVByZXZpZXcpIHtcbiAgICAgICAgY29uc3QgZGF0YVVSTCA9IChfZyA9IHRoaXMuZmlsZXNbZmlsZUlkXSkgPT09IG51bGwgfHwgX2cgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9nLmRhdGFVUkw7IC8vIG9wdGltaXphdGlvbiBzbyB0aGF0IHdlIGRvbid0IHVubmVjZXNzYXJpbHkgcmVzaXplIHRoZSBvcmlnaW5hbFxuICAgICAgICAvLyBmdWxsLXNpemUgZmlsZSBmb3IgY3Vyc29yIHByZXZpZXdcbiAgICAgICAgLy8gKGl0J3MgbXVjaCBmYXN0ZXIgdG8gY29udmVydCB0aGUgcmVzaXplZCBkYXRhVVJMIHRvIEZpbGUpXG5cbiAgICAgICAgY29uc3QgcmVzaXplZEZpbGUgPSBkYXRhVVJMICYmIGRhdGFVUkxUb0ZpbGUoZGF0YVVSTCk7XG4gICAgICAgIHRoaXMuc2V0SW1hZ2VQcmV2aWV3Q3Vyc29yKHJlc2l6ZWRGaWxlIHx8IGltYWdlRmlsZSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRhdGFVUkwgPSAoKF9oID0gdGhpcy5maWxlc1tmaWxlSWRdKSA9PT0gbnVsbCB8fCBfaCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2guZGF0YVVSTCkgfHwgKHlpZWxkIGdldERhdGFVUkwoaW1hZ2VGaWxlKSk7XG4gICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSBtdXRhdGVFbGVtZW50KF9pbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgZmlsZUlkXG4gICAgICB9LCBmYWxzZSk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgICB2YXIgX2o7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0aGlzLmZpbGVzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwge1xuICAgICAgICAgICAgW2ZpbGVJZF06IHtcbiAgICAgICAgICAgICAgbWltZVR5cGUsXG4gICAgICAgICAgICAgIGlkOiBmaWxlSWQsXG4gICAgICAgICAgICAgIGRhdGFVUkwsXG4gICAgICAgICAgICAgIGNyZWF0ZWQ6IERhdGUubm93KCksXG4gICAgICAgICAgICAgIGxhc3RSZXRyaWV2ZWQ6IERhdGUubm93KClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICBjb25zdCBjYWNoZWRJbWFnZURhdGEgPSB0aGlzLmltYWdlQ2FjaGUuZ2V0KGZpbGVJZCk7XG5cbiAgICAgICAgICBpZiAoIWNhY2hlZEltYWdlRGF0YSkge1xuICAgICAgICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICAgICAgICAgIHlpZWxkIHRoaXMudXBkYXRlSW1hZ2VDYWNoZShbaW1hZ2VFbGVtZW50XSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKChjYWNoZWRJbWFnZURhdGEgPT09IG51bGwgfHwgY2FjaGVkSW1hZ2VEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjYWNoZWRJbWFnZURhdGEuaW1hZ2UpIGluc3RhbmNlb2YgUHJvbWlzZSkge1xuICAgICAgICAgICAgeWllbGQgY2FjaGVkSW1hZ2VEYXRhLmltYWdlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCAhPT0gaW1hZ2VFbGVtZW50LmlkICYmICgoX2ogPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCkgPT09IG51bGwgfHwgX2ogPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9qLmlkKSAhPT0gaW1hZ2VFbGVtZW50LmlkKSB7XG4gICAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50LCB0cnVlKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXNvbHZlKGltYWdlRWxlbWVudCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcih0KFwiZXJyb3JzLmltYWdlSW5zZXJ0RXJyb3JcIikpKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBpZiAoIXNob3dDdXJzb3JJbWFnZVByZXZpZXcpIHtcbiAgICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSkpO1xuICAgIH0pO1xuICAgIC8qKlxuICAgICAqIGluc2VydHMgaW1hZ2UgaW50byBlbGVtZW50cyBhcnJheSBhbmQgcmVyZW5kZXJzXG4gICAgICovXG5cblxuICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50ID0gKGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlLCBzaG93Q3Vyc29ySW1hZ2VQcmV2aWV3KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAvLyB3ZSBzaG91bGQgYmUgaGFuZGxpbmcgYWxsIGNhc2VzIHVwc3RyZWFtLCBidXQgaW4gY2FzZSB3ZSBmb3JnZXQgdG8gaGFuZGxlXG4gICAgICAvLyBhIGZ1dHVyZSBjYXNlLCBsZXQncyB0aHJvdyBoZXJlXG4gICAgICBpZiAoIXRoaXMuaXNUb29sU3VwcG9ydGVkKFwiaW1hZ2VcIikpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiB0KFwiZXJyb3JzLmltYWdlVG9vbE5vdFN1cHBvcnRlZFwiKVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoaW1hZ2VFbGVtZW50KTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIHlpZWxkIHRoaXMuaW5pdGlhbGl6ZUltYWdlKHtcbiAgICAgICAgICBpbWFnZUZpbGUsXG4gICAgICAgICAgaW1hZ2VFbGVtZW50LFxuICAgICAgICAgIHNob3dDdXJzb3JJbWFnZVByZXZpZXdcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UgfHwgdChcImVycm9ycy5pbWFnZUluc2VydEVycm9yXCIpXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuc2V0SW1hZ2VQcmV2aWV3Q3Vyc29yID0gaW1hZ2VGaWxlID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIC8vIG11c3RuJ3QgYmUgbGFyZ2VyIHRoYW4gMTI4IHB4XG4gICAgICAvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9DU1MvQ1NTX0Jhc2ljX1VzZXJfSW50ZXJmYWNlL1VzaW5nX1VSTF92YWx1ZXNfZm9yX3RoZV9jdXJzb3JfcHJvcGVydHlcbiAgICAgIGNvbnN0IGN1cnNvckltYWdlU2l6ZVB4ID0gOTY7XG4gICAgICBjb25zdCBpbWFnZVByZXZpZXcgPSB5aWVsZCByZXNpemVJbWFnZUZpbGUoaW1hZ2VGaWxlLCB7XG4gICAgICAgIG1heFdpZHRoT3JIZWlnaHQ6IGN1cnNvckltYWdlU2l6ZVB4XG4gICAgICB9KTtcbiAgICAgIGxldCBwcmV2aWV3RGF0YVVSTCA9IHlpZWxkIGdldERhdGFVUkwoaW1hZ2VQcmV2aWV3KTsgLy8gU1ZHIGNhbm5vdCBiZSByZXNpemVkIHZpYSBgcmVzaXplSW1hZ2VGaWxlYCBzbyB3ZSByZXNpemUgYnkgcmVuZGVyaW5nIHRvXG4gICAgICAvLyBhIHNtYWxsIGNhbnZhc1xuXG4gICAgICBpZiAoaW1hZ2VGaWxlLnR5cGUgPT09IE1JTUVfVFlQRVMuc3ZnKSB7XG4gICAgICAgIGNvbnN0IGltZyA9IHlpZWxkIGxvYWRIVE1MSW1hZ2VFbGVtZW50KHByZXZpZXdEYXRhVVJMKTtcbiAgICAgICAgbGV0IGhlaWdodCA9IE1hdGgubWluKGltZy5oZWlnaHQsIGN1cnNvckltYWdlU2l6ZVB4KTtcbiAgICAgICAgbGV0IHdpZHRoID0gaGVpZ2h0ICogKGltZy53aWR0aCAvIGltZy5oZWlnaHQpO1xuXG4gICAgICAgIGlmICh3aWR0aCA+IGN1cnNvckltYWdlU2l6ZVB4KSB7XG4gICAgICAgICAgd2lkdGggPSBjdXJzb3JJbWFnZVNpemVQeDtcbiAgICAgICAgICBoZWlnaHQgPSB3aWR0aCAqIChpbWcuaGVpZ2h0IC8gaW1nLndpZHRoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgICAgIGNhbnZhcy5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgICAgIGNhbnZhcy53aWR0aCA9IHdpZHRoO1xuICAgICAgICBjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoXCIyZFwiKTtcbiAgICAgICAgY29udGV4dC5kcmF3SW1hZ2UoaW1nLCAwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICAgICAgcHJldmlld0RhdGFVUkwgPSBjYW52YXMudG9EYXRhVVJMKE1JTUVfVFlQRVMuc3ZnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBgdXJsKCR7cHJldmlld0RhdGFVUkx9KSA0IDQsIGF1dG9gKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub25JbWFnZUFjdGlvbiA9ICh7XG4gICAgICBpbnNlcnRPbkNhbnZhc0RpcmVjdGx5XG4gICAgfSkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY2xpZW50WCA9IHRoaXMuc3RhdGUud2lkdGggLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0O1xuICAgICAgICBjb25zdCBjbGllbnRZID0gdGhpcy5zdGF0ZS5oZWlnaHQgLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRUb3A7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgY2xpZW50WCxcbiAgICAgICAgICBjbGllbnRZXG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBpbWFnZUZpbGUgPSB5aWVsZCBmaWxlT3Blbih7XG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiSW1hZ2VcIixcbiAgICAgICAgICBleHRlbnNpb25zOiBPYmplY3Qua2V5cyhJTUFHRV9NSU1FX1RZUEVTKVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQoe1xuICAgICAgICAgIHNjZW5lWDogeCxcbiAgICAgICAgICBzY2VuZVk6IHksXG4gICAgICAgICAgYWRkVG9GcmFtZVVuZGVyQ3Vyc29yOiBmYWxzZVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoaW5zZXJ0T25DYW52YXNEaXJlY3RseSkge1xuICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlKTtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IGltYWdlRWxlbWVudC5pZFxuICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlLFxuICAgICAgICAgICAgLyogc2hvd0N1cnNvckltYWdlUHJldmlldyAqL1xuICAgICAgICAgICAgdHJ1ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmIChlcnJvci5uYW1lICE9PSBcIkFib3J0RXJyb3JcIikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGwsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMgPSAoaW1hZ2VFbGVtZW50LCBmb3JjZU5hdHVyYWxTaXplID0gZmFsc2UpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaW1hZ2UgPSBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCkgJiYgKChfYSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoaW1hZ2VFbGVtZW50LmZpbGVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pbWFnZSk7XG5cbiAgICAgIGlmICghaW1hZ2UgfHwgaW1hZ2UgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgIGlmIChpbWFnZUVsZW1lbnQud2lkdGggPCBEUkFHR0lOR19USFJFU0hPTEQgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUgJiYgaW1hZ2VFbGVtZW50LmhlaWdodCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkge1xuICAgICAgICAgIGNvbnN0IHBsYWNlaG9sZGVyU2l6ZSA9IDEwMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgICAgeDogaW1hZ2VFbGVtZW50LnggLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgeTogaW1hZ2VFbGVtZW50LnkgLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgd2lkdGg6IHBsYWNlaG9sZGVyU2l6ZSxcbiAgICAgICAgICAgIGhlaWdodDogcGxhY2Vob2xkZXJTaXplXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChmb3JjZU5hdHVyYWxTaXplIHx8IC8vIGlmIHVzZXItY3JlYXRlZCBib3VuZGluZyBib3ggaXMgYmVsb3cgdGhyZXNob2xkLCBhc3N1bWUgdGhlXG4gICAgICAvLyBpbnRlbnRpb24gd2FzIHRvIGNsaWNrIGluc3RlYWQgb2YgZHJhZywgYW5kIHVzZSB0aGUgaW1hZ2Unc1xuICAgICAgLy8gaW50cmluc2ljIHNpemVcbiAgICAgIGltYWdlRWxlbWVudC53aWR0aCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSAmJiBpbWFnZUVsZW1lbnQuaGVpZ2h0IDwgRFJBR0dJTkdfVEhSRVNIT0xEIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlKSB7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IE1hdGgubWF4KHRoaXMuc3RhdGUuaGVpZ2h0IC0gMTIwLCAxNjApOyAvLyBtYXggNjUlIG9mIGNhbnZhcyBoZWlnaHQsIGNsYW1wZWQgdG8gPDMwMHB4LCB2aCAtIDEyMHB4PlxuXG4gICAgICAgIGNvbnN0IG1heEhlaWdodCA9IE1hdGgubWluKG1pbkhlaWdodCwgTWF0aC5mbG9vcih0aGlzLnN0YXRlLmhlaWdodCAqIDAuNSkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUpO1xuICAgICAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1pbihpbWFnZS5uYXR1cmFsSGVpZ2h0LCBtYXhIZWlnaHQpO1xuICAgICAgICBjb25zdCB3aWR0aCA9IGhlaWdodCAqIChpbWFnZS5uYXR1cmFsV2lkdGggLyBpbWFnZS5uYXR1cmFsSGVpZ2h0KTsgLy8gYWRkIGN1cnJlbnQgaW1hZ2VFbGVtZW50IHdpZHRoL2hlaWdodCB0byBhY2NvdW50IGZvciBwcmV2aW91cyBjZW50ZXJpbmdcbiAgICAgICAgLy8gb2YgdGhlIHBsYWNlaG9sZGVyIGltYWdlXG5cbiAgICAgICAgY29uc3QgeCA9IGltYWdlRWxlbWVudC54ICsgaW1hZ2VFbGVtZW50LndpZHRoIC8gMiAtIHdpZHRoIC8gMjtcbiAgICAgICAgY29uc3QgeSA9IGltYWdlRWxlbWVudC55ICsgaW1hZ2VFbGVtZW50LmhlaWdodCAvIDIgLSBoZWlnaHQgLyAyO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeSxcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHRcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcbiAgICAvKiogdXBkYXRlcyBpbWFnZSBjYWNoZSwgcmVmcmVzaGluZyB1cGRhdGVkIGVsZW1lbnRzIGFuZC9vciBzZXR0aW5nIHN0YXR1c1xuICAgICAgICB0byBlcnJvciBmb3IgaW1hZ2VzIHRoYXQgZmFpbCBkdXJpbmcgPGltZz4gZWxlbWVudCBjcmVhdGlvbiAqL1xuXG5cbiAgICB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUgPSAoZWxlbWVudHMsIGZpbGVzID0gdGhpcy5maWxlcykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgY29uc3Qge1xuICAgICAgICB1cGRhdGVkRmlsZXMsXG4gICAgICAgIGVycm9yZWRGaWxlc1xuICAgICAgfSA9IHlpZWxkIF91cGRhdGVJbWFnZUNhY2hlKHtcbiAgICAgICAgaW1hZ2VDYWNoZTogdGhpcy5pbWFnZUNhY2hlLFxuICAgICAgICBmaWxlSWRzOiBlbGVtZW50cy5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgICAgIGZpbGVzXG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplIHx8IGVycm9yZWRGaWxlcy5zaXplKSB7XG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgIGlmICh1cGRhdGVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChlcnJvcmVkRmlsZXMuc2l6ZSkge1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChlbGVtZW50KSAmJiBlcnJvcmVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgc3RhdHVzOiBcImVycm9yXCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBlbGVtZW50O1xuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHVwZGF0ZWRGaWxlcyxcbiAgICAgICAgZXJyb3JlZEZpbGVzXG4gICAgICB9O1xuICAgIH0pO1xuICAgIC8qKiBhZGRzIG5ldyBpbWFnZXMgdG8gaW1hZ2VDYWNoZSBhbmQgcmUtcmVuZGVycyBpZiBuZWVkZWQgKi9cblxuXG4gICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUgPSAoaW1hZ2VFbGVtZW50cyA9IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSwgZmlsZXMgPSB0aGlzLmZpbGVzKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCB1bmNhY2hlZEltYWdlRWxlbWVudHMgPSBpbWFnZUVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+ICFlbGVtZW50LmlzRGVsZXRlZCAmJiAhdGhpcy5pbWFnZUNhY2hlLmhhcyhlbGVtZW50LmZpbGVJZCkpO1xuXG4gICAgICBpZiAodW5jYWNoZWRJbWFnZUVsZW1lbnRzLmxlbmd0aCkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgdXBkYXRlZEZpbGVzXG4gICAgICAgIH0gPSB5aWVsZCB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUodW5jYWNoZWRJbWFnZUVsZW1lbnRzLCBmaWxlcyk7XG5cbiAgICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplKSB7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgLyoqIGdlbmVyYWxseSB5b3Ugc2hvdWxkIHVzZSBgYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKClgIGRpcmVjdGx5IGlmIHlvdSBuZWVkXG4gICAgICogIHRvIHJlbmRlciBuZXcgaW1hZ2VzLiBUaGlzIGlzIGp1c3QgYSBmYWlsc2FmZSAgKi9cblxuXG4gICAgdGhpcy5zY2hlZHVsZUltYWdlUmVmcmVzaCA9IHRocm90dGxlKCgpID0+IHtcbiAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgfSwgSU1BR0VfUkVOREVSX1RJTUVPVVQpO1xuXG4gICAgdGhpcy51cGRhdGVCaW5kaW5nRW5hYmxlZE9uUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICBjb25zdCBzaG91bGRFbmFibGVCaW5kaW5nID0gc2hvdWxkRW5hYmxlQmluZGluZ0ZvclBvaW50ZXJFdmVudChldmVudCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQgIT09IHNob3VsZEVuYWJsZUJpbmRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogc2hvdWxkRW5hYmxlQmluZGluZ1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3IgPSBwb2ludGVyQ29vcmRzID0+IHtcbiAgICAgIGNvbnN0IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckNvb3JkcywgdGhpcy5zY2VuZSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgIT0gbnVsbCA/IFtob3ZlcmVkQmluZGFibGVFbGVtZW50XSA6IFtdXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyA9IChsaW5lYXJFbGVtZW50LFxuICAgIC8qKiBzY2VuZSBjb29yZHMgKi9cbiAgICBwb2ludGVyQ29vcmRzLCAvLyBEdXJpbmcgbGluZSBjcmVhdGlvbiB0aGUgc3RhcnQgYmluZGluZyBoYXNuJ3QgYmVlbiB3cml0dGVuIHlldFxuICAgIC8vIGludG8gYGxpbmVhckVsZW1lbnRgXG4gICAgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50KSA9PiB7XG4gICAgICBpZiAoIXBvaW50ZXJDb29yZHMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3VnZ2VzdGVkQmluZGluZ3MgPSBwb2ludGVyQ29vcmRzLnJlZHVjZSgoYWNjLCBjb29yZHMpID0+IHtcbiAgICAgICAgY29uc3QgaG92ZXJlZEJpbmRhYmxlRWxlbWVudCA9IGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZyhjb29yZHMsIHRoaXMuc2NlbmUpO1xuXG4gICAgICAgIGlmIChob3ZlcmVkQmluZGFibGVFbGVtZW50ICE9IG51bGwgJiYgIWlzTGluZWFyRWxlbWVudFNpbXBsZUFuZEFscmVhZHlCb3VuZChsaW5lYXJFbGVtZW50LCBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQgPT09IG51bGwgfHwgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQuaWQsIGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQpKSB7XG4gICAgICAgICAgYWNjLnB1c2goaG92ZXJlZEJpbmRhYmxlRWxlbWVudCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwgW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVJbnRlcmFjdGl2ZUNhbnZhc1JlZiA9IGNhbnZhcyA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYzsgLy8gY2FudmFzIGlzIG51bGwgd2hlbiB1bm1vdW50aW5nXG5cblxuICAgICAgaWYgKGNhbnZhcyAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzID0gY2FudmFzOyAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAvLyBOT1RFIHdoZWVsLCB0b3VjaHN0YXJ0LCB0b3VjaGVuZCBldmVudHMgbXVzdCBiZSByZWdpc3RlcmVkIG91dHNpZGVcbiAgICAgICAgLy8gb2YgcmVhY3QgYmVjYXVzZSByZWFjdCBiaW5kcyB0aGVtIHRoZW0gcGFzc2l2ZWx5IChzbyB3ZSBjYW4ndCBwcmV2ZW50XG4gICAgICAgIC8vIGRlZmF1bHQgb24gdGhlbSlcblxuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuV0hFRUwsIHRoaXMuaGFuZGxlV2hlZWwpO1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlRPVUNIX0VORCwgdGhpcy5vblRvdWNoRW5kKTsgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIChfYSA9IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLmhhbmRsZVdoZWVsKTtcbiAgICAgICAgKF9iID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgKF9jID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfRU5ELCB0aGlzLm9uVG91Y2hFbmQpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUFwcE9uRHJvcCA9IGV2ZW50ID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfaywgX2wsIF9tLCBfbzsgLy8gbXVzdCBiZSByZXRyaWV2ZWQgZmlyc3QsIGluIHRoZSBzYW1lIGZyYW1lXG5cblxuICAgICAgY29uc3Qge1xuICAgICAgICBmaWxlLFxuICAgICAgICBmaWxlSGFuZGxlXG4gICAgICB9ID0geWllbGQgZ2V0RmlsZUZyb21FdmVudChldmVudCk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gaWYgaW1hZ2UgdG9vbCBub3Qgc3VwcG9ydGVkLCBkb24ndCBzaG93IGFuIGVycm9yIGhlcmUgYW5kIGxldCBpdCBmYWxsXG4gICAgICAgIC8vIHRocm91Z2ggc28gd2Ugc3RpbGwgc3VwcG9ydCBpbXBvcnRpbmcgc2NlbmUgZGF0YSBmcm9tIGltYWdlcy4gSWYgbm9cbiAgICAgICAgLy8gc2NlbmUgZGF0YSBlbmNvZGVkLCB3ZSdsbCBzaG93IGFuIGVycm9yIHRoZW5cbiAgICAgICAgaWYgKGlzU3VwcG9ydGVkSW1hZ2VGaWxlKGZpbGUpICYmIHRoaXMuaXNUb29sU3VwcG9ydGVkKFwiaW1hZ2VcIikpIHtcbiAgICAgICAgICAvLyBmaXJzdCBhdHRlbXB0IHRvIGRlY29kZSBzY2VuZSBmcm9tIHRoZSBpbWFnZSBpZiBpdCdzIGVtYmVkZGVkXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgICAgaWYgKChmaWxlID09PSBudWxsIHx8IGZpbGUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGZpbGUudHlwZSkgPT09IE1JTUVfVFlQRVMucG5nIHx8IChmaWxlID09PSBudWxsIHx8IGZpbGUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGZpbGUudHlwZSkgPT09IE1JTUVfVFlQRVMuc3ZnKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCBzY2VuZSA9IHlpZWxkIGxvYWRGcm9tQmxvYihmaWxlLCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBmaWxlSGFuZGxlKTtcbiAgICAgICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUpLCB7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUgfHwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGlzTG9hZGluZzogZmFsc2VcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICByZXBsYWNlRmlsZXM6IHRydWUsXG4gICAgICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgaWYgKGVycm9yLm5hbWUgIT09IFwiRW5jb2RpbmdFcnJvclwiKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIGlmIG5vIHNjZW5lIGlzIGVtYmVkZGVkIG9yIHdlIGZhaWwgZm9yIHdoYXRldmVyIHJlYXNvbiwgZmFsbCBiYWNrXG4gICAgICAgICAgLy8gdG8gaW1wb3J0aW5nIGFzIHJlZ3VsYXIgaW1hZ2VcbiAgICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gICAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQoe1xuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5pbnNlcnRJbWFnZUVsZW1lbnQoaW1hZ2VFbGVtZW50LCBmaWxlKTtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbGlicmFyeUpTT04gPSBldmVudC5kYXRhVHJhbnNmZXIuZ2V0RGF0YShNSU1FX1RZUEVTLmV4Y2FsaWRyYXdsaWIpO1xuXG4gICAgICBpZiAobGlicmFyeUpTT04gJiYgdHlwZW9mIGxpYnJhcnlKU09OID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgbGlicmFyeUl0ZW1zID0gcGFyc2VMaWJyYXJ5SlNPTihsaWJyYXJ5SlNPTik7XG4gICAgICAgICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSh7XG4gICAgICAgICAgICBlbGVtZW50czogZGlzdHJpYnV0ZUxpYnJhcnlJdGVtc09uU3F1YXJlR3JpZChsaWJyYXJ5SXRlbXMpLFxuICAgICAgICAgICAgcG9zaXRpb246IGV2ZW50LFxuICAgICAgICAgICAgZmlsZXM6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZmlsZSkge1xuICAgICAgICAvLyBhdGV0bXB0IHRvIHBhcnNlIGFuIGV4Y2FsaWRyYXcvZXhjYWxpZHJhd2xpYiBmaWxlXG4gICAgICAgIHlpZWxkIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhmaWxlLCBmaWxlSGFuZGxlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKChfbCA9IChfayA9IGV2ZW50LmRhdGFUcmFuc2ZlcikgPT09IG51bGwgfHwgX2sgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9rLnR5cGVzKSA9PT0gbnVsbCB8fCBfbCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2wuaW5jbHVkZXMoXCJ0ZXh0L3BsYWluXCIpKSB7XG4gICAgICAgIGNvbnN0IHRleHQgPSAoX20gPSBldmVudC5kYXRhVHJhbnNmZXIpID09PSBudWxsIHx8IF9tID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfbS5nZXREYXRhKFwidGV4dFwiKTtcblxuICAgICAgICBpZiAodGV4dCAmJiBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yKHRleHQsIHRoaXMucHJvcHMudmFsaWRhdGVFbWJlZGRhYmxlKSAmJiAoL14oaHR0cHxodHRwcyk6XFwvXFwvW15cXHMvJC4/I10uW15cXHNdKiQvLnRlc3QodGV4dCkgfHwgKChfbyA9IGdldEVtYmVkTGluayh0ZXh0KSkgPT09IG51bGwgfHwgX28gPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9vLnR5cGUpID09PSBcInZpZGVvXCIpKSB7XG4gICAgICAgICAgY29uc3QgZW1iZWRkYWJsZSA9IHRoaXMuaW5zZXJ0RW1iZWRkYWJsZUVsZW1lbnQoe1xuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZLFxuICAgICAgICAgICAgbGluazogbm9ybWFsaXplTGluayh0ZXh0KVxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKGVtYmVkZGFibGUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICAgICAgICBbZW1iZWRkYWJsZS5pZF06IHRydWVcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmxvYWRGaWxlVG9DYW52YXMgPSAoZmlsZSwgZmlsZUhhbmRsZSkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgZmlsZSA9IHlpZWxkIG5vcm1hbGl6ZUZpbGUoZmlsZSk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJldCA9IHlpZWxkIGxvYWRTY2VuZU9yTGlicmFyeUZyb21CbG9iKGZpbGUsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGZpbGVIYW5kbGUpO1xuXG4gICAgICAgIGlmIChyZXQudHlwZSA9PT0gTUlNRV9UWVBFUy5leGNhbGlkcmF3KSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBpc0xvYWRpbmc6IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCByZXQuZGF0YSksIHtcbiAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHJldC5kYXRhLmFwcFN0YXRlIHx8IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgIGlzTG9hZGluZzogZmFsc2VcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgcmVwbGFjZUZpbGVzOiB0cnVlLFxuICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgfSkpO1xuICAgICAgICB9IGVsc2UgaWYgKHJldC50eXBlID09PSBNSU1FX1RZUEVTLmV4Y2FsaWRyYXdsaWIpIHtcbiAgICAgICAgICB5aWVsZCB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSh7XG4gICAgICAgICAgICBsaWJyYXJ5SXRlbXM6IGZpbGUsXG4gICAgICAgICAgICBtZXJnZTogdHJ1ZSxcbiAgICAgICAgICAgIG9wZW5MaWJyYXJ5TWVudTogdHJ1ZVxuICAgICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogdChcImVycm9ycy5pbXBvcnRMaWJyYXJ5RXJyb3JcIilcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBJbWFnZVNjZW5lRGF0YUVycm9yICYmIGVycm9yLmNvZGUgPT09IFwiSU1BR0VfTk9UX0NPTlRBSU5TX1NDRU5FX0RBVEFcIiAmJiAhdGhpcy5pc1Rvb2xTdXBwb3J0ZWQoXCJpbWFnZVwiKSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogdChcImVycm9ycy5pbWFnZVRvb2xOb3RTdXBwb3J0ZWRcIilcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUgPSBldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAoKFwicG9pbnRlclR5cGVcIiBpbiBldmVudC5uYXRpdmVFdmVudCAmJiBldmVudC5uYXRpdmVFdmVudC5wb2ludGVyVHlwZSA9PT0gXCJ0b3VjaFwiIHx8IFwicG9pbnRlclR5cGVcIiBpbiBldmVudC5uYXRpdmVFdmVudCAmJiBldmVudC5uYXRpdmVFdmVudC5wb2ludGVyVHlwZSA9PT0gXCJwZW5cIiAmJiAvLyBhbHdheXMgYWxsb3cgaWYgdXNlciB1c2VzIGEgcGVuIHNlY29uZGFyeSBidXR0b25cbiAgICAgIGV2ZW50LmJ1dHRvbiAhPT0gUE9JTlRFUl9CVVRUT04uU0VDT05EQVJZKSAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbih4LCB5LCB7XG4gICAgICAgIHByZWZlclNlbGVjdGVkOiB0cnVlLFxuICAgICAgICBpbmNsdWRlTG9ja2VkRWxlbWVudHM6IHRydWVcbiAgICAgIH0pO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGlzSGl0dGlnbkNvbW1vbkJvdW5kQm94ID0gdGhpcy5pc0hpdHRpbmdDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0sIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgY29uc3QgdHlwZSA9IGVsZW1lbnQgfHwgaXNIaXR0aWduQ29tbW9uQm91bmRCb3ggPyBcImVsZW1lbnRcIiA6IFwiY2FudmFzXCI7XG4gICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgdG9wOiBvZmZzZXRUb3AsXG4gICAgICAgIGxlZnQ6IG9mZnNldExlZnRcbiAgICAgIH0gPSBjb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICBjb25zdCBsZWZ0ID0gZXZlbnQuY2xpZW50WCAtIG9mZnNldExlZnQ7XG4gICAgICBjb25zdCB0b3AgPSBldmVudC5jbGllbnRZIC0gb2Zmc2V0VG9wO1xuICAgICAgdHJhY2tFdmVudChcImNvbnRleHRNZW51XCIsIFwib3BlbkNvbnRleHRNZW51XCIsIHR5cGUpO1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdID8gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgIFtlbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICB9XG4gICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBpc0xpbmVhckVsZW1lbnQoZWxlbWVudCkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihlbGVtZW50LCB0aGlzLnNjZW5lKSA6IG51bGxcbiAgICAgIH0pIDogdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBmYWxzZVxuICAgICAgfSksICgpID0+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgY29udGV4dE1lbnU6IHtcbiAgICAgICAgICAgIHRvcCxcbiAgICAgICAgICAgIGxlZnQsXG4gICAgICAgICAgICBpdGVtczogdGhpcy5nZXRDb250ZXh0TWVudUl0ZW1zKHR5cGUpXG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50ID0gKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lO1xuXG4gICAgICBjb25zdCBkcmFnZ2luZ0VsZW1lbnQgPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudDtcbiAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHM7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcInNlbGVjdGlvblwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyQ29vcmRzLngpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBwb2ludGVyQ29vcmRzLnkpLCBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgICAgY29uc3QgaW1hZ2UgPSBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgJiYgKChfYSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoZHJhZ2dpbmdFbGVtZW50LmZpbGVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pbWFnZSk7XG4gICAgICAgIGNvbnN0IGFzcGVjdFJhdGlvID0gaW1hZ2UgJiYgIShpbWFnZSBpbnN0YW5jZW9mIFByb21pc2UpID8gaW1hZ2Uud2lkdGggLyBpbWFnZS5oZWlnaHQgOiBudWxsO1xuICAgICAgICB0aGlzLm1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBbZHJhZ2dpbmdFbGVtZW50XSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBzbmFwT2Zmc2V0LFxuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9ID0gc25hcE5ld0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlLCBldmVudCwge1xuICAgICAgICAgIHg6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnggKyAoKF9jID0gKF9iID0gdGhpcy5zdGF0ZS5vcmlnaW5TbmFwT2Zmc2V0KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IueCkgIT09IG51bGwgJiYgX2MgIT09IHZvaWQgMCA/IF9jIDogMCksXG4gICAgICAgICAgeTogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueSArICgoX2UgPSAoX2QgPSB0aGlzLnN0YXRlLm9yaWdpblNuYXBPZmZzZXQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC55KSAhPT0gbnVsbCAmJiBfZSAhPT0gdm9pZCAwID8gX2UgOiAwKVxuICAgICAgICB9LCB7XG4gICAgICAgICAgeDogZ3JpZFggLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54LFxuICAgICAgICAgIHk6IGdyaWRZIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueVxuICAgICAgICB9KTtcbiAgICAgICAgZ3JpZFggKz0gc25hcE9mZnNldC54O1xuICAgICAgICBncmlkWSArPSBzbmFwT2Zmc2V0Lnk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9KTtcbiAgICAgICAgZHJhZ05ld0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueSwgZ3JpZFgsIGdyaWRZLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54LCBncmlkWCksIGRpc3RhbmNlKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnksIGdyaWRZKSwgaXNJbWFnZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSA/ICFzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSA6IHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyKGV2ZW50KSwgYXNwZWN0UmF0aW8sIHRoaXMuc3RhdGUub3JpZ2luU25hcE9mZnNldCk7XG4gICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChbZHJhZ2dpbmdFbGVtZW50XSk7IC8vIGhpZ2hsaWdodCBlbGVtZW50cyB0aGF0IGFyZSB0byBiZSBhZGRlZCB0byBmcmFtZXMgb24gZnJhbWVzIGNyZWF0aW9uXG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyYW1lXCIpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVsZW1lbnRzVG9IaWdobGlnaHQ6IGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLm1heWJlSGFuZGxlUmVzaXplID0gKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSA9PiB7XG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRGcmFtZXMgPSBzZWxlY3RlZEVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKTtcbiAgICAgIGNvbnN0IHRyYW5zZm9ybUhhbmRsZVR5cGUgPSBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRGcmFtZXMubGVuZ3RoID4gMCAmJiB0cmFuc2Zvcm1IYW5kbGVUeXBlID09PSBcInJvdGF0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgLy8gVE9ETzogcmVuYW1lIHRoaXMgc3RhdGUgZmllbGQgdG8gXCJpc1NjYWxpbmdcIiB0byBkaXN0aW5ndWlzaFxuICAgICAgICAvLyBpdCBmcm9tIHRoZSBnZW5lcmljIFwiaXNSZXNpemluZ1wiIHdoaWNoIGluY2x1ZGVzIHNjYWxpbmcgYW5kXG4gICAgICAgIC8vIHJvdGF0aW5nXG4gICAgICAgIGlzUmVzaXppbmc6IHRyYW5zZm9ybUhhbmRsZVR5cGUgJiYgdHJhbnNmb3JtSGFuZGxlVHlwZSAhPT0gXCJyb3RhdGlvblwiLFxuICAgICAgICBpc1JvdGF0aW5nOiB0cmFuc2Zvcm1IYW5kbGVUeXBlID09PSBcInJvdGF0aW9uXCIsXG4gICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3JkcztcbiAgICAgIGxldCBbcmVzaXplWCwgcmVzaXplWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54IC0gcG9pbnRlckRvd25TdGF0ZS5yZXNpemUub2Zmc2V0LngsIHBvaW50ZXJDb29yZHMueSAtIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldC55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwID0gbmV3IE1hcCgpO1xuICAgICAgc2VsZWN0ZWRGcmFtZXMuZm9yRWFjaChmcmFtZSA9PiB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzSW5GcmFtZSA9IGdldEZyYW1lQ2hpbGRyZW4odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZnJhbWUuaWQpO1xuICAgICAgICBlbGVtZW50c0luRnJhbWUuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5zZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkLCB7XG4gICAgICAgICAgICB4OiBlbGVtZW50LnggLSBmcmFtZS54LFxuICAgICAgICAgICAgeTogZWxlbWVudC55IC0gZnJhbWUueVxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0pOyAvLyBjaGVjayBuZWVkZWQgZm9yIGF2b2lkaW5nIGZsaWNrZXJpbmcgd2hlbiBhIGtleSBnZXRzIHByZXNzZWRcbiAgICAgIC8vIGR1cmluZyBkcmFnZ2luZ1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZCkge1xuICAgICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgIGNvbnN0IGRyYWdPZmZzZXQgPSB7XG4gICAgICAgICAgeDogZ3JpZFggLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54LFxuICAgICAgICAgIHk6IGdyaWRZIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueVxuICAgICAgICB9O1xuICAgICAgICBjb25zdCBvcmlnaW5hbEVsZW1lbnRzID0gWy4uLnBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50cy52YWx1ZXMoKV07XG4gICAgICAgIHRoaXMubWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgc25hcE9mZnNldCxcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSA9IHNuYXBSZXNpemluZ0VsZW1lbnRzKHNlbGVjdGVkRWxlbWVudHMsIGdldFNlbGVjdGVkRWxlbWVudHMob3JpZ2luYWxFbGVtZW50cywgdGhpcy5zdGF0ZSksIHRoaXMuc3RhdGUsIGV2ZW50LCBkcmFnT2Zmc2V0LCB0cmFuc2Zvcm1IYW5kbGVUeXBlKTtcbiAgICAgICAgcmVzaXplWCArPSBzbmFwT2Zmc2V0Lng7XG4gICAgICAgIHJlc2l6ZVkgKz0gc25hcE9mZnNldC55O1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0cmFuc2Zvcm1FbGVtZW50cyhwb2ludGVyRG93blN0YXRlLCB0cmFuc2Zvcm1IYW5kbGVUeXBlLCBzZWxlY3RlZEVsZW1lbnRzLCBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5hcnJvd0RpcmVjdGlvbiwgc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyKGV2ZW50KSwgc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNJbWFnZUVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkgPyAhc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCkgOiBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgcmVzaXplWCwgcmVzaXplWSwgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuY2VudGVyLngsIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmNlbnRlci55LCB0aGlzLnN0YXRlKSkge1xuICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzVG9IaWdobGlnaHQgPSBuZXcgU2V0KCk7XG4gICAgICAgIHNlbGVjdGVkRnJhbWVzLmZvckVhY2goZnJhbWUgPT4ge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzSW5GcmFtZSA9IGdldEZyYW1lQ2hpbGRyZW4odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZnJhbWUuaWQpOyAvLyBrZWVwIGVsZW1lbnRzJyBwb3NpdGlvbnMgcmVsYXRpdmUgdG8gdGhlaXIgZnJhbWVzIG9uIGZyYW1lcyByZXNpemluZ1xuXG4gICAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICAgIGlmICh0cmFuc2Zvcm1IYW5kbGVUeXBlLmluY2x1ZGVzKFwid1wiKSkge1xuICAgICAgICAgICAgICBlbGVtZW50c0luRnJhbWUuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICB4OiBmcmFtZS54ICsgKCgoX2EgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLngpIHx8IDApLFxuICAgICAgICAgICAgICAgICAgeTogZnJhbWUueSArICgoKF9iID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi55KSB8fCAwKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUuaW5jbHVkZXMoXCJuXCIpKSB7XG4gICAgICAgICAgICAgIGVsZW1lbnRzSW5GcmFtZS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgIHg6IGZyYW1lLnggKyAoKChfYSA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EueCkgfHwgMCksXG4gICAgICAgICAgICAgICAgICB5OiBmcmFtZS55ICsgKCgoX2IgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnkpIHx8IDApXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLCB0aGlzLnN0YXRlKS5mb3JFYWNoKGVsZW1lbnQgPT4gZWxlbWVudHNUb0hpZ2hsaWdodC5hZGQoZWxlbWVudCkpO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZWxlbWVudHNUb0hpZ2hsaWdodDogWy4uLmVsZW1lbnRzVG9IaWdobGlnaHRdXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLmdldENvbnRleHRNZW51SXRlbXMgPSB0eXBlID0+IHtcbiAgICAgIGNvbnN0IG9wdGlvbnMgPSBbXTtcbiAgICAgIG9wdGlvbnMucHVzaChhY3Rpb25Db3B5QXNQbmcsIGFjdGlvbkNvcHlBc1N2Zyk7IC8vIGNhbnZhcyBjb250ZXh0TWVudVxuICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgICBpZiAodHlwZSA9PT0gXCJjYW52YXNcIikge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICByZXR1cm4gWy4uLm9wdGlvbnMsIGFjdGlvblRvZ2dsZUdyaWRNb2RlLCBhY3Rpb25Ub2dnbGVaZW5Nb2RlLCBhY3Rpb25Ub2dnbGVWaWV3TW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHNdO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFthY3Rpb25QYXN0ZSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcsIGNvcHlUZXh0LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25TZWxlY3RBbGwsIGFjdGlvblVubG9ja0FsbEVsZW1lbnRzLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlT2JqZWN0c1NuYXBNb2RlLCBhY3Rpb25Ub2dnbGVaZW5Nb2RlLCBhY3Rpb25Ub2dnbGVWaWV3TW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHNdO1xuICAgICAgfSAvLyBlbGVtZW50IGNvbnRleHRNZW51XG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuICAgICAgb3B0aW9ucy5wdXNoKGNvcHlUZXh0KTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHJldHVybiBbYWN0aW9uQ29weSwgLi4ub3B0aW9uc107XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBbYWN0aW9uQ3V0LCBhY3Rpb25Db3B5LCBhY3Rpb25QYXN0ZSwgYWN0aW9uU2VsZWN0QWxsRWxlbWVudHNJbkZyYW1lLCBhY3Rpb25SZW1vdmVBbGxFbGVtZW50c0Zyb21GcmFtZSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgLi4ub3B0aW9ucywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQ29weVN0eWxlcywgYWN0aW9uUGFzdGVTdHlsZXMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkdyb3VwLCBhY3Rpb25VbmJpbmRUZXh0LCBhY3Rpb25CaW5kVGV4dCwgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciwgYWN0aW9uVW5ncm91cCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQWRkVG9MaWJyYXJ5LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25TZW5kQmFja3dhcmQsIGFjdGlvbkJyaW5nRm9yd2FyZCwgYWN0aW9uU2VuZFRvQmFjaywgYWN0aW9uQnJpbmdUb0Zyb250LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25GbGlwSG9yaXpvbnRhbCwgYWN0aW9uRmxpcFZlcnRpY2FsLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Ub2dnbGVMaW5lYXJFZGl0b3IsIGFjdGlvbkxpbmssIGFjdGlvbkR1cGxpY2F0ZVNlbGVjdGlvbiwgYWN0aW9uVG9nZ2xlRWxlbWVudExvY2ssIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkRlbGV0ZVNlbGVjdGVkXTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVXaGVlbCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAoaXNQYW5uaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICBkZWx0YVgsXG4gICAgICAgIGRlbHRhWVxuICAgICAgfSA9IGV2ZW50OyAvLyBub3RlIHRoYXQgZXZlbnQuY3RybEtleSBpcyBuZWNlc3NhcnkgdG8gaGFuZGxlIHBpbmNoIHpvb21pbmdcblxuICAgICAgaWYgKGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuY3RybEtleSkge1xuICAgICAgICBjb25zdCBzaWduID0gTWF0aC5zaWduKGRlbHRhWSk7XG4gICAgICAgIGNvbnN0IE1BWF9TVEVQID0gWk9PTV9TVEVQICogMTAwO1xuICAgICAgICBjb25zdCBhYnNEZWx0YSA9IE1hdGguYWJzKGRlbHRhWSk7XG4gICAgICAgIGxldCBkZWx0YSA9IGRlbHRhWTtcblxuICAgICAgICBpZiAoYWJzRGVsdGEgPiBNQVhfU1RFUCkge1xuICAgICAgICAgIGRlbHRhID0gTUFYX1NURVAgKiBzaWduO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG5ld1pvb20gPSB0aGlzLnN0YXRlLnpvb20udmFsdWUgLSBkZWx0YSAvIDEwMDsgLy8gaW5jcmVhc2Ugem9vbSBzdGVwcyB0aGUgbW9yZSB6b29tZWQtaW4gd2UgYXJlIChhcHBsaWVzIHRvID4xMDAlIG9ubHkpXG5cbiAgICAgICAgbmV3Wm9vbSArPSBNYXRoLmxvZzEwKE1hdGgubWF4KDEsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpICogLXNpZ24gKiAvLyByZWR1Y2VkIGFtcGxpZmljYXRpb24gZm9yIHNtYWxsIGRlbHRhcyAoc21hbGwgbW92ZW1lbnRzIG9uIGEgdHJhY2twYWQpXG4gICAgICAgIE1hdGgubWluKDEsIGFic0RlbHRhIC8gMjApO1xuICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgdmlld3BvcnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgICAgdmlld3BvcnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnksXG4gICAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKG5ld1pvb20pXG4gICAgICAgIH0sIHN0YXRlKSksIHtcbiAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgfSkpO1xuICAgICAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gc2Nyb2xsIGhvcml6b250YWxseSB3aGVuIHNoaWZ0IHByZXNzZWRcblxuXG4gICAgICBpZiAoZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoKHtcbiAgICAgICAgICB6b29tLFxuICAgICAgICAgIHNjcm9sbFhcbiAgICAgICAgfSkgPT4gKHtcbiAgICAgICAgICAvLyBvbiBNYWMsIHNoaWZ0K3doZWVsIHRlbmRzIHRvIHJlc3VsdCBpbiBkZWx0YVhcbiAgICAgICAgICBzY3JvbGxYOiBzY3JvbGxYIC0gKGRlbHRhWSB8fCBkZWx0YVgpIC8gem9vbS52YWx1ZVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoKHtcbiAgICAgICAgem9vbSxcbiAgICAgICAgc2Nyb2xsWCxcbiAgICAgICAgc2Nyb2xsWVxuICAgICAgfSkgPT4gKHtcbiAgICAgICAgc2Nyb2xsWDogc2Nyb2xsWCAtIGRlbHRhWCAvIHpvb20udmFsdWUsXG4gICAgICAgIHNjcm9sbFk6IHNjcm9sbFkgLSBkZWx0YVkgLyB6b29tLnZhbHVlXG4gICAgICB9KSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnNhdmVQb2ludGVyID0gKHgsIHksIGJ1dHRvbikgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgaWYgKCF4IHx8ICF5KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgIGNsaWVudFg6IHgsXG4gICAgICAgIGNsaWVudFk6IHlcbiAgICAgIH0sIHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoaXNOYU4oc2NlbmVYKSB8fCBpc05hTihzY2VuZVkpKSB7Ly8gc29tZXRpbWVzIHRoZSBwb2ludGVyIGdvZXMgb2ZmIHNjcmVlblxuICAgICAgfVxuXG4gICAgICBjb25zdCBwb2ludGVyID0ge1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWSxcbiAgICAgICAgdG9vbDogdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIiA/IFwibGFzZXJcIiA6IFwicG9pbnRlclwiXG4gICAgICB9O1xuICAgICAgKF9iID0gKF9hID0gdGhpcy5wcm9wcykub25Qb2ludGVyVXBkYXRlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwge1xuICAgICAgICBwb2ludGVyLFxuICAgICAgICBidXR0b24sXG4gICAgICAgIHBvaW50ZXJzTWFwOiBnZXN0dXJlLnBvaW50ZXJzXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldFNob3VsZENhY2hlSWdub3JlWm9vbURlYm91bmNlZCA9IGRlYm91bmNlKCgpID0+IHtcbiAgICAgIGlmICghdGhpcy51bm1vdW50ZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LCAzMDApO1xuXG4gICAgdGhpcy51cGRhdGVET01SZWN0ID0gY2IgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBpZiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkge1xuICAgICAgICBjb25zdCBleGNhbGlkcmF3Q29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgbGVmdDogb2Zmc2V0TGVmdCxcbiAgICAgICAgICB0b3A6IG9mZnNldFRvcFxuICAgICAgICB9ID0gZXhjYWxpZHJhd0NvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHdpZHRoOiBjdXJyZW50V2lkdGgsXG4gICAgICAgICAgaGVpZ2h0OiBjdXJyZW50SGVpZ2h0LFxuICAgICAgICAgIG9mZnNldFRvcDogY3VycmVudE9mZnNldFRvcCxcbiAgICAgICAgICBvZmZzZXRMZWZ0OiBjdXJyZW50T2Zmc2V0TGVmdFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBpZiAod2lkdGggPT09IGN1cnJlbnRXaWR0aCAmJiBoZWlnaHQgPT09IGN1cnJlbnRIZWlnaHQgJiYgb2Zmc2V0TGVmdCA9PT0gY3VycmVudE9mZnNldExlZnQgJiYgb2Zmc2V0VG9wID09PSBjdXJyZW50T2Zmc2V0VG9wKSB7XG4gICAgICAgICAgaWYgKGNiKSB7XG4gICAgICAgICAgICBjYigpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHdpZHRoLFxuICAgICAgICAgIGhlaWdodCxcbiAgICAgICAgICBvZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcFxuICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgY2IgJiYgY2IoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMucmVmcmVzaCA9ICgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5nZXRDYW52YXNPZmZzZXRzKCkpKTtcbiAgICB9O1xuXG4gICAgY29uc3QgZGVmYXVsdEFwcFN0YXRlID0gZ2V0RGVmYXVsdEFwcFN0YXRlKCk7XG4gICAgY29uc3Qge1xuICAgICAgZXhjYWxpZHJhd0FQSSxcbiAgICAgIHZpZXdNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgemVuTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIGdyaWRNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgb2JqZWN0c1NuYXBNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgdGhlbWUgPSBkZWZhdWx0QXBwU3RhdGUudGhlbWUsXG4gICAgICBuYW1lID0gZGVmYXVsdEFwcFN0YXRlLm5hbWVcbiAgICB9ID0gcHJvcHM7XG4gICAgdGhpcy5zdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGRlZmF1bHRBcHBTdGF0ZSksIHtcbiAgICAgIHRoZW1lLFxuICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgfSksIHRoaXMuZ2V0Q2FudmFzT2Zmc2V0cygpKSwge1xuICAgICAgdmlld01vZGVFbmFibGVkLFxuICAgICAgemVuTW9kZUVuYWJsZWQsXG4gICAgICBvYmplY3RzU25hcE1vZGVFbmFibGVkLFxuICAgICAgZ3JpZFNpemU6IGdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGwsXG4gICAgICBuYW1lLFxuICAgICAgd2lkdGg6IHdpbmRvdy5pbm5lcldpZHRoLFxuICAgICAgaGVpZ2h0OiB3aW5kb3cuaW5uZXJIZWlnaHRcbiAgICB9KTtcbiAgICB0aGlzLmlkID0gbmFub2lkKCk7XG4gICAgdGhpcy5saWJyYXJ5ID0gbmV3IExpYnJhcnkodGhpcyk7XG4gICAgdGhpcy5zY2VuZSA9IG5ldyBTY2VuZSgpO1xuICAgIHRoaXMuY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgICB0aGlzLnJjID0gcm91Z2guY2FudmFzKHRoaXMuY2FudmFzKTtcbiAgICB0aGlzLnJlbmRlcmVyID0gbmV3IFJlbmRlcmVyKHRoaXMuc2NlbmUpO1xuXG4gICAgaWYgKGV4Y2FsaWRyYXdBUEkpIHtcbiAgICAgIGNvbnN0IGFwaSA9IHtcbiAgICAgICAgdXBkYXRlU2NlbmU6IHRoaXMudXBkYXRlU2NlbmUsXG4gICAgICAgIHVwZGF0ZUxpYnJhcnk6IHRoaXMubGlicmFyeS51cGRhdGVMaWJyYXJ5LFxuICAgICAgICBhZGRGaWxlczogdGhpcy5hZGRGaWxlcyxcbiAgICAgICAgcmVzZXRTY2VuZTogdGhpcy5yZXNldFNjZW5lLFxuICAgICAgICBnZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZDogdGhpcy5nZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCxcbiAgICAgICAgaGlzdG9yeToge1xuICAgICAgICAgIGNsZWFyOiB0aGlzLnJlc2V0SGlzdG9yeVxuICAgICAgICB9LFxuICAgICAgICBzY3JvbGxUb0NvbnRlbnQ6IHRoaXMuc2Nyb2xsVG9Db250ZW50LFxuICAgICAgICBnZXRTY2VuZUVsZW1lbnRzOiB0aGlzLmdldFNjZW5lRWxlbWVudHMsXG4gICAgICAgIGdldEFwcFN0YXRlOiAoKSA9PiB0aGlzLnN0YXRlLFxuICAgICAgICBnZXRGaWxlczogKCkgPT4gdGhpcy5maWxlcyxcbiAgICAgICAgcmVmcmVzaDogdGhpcy5yZWZyZXNoLFxuICAgICAgICBzZXRUb2FzdDogdGhpcy5zZXRUb2FzdCxcbiAgICAgICAgaWQ6IHRoaXMuaWQsXG4gICAgICAgIHNldEFjdGl2ZVRvb2w6IHRoaXMuc2V0QWN0aXZlVG9vbCxcbiAgICAgICAgc2V0Q3Vyc29yOiB0aGlzLnNldEN1cnNvcixcbiAgICAgICAgcmVzZXRDdXJzb3I6IHRoaXMucmVzZXRDdXJzb3IsXG4gICAgICAgIHVwZGF0ZUZyYW1lUmVuZGVyaW5nOiB0aGlzLnVwZGF0ZUZyYW1lUmVuZGVyaW5nLFxuICAgICAgICB0b2dnbGVTaWRlYmFyOiB0aGlzLnRvZ2dsZVNpZGViYXIsXG4gICAgICAgIG9uQ2hhbmdlOiBjYiA9PiB0aGlzLm9uQ2hhbmdlRW1pdHRlci5vbihjYiksXG4gICAgICAgIG9uUG9pbnRlckRvd246IGNiID0+IHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIub24oY2IpLFxuICAgICAgICBvblBvaW50ZXJVcDogY2IgPT4gdGhpcy5vblBvaW50ZXJVcEVtaXR0ZXIub24oY2IpXG4gICAgICB9O1xuXG4gICAgICBpZiAodHlwZW9mIGV4Y2FsaWRyYXdBUEkgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBleGNhbGlkcmF3QVBJKGFwaSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiZXhjYWxpZHJhd0FQSSBzaG91bGQgYmUgYSBmdW5jdGlvbiFcIik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWUgPSB7XG4gICAgICBjb250YWluZXI6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LFxuICAgICAgaWQ6IHRoaXMuaWRcbiAgICB9O1xuICAgIHRoaXMuZm9udHMgPSBuZXcgRm9udHMoe1xuICAgICAgc2NlbmU6IHRoaXMuc2NlbmUsXG4gICAgICBvblNjZW5lVXBkYXRlZDogdGhpcy5vblNjZW5lVXBkYXRlZFxuICAgIH0pO1xuICAgIHRoaXMuaGlzdG9yeSA9IG5ldyBIaXN0b3J5KCk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyID0gbmV3IEFjdGlvbk1hbmFnZXIodGhpcy5zeW5jQWN0aW9uUmVzdWx0LCAoKSA9PiB0aGlzLnN0YXRlLCAoKSA9PiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBbGwoYWN0aW9ucyk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVVuZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVJlZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gIH1cblxuICBvbldpbmRvd01lc3NhZ2UoZXZlbnQpIHtcbiAgICBpZiAoZXZlbnQub3JpZ2luICE9PSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiICYmIGV2ZW50Lm9yaWdpbiAhPT0gXCJodHRwczovL3d3dy55b3V0dWJlLmNvbVwiKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IGRhdGEgPSBudWxsO1xuXG4gICAgdHJ5IHtcbiAgICAgIGRhdGEgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG5cbiAgICBpZiAoIWRhdGEpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKGV2ZW50Lm9yaWdpbikge1xuICAgICAgY2FzZSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiOlxuICAgICAgICAvL0FsbG93aW5nIGZvciBtdWx0aXBsZSBpbnN0YW5jZXMgb2YgRXhjYWxpZHJhdyBydW5uaW5nIGluIHRoZSB3aW5kb3dcbiAgICAgICAgaWYgKGRhdGEubWV0aG9kID09PSBcInBhdXNlZFwiKSB7XG4gICAgICAgICAgbGV0IHNvdXJjZSA9IG51bGw7XG4gICAgICAgICAgY29uc3QgaWZyYW1lcyA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvckFsbChcImlmcmFtZS5leGNhbGlkcmF3X19lbWJlZGRhYmxlXCIpO1xuXG4gICAgICAgICAgaWYgKCFpZnJhbWVzKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBmb3IgKGNvbnN0IGlmcmFtZSBvZiBpZnJhbWVzKSB7XG4gICAgICAgICAgICBpZiAoaWZyYW1lLmNvbnRlbnRXaW5kb3cgPT09IGV2ZW50LnNvdXJjZSkge1xuICAgICAgICAgICAgICBzb3VyY2UgPSBpZnJhbWUuY29udGVudFdpbmRvdztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzb3VyY2UgPT09IG51bGwgfHwgc291cmNlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBzb3VyY2UucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgbWV0aG9kOiBkYXRhLnZhbHVlID8gXCJwbGF5XCIgOiBcInBhdXNlXCIsXG4gICAgICAgICAgICB2YWx1ZTogdHJ1ZVxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBcImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tXCI6XG4gICAgICAgIGlmIChkYXRhLmV2ZW50ID09PSBcImluZm9EZWxpdmVyeVwiICYmIGRhdGEuaW5mbyAmJiBkYXRhLmlkICYmIHR5cGVvZiBkYXRhLmluZm8ucGxheWVyU3RhdGUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICBjb25zdCBpZCA9IGRhdGEuaWQ7XG4gICAgICAgICAgY29uc3QgcGxheWVyU3RhdGUgPSBkYXRhLmluZm8ucGxheWVyU3RhdGU7XG5cbiAgICAgICAgICBpZiAoT2JqZWN0LnZhbHVlcyhZT1VUVUJFX1NUQVRFUykuaW5jbHVkZXMocGxheWVyU3RhdGUpKSB7XG4gICAgICAgICAgICBZT1VUVUJFX1ZJREVPX1NUQVRFUy5zZXQoaWQsIHBsYXllclN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICB1cGRhdGVFbWJlZGRhYmxlUmVmKGlkLCByZWYpIHtcbiAgICBpZiAocmVmKSB7XG4gICAgICB0aGlzLmlGcmFtZVJlZnMuc2V0KGlkLCByZWYpO1xuICAgIH1cbiAgfVxuXG4gIGdldEhUTUxJRnJhbWVFbGVtZW50KGlkKSB7XG4gICAgcmV0dXJuIHRoaXMuaUZyYW1lUmVmcy5nZXQoaWQpO1xuICB9XG5cbiAgaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKGVsZW1lbnQpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG5cbiAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpID09PSBlbGVtZW50ICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiYWN0aXZlXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9IC8vIFRoZSBkZWxheSBzZXJ2ZXMgdHdvIHB1cnBvc2VzXG4gICAgLy8gMS4gVG8gcHJldmVudCBmaXJzdCBjbGljayBwcm9wYWdhdGluZyB0byBpZnJhbWUgb24gbW9iaWxlLFxuICAgIC8vICAgIGVsc2UgdGhlIGNsaWNrIHdpbGwgaW1tZWRpYXRlbHkgc3RhcnQgYW5kIHN0b3AgdGhlIHZpZGVvXG4gICAgLy8gMi4gSWYgdGhlIHVzZXIgZG91YmxlIGNsaWNrcyB0aGUgZnJhbWUgY2VudGVyIHRvIGFjdGl2YXRlIGl0XG4gICAgLy8gICAgd2l0aG91dCB0aGUgZGVsYXkgeW91dHViZSB3aWxsIGltbWVkaWF0ZWx5IG9wZW4gdGhlIHZpZGVvXG4gICAgLy8gICAgaW4gZnVsbHNjcmVlbiBtb2RlXG5cblxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IHtcbiAgICAgICAgICBlbGVtZW50LFxuICAgICAgICAgIHN0YXRlOiBcImFjdGl2ZVwiXG4gICAgICAgIH0sXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgIFtlbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGlvbkVsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH0sIDEwMCk7XG4gICAgY29uc3QgaWZyYW1lID0gdGhpcy5nZXRIVE1MSUZyYW1lRWxlbWVudChlbGVtZW50LmlkKTtcblxuICAgIGlmICghKGlmcmFtZSA9PT0gbnVsbCB8fCBpZnJhbWUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGlmcmFtZS5jb250ZW50V2luZG93KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpZnJhbWUuc3JjLmluY2x1ZGVzKFwieW91dHViZVwiKSkge1xuICAgICAgY29uc3Qgc3RhdGUgPSBZT1VUVUJFX1ZJREVPX1NUQVRFUy5nZXQoZWxlbWVudC5pZCk7XG5cbiAgICAgIGlmICghc3RhdGUpIHtcbiAgICAgICAgWU9VVFVCRV9WSURFT19TVEFURVMuc2V0KGVsZW1lbnQuaWQsIFlPVVRVQkVfU1RBVEVTLlVOU1RBUlRFRCk7XG4gICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBldmVudDogXCJsaXN0ZW5pbmdcIixcbiAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgfVxuXG4gICAgICBzd2l0Y2ggKHN0YXRlKSB7XG4gICAgICAgIGNhc2UgWU9VVFVCRV9TVEFURVMuUExBWUlORzpcbiAgICAgICAgY2FzZSBZT1VUVUJFX1NUQVRFUy5CVUZGRVJJTkc6XG4gICAgICAgICAgKF9jID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBhdXNlVmlkZW9cIixcbiAgICAgICAgICAgIGFyZ3M6IFwiXCJcbiAgICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgKF9kID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBsYXlWaWRlb1wiLFxuICAgICAgICAgICAgYXJnczogXCJcIlxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGlmcmFtZS5zcmMuaW5jbHVkZXMoXCJwbGF5ZXIudmltZW8uY29tXCIpKSB7XG4gICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIG1ldGhvZDogXCJwYXVzZWRcIiAvL3ZpZGVvIHBsYXkvcGF1c2UgaW4gb25XaW5kb3dNZXNzYWdlIGhhbmRsZXJcblxuICAgICAgfSksIFwiKlwiKTtcbiAgICB9XG4gIH1cblxuICBpc0VtYmVkZGFibGVDZW50ZXIoZWwsIGV2ZW50LCBzY2VuZVgsIHNjZW5lWSkge1xuICAgIHZhciBfYSwgX2I7XG5cbiAgICByZXR1cm4gZWwgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQuc2hpZnRLZXkgJiYgIWV2ZW50Lm1ldGFLZXkgJiYgIWV2ZW50LmN0cmxLZXkgJiYgKCgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSAhPT0gZWwgfHwgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJob3ZlclwiIHx8ICF0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpICYmIHNjZW5lWCA+PSBlbC54ICsgZWwud2lkdGggLyAzICYmIHNjZW5lWCA8PSBlbC54ICsgMiAqIGVsLndpZHRoIC8gMyAmJiBzY2VuZVkgPj0gZWwueSArIGVsLmhlaWdodCAvIDMgJiYgc2NlbmVZIDw9IGVsLnkgKyAyICogZWwuaGVpZ2h0IC8gMztcbiAgfVxuXG4gIHJlbmRlckVtYmVkZGFibGVzKCkge1xuICAgIGNvbnN0IHNjYWxlID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRXaWR0aCA9IHRoaXMuc3RhdGUud2lkdGg7XG4gICAgY29uc3Qgbm9ybWFsaXplZEhlaWdodCA9IHRoaXMuc3RhdGUuaGVpZ2h0O1xuICAgIGNvbnN0IGVtYmVkZGFibGVFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsID0+IGlzRW1iZWRkYWJsZUVsZW1lbnQoZWwpICYmICEhZWwudmFsaWRhdGVkKTtcbiAgICByZXR1cm4gX2pzeChfRnJhZ21lbnQsIHtcbiAgICAgIGNoaWxkcmVuOiBlbWJlZGRhYmxlRWxlbWVudHMubWFwKGVsID0+IHtcbiAgICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaCwgX2o7XG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IGVsLngsXG4gICAgICAgICAgc2NlbmVZOiBlbC55XG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBlbWJlZExpbmsgPSBnZXRFbWJlZExpbmsodG9WYWxpZFVSTChlbC5saW5rIHx8IFwiXCIpKTtcbiAgICAgICAgY29uc3QgaXNWaXNpYmxlID0gaXNFbGVtZW50SW5WaWV3cG9ydChlbCwgbm9ybWFsaXplZFdpZHRoLCBub3JtYWxpemVkSGVpZ2h0LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgaXNBY3RpdmUgPSAoKF9hID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgPT09IGVsICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiYWN0aXZlXCI7XG4gICAgICAgIGNvbnN0IGlzSG92ZXJlZCA9ICgoX2MgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5lbGVtZW50KSA9PT0gZWwgJiYgKChfZCA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnN0YXRlKSA9PT0gXCJob3ZlclwiO1xuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBjbGFzc05hbWU6IGNsc3goXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlLWNvbnRhaW5lclwiLCB7XG4gICAgICAgICAgICBcImlzLWhvdmVyZWRcIjogaXNIb3ZlcmVkXG4gICAgICAgICAgfSksXG4gICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgIHRyYW5zZm9ybTogaXNWaXNpYmxlID8gYHRyYW5zbGF0ZSgke3ggLSB0aGlzLnN0YXRlLm9mZnNldExlZnR9cHgsICR7eSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wfXB4KSBzY2FsZSgke3NjYWxlfSlgIDogXCJub25lXCIsXG4gICAgICAgICAgICBkaXNwbGF5OiBpc1Zpc2libGUgPyBcImJsb2NrXCIgOiBcIm5vbmVcIixcbiAgICAgICAgICAgIG9wYWNpdHk6IGVsLm9wYWNpdHkgLyAxMDAsXG4gICAgICAgICAgICBbXCItLWVtYmVkZGFibGUtcmFkaXVzXCJdOiBgJHtnZXRDb3JuZXJSYWRpdXMoTWF0aC5taW4oZWwud2lkdGgsIGVsLmhlaWdodCksIGVsKX1weGBcbiAgICAgICAgICB9XG4gICAgICAgIH0sIHtcbiAgICAgICAgICBjaGlsZHJlbjogX2pzeHMoXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAvL3RoaXMgaXMgYSBoYWNrIHRoYXQgYWRkcmVzc2VzIGlzc2Ugd2l0aCBlbWJlZGRlZCBleGNhbGlkcmF3LmNvbSBlbWJlZGRhYmxlXG4gICAgICAgICAgICAvL2h0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC82NjkxI2lzc3VlY29tbWVudC0xNjA3MzgzOTM4XG5cbiAgICAgICAgICAgIC8qcmVmPXsocmVmKSA9PiB7XG4gICAgICAgICAgICAgIGlmICghdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICAgICAgICAgIGNvbnN0IHNoID0gY29udGFpbmVyLnNjcm9sbEhlaWdodDtcbiAgICAgICAgICAgICAgY29uc3QgY2ggPSBjb250YWluZXIuY2xpZW50SGVpZ2h0O1xuICAgICAgICAgICAgICBpZiAoc2ggIT09IGNoKSB7XG4gICAgICAgICAgICAgICAgY29udGFpbmVyLnN0eWxlLmhlaWdodCA9IGAke3NofXB4YDtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgIGNvbnRhaW5lci5zdHlsZS5oZWlnaHQgPSBgMTAwJWA7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH19Ki9cbiAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlLWNvbnRhaW5lcl9faW5uZXJcIixcbiAgICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICAgIHdpZHRoOiBpc1Zpc2libGUgPyBgJHtlbC53aWR0aH1weGAgOiAwLFxuICAgICAgICAgICAgICBoZWlnaHQ6IGlzVmlzaWJsZSA/IGAke2VsLmhlaWdodH1weGAgOiAwLFxuICAgICAgICAgICAgICB0cmFuc2Zvcm06IGlzVmlzaWJsZSA/IGByb3RhdGUoJHtlbC5hbmdsZX1yYWQpYCA6IFwibm9uZVwiLFxuICAgICAgICAgICAgICBwb2ludGVyRXZlbnRzOiBpc0FjdGl2ZSA/IFBPSU5URVJfRVZFTlRTLmVuYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgIGNoaWxkcmVuOiBbaXNIb3ZlcmVkICYmIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlLWhpbnRcIlxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICBjaGlsZHJlbjogdChcImJ1dHRvbnMuZW1iZWRkYWJsZUludGVyYWN0aW9uQnV0dG9uXCIpXG4gICAgICAgICAgICB9KSksIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlX19vdXRlclwiLFxuICAgICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICAgIHBhZGRpbmc6IGAke2VsLnN0cm9rZVdpZHRofXB4YFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgIGNoaWxkcmVuOiAoX2cgPSAoX2YgPSAoX2UgPSB0aGlzLnByb3BzKS5yZW5kZXJFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuY2FsbChfZSwgZWwsIHRoaXMuc3RhdGUpKSAhPT0gbnVsbCAmJiBfZyAhPT0gdm9pZCAwID8gX2cgOiBfanN4KFwiaWZyYW1lXCIsIHtcbiAgICAgICAgICAgICAgICByZWY6IHJlZiA9PiB0aGlzLnVwZGF0ZUVtYmVkZGFibGVSZWYoZWwuaWQsIHJlZiksXG4gICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGVcIixcbiAgICAgICAgICAgICAgICBzcmNEb2M6IChlbWJlZExpbmsgPT09IG51bGwgfHwgZW1iZWRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbWJlZExpbmsudHlwZSkgPT09IFwiZG9jdW1lbnRcIiA/IGVtYmVkTGluay5zcmNkb2ModGhpcy5zdGF0ZS50aGVtZSkgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgc3JjOiAoZW1iZWRMaW5rID09PSBudWxsIHx8IGVtYmVkTGluayA9PT0gdm9pZCAwID8gdm9pZCAwIDogZW1iZWRMaW5rLnR5cGUpICE9PSBcImRvY3VtZW50XCIgPyAoX2ggPSBlbWJlZExpbmsgPT09IG51bGwgfHwgZW1iZWRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbWJlZExpbmsubGluaykgIT09IG51bGwgJiYgX2ggIT09IHZvaWQgMCA/IF9oIDogXCJcIiA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAvLyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3EvMTg0NzAwMTVcbiAgICAgICAgICAgICAgICBzY3JvbGxpbmc6IFwibm9cIixcbiAgICAgICAgICAgICAgICByZWZlcnJlclBvbGljeTogXCJuby1yZWZlcnJlci13aGVuLWRvd25ncmFkZVwiLFxuICAgICAgICAgICAgICAgIHRpdGxlOiBcIkV4Y2FsaWRyYXcgRW1iZWRkZWQgQ29udGVudFwiLFxuICAgICAgICAgICAgICAgIGFsbG93OiBcImFjY2VsZXJvbWV0ZXI7IGF1dG9wbGF5OyBjbGlwYm9hcmQtd3JpdGU7IGVuY3J5cHRlZC1tZWRpYTsgZ3lyb3Njb3BlOyBwaWN0dXJlLWluLXBpY3R1cmVcIixcbiAgICAgICAgICAgICAgICBhbGxvd0Z1bGxTY3JlZW46IHRydWUsXG4gICAgICAgICAgICAgICAgc2FuZGJveDogYCR7KChfaiA9IGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay5zYW5kYm94KSA9PT0gbnVsbCB8fCBfaiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2ouYWxsb3dTYW1lT3JpZ2luKSA/IFwiYWxsb3ctc2FtZS1vcmlnaW5cIiA6IFwiXCJ9IGFsbG93LXNjcmlwdHMgYWxsb3ctZm9ybXMgYWxsb3ctcG9wdXBzIGFsbG93LXBvcHVwcy10by1lc2NhcGUtc2FuZGJveCBhbGxvdy1wcmVzZW50YXRpb24gYWxsb3ctZG93bmxvYWRzYFxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSkpXVxuICAgICAgICAgIH0pKVxuICAgICAgICB9KSwgZWwuaWQpO1xuICAgICAgfSlcbiAgICB9KTtcbiAgfVxuXG4gIHJlbmRlcigpIHtcbiAgICB2YXIgX2EsIF9iLCBfYztcblxuICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgY29uc3Qge1xuICAgICAgcmVuZGVyVG9wUmlnaHRVSSxcbiAgICAgIHJlbmRlckN1c3RvbVN0YXRzXG4gICAgfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3QgdmVyc2lvbk5vbmNlID0gdGhpcy5zY2VuZS5nZXRWZXJzaW9uTm9uY2UoKTtcbiAgICBjb25zdCB7XG4gICAgICBjYW52YXNFbGVtZW50cyxcbiAgICAgIHZpc2libGVFbGVtZW50c1xuICAgIH0gPSB0aGlzLnJlbmRlcmVyLmdldFJlbmRlcmFibGVFbGVtZW50cyh7XG4gICAgICB2ZXJzaW9uTm9uY2UsXG4gICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb20sXG4gICAgICBvZmZzZXRMZWZ0OiB0aGlzLnN0YXRlLm9mZnNldExlZnQsXG4gICAgICBvZmZzZXRUb3A6IHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZLFxuICAgICAgaGVpZ2h0OiB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgIHdpZHRoOiB0aGlzLnN0YXRlLndpZHRoLFxuICAgICAgZWRpdGluZ0VsZW1lbnQ6IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQsXG4gICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkXG4gICAgfSk7XG4gICAgY29uc3Qgc2hvdWxkQmxvY2tQb2ludGVyRXZlbnRzID0gISh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICYmIGlzTGluZWFyRWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSkgJiYgKHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCB8fCB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLnJlc2l6aW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsYXNlclwiICYmIC8vIHRlY2huaWNhbGx5IHdlIGNhbiBqdXN0IHRlc3Qgb24gdGhpcyBvbmNlIHdlIG1ha2UgaXQgbW9yZSBzYWZlXG4gICAgdGhpcy5zdGF0ZS5jdXJzb3JCdXR0b24gPT09IFwiZG93blwiIHx8IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQgJiYgIWlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkpO1xuICAgIHJldHVybiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgY2xhc3NOYW1lOiBjbHN4KFwiZXhjYWxpZHJhdyBleGNhbGlkcmF3LWNvbnRhaW5lclwiLCB7XG4gICAgICAgIFwiZXhjYWxpZHJhdy0tdmlldy1tb2RlXCI6IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkLFxuICAgICAgICBcImV4Y2FsaWRyYXctLW1vYmlsZVwiOiB0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGVcbiAgICAgIH0pLFxuICAgICAgc3R5bGU6IHtcbiAgICAgICAgW1wiLS11aS1wb2ludGVyRXZlbnRzXCJdOiBzaG91bGRCbG9ja1BvaW50ZXJFdmVudHMgPyBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZCA6IFBPSU5URVJfRVZFTlRTLmVuYWJsZWRcbiAgICAgIH0sXG4gICAgICByZWY6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZixcbiAgICAgIG9uRHJvcDogdGhpcy5oYW5kbGVBcHBPbkRyb3AsXG4gICAgICB0YWJJbmRleDogMCxcbiAgICAgIG9uS2V5RG93bjogdGhpcy5wcm9wcy5oYW5kbGVLZXlib2FyZEdsb2JhbGx5ID8gdW5kZWZpbmVkIDogdGhpcy5vbktleURvd25cbiAgICB9LCB7XG4gICAgICBjaGlsZHJlbjogX2pzeChBcHBDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgdmFsdWU6IHRoaXNcbiAgICAgIH0sIHtcbiAgICAgICAgY2hpbGRyZW46IF9qc3goQXBwUHJvcHNDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICB2YWx1ZTogdGhpcy5wcm9wc1xuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgdmFsdWU6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlXG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRGV2aWNlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmRldmljZVxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICBjaGlsZHJlbjogX2pzeChFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5zZXRBcHBTdGF0ZVxuICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5zdGF0ZVxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4cyhFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKClcbiAgICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IFtfanN4cyhFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmFjdGlvbk1hbmFnZXJcbiAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbX2pzeHMoTGF5ZXJVSSwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBmaWxlczogdGhpcy5maWxlcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldEFwcFN0YXRlOiB0aGlzLnNldEFwcFN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uTWFuYWdlcjogdGhpcy5hY3Rpb25NYW5hZ2VyLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkxvY2tUb2dnbGU6IHRoaXMudG9nZ2xlTG9jayxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUGVuTW9kZVRvZ2dsZTogdGhpcy50b2dnbGVQZW5Nb2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25IYW5kVG9vbFRvZ2dsZTogdGhpcy5vbkhhbmRUb29sVG9nZ2xlLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGFuZ0NvZGU6IGdldExhbmd1YWdlKCkuY29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlclRvcFJpZ2h0VUk6IHJlbmRlclRvcFJpZ2h0VUksXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJDdXN0b21TdGF0czogcmVuZGVyQ3VzdG9tU3RhdHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzaG93RXhpdFplbk1vZGVCdG46IHR5cGVvZiAoKF9hID0gdGhpcy5wcm9wcykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnplbk1vZGVFbmFibGVkKSA9PT0gXCJ1bmRlZmluZWRcIiAmJiB0aGlzLnN0YXRlLnplbk1vZGVFbmFibGVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgVUlPcHRpb25zOiB0aGlzLnByb3BzLlVJT3B0aW9ucyxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uRXhwb3J0SW1hZ2U6IHRoaXMub25FeHBvcnRJbWFnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlcldlbGNvbWVTY3JlZW46ICF0aGlzLnN0YXRlLmlzTG9hZGluZyAmJiB0aGlzLnN0YXRlLnNob3dXZWxjb21lU2NyZWVuICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiICYmICF0aGlzLnN0YXRlLnplbk1vZGVFbmFibGVkICYmICF0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcDogdGhpcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzQ29sbGFib3JhdGluZzogdGhpcy5wcm9wcy5pc0NvbGxhYm9yYXRpbmdcbiAgICAgICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW3RoaXMucHJvcHMuY2hpbGRyZW4sIHRoaXMuc3RhdGUub3BlbkRpYWxvZyA9PT0gXCJtZXJtYWlkXCIgJiYgX2pzeChNZXJtYWlkVG9FeGNhbGlkcmF3LCB7fSldXG4gICAgICAgICAgICAgICAgICAgICAgfSkpLCBfanN4KFwiZGl2XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3LXRleHRFZGl0b3JDb250YWluZXJcIlxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KFwiZGl2XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3LWNvbnRleHRNZW51Q29udGFpbmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgX2pzeChcImRpdlwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhdy1leWUtZHJvcHBlci1jb250YWluZXJcIlxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KExhc2VyVG9vbE92ZXJsYXksIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hbmFnZXI6IHRoaXMubGFzZXJQYXRoTWFuYWdlclxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiAhdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiB0aGlzLnN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cCAmJiBfanN4KEh5cGVybGluaywge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudDogc2VsZWN0ZWRFbGVtZW50c1swXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldEFwcFN0YXRlOiB0aGlzLnNldEFwcFN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25MaW5rT3BlbjogdGhpcy5wcm9wcy5vbkxpbmtPcGVuLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0VG9hc3Q6IHRoaXMuc2V0VG9hc3RcbiAgICAgICAgICAgICAgICAgICAgICB9LCBzZWxlY3RlZEVsZW1lbnRzWzBdLmlkKSwgdGhpcy5zdGF0ZS50b2FzdCAhPT0gbnVsbCAmJiBfanN4KFRvYXN0LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiB0aGlzLnN0YXRlLnRvYXN0Lm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkNsb3NlOiAoKSA9PiB0aGlzLnNldFRvYXN0KG51bGwpLFxuICAgICAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IHRoaXMuc3RhdGUudG9hc3QuZHVyYXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICBjbG9zYWJsZTogdGhpcy5zdGF0ZS50b2FzdC5jbG9zYWJsZVxuICAgICAgICAgICAgICAgICAgICAgIH0pLCB0aGlzLnN0YXRlLmNvbnRleHRNZW51ICYmIF9qc3goQ29udGV4dE1lbnUsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW1zOiB0aGlzLnN0YXRlLmNvbnRleHRNZW51Lml0ZW1zLFxuICAgICAgICAgICAgICAgICAgICAgICAgdG9wOiB0aGlzLnN0YXRlLmNvbnRleHRNZW51LnRvcCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxlZnQ6IHRoaXMuc3RhdGUuY29udGV4dE1lbnUubGVmdCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGlvbk1hbmFnZXI6IHRoaXMuYWN0aW9uTWFuYWdlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xvc2U6IGNhbGxiYWNrID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dE1lbnU6IG51bGxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayA9PT0gbnVsbCB8fCBjYWxsYmFjayA9PT0gdm9pZCAwID8gdm9pZCAwIDogY2FsbGJhY2soKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goU3RhdGljQ2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmM6IHRoaXMucmMsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogY2FudmFzRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB2aXNpYmxlRWxlbWVudHM6IHZpc2libGVFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb25Ob25jZTogdmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uTm9uY2U6IChfYiA9IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyQ29uZmlnOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlQ2FjaGU6IHRoaXMuaW1hZ2VDYWNoZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaXNFeHBvcnRpbmc6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJHcmlkOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goSW50ZXJhY3RpdmVDYW52YXMsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lclJlZjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmludGVyYWN0aXZlQ2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IGNhbnZhc0VsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZUVsZW1lbnRzOiB2aXNpYmxlRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzOiBzZWxlY3RlZEVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmVyc2lvbk5vbmNlOiB2ZXJzaW9uTm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25Ob25jZTogKF9jID0gdGhpcy5zdGF0ZS5zZWxlY3Rpb25FbGVtZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MudmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGU6IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJJbnRlcmFjdGl2ZVNjZW5lQ2FsbGJhY2s6IHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlQ2FudmFzUmVmOiB0aGlzLmhhbmRsZUludGVyYWN0aXZlQ2FudmFzUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Db250ZXh0TWVudTogdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlck1vdmU6IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJVcDogdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJDYW5jZWw6IHRoaXMucmVtb3ZlUG9pbnRlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uVG91Y2hNb3ZlOiB0aGlzLmhhbmRsZVRvdWNoTW92ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlckRvd246IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24sXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkRvdWJsZUNsaWNrOiB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHRoaXMucmVuZGVyRnJhbWVOYW1lcygpXVxuICAgICAgICAgICAgICAgICAgICB9KSksIHRoaXMucmVuZGVyRW1iZWRkYWJsZXMoKV1cbiAgICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgIH0pKVxuICAgICAgICB9KSlcbiAgICAgIH0pKVxuICAgIH0pKTtcbiAgfVxuXG4gIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgIHZhciBfYTtcblxuICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB0aGlzLnVubW91bnRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWUuY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG5cbiAgICAgIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gRU5WLlRFU1QgfHwgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09IFwicHJvZHVjdGlvblwiKSB7XG4gICAgICAgIGNvbnN0IHNldFN0YXRlID0gdGhpcy5zZXRTdGF0ZS5iaW5kKHRoaXMpO1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh3aW5kb3cuaCwge1xuICAgICAgICAgIHN0YXRlOiB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICBnZXQ6ICgpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBzZXRTdGF0ZToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6ICguLi5hcmdzKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLnNldFN0YXRlKC4uLmFyZ3MpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgYXBwOiB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogdGhpc1xuICAgICAgICAgIH0sXG4gICAgICAgICAgaGlzdG9yeToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHRoaXMuaGlzdG9yeVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2NlbmUuYWRkQ2FsbGJhY2sodGhpcy5vblNjZW5lVXBkYXRlZCk7XG4gICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXJzKCk7XG5cbiAgICAgIGlmICh0aGlzLnByb3BzLmF1dG9Gb2N1cyAmJiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkge1xuICAgICAgICB0aGlzLmZvY3VzQ29udGFpbmVyKCk7XG4gICAgICB9XG5cbiAgICAgIGlmICggLy8gYm91bmRpbmcgcmVjdHMgZG9uJ3Qgd29yayBpbiB0ZXN0cyBzbyB1cGRhdGluZ1xuICAgICAgLy8gdGhlIHN0YXRlIG9uIGluaXQgd291bGQgcmVzdWx0IGluIG1ha2luZyB0aGUgdGVzdCBlbnZpcm8gcnVuXG4gICAgICAvLyBpbiBtb2JpbGUgYnJlYWtwb2ludCAoMCB3aWR0aC9oZWlnaHQpLCBtYWtpbmcgZXZlcnl0aGluZyBmYWlsXG4gICAgICAhaXNUZXN0RW52KCkpIHtcbiAgICAgICAgdGhpcy5yZWZyZXNoVmlld3BvcnRCcmVha3BvaW50cygpO1xuICAgICAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cygpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3VwcG9ydHNSZXNpemVPYnNlcnZlciAmJiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkge1xuICAgICAgICB0aGlzLnJlc2l6ZU9ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKCgpID0+IHtcbiAgICAgICAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cygpO1xuICAgICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgKF9hID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm9ic2VydmUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzZWFyY2hQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2guc2xpY2UoMSkpO1xuXG4gICAgICBpZiAoc2VhcmNoUGFyYW1zLmhhcyhcIndlYi1zaGFyZS10YXJnZXRcIikpIHtcbiAgICAgICAgLy8gT2J0YWluIGEgZmlsZSB0aGF0IHdhcyBzaGFyZWQgdmlhIHRoZSBXZWIgU2hhcmUgVGFyZ2V0IEFQSS5cbiAgICAgICAgdGhpcy5yZXN0b3JlRmlsZUZyb21TaGFyZSgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy51cGRhdGVET01SZWN0KHRoaXMuaW5pdGlhbGl6ZVNjZW5lKTtcbiAgICAgIH0gLy8gbm90ZSB0aGF0IHRoaXMgY2hlY2sgc2VlbXMgdG8gYWx3YXlzIHBhc3MgaW4gbG9jYWxob3N0XG5cblxuICAgICAgaWYgKGlzQnJhdmUoKSAmJiAhaXNNZWFzdXJlVGV4dFN1cHBvcnRlZCgpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogX2pzeChCcmF2ZU1lYXN1cmVUZXh0RXJyb3IsIHt9KVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgIHZhciBfYTtcblxuICAgIHRoaXMucmVuZGVyZXIuZGVzdHJveSgpO1xuICAgIHRoaXMuc2NlbmUgPSBuZXcgU2NlbmUoKTtcbiAgICB0aGlzLnJlbmRlcmVyID0gbmV3IFJlbmRlcmVyKHRoaXMuc2NlbmUpO1xuICAgIHRoaXMuZmlsZXMgPSB7fTtcbiAgICB0aGlzLmltYWdlQ2FjaGUuY2xlYXIoKTtcbiAgICAoX2EgPSB0aGlzLnJlc2l6ZU9ic2VydmVyKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZGlzY29ubmVjdCgpO1xuICAgIHRoaXMudW5tb3VudGVkID0gdHJ1ZTtcbiAgICB0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXJzKCk7XG4gICAgdGhpcy5zY2VuZS5kZXN0cm95KCk7XG4gICAgdGhpcy5saWJyYXJ5LmRlc3Ryb3koKTtcbiAgICB0aGlzLmxhc2VyUGF0aE1hbmFnZXIuZGVzdHJveSgpO1xuICAgIHRoaXMub25DaGFuZ2VFbWl0dGVyLmRlc3Ryb3koKTtcbiAgICBTaGFwZUNhY2hlLmRlc3Ryb3koKTtcbiAgICBTbmFwQ2FjaGUuZGVzdHJveSgpO1xuICAgIGNsZWFyVGltZW91dCh0b3VjaFRpbWVvdXQpO1xuICAgIGlzU29tZUVsZW1lbnRTZWxlY3RlZC5jbGVhckNhY2hlKCk7XG4gICAgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cy5jbGVhckNhY2hlKCk7XG4gICAgdG91Y2hUaW1lb3V0ID0gMDtcbiAgfVxuXG4gIHJlbW92ZUV2ZW50TGlzdGVuZXJzKCkge1xuICAgIHZhciBfYSwgX2IsIF9jLCBfZDtcblxuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGhpcy5yZW1vdmVQb2ludGVyKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkNPUFksIHRoaXMub25Db3B5KTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5DVVQsIHRoaXMub25DdXQpO1xuICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5XSEVFTCwgdGhpcy5vbldoZWVsKTtcbiAgICAoX2IgPSB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5TQ1JPTEwsIHRoaXMub25TY3JvbGwpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgdGhpcy5vbktleURvd24sIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1PVVNFX01PVkUsIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfYyA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9kID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX1NUQVJULCB0aGlzLm9uR2VzdHVyZVN0YXJ0LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0NIQU5HRSwgdGhpcy5vbkdlc3R1cmVDaGFuZ2UsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfRU5ELCB0aGlzLm9uR2VzdHVyZUVuZCwgZmFsc2UpO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gIH1cblxuICBhZGRFdmVudExpc3RlbmVycygpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lO1xuXG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0aGlzLnJlbW92ZVBvaW50ZXIpOyAvLyAjMzU1M1xuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5DT1BZLCB0aGlzLm9uQ29weSk7XG4gICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLm9uV2hlZWwsIHtcbiAgICAgIHBhc3NpdmU6IGZhbHNlXG4gICAgfSk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5oYW5kbGVLZXlib2FyZEdsb2JhbGx5KSB7XG4gICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHRoaXMub25LZXlEb3duLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwLCB7XG4gICAgICBwYXNzaXZlOiB0cnVlXG4gICAgfSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5NT1VTRV9NT1ZFLCB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbik7IC8vIHJlcmVuZGVyIHRleHQgZWxlbWVudHMgb24gZm9udCBsb2FkIHRvIGZpeCAjNjM3ICYmICMxNTUzXG5cbiAgICAoX2MgPSAoX2IgPSBkb2N1bWVudC5mb250cykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmFkZEV2ZW50TGlzdGVuZXIpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5jYWxsKF9iLCBcImxvYWRpbmdkb25lXCIsIGV2ZW50ID0+IHtcbiAgICAgIGNvbnN0IGxvYWRlZEZvbnRGYWNlcyA9IGV2ZW50LmZvbnRmYWNlcztcbiAgICAgIHRoaXMuZm9udHMub25Gb250c0xvYWRlZChsb2FkZWRGb250RmFjZXMpO1xuICAgIH0pOyAvLyBTYWZhcmktb25seSBkZXNrdG9wIHBpbmNoIHpvb21cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9TVEFSVCwgdGhpcy5vbkdlc3R1cmVTdGFydCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9DSEFOR0UsIHRoaXMub25HZXN0dXJlQ2hhbmdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0VORCwgdGhpcy5vbkdlc3R1cmVFbmQsIGZhbHNlKTtcblxuICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHRoaXMucGFzdGVGcm9tQ2xpcGJvYXJkKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkNVVCwgdGhpcy5vbkN1dCk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5kZXRlY3RTY3JvbGwpIHtcbiAgICAgIHRoaXMubmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIgPSBnZXROZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lcih0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCk7XG4gICAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuU0NST0xMLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICB9XG5cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfZCA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9lID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gIH1cblxuICBjb21wb25lbnREaWRVcGRhdGUocHJldlByb3BzLCBwcmV2U3RhdGUpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZjtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMoKTtcblxuICAgIGlmICghdGhpcy5zdGF0ZS5zaG93V2VsY29tZVNjcmVlbiAmJiAhdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5sZW5ndGgpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzaG93V2VsY29tZVNjcmVlbjogdHJ1ZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT09IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50KSB7XG4gICAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cygpO1xuICAgIH1cblxuICAgIGlmIChwcmV2U3RhdGUuc2Nyb2xsWCAhPT0gdGhpcy5zdGF0ZS5zY3JvbGxYIHx8IHByZXZTdGF0ZS5zY3JvbGxZICE9PSB0aGlzLnN0YXRlLnNjcm9sbFkpIHtcbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vblNjcm9sbENoYW5nZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHRoaXMuc3RhdGUuc2Nyb2xsWCwgdGhpcy5zdGF0ZS5zY3JvbGxZKTtcbiAgICB9XG5cbiAgICBpZiAoT2JqZWN0LmtleXModGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLmxlbmd0aCAmJiBpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgfSlcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJlcmFzZXJcIiAmJiBwcmV2U3RhdGUudGhlbWUgIT09IHRoaXMuc3RhdGUudGhlbWUpIHtcbiAgICAgIHNldEVyYXNlckN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlLnRoZW1lKTtcbiAgICB9IC8vIEhpZGUgaHlwZXJsaW5rIHBvcHVwIGlmIHNob3duIHdoZW4gZWxlbWVudCB0eXBlIGlzIG5vdCBzZWxlY3Rpb25cblxuXG4gICAgaWYgKHByZXZTdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXApIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGZhbHNlXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLmxhbmdDb2RlICE9PSB0aGlzLnByb3BzLmxhbmdDb2RlKSB7XG4gICAgICB0aGlzLnVwZGF0ZUxhbmd1YWdlKCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy52aWV3TW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMudmlld01vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgdmlld01vZGVFbmFibGVkOiAhIXRoaXMucHJvcHMudmlld01vZGVFbmFibGVkXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlN0YXRlLnZpZXdNb2RlRW5hYmxlZCAhPT0gdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICAgIHRoaXMuZGVzZWxlY3RFbGVtZW50cygpO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMuemVuTW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB6ZW5Nb2RlRW5hYmxlZDogISF0aGlzLnByb3BzLnplbk1vZGVFbmFibGVkXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLnRoZW1lICE9PSB0aGlzLnByb3BzLnRoZW1lICYmIHRoaXMucHJvcHMudGhlbWUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy5ncmlkTW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZ3JpZFNpemU6IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkID8gR1JJRF9TSVpFIDogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucHJvcHMubmFtZSAmJiBwcmV2UHJvcHMubmFtZSAhPT0gdGhpcy5wcm9wcy5uYW1lKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgbmFtZTogdGhpcy5wcm9wcy5uYW1lXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAoX2MgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmNsYXNzTGlzdC50b2dnbGUoXCJ0aGVtZS0tZGFya1wiLCB0aGlzLnN0YXRlLnRoZW1lID09PSBcImRhcmtcIik7XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWRdKSB7XG4gICAgICAvLyBkZWZlciBzbyB0aGF0IHRoZSBjb21taXRUb0hpc3RvcnkgZmxhZyBpc24ndCByZXNldCB2aWEgY3VycmVudCB1cGRhdGVcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAvLyBleGVjdXRlIG9ubHkgaWYgdGhlIGNvbmRpdGlvbiBzdGlsbCBob2xkcyB3aGVuIHRoZSBkZWZlcnJlZCBjYWxsYmFja1xuICAgICAgICAvLyBleGVjdXRlcyAoaXQgY2FuIGJlIHNjaGVkdWxlZCBtdWx0aXBsZSB0aW1lcyBkZXBlbmRpbmcgb24gaG93XG4gICAgICAgIC8vIG1hbnkgdGltZXMgdGhlIGNvbXBvbmVudCByZW5kZXJzKVxuICAgICAgICB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgIH0pO1xuICAgIH0gLy8gZmFpbHNhZmUgaW4gY2FzZSB0aGUgc3RhdGUgaXMgYmVpbmcgdXBkYXRlZCBpbiBpbmNvcnJlY3Qgb3JkZXIgcmVzdWx0aW5nXG4gICAgLy8gaW4gdGhlIGVkaXRpbmdFbGVtZW50IGJlaW5nIG5vdyBhIGRlbGV0ZWQgZWxlbWVudFxuXG5cbiAgICBpZiAoKF9kID0gdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmlzRGVsZXRlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmVsZW1lbnRJZF0pIHtcbiAgICAgIC8vIFRvIG1ha2Ugc3VyZSBgc2VsZWN0ZWRMaW5lYXJFbGVtZW50YCBpcyBpbiBzeW5jIHdpdGggYHNlbGVjdGVkRWxlbWVudElkc2AsIGhvd2V2ZXIgdGhpcyBzaG91bGRuJ3QgYmUgbmVlZGVkIG9uY2VcbiAgICAgIC8vIHdlIGhhdmUgYSBzaW5nbGUgQVBJIHRvIHVwZGF0ZSBgc2VsZWN0ZWRFbGVtZW50SWRzYFxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3Qge1xuICAgICAgbXVsdGlFbGVtZW50XG4gICAgfSA9IHByZXZTdGF0ZTtcblxuICAgIGlmIChwcmV2U3RhdGUuYWN0aXZlVG9vbCAhPT0gdGhpcy5zdGF0ZS5hY3RpdmVUb29sICYmIG11bHRpRWxlbWVudCAhPSBudWxsICYmIGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgJiYgaXNCaW5kaW5nRWxlbWVudChtdWx0aUVsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgbWF5YmVCaW5kTGluZWFyRWxlbWVudChtdWx0aUVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUsIHR1cGxlVG9Db29ycyhMaW5lYXJFbGVtZW50RWRpdG9yLmdldFBvaW50QXRJbmRleEdsb2JhbENvb3JkaW5hdGVzKG11bHRpRWxlbWVudCwgLTEpKSk7XG4gICAgfVxuXG4gICAgdGhpcy5oaXN0b3J5LnJlY29yZCh0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpKTsgLy8gRG8gbm90IG5vdGlmeSBjb25zdW1lcnMgaWYgd2UncmUgc3RpbGwgbG9hZGluZyB0aGUgc2NlbmUuIEFtb25nIG90aGVyXG4gICAgLy8gcG90ZW50aWFsIGlzc3VlcywgdGhpcyBmaXhlcyBhIGNhc2Ugd2hlcmUgdGhlIHRhYiBpc24ndCBmb2N1c2VkIGR1cmluZ1xuICAgIC8vIGluaXQsIHdoaWNoIHdvdWxkIHRyaWdnZXIgb25DaGFuZ2Ugd2l0aCBlbXB0eSBlbGVtZW50cywgd2hpY2ggd291bGQgdGhlblxuICAgIC8vIG92ZXJyaWRlIHdoYXRldmVyIGlzIGluIGxvY2FsU3RvcmFnZSBjdXJyZW50bHkuXG5cbiAgICBpZiAoIXRoaXMuc3RhdGUuaXNMb2FkaW5nKSB7XG4gICAgICAoX2YgPSAoX2UgPSB0aGlzLnByb3BzKS5vbkNoYW5nZSkgPT09IG51bGwgfHwgX2YgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9mLmNhbGwoX2UsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMuc3RhdGUsIHRoaXMuZmlsZXMpO1xuICAgICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIudHJpZ2dlcih0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzLnN0YXRlLCB0aGlzLmZpbGVzKTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgcmVzZXRUYXBUd2ljZSgpIHtcbiAgICBkaWRUYXBUd2ljZSA9IGZhbHNlO1xuICB9IC8vIFRPRE8gcmV3cml0ZSB0aGlzIHRvIHBhc3RlIGJvdGggdGV4dCAmIGltYWdlcyBhdCB0aGUgc2FtZSB0aW1lIGlmXG4gIC8vIHBhc3RlZCBkYXRhIGNvbnRhaW5zIGJvdGhcblxuXG4gIGFkZEVsZW1lbnRzRnJvbU1peGVkQ29udGVudFBhc3RlKG1peGVkQ29udGVudCwge1xuICAgIGlzUGxhaW5QYXN0ZSxcbiAgICBzY2VuZVgsXG4gICAgc2NlbmVZXG4gIH0pIHtcbiAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgaWYgKCFpc1BsYWluUGFzdGUgJiYgbWl4ZWRDb250ZW50LnNvbWUobm9kZSA9PiBub2RlLnR5cGUgPT09IFwiaW1hZ2VVcmxcIikgJiYgdGhpcy5pc1Rvb2xTdXBwb3J0ZWQoXCJpbWFnZVwiKSkge1xuICAgICAgICBjb25zdCBpbWFnZVVSTHMgPSBtaXhlZENvbnRlbnQuZmlsdGVyKG5vZGUgPT4gbm9kZS50eXBlID09PSBcImltYWdlVXJsXCIpLm1hcChub2RlID0+IG5vZGUudmFsdWUpO1xuICAgICAgICBjb25zdCByZXNwb25zZXMgPSB5aWVsZCBQcm9taXNlLmFsbChpbWFnZVVSTHMubWFwKHVybCA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGZpbGU6IHlpZWxkIEltYWdlVVJMVG9GaWxlKHVybClcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pKSk7XG4gICAgICAgIGxldCB5ID0gc2NlbmVZO1xuICAgICAgICBsZXQgZmlyc3RJbWFnZVlPZmZzZXREb25lID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZElkcyA9IHt9O1xuXG4gICAgICAgIGZvciAoY29uc3QgcmVzcG9uc2Ugb2YgcmVzcG9uc2VzKSB7XG4gICAgICAgICAgaWYgKHJlc3BvbnNlLmZpbGUpIHtcbiAgICAgICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50KHtcbiAgICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgICBzY2VuZVk6IHlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3QgaW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQgPSB5aWVsZCB0aGlzLmluc2VydEltYWdlRWxlbWVudChpbWFnZUVsZW1lbnQsIHJlc3BvbnNlLmZpbGUpO1xuXG4gICAgICAgICAgICBpZiAoaW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgLy8gdmVydGljYWxseSBjZW50ZXIgZmlyc3QgaW1hZ2UgaW4gdGhlIGJhdGNoXG4gICAgICAgICAgICAgIGlmICghZmlyc3RJbWFnZVlPZmZzZXREb25lKSB7XG4gICAgICAgICAgICAgICAgZmlyc3RJbWFnZVlPZmZzZXREb25lID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB5IC09IGluaXRpYWxpemVkSW1hZ2VFbGVtZW50LmhlaWdodCAvIDI7XG4gICAgICAgICAgICAgIH0gLy8gaGFjayB0byByZXNldCB0aGUgYHlgIGNvb3JkIGJlY2F1c2Ugd2UgdmVydGljYWxseSBjZW50ZXIgZHVyaW5nXG4gICAgICAgICAgICAgIC8vIGluc2VydEltYWdlRWxlbWVudFxuXG5cbiAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChpbml0aWFsaXplZEltYWdlRWxlbWVudCwge1xuICAgICAgICAgICAgICAgIHlcbiAgICAgICAgICAgICAgfSwgZmFsc2UpO1xuICAgICAgICAgICAgICB5ID0gaW1hZ2VFbGVtZW50LnkgKyBpbWFnZUVsZW1lbnQuaGVpZ2h0ICsgMjU7XG4gICAgICAgICAgICAgIG5leHRTZWxlY3RlZElkc1tpbWFnZUVsZW1lbnQuaWRdID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKG5leHRTZWxlY3RlZElkcywgdGhpcy5zdGF0ZSlcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IGVycm9yID0gcmVzcG9uc2VzLmZpbmQocmVzcG9uc2UgPT4gISFyZXNwb25zZS5lcnJvck1lc3NhZ2UpO1xuXG4gICAgICAgIGlmIChlcnJvciAmJiBlcnJvci5lcnJvck1lc3NhZ2UpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IuZXJyb3JNZXNzYWdlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHRleHROb2RlcyA9IG1peGVkQ29udGVudC5maWx0ZXIobm9kZSA9PiBub2RlLnR5cGUgPT09IFwidGV4dFwiKTtcblxuICAgICAgICBpZiAodGV4dE5vZGVzLmxlbmd0aCkge1xuICAgICAgICAgIHRoaXMuYWRkVGV4dEZyb21QYXN0ZSh0ZXh0Tm9kZXMubWFwKG5vZGUgPT4gbm9kZS52YWx1ZSkuam9pbihcIlxcblxcblwiKSwgaXNQbGFpblBhc3RlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgYWRkVGV4dEZyb21QYXN0ZSh0ZXh0LCBpc1BsYWluUGFzdGUgPSBmYWxzZSkge1xuICAgIGNvbnN0IHtcbiAgICAgIHgsXG4gICAgICB5XG4gICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICBjbGllbnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICBjbGllbnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnlcbiAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICBjb25zdCB0ZXh0RWxlbWVudFByb3BzID0ge1xuICAgICAgeCxcbiAgICAgIHksXG4gICAgICBzdHJva2VDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZUNvbG9yLFxuICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgc3Ryb2tlV2lkdGg6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VXaWR0aCxcbiAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICByb3VuZG5lc3M6IG51bGwsXG4gICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgIHRleHQsXG4gICAgICBmb250U2l6ZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRTaXplLFxuICAgICAgZm9udEZhbWlseTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRGYW1pbHksXG4gICAgICB0ZXh0QWxpZ246IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1UZXh0QWxpZ24sXG4gICAgICB2ZXJ0aWNhbEFsaWduOiBERUZBVUxUX1ZFUlRJQ0FMX0FMSUdOLFxuICAgICAgbG9ja2VkOiBmYWxzZVxuICAgIH07XG4gICAgY29uc3QgTElORV9HQVAgPSAxMDtcbiAgICBsZXQgY3VycmVudFkgPSB5O1xuICAgIGNvbnN0IGxpbmVzID0gaXNQbGFpblBhc3RlID8gW3RleHRdIDogdGV4dC5zcGxpdChcIlxcblwiKTtcbiAgICBjb25zdCB0ZXh0RWxlbWVudHMgPSBsaW5lcy5yZWR1Y2UoKGFjYywgbGluZSwgaWR4KSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IHRleHQgPSBsaW5lLnRyaW0oKTtcbiAgICAgIGNvbnN0IGxpbmVIZWlnaHQgPSBnZXREZWZhdWx0TGluZUhlaWdodCh0ZXh0RWxlbWVudFByb3BzLmZvbnRGYW1pbHkpO1xuXG4gICAgICBpZiAodGV4dC5sZW5ndGgpIHtcbiAgICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeTogY3VycmVudFlcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdUZXh0RWxlbWVudChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRleHRFbGVtZW50UHJvcHMpLCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5OiBjdXJyZW50WSxcbiAgICAgICAgICB0ZXh0LFxuICAgICAgICAgIGxpbmVIZWlnaHQsXG4gICAgICAgICAgZnJhbWVJZDogdG9wTGF5ZXJGcmFtZSA/IHRvcExheWVyRnJhbWUuaWQgOiBudWxsXG4gICAgICAgIH0pKTtcbiAgICAgICAgYWNjLnB1c2goZWxlbWVudCk7XG4gICAgICAgIGN1cnJlbnRZICs9IGVsZW1lbnQuaGVpZ2h0ICsgTElORV9HQVA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBwcmV2TGluZSA9IChfYSA9IGxpbmVzW2lkeCAtIDFdKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudHJpbSgpOyAvLyBhZGQgcGFyYWdyYXBoIG9ubHkgaWYgcHJldmlvdXMgbGluZSB3YXMgbm90IGVtcHR5LCBJT1cgZG9uJ3QgYWRkXG4gICAgICAgIC8vIG1vcmUgdGhhbiBvbmUgZW1wdHkgbGluZVxuXG4gICAgICAgIGlmIChwcmV2TGluZSkge1xuICAgICAgICAgIGN1cnJlbnRZICs9IGdldExpbmVIZWlnaHRJblB4KHRleHRFbGVtZW50UHJvcHMuZm9udFNpemUsIGxpbmVIZWlnaHQpICsgTElORV9HQVA7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCBbXSk7XG5cbiAgICBpZiAodGV4dEVsZW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGZyYW1lSWQgPSB0ZXh0RWxlbWVudHNbMF0uZnJhbWVJZDtcblxuICAgIGlmIChmcmFtZUlkKSB7XG4gICAgICB0aGlzLnNjZW5lLmluc2VydEVsZW1lbnRzQXRJbmRleCh0ZXh0RWxlbWVudHMsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudEluZGV4KGZyYW1lSWQpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoWy4uLnRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIC4uLnRleHRFbGVtZW50c10pO1xuICAgIH1cblxuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuZnJvbUVudHJpZXModGV4dEVsZW1lbnRzLm1hcChlbCA9PiBbZWwuaWQsIHRydWVdKSksIHRoaXMuc3RhdGUpXG4gICAgfSk7XG5cbiAgICBpZiAoIWlzUGxhaW5QYXN0ZSAmJiB0ZXh0RWxlbWVudHMubGVuZ3RoID4gMSAmJiBQTEFJTl9QQVNURV9UT0FTVF9TSE9XTiA9PT0gZmFsc2UgJiYgIXRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSkge1xuICAgICAgdGhpcy5zZXRUb2FzdCh7XG4gICAgICAgIG1lc3NhZ2U6IHQoXCJ0b2FzdC5wYXN0ZUFzU2luZ2xlRWxlbWVudFwiLCB7XG4gICAgICAgICAgc2hvcnRjdXQ6IGdldFNob3J0Y3V0S2V5KFwiQ3RybE9yQ21kK1NoaWZ0K1ZcIilcbiAgICAgICAgfSksXG4gICAgICAgIGR1cmF0aW9uOiA1MDAwXG4gICAgICB9KTtcbiAgICAgIFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gIH1cblxuICBoYW5kbGVUZXh0V3lzaXd5ZyhlbGVtZW50LCB7XG4gICAgaXNFeGlzdGluZ0VsZW1lbnQgPSBmYWxzZVxuICB9KSB7XG4gICAgY29uc3QgdXBkYXRlRWxlbWVudCA9ICh0ZXh0LCBvcmlnaW5hbFRleHQsIGlzRGVsZXRlZCkgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoWy4uLnRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKF9lbGVtZW50ID0+IHtcbiAgICAgICAgaWYgKF9lbGVtZW50LmlkID09PSBlbGVtZW50LmlkICYmIGlzVGV4dEVsZW1lbnQoX2VsZW1lbnQpKSB7XG4gICAgICAgICAgcmV0dXJuIHVwZGF0ZVRleHRFbGVtZW50KF9lbGVtZW50LCB7XG4gICAgICAgICAgICB0ZXh0LFxuICAgICAgICAgICAgaXNEZWxldGVkLFxuICAgICAgICAgICAgb3JpZ2luYWxUZXh0XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2VsZW1lbnQ7XG4gICAgICB9KV0pO1xuICAgIH07XG5cbiAgICB0ZXh0V3lzaXd5Zyh7XG4gICAgICBpZDogZWxlbWVudC5pZCxcbiAgICAgIGNhbnZhczogdGhpcy5jYW52YXMsXG4gICAgICBnZXRWaWV3cG9ydENvb3JkczogKHgsIHkpID0+IHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHZpZXdwb3J0WCxcbiAgICAgICAgICB5OiB2aWV3cG9ydFlcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiB4LFxuICAgICAgICAgIHNjZW5lWTogeVxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgcmV0dXJuIFt2aWV3cG9ydFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIHZpZXdwb3J0WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wXTtcbiAgICAgIH0sXG4gICAgICBvbkNoYW5nZTogd2l0aEJhdGNoZWRVcGRhdGVzKHRleHQgPT4ge1xuICAgICAgICB1cGRhdGVFbGVtZW50KHRleHQsIHRleHQsIGZhbHNlKTtcblxuICAgICAgICBpZiAoaXNOb25EZWxldGVkRWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICAgIHVwZGF0ZUJvdW5kRWxlbWVudHMoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0pLFxuICAgICAgb25TdWJtaXQ6IHdpdGhCYXRjaGVkVXBkYXRlcygoe1xuICAgICAgICB0ZXh0LFxuICAgICAgICB2aWFLZXlib2FyZCxcbiAgICAgICAgb3JpZ2luYWxUZXh0XG4gICAgICB9KSA9PiB7XG4gICAgICAgIGNvbnN0IGlzRGVsZXRlZCA9ICF0ZXh0LnRyaW0oKTtcbiAgICAgICAgdXBkYXRlRWxlbWVudCh0ZXh0LCBvcmlnaW5hbFRleHQsIGlzRGVsZXRlZCk7IC8vIHNlbGVjdCB0aGUgY3JlYXRlZCB0ZXh0IGVsZW1lbnQgb25seSBpZiBzdWJtaXR0aW5nIHZpYSBrZXlib2FyZFxuICAgICAgICAvLyAod2hlbiBzdWJtaXR0aW5nIHZpYSBjbGljayBpdCBzaG91bGQgYWN0IGFzIHNpZ25hbCB0byBkZXNlbGVjdClcblxuICAgICAgICBpZiAoIWlzRGVsZXRlZCAmJiB2aWFLZXlib2FyZCkge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRJZFRvU2VsZWN0ID0gZWxlbWVudC5jb250YWluZXJJZCA/IGVsZW1lbnQuY29udGFpbmVySWQgOiBlbGVtZW50LmlkO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgW2VsZW1lbnRJZFRvU2VsZWN0XTogdHJ1ZVxuICAgICAgICAgICAgfSksIHByZXZTdGF0ZSlcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNEZWxldGVkKSB7XG4gICAgICAgICAgZml4QmluZGluZ3NBZnRlckRlbGV0aW9uKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIFtlbGVtZW50XSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWlzRGVsZXRlZCB8fCBpc0V4aXN0aW5nRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogbnVsbFxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLmxvY2tlZCkge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfSksXG4gICAgICBlbGVtZW50LFxuICAgICAgZXhjYWxpZHJhd0NvbnRhaW5lcjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQsXG4gICAgICBhcHA6IHRoaXNcbiAgICB9KTsgLy8gZGVzZWxlY3QgYWxsIG90aGVyIGVsZW1lbnRzIHdoZW4gaW5zZXJ0aW5nIHRleHRcblxuICAgIHRoaXMuZGVzZWxlY3RFbGVtZW50cygpOyAvLyBkbyBhbiBpbml0aWFsIHVwZGF0ZSB0byByZS1pbml0aWFsaXplIGVsZW1lbnQgcG9zaXRpb24gc2luY2Ugd2Ugd2VyZVxuICAgIC8vIG1vZGlmeWluZyBlbGVtZW50J3MgeC95IGZvciBzYWtlIG9mIGVkaXRvciAoY2FzZTogc3luY2luZyB0byByZW1vdGUpXG5cbiAgICB1cGRhdGVFbGVtZW50KGVsZW1lbnQudGV4dCwgZWxlbWVudC5vcmlnaW5hbFRleHQsIGZhbHNlKTtcbiAgfVxuXG4gIGRlc2VsZWN0RWxlbWVudHMoKSB7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgfSk7XG4gIH1cblxuICBnZXRUZXh0RWxlbWVudEF0UG9zaXRpb24oeCwgeSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHgsIHksIHtcbiAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlXG4gICAgfSk7XG5cbiAgICBpZiAoZWxlbWVudCAmJiBpc1RleHRFbGVtZW50KGVsZW1lbnQpICYmICFlbGVtZW50LmlzRGVsZXRlZCkge1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBnZXRFbGVtZW50QXRQb3NpdGlvbih4LCB5LCBvcHRzKSB7XG4gICAgY29uc3QgYWxsSGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbih4LCB5LCBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQsIG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5pbmNsdWRlTG9ja2VkRWxlbWVudHMpO1xuXG4gICAgaWYgKGFsbEhpdEVsZW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIGlmIChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucHJlZmVyU2VsZWN0ZWQpIHtcbiAgICAgICAgZm9yIChsZXQgaW5kZXggPSBhbGxIaXRFbGVtZW50cy5sZW5ndGggLSAxOyBpbmRleCA+IC0xOyBpbmRleC0tKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2FsbEhpdEVsZW1lbnRzW2luZGV4XS5pZF0pIHtcbiAgICAgICAgICAgIHJldHVybiBhbGxIaXRFbGVtZW50c1tpbmRleF07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleCA9IGFsbEhpdEVsZW1lbnRzW2FsbEhpdEVsZW1lbnRzLmxlbmd0aCAtIDFdOyAvLyBJZiB3ZSdyZSBoaXR0aW5nIGVsZW1lbnQgd2l0aCBoaWdoZXN0IHotaW5kZXggb25seSBvbiBpdHMgYm91bmRpbmcgYm94XG4gICAgICAvLyB3aGlsZSBhbHNvIGhpdHRpbmcgb3RoZXIgZWxlbWVudCBmaWd1cmUsIHRoZSBsYXR0ZXIgc2hvdWxkIGJlIGNvbnNpZGVyZWQuXG5cbiAgICAgIHJldHVybiBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQoZWxlbWVudFdpdGhIaWdoZXN0WkluZGV4LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCB4LCB5KSA/IGFsbEhpdEVsZW1lbnRzW2FsbEhpdEVsZW1lbnRzLmxlbmd0aCAtIDJdIDogZWxlbWVudFdpdGhIaWdoZXN0WkluZGV4O1xuICAgIH1cblxuICAgIGlmIChhbGxIaXRFbGVtZW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHJldHVybiBhbGxIaXRFbGVtZW50c1swXTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGdldEVsZW1lbnRzQXRQb3NpdGlvbih4LCB5LCBpbmNsdWRlQm91bmRUZXh0RWxlbWVudCA9IGZhbHNlLCBpbmNsdWRlTG9ja2VkRWxlbWVudHMgPSBmYWxzZSkge1xuICAgIGNvbnN0IGVsZW1lbnRzID0gaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgJiYgaW5jbHVkZUxvY2tlZEVsZW1lbnRzID8gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSA6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsZW1lbnQgPT4gKGluY2x1ZGVMb2NrZWRFbGVtZW50cyB8fCAhZWxlbWVudC5sb2NrZWQpICYmIChpbmNsdWRlQm91bmRUZXh0RWxlbWVudCB8fCAhKGlzVGV4dEVsZW1lbnQoZWxlbWVudCkgJiYgZWxlbWVudC5jb250YWluZXJJZCkpKTtcbiAgICByZXR1cm4gZ2V0RWxlbWVudHNBdFBvc2l0aW9uKGVsZW1lbnRzLCBlbGVtZW50ID0+IGhpdFRlc3QoZWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgeCwgeSkpLmZpbHRlcihlbGVtZW50ID0+IHtcbiAgICAgIC8vIGhpdHRpbmcgYSBmcmFtZSdzIGVsZW1lbnQgZnJvbSBvdXRzaWRlIHRoZSBmcmFtZSBpcyBub3QgY29uc2lkZXJlZCBhIGhpdFxuICAgICAgY29uc3QgY29udGFpbmluZ0ZyYW1lID0gZ2V0Q29udGFpbmluZ0ZyYW1lKGVsZW1lbnQpO1xuICAgICAgcmV0dXJuIGNvbnRhaW5pbmdGcmFtZSAmJiB0aGlzLnN0YXRlLmZyYW1lUmVuZGVyaW5nLmVuYWJsZWQgJiYgdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5jbGlwID8gaXNDdXJzb3JJbkZyYW1lKHtcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfSwgY29udGFpbmluZ0ZyYW1lKSA6IHRydWU7XG4gICAgfSk7XG4gIH1cblxuICBoYW5kbGVIb3ZlclNlbGVjdGVkTGluZWFyRWxlbWVudChsaW5lYXJFbGVtZW50RWRpdG9yLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSB7XG4gICAgY29uc3QgZWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0RWxlbWVudChsaW5lYXJFbGVtZW50RWRpdG9yLmVsZW1lbnRJZCk7XG4gICAgY29uc3QgYm91bmRUZXh0RWxlbWVudCA9IGdldEJvdW5kVGV4dEVsZW1lbnQoZWxlbWVudCk7XG5cbiAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgIGxldCBob3ZlclBvaW50SW5kZXggPSAtMTtcbiAgICAgIGxldCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzID0gbnVsbDtcblxuICAgICAgaWYgKGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94KGVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIFtzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZXSkpIHtcbiAgICAgICAgaG92ZXJQb2ludEluZGV4ID0gTGluZWFyRWxlbWVudEVkaXRvci5nZXRQb2ludEluZGV4VW5kZXJDdXJzb3IoZWxlbWVudCwgdGhpcy5zdGF0ZS56b29tLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKTtcbiAgICAgICAgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3JkcyA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0U2VnbWVudE1pZHBvaW50SGl0Q29vcmRzKGxpbmVhckVsZW1lbnRFZGl0b3IsIHtcbiAgICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKGhvdmVyUG9pbnRJbmRleCA+PSAwIHx8IHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuUE9JTlRFUik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHNob3VsZFNob3dCb3VuZGluZ0JveChbZWxlbWVudF0sIHRoaXMuc3RhdGUpICYmIGlzSGl0dGluZ0VsZW1lbnRCb3VuZGluZ0JveFdpdGhvdXRIaXR0aW5nRWxlbWVudChlbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSkge1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG4gICAgICB9IGVsc2UgaWYgKGJvdW5kVGV4dEVsZW1lbnQgJiYgaGl0VGVzdChib3VuZFRleHRFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSkge1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5ob3ZlclBvaW50SW5kZXggIT09IGhvdmVyUG9pbnRJbmRleCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICBob3ZlclBvaW50SW5kZXhcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFMaW5lYXJFbGVtZW50RWRpdG9yLmFyZVBvaW50c0VxdWFsKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LnNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMsIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHNcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkFVVE8pO1xuICAgIH1cbiAgfVxuXG4gIG1heWJlQ2xlYW51cEFmdGVyTWlzc2luZ1BvaW50ZXJVcChldmVudCkge1xuICAgIGlmIChsYXN0UG9pbnRlclVwICE9PSBudWxsKSB7XG4gICAgICAvLyBVbmZvcnR1bmF0ZWx5LCBzb21ldGltZXMgd2UgZG9uJ3QgZ2V0IGEgcG9pbnRlcnVwIGFmdGVyIGEgcG9pbnRlcmRvd24sXG4gICAgICAvLyB0aGlzIGNhbiBoYXBwZW4gd2hlbiBhIGNvbnRleHR1YWwgbWVudSBvciBhbGVydCBpcyB0cmlnZ2VyZWQuIEluIG9yZGVyIHRvIGF2b2lkXG4gICAgICAvLyBiZWluZyBpbiBhIHdlaXJkIHN0YXRlLCB3ZSBjbGVhbiB1cCBvbiB0aGUgbmV4dCBwb2ludGVyZG93blxuICAgICAgbGFzdFBvaW50ZXJVcChldmVudCk7XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlR2VzdHVyZU9uUG9pbnRlckRvd24oZXZlbnQpIHtcbiAgICBnZXN0dXJlLnBvaW50ZXJzLnNldChldmVudC5wb2ludGVySWQsIHtcbiAgICAgIHg6IGV2ZW50LmNsaWVudFgsXG4gICAgICB5OiBldmVudC5jbGllbnRZXG4gICAgfSk7XG5cbiAgICBpZiAoZ2VzdHVyZS5wb2ludGVycy5zaXplID09PSAyKSB7XG4gICAgICBnZXN0dXJlLmxhc3RDZW50ZXIgPSBnZXRDZW50ZXIoZ2VzdHVyZS5wb2ludGVycyk7XG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlID0gZ2V0RGlzdGFuY2UoQXJyYXkuZnJvbShnZXN0dXJlLnBvaW50ZXJzLnZhbHVlcygpKSk7XG4gICAgfVxuICB9XG5cbiAgaW5pdGlhbFBvaW50ZXJEb3duU3RhdGUoZXZlbnQpIHtcbiAgICBjb25zdCBvcmlnaW4gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgY29uc3QgW21pblgsIG1pblksIG1heFgsIG1heFldID0gZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgIHJldHVybiB7XG4gICAgICBvcmlnaW4sXG4gICAgICB3aXRoQ21kT3JDdHJsOiBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSxcbiAgICAgIG9yaWdpbkluR3JpZDogdHVwbGVUb0Nvb3JzKGdldEdyaWRQb2ludChvcmlnaW4ueCwgb3JpZ2luLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpKSxcbiAgICAgIHNjcm9sbGJhcnM6IGlzT3ZlclNjcm9sbEJhcnMoY3VycmVudFNjcm9sbEJhcnMsIGV2ZW50LmNsaWVudFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIGV2ZW50LmNsaWVudFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcCksXG4gICAgICAvLyB3ZSBuZWVkIHRvIGR1cGxpY2F0ZSBiZWNhdXNlIHdlJ2xsIGJlIHVwZGF0aW5nIHRoaXMgc3RhdGVcbiAgICAgIGxhc3RDb29yZHM6IE9iamVjdC5hc3NpZ24oe30sIG9yaWdpbiksXG4gICAgICBvcmlnaW5hbEVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgIGFjYy5zZXQoZWxlbWVudC5pZCwgZGVlcENvcHlFbGVtZW50KGVsZW1lbnQpKTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIG5ldyBNYXAoKSksXG4gICAgICByZXNpemU6IHtcbiAgICAgICAgaGFuZGxlVHlwZTogZmFsc2UsXG4gICAgICAgIGlzUmVzaXppbmc6IGZhbHNlLFxuICAgICAgICBvZmZzZXQ6IHtcbiAgICAgICAgICB4OiAwLFxuICAgICAgICAgIHk6IDBcbiAgICAgICAgfSxcbiAgICAgICAgYXJyb3dEaXJlY3Rpb246IFwib3JpZ2luXCIsXG4gICAgICAgIGNlbnRlcjoge1xuICAgICAgICAgIHg6IChtYXhYICsgbWluWCkgLyAyLFxuICAgICAgICAgIHk6IChtYXhZICsgbWluWSkgLyAyXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBoaXQ6IHtcbiAgICAgICAgZWxlbWVudDogbnVsbCxcbiAgICAgICAgYWxsSGl0RWxlbWVudHM6IFtdLFxuICAgICAgICB3YXNBZGRlZFRvU2VsZWN0aW9uOiBmYWxzZSxcbiAgICAgICAgaGFzQmVlbkR1cGxpY2F0ZWQ6IGZhbHNlLFxuICAgICAgICBoYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50czogdGhpcy5pc0hpdHRpbmdDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cyhvcmlnaW4sIHNlbGVjdGVkRWxlbWVudHMpXG4gICAgICB9LFxuICAgICAgZHJhZzoge1xuICAgICAgICBoYXNPY2N1cnJlZDogZmFsc2UsXG4gICAgICAgIG9mZnNldDogbnVsbFxuICAgICAgfSxcbiAgICAgIGV2ZW50TGlzdGVuZXJzOiB7XG4gICAgICAgIG9uTW92ZTogbnVsbCxcbiAgICAgICAgb25VcDogbnVsbCxcbiAgICAgICAgb25LZXlVcDogbnVsbCxcbiAgICAgICAgb25LZXlEb3duOiBudWxsXG4gICAgICB9LFxuICAgICAgYm94U2VsZWN0aW9uOiB7XG4gICAgICAgIGhhc09jY3VycmVkOiBmYWxzZVxuICAgICAgfSxcbiAgICAgIGVsZW1lbnRJZHNUb0VyYXNlOiB7fVxuICAgIH07XG4gIH0gLy8gUmV0dXJucyB3aGV0aGVyIHRoZSBldmVudCBpcyBhIGRyYWdnaW5nIGEgc2Nyb2xsYmFyXG5cblxuICBoYW5kbGVEcmFnZ2luZ1Njcm9sbEJhcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkge1xuICAgIGlmICghKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJFaXRoZXIgJiYgIXRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlzRHJhZ2dpbmdTY3JvbGxCYXIgPSB0cnVlO1xuICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gZXZlbnQuY2xpZW50WDtcbiAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IGV2ZW50LmNsaWVudFk7XG4gICAgY29uc3Qgb25Qb2ludGVyTW92ZSA9IHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZChldmVudCA9PiB7XG4gICAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQ7XG5cbiAgICAgIGlmICghKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgfSk7XG4gICAgY29uc3Qgb25Qb2ludGVyVXAgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoKCkgPT4ge1xuICAgICAgaXNEcmFnZ2luZ1Njcm9sbEJhciA9IGZhbHNlO1xuICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICBsYXN0UG9pbnRlclVwID0gbnVsbDtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIlxuICAgICAgfSk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgb25Qb2ludGVyVXApO1xuICAgICAgb25Qb2ludGVyTW92ZS5mbHVzaCgpO1xuICAgIH0pO1xuICAgIGxhc3RQb2ludGVyVXAgPSBvblBvaW50ZXJVcDtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGlzQVNlbGVjdGVkRWxlbWVudChoaXRFbGVtZW50KSB7XG4gICAgcmV0dXJuIGhpdEVsZW1lbnQgIT0gbnVsbCAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXTtcbiAgfVxuXG4gIGlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHBvaW50LCBzZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoIDwgMikge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gLy8gSG93IG1hbnkgcGl4ZWxzIG9mZiB0aGUgc2hhcGUgYm91bmRhcnkgd2Ugc3RpbGwgY29uc2lkZXIgYSBoaXRcblxuXG4gICAgY29uc3QgdGhyZXNob2xkID0gMTAgLyB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgY29uc3QgW3gxLCB5MSwgeDIsIHkyXSA9IGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICByZXR1cm4gcG9pbnQueCA+IHgxIC0gdGhyZXNob2xkICYmIHBvaW50LnggPCB4MiArIHRocmVzaG9sZCAmJiBwb2ludC55ID4geTEgLSB0aHJlc2hvbGQgJiYgcG9pbnQueSA8IHkyICsgdGhyZXNob2xkO1xuICB9XG5cbiAgZ2V0Q3VycmVudEl0ZW1Sb3VuZG5lc3MoZWxlbWVudFR5cGUpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdW5kbmVzcyA9PT0gXCJyb3VuZFwiID8ge1xuICAgICAgdHlwZTogaXNVc2luZ0FkYXB0aXZlUmFkaXVzKGVsZW1lbnRUeXBlKSA/IFJPVU5ETkVTUy5BREFQVElWRV9SQURJVVMgOiBST1VORE5FU1MuUFJPUE9SVElPTkFMX1JBRElVU1xuICAgIH0gOiBudWxsO1xuICB9XG5cbiAgbWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMsIHJlY29tcHV0ZUFueXdheXMgPSBmYWxzZSkge1xuICAgIGlmIChpc1NuYXBwaW5nRW5hYmxlZCh7XG4gICAgICBldmVudCxcbiAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgc2VsZWN0ZWRFbGVtZW50c1xuICAgIH0pICYmIChyZWNvbXB1dGVBbnl3YXlzIHx8ICFTbmFwQ2FjaGUuZ2V0UmVmZXJlbmNlU25hcFBvaW50cygpKSkge1xuICAgICAgU25hcENhY2hlLnNldFJlZmVyZW5jZVNuYXBQb2ludHMoZ2V0UmVmZXJlbmNlU25hcFBvaW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBzZWxlY3RlZEVsZW1lbnRzLCB0aGlzLnN0YXRlKSk7XG4gICAgfVxuICB9XG5cbiAgbWF5YmVDYWNoZVZpc2libGVHYXBzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzLCByZWNvbXB1dGVBbnl3YXlzID0gZmFsc2UpIHtcbiAgICBpZiAoaXNTbmFwcGluZ0VuYWJsZWQoe1xuICAgICAgZXZlbnQsXG4gICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgIHNlbGVjdGVkRWxlbWVudHNcbiAgICB9KSAmJiAocmVjb21wdXRlQW55d2F5cyB8fCAhU25hcENhY2hlLmdldFZpc2libGVHYXBzKCkpKSB7XG4gICAgICBTbmFwQ2FjaGUuc2V0VmlzaWJsZUdhcHMoZ2V0VmlzaWJsZUdhcHModGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgc2VsZWN0ZWRFbGVtZW50cywgdGhpcy5zdGF0ZSkpO1xuICAgIH1cbiAgfVxuXG4gIG9uS2V5RG93bkZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSkge1xuICAgIHJldHVybiB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgaWYgKHRoaXMubWF5YmVIYW5kbGVSZXNpemUocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudChwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgfSk7XG4gIH1cblxuICBvbktleVVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICAvLyBQcmV2ZW50cyBmb2N1cyBmcm9tIGVzY2FwaW5nIGV4Y2FsaWRyYXcgdGFiXG4gICAgICBldmVudC5rZXkgPT09IEtFWVMuQUxUICYmIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgIGlmICh0aGlzLm1heWJlSGFuZGxlUmVzaXplKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubWF5YmVEcmFnTmV3R2VuZXJpY0VsZW1lbnQocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpO1xuICAgIH0pO1xuICB9XG5cbiAgb25Qb2ludGVyTW92ZUZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSkge1xuICAgIHJldHVybiB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQoZXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYjsgLy8gV2UgbmVlZCB0byBpbml0aWFsaXplIGRyYWdPZmZzZXRYWSBvbmx5IGFmdGVyIHdlJ3ZlIHVwZGF0ZWRcbiAgICAgIC8vIGBzdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNgIG9uIHBvaW50ZXJEb3duLiBEb2luZyBpdCBoZXJlIGluIHBvaW50ZXJNb3ZlXG4gICAgICAvLyBldmVudCBoYW5kbGVyIHNob3VsZCBob3BlZnVsbHkgZW5zdXJlIHdlJ3JlIGFscmVhZHkgd29ya2luZyB3aXRoXG4gICAgICAvLyB0aGUgdXBkYXRlZCBzdGF0ZS5cblxuXG4gICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5kcmFnLm9mZnNldCA9PT0gbnVsbCkge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0ID0gdHVwbGVUb0Nvb3JzKGdldERyYWdPZmZzZXRYWSh0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSksIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0O1xuXG4gICAgICBpZiAoISh0YXJnZXQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5oYW5kbGVQb2ludGVyTW92ZU92ZXJTY3JvbGxiYXJzKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoaXNFcmFzZXJBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVFcmFzZXIoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUsIHBvaW50ZXJDb29yZHMpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsYXNlclwiKSB7XG4gICAgICAgIHRoaXMubGFzZXJQYXRoTWFuYWdlci5hZGRQb2ludFRvUGF0aChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTsgLy8gZm9yIGFycm93cy9saW5lcywgZG9uJ3Qgc3RhcnQgZHJhZ2dpbmcgdW50aWwgYSBnaXZlbiB0aHJlc2hvbGRcbiAgICAgIC8vIHRvIGVuc3VyZSB3ZSBkb24ndCBjcmVhdGUgYSAyLXBvaW50IGFycm93IGJ5IG1pc3Rha2Ugd2hlblxuICAgICAgLy8gdXNlciBjbGlja3MgbW91c2UgaW4gYSB3YXkgdGhhdCBpdCBtb3ZlcyBhIHRpbnkgYml0ICh0aHVzXG4gICAgICAvLyB0cmlnZ2VyaW5nIHBvaW50ZXJtb3ZlKVxuXG4gICAgICBpZiAoIXBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiYXJyb3dcIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsaW5lXCIpKSB7XG4gICAgICAgIGlmIChkaXN0YW5jZTJkKHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSA8IERSQUdHSU5HX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaXNSZXNpemluZykge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHBvaW50ZXJDb29yZHMueDtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBwb2ludGVyQ29vcmRzLnk7XG5cbiAgICAgICAgaWYgKHRoaXMubWF5YmVIYW5kbGVSZXNpemUocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGxpbmVhckVsZW1lbnRFZGl0b3IgPSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50O1xuXG4gICAgICAgIGlmIChMaW5lYXJFbGVtZW50RWRpdG9yLnNob3VsZEFkZE1pZHBvaW50KHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LCBwb2ludGVyQ29vcmRzLCB0aGlzLnN0YXRlKSkge1xuICAgICAgICAgIGNvbnN0IHJldCA9IExpbmVhckVsZW1lbnRFZGl0b3IuYWRkTWlkcG9pbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHBvaW50ZXJDb29yZHMsIHRoaXMuc3RhdGUsICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSk7XG5cbiAgICAgICAgICBpZiAoIXJldCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH0gLy8gU2luY2Ugd2UgYXJlIHJlYWRpbmcgZnJvbSBwcmV2aW91cyBzdGF0ZSB3aGljaCBpcyBub3QgcG9zc2libGUgd2l0aFxuICAgICAgICAgIC8vIGF1dG9tYXRpYyBiYXRjaGluZyBpbiBSZWFjdCAxOCBoZW5jZSB1c2luZyBmbHVzaCBzeW5jIHRvIHN5bmNocm9ub3VzbHlcbiAgICAgICAgICAvLyB1cGRhdGUgdGhlIHN0YXRlLiBDaGVjayBodHRwczovL2dpdGh1Yi5jb20vZXhjYWxpZHJhdy9leGNhbGlkcmF3L3B1bGwvNTUwOCBmb3IgbW9yZSBkZXRhaWxzLlxuXG5cbiAgICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGU6IHJldC5wb2ludGVyRG93blN0YXRlLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRQb2ludHNJbmRpY2VzOiByZXQuc2VsZWN0ZWRQb2ludHNJbmRpY2VzXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlOiByZXQucG9pbnRlckRvd25TdGF0ZSxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkUG9pbnRzSW5kaWNlczogcmV0LnNlbGVjdGVkUG9pbnRzSW5kaWNlc1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSBlbHNlIGlmIChsaW5lYXJFbGVtZW50RWRpdG9yLnBvaW50ZXJEb3duU3RhdGUuc2VnbWVudE1pZHBvaW50LnZhbHVlICE9PSBudWxsICYmICFsaW5lYXJFbGVtZW50RWRpdG9yLnBvaW50ZXJEb3duU3RhdGUuc2VnbWVudE1pZHBvaW50LmFkZGVkKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZGlkRHJhZyA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnREcmFnZ2luZyhldmVudCwgdGhpcy5zdGF0ZSwgcG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIChlbGVtZW50LCBwb2ludHNTY2VuZUNvb3JkcykgPT4ge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ3NGb3JMaW5lYXJFbGVtZW50QXRDb29yZHMoZWxlbWVudCwgcG9pbnRzU2NlbmVDb29yZHMpO1xuICAgICAgICB9LCBsaW5lYXJFbGVtZW50RWRpdG9yKTtcblxuICAgICAgICBpZiAoZGlkRHJhZykge1xuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gcG9pbnRlckNvb3Jkcy54O1xuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCA9IHRydWU7XG5cbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICBpc0RyYWdnaW5nOiB0cnVlXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICAgICAgaXNEcmFnZ2luZzogdHJ1ZVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhhc0hpdEFTZWxlY3RlZEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5hbGxIaXRFbGVtZW50cy5zb21lKGVsZW1lbnQgPT4gdGhpcy5pc0FTZWxlY3RlZEVsZW1lbnQoZWxlbWVudCkpO1xuICAgICAgY29uc3QgaXNTZWxlY3RpbmdQb2ludHNJbkxpbmVFZGl0b3IgPSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmIGV2ZW50LnNoaWZ0S2V5ICYmIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkID09PSAoKF9hID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmlkKTtcblxuICAgICAgaWYgKChoYXNIaXRBU2VsZWN0ZWRFbGVtZW50IHx8IHBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKSAmJiAhaXNTZWxlY3RpbmdQb2ludHNJbkxpbmVFZGl0b3IpIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5ldmVyeShlbGVtZW50ID0+IGVsZW1lbnQubG9ja2VkKSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHNIYXNBRnJhbWUgPSBzZWxlY3RlZEVsZW1lbnRzLmZpbmQoZSA9PiBpc0ZyYW1lRWxlbWVudChlKSk7XG4gICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHBvaW50ZXJDb29yZHMpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBmcmFtZVRvSGlnaGxpZ2h0OiB0b3BMYXllckZyYW1lICYmICFzZWxlY3RlZEVsZW1lbnRzSGFzQUZyYW1lID8gdG9wTGF5ZXJGcmFtZSA6IG51bGxcbiAgICAgICAgfSk7IC8vIE1hcmtpbmcgdGhhdCBjbGljayB3YXMgdXNlZCBmb3IgZHJhZ2dpbmcgdG8gY2hlY2tcbiAgICAgICAgLy8gaWYgZWxlbWVudHMgc2hvdWxkIGJlIGRlc2VsZWN0ZWQgb24gcG9pbnRlcnVwXG5cbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogdHJ1ZVxuICAgICAgICB9KTsgLy8gcHJldmVudCBkcmFnZ2luZyBldmVuIGlmIHdlJ3JlIG5vIGxvbmdlciBob2xkaW5nIGNtZC9jdHJsIG90aGVyd2lzZVxuICAgICAgICAvLyBpdCB3b3VsZCBoYXZlIHdlaXJkIHJlc3VsdHMgKHN0dWZmIGp1bXBpbmcgYWxsIG92ZXIgdGhlIHNjcmVlbilcbiAgICAgICAgLy8gQ2hlY2tpbmcgZm9yIGVkaXRpbmdFbGVtZW50IHRvIGF2b2lkIGp1bXAgd2hpbGUgZWRpdGluZyBvbiBtb2JpbGUgIzY1MDNcblxuICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiAwICYmICFwb2ludGVyRG93blN0YXRlLndpdGhDbWRPckN0cmwgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQgJiYgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSAhPT0gXCJhY3RpdmVcIikge1xuICAgICAgICAgIGNvbnN0IGRyYWdPZmZzZXQgPSB7XG4gICAgICAgICAgICB4OiBwb2ludGVyQ29vcmRzLnggLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LFxuICAgICAgICAgICAgeTogcG9pbnRlckNvb3Jkcy55IC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueVxuICAgICAgICAgIH07XG4gICAgICAgICAgY29uc3Qgb3JpZ2luYWxFbGVtZW50cyA9IFsuLi5wb2ludGVyRG93blN0YXRlLm9yaWdpbmFsRWxlbWVudHMudmFsdWVzKCldOyAvLyBXZSBvbmx5IGRyYWcgaW4gb25lIGRpcmVjdGlvbiBpZiBzaGlmdCBpcyBwcmVzc2VkXG5cbiAgICAgICAgICBjb25zdCBsb2NrRGlyZWN0aW9uID0gZXZlbnQuc2hpZnRLZXk7XG5cbiAgICAgICAgICBpZiAobG9ja0RpcmVjdGlvbikge1xuICAgICAgICAgICAgY29uc3QgZGlzdGFuY2VYID0gTWF0aC5hYnMoZHJhZ09mZnNldC54KTtcbiAgICAgICAgICAgIGNvbnN0IGRpc3RhbmNlWSA9IE1hdGguYWJzKGRyYWdPZmZzZXQueSk7XG4gICAgICAgICAgICBjb25zdCBsb2NrWCA9IGxvY2tEaXJlY3Rpb24gJiYgZGlzdGFuY2VYIDwgZGlzdGFuY2VZO1xuICAgICAgICAgICAgY29uc3QgbG9ja1kgPSBsb2NrRGlyZWN0aW9uICYmIGRpc3RhbmNlWCA+IGRpc3RhbmNlWTtcblxuICAgICAgICAgICAgaWYgKGxvY2tYKSB7XG4gICAgICAgICAgICAgIGRyYWdPZmZzZXQueCA9IDA7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChsb2NrWSkge1xuICAgICAgICAgICAgICBkcmFnT2Zmc2V0LnkgPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gU25hcCBjYWNoZSAqbXVzdCogYmUgc3luY2hyb25vdXNseSBwb3B1cGxhdGVkIGJlZm9yZSBpbml0aWFsIGRyYWcsXG4gICAgICAgICAgLy8gb3RoZXJ3aXNlIHRoZSBmaXJzdCBkcmFnIGV2ZW4gd2lsbCBub3Qgc25hcCwgY2F1c2luZyBhIGp1bXAgYmVmb3JlXG4gICAgICAgICAgLy8gaXQgc25hcHMgdG8gaXRzIHBvc2l0aW9uIGlmIHByZXZpb3VzbHkgc25hcHBlZCBhbHJlYWR5LlxuXG5cbiAgICAgICAgICB0aGlzLm1heWJlQ2FjaGVWaXNpYmxlR2FwcyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgICAgdGhpcy5tYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgICAgY29uc3Qge1xuICAgICAgICAgICAgc25hcE9mZnNldCxcbiAgICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICAgIH0gPSBzbmFwRHJhZ2dlZEVsZW1lbnRzKGdldFNlbGVjdGVkRWxlbWVudHMob3JpZ2luYWxFbGVtZW50cywgdGhpcy5zdGF0ZSksIGRyYWdPZmZzZXQsIHRoaXMuc3RhdGUsIGV2ZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICAgIH0pOyAvLyB3aGVuIHdlJ3JlIGVkaXRpbmcgdGhlIG5hbWUgb2YgYSBmcmFtZSwgd2Ugd2FudCB0aGUgdXNlciB0byBiZVxuICAgICAgICAgIC8vIGFibGUgdG8gc2VsZWN0IGFuZCBpbnRlcmFjdCB3aXRoIHRoZSB0ZXh0IGlucHV0XG5cbiAgICAgICAgICAhdGhpcy5zdGF0ZS5lZGl0aW5nRnJhbWUgJiYgZHJhZ1NlbGVjdGVkRWxlbWVudHMocG9pbnRlckRvd25TdGF0ZSwgc2VsZWN0ZWRFbGVtZW50cywgZHJhZ09mZnNldCwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZSwgc25hcE9mZnNldCwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpOyAvLyBXZSBkdXBsaWNhdGUgdGhlIHNlbGVjdGVkIGVsZW1lbnQgaWYgYWx0IGlzIHByZXNzZWQgb24gcG9pbnRlciBtb3ZlXG5cbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5ICYmICFwb2ludGVyRG93blN0YXRlLmhpdC5oYXNCZWVuRHVwbGljYXRlZCkge1xuICAgICAgICAgICAgLy8gTW92ZSB0aGUgY3VycmVudGx5IHNlbGVjdGVkIGVsZW1lbnRzIHRvIHRoZSB0b3Agb2YgdGhlIHogaW5kZXggc3RhY2ssIGFuZFxuICAgICAgICAgICAgLy8gcHV0IHRoZSBkdXBsaWNhdGVzIHdoZXJlIHRoZSBzZWxlY3RlZCBlbGVtZW50cyB1c2VkIHRvIGJlLlxuICAgICAgICAgICAgLy8gKHRoZSBvcmlnaW4gcG9pbnQgd2hlcmUgdGhlIGRyYWdnaW5nIHN0YXJ0ZWQpXG4gICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC5oYXNCZWVuRHVwbGljYXRlZCA9IHRydWU7XG4gICAgICAgICAgICBjb25zdCBuZXh0RWxlbWVudHMgPSBbXTtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzVG9BcHBlbmQgPSBbXTtcbiAgICAgICAgICAgIGNvbnN0IGdyb3VwSWRNYXAgPSBuZXcgTWFwKCk7XG4gICAgICAgICAgICBjb25zdCBvbGRJZFRvRHVwbGljYXRlZElkID0gbmV3IE1hcCgpO1xuICAgICAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQ7XG4gICAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRJZHMgPSBuZXcgU2V0KHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMsXG4gICAgICAgICAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlLFxuICAgICAgICAgICAgICBpbmNsdWRlRWxlbWVudHNJbkZyYW1lczogdHJ1ZVxuICAgICAgICAgICAgfSkubWFwKGVsZW1lbnQgPT4gZWxlbWVudC5pZCkpO1xuICAgICAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZWxlbWVudHMpIHtcbiAgICAgICAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudElkcy5oYXMoZWxlbWVudC5pZCkgfHwgLy8gY2FzZTogdGhlIHN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyBtaWdodCBub3QgaGF2ZSBiZWVuXG4gICAgICAgICAgICAgIC8vIHVwZGF0ZWQgeWV0IGJ5IHRoZSB0aW1lIHRoaXMgbW91c2Vtb3ZlIGV2ZW50IGlzIGZpcmVkXG4gICAgICAgICAgICAgIGVsZW1lbnQuaWQgPT09IChoaXRFbGVtZW50ID09PSBudWxsIHx8IGhpdEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGhpdEVsZW1lbnQuaWQpICYmIHBvaW50ZXJEb3duU3RhdGUuaGl0Lndhc0FkZGVkVG9TZWxlY3Rpb24pIHtcbiAgICAgICAgICAgICAgICBjb25zdCBkdXBsaWNhdGVkRWxlbWVudCA9IGR1cGxpY2F0ZUVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCwgZ3JvdXBJZE1hcCwgZWxlbWVudCk7XG4gICAgICAgICAgICAgICAgY29uc3Qgb3JpZ0VsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLm9yaWdpbmFsRWxlbWVudHMuZ2V0KGVsZW1lbnQuaWQpO1xuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHVwbGljYXRlZEVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgIHg6IG9yaWdFbGVtZW50LngsXG4gICAgICAgICAgICAgICAgICB5OiBvcmlnRWxlbWVudC55XG4gICAgICAgICAgICAgICAgfSk7IC8vIHB1dCBkdXBsaWNhdGVkIGVsZW1lbnQgdG8gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzXG4gICAgICAgICAgICAgICAgLy8gc28gdGhhdCB3ZSBjYW4gc25hcCB0byB0aGUgZHVwbGljYXRlZCBlbGVtZW50IHdpdGhvdXQgcmVsZWFzaW5nXG5cbiAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLm9yaWdpbmFsRWxlbWVudHMuc2V0KGR1cGxpY2F0ZWRFbGVtZW50LmlkLCBkdXBsaWNhdGVkRWxlbWVudCk7XG4gICAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzLnB1c2goZHVwbGljYXRlZEVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIGVsZW1lbnRzVG9BcHBlbmQucHVzaChlbGVtZW50KTtcbiAgICAgICAgICAgICAgICBvbGRJZFRvRHVwbGljYXRlZElkLnNldChlbGVtZW50LmlkLCBkdXBsaWNhdGVkRWxlbWVudC5pZCk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzLnB1c2goZWxlbWVudCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbmV4dFNjZW5lRWxlbWVudHMgPSBbLi4ubmV4dEVsZW1lbnRzLCAuLi5lbGVtZW50c1RvQXBwZW5kXTtcbiAgICAgICAgICAgIGJpbmRUZXh0VG9TaGFwZUFmdGVyRHVwbGljYXRpb24obmV4dEVsZW1lbnRzLCBlbGVtZW50c1RvQXBwZW5kLCBvbGRJZFRvRHVwbGljYXRlZElkKTtcbiAgICAgICAgICAgIGZpeEJpbmRpbmdzQWZ0ZXJEdXBsaWNhdGlvbihuZXh0U2NlbmVFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCwgXCJkdXBsaWNhdGVzU2VydmVBc09sZFwiKTtcbiAgICAgICAgICAgIGJpbmRFbGVtZW50c1RvRnJhbWVzQWZ0ZXJEdXBsaWNhdGlvbihuZXh0U2NlbmVFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCk7XG4gICAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0U2NlbmVFbGVtZW50cyk7XG4gICAgICAgICAgICB0aGlzLm1heWJlQ2FjaGVWaXNpYmxlR2FwcyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgdHJ1ZSk7XG4gICAgICAgICAgICB0aGlzLm1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzLCB0cnVlKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gLy8gSXQgaXMgdmVyeSBpbXBvcnRhbnQgdG8gcmVhZCB0aGlzLnN0YXRlIHdpdGhpbiBlYWNoIG1vdmUgZXZlbnQsXG4gICAgICAvLyBvdGhlcndpc2Ugd2Ugd291bGQgcmVhZCBhIHN0YWxlIG9uZSFcblxuXG4gICAgICBjb25zdCBkcmFnZ2luZ0VsZW1lbnQgPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudDtcblxuICAgICAgaWYgKCFkcmFnZ2luZ0VsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZHJhZ2dpbmdFbGVtZW50LnR5cGUgPT09IFwiZnJlZWRyYXdcIikge1xuICAgICAgICBjb25zdCBwb2ludHMgPSBkcmFnZ2luZ0VsZW1lbnQucG9pbnRzO1xuICAgICAgICBjb25zdCBkeCA9IHBvaW50ZXJDb29yZHMueCAtIGRyYWdnaW5nRWxlbWVudC54O1xuICAgICAgICBjb25zdCBkeSA9IHBvaW50ZXJDb29yZHMueSAtIGRyYWdnaW5nRWxlbWVudC55O1xuICAgICAgICBjb25zdCBsYXN0UG9pbnQgPSBwb2ludHMubGVuZ3RoID4gMCAmJiBwb2ludHNbcG9pbnRzLmxlbmd0aCAtIDFdO1xuICAgICAgICBjb25zdCBkaXNjYXJkUG9pbnQgPSBsYXN0UG9pbnQgJiYgbGFzdFBvaW50WzBdID09PSBkeCAmJiBsYXN0UG9pbnRbMV0gPT09IGR5O1xuXG4gICAgICAgIGlmICghZGlzY2FyZFBvaW50KSB7XG4gICAgICAgICAgY29uc3QgcHJlc3N1cmVzID0gZHJhZ2dpbmdFbGVtZW50LnNpbXVsYXRlUHJlc3N1cmUgPyBkcmFnZ2luZ0VsZW1lbnQucHJlc3N1cmVzIDogWy4uLmRyYWdnaW5nRWxlbWVudC5wcmVzc3VyZXMsIGV2ZW50LnByZXNzdXJlXTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLCBbZHgsIGR5XV0sXG4gICAgICAgICAgICBwcmVzc3VyZXNcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChpc0xpbmVhckVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSkge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBwb2ludHMgPSBkcmFnZ2luZ0VsZW1lbnQucG9pbnRzO1xuICAgICAgICBsZXQgZHggPSBncmlkWCAtIGRyYWdnaW5nRWxlbWVudC54O1xuICAgICAgICBsZXQgZHkgPSBncmlkWSAtIGRyYWdnaW5nRWxlbWVudC55O1xuXG4gICAgICAgIGlmIChzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZShldmVudCkgJiYgcG9pbnRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgICh7XG4gICAgICAgICAgICB3aWR0aDogZHgsXG4gICAgICAgICAgICBoZWlnaHQ6IGR5XG4gICAgICAgICAgfSA9IGdldExvY2tlZExpbmVhckN1cnNvckFsaWduU2l6ZShkcmFnZ2luZ0VsZW1lbnQueCwgZHJhZ2dpbmdFbGVtZW50LnksIHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55KSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocG9pbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtkeCwgZHldXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKHBvaW50cy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLnNsaWNlKDAsIC0xKSwgW2R4LCBkeV1dXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNCaW5kaW5nRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgICAgIC8vIFdoZW4gY3JlYXRpbmcgYSBsaW5lYXIgZWxlbWVudCBieSBkcmFnZ2luZ1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ3NGb3JMaW5lYXJFbGVtZW50QXRDb29yZHMoZHJhZ2dpbmdFbGVtZW50LCBbcG9pbnRlckNvb3Jkc10sIHRoaXMuc3RhdGUuc3RhcnRCb3VuZEVsZW1lbnQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHBvaW50ZXJDb29yZHMueDtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBwb2ludGVyQ29vcmRzLnk7XG4gICAgICAgIHRoaXMubWF5YmVEcmFnTmV3R2VuZXJpY0VsZW1lbnQocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5ib3hTZWxlY3Rpb24uaGFzT2NjdXJyZWQgPSB0cnVlO1xuICAgICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCk7IC8vIGJveC1zZWxlY3QgbGluZSBlZGl0b3IgcG9pbnRzXG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZUJveFNlbGVjdGlvbihldmVudCwgdGhpcy5zdGF0ZSwgdGhpcy5zZXRTdGF0ZS5iaW5kKHRoaXMpKTsgLy8gcmVndWxhciBib3gtc2VsZWN0XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbGV0IHNob3VsZFJldXNlU2VsZWN0aW9uID0gdHJ1ZTtcblxuICAgICAgICAgIGlmICghZXZlbnQuc2hpZnRLZXkgJiYgaXNTb21lRWxlbWVudFNlbGVjdGVkKGVsZW1lbnRzLCB0aGlzLnN0YXRlKSkge1xuICAgICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUud2l0aENtZE9yQ3RybCAmJiBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSB7XG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgICBbcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pLCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHNob3VsZFJldXNlU2VsZWN0aW9uID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24gPSBnZXRFbGVtZW50c1dpdGhpblNlbGVjdGlvbihlbGVtZW50cywgZHJhZ2dpbmdFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzaG91bGRSZXVzZVNlbGVjdGlvbiAmJiBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwgZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24ucmVkdWNlKChhY2MsIGVsZW1lbnQpID0+IHtcbiAgICAgICAgICAgICAgYWNjW2VsZW1lbnQuaWRdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgICAgIH0sIHt9KSk7XG5cbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSB7XG4gICAgICAgICAgICAgIC8vIGlmIHVzaW5nIGN0cmwvY21kLCBzZWxlY3QgdGhlIGhpdEVsZW1lbnQgb25seSBpZiB3ZVxuICAgICAgICAgICAgICAvLyBoYXZlbid0IGJveC1zZWxlY3RlZCBhbnl0aGluZyBlbHNlXG4gICAgICAgICAgICAgIGlmICghZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgbmV4dFNlbGVjdGVkRWxlbWVudElkc1twb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcHJldlN0YXRlID0gIXNob3VsZFJldXNlU2VsZWN0aW9uID8gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUpLCB7XG4gICAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbFxuICAgICAgICAgICAgfSkgOiBwcmV2U3RhdGU7XG4gICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICAvLyBzZWxlY3QgbGluZWFyIGVsZW1lbnQgb25seSB3aGVuIHdlIGhhdmVuJ3QgYm94LXNlbGVjdGVkIGFueXRoaW5nIGVsc2VcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBlbGVtZW50c1dpdGhpblNlbGVjdGlvbi5sZW5ndGggPT09IDEgJiYgaXNMaW5lYXJFbGVtZW50KGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdKSA/IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdLCB0aGlzLnNjZW5lKSA6IG51bGwsXG4gICAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24ubGVuZ3RoID09PSAxICYmIChlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXS5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0pKSA/IFwiaW5mb1wiIDogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH0gLy8gUmV0dXJucyB3aGV0aGVyIHRoZSBwb2ludGVyIG1vdmUgaGFwcGVuZWQgb3ZlciBlaXRoZXIgc2Nyb2xsYmFyXG5cblxuICBoYW5kbGVQb2ludGVyTW92ZU92ZXJTY3JvbGxiYXJzKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSB7XG4gICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJIb3Jpem9udGFsKSB7XG4gICAgICBjb25zdCB4ID0gZXZlbnQuY2xpZW50WDtcbiAgICAgIGNvbnN0IGR4ID0geCAtIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54O1xuICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoe1xuICAgICAgICBzY3JvbGxYOiB0aGlzLnN0YXRlLnNjcm9sbFggLSBkeCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZVxuICAgICAgfSk7XG4gICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHg7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5zY3JvbGxiYXJzLmlzT3ZlclZlcnRpY2FsKSB7XG4gICAgICBjb25zdCB5ID0gZXZlbnQuY2xpZW50WTtcbiAgICAgIGNvbnN0IGR5ID0geSAtIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55O1xuICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoe1xuICAgICAgICBzY3JvbGxZOiB0aGlzLnN0YXRlLnNjcm9sbFkgLSBkeSAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZVxuICAgICAgfSk7XG4gICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBvblBvaW50ZXJVcEZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSkge1xuICAgIHJldHVybiB3aXRoQmF0Y2hlZFVwZGF0ZXMoY2hpbGRFdmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZjtcblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25Nb3ZlKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25Nb3ZlLmZsdXNoKCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZHJhZ2dpbmdFbGVtZW50LFxuICAgICAgICByZXNpemluZ0VsZW1lbnQsXG4gICAgICAgIG11bHRpRWxlbWVudCxcbiAgICAgICAgYWN0aXZlVG9vbCxcbiAgICAgICAgaXNSZXNpemluZyxcbiAgICAgICAgaXNSb3RhdGluZ1xuICAgICAgfSA9IHRoaXMuc3RhdGU7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgaXNSZXNpemluZzogZmFsc2UsXG4gICAgICAgIGlzUm90YXRpbmc6IGZhbHNlLFxuICAgICAgICByZXNpemluZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGlvbkVsZW1lbnQ6IG51bGwsXG4gICAgICAgIGZyYW1lVG9IaWdobGlnaHQ6IG51bGwsXG4gICAgICAgIGVsZW1lbnRzVG9IaWdobGlnaHQ6IG51bGwsXG4gICAgICAgIGN1cnNvckJ1dHRvbjogXCJ1cFwiLFxuICAgICAgICAvLyB0ZXh0IGVsZW1lbnRzIGFyZSByZXNldCBvbiBmaW5hbGl6ZSwgYW5kIHJlc2V0dGluZyBvbiBwb2ludGVydXBcbiAgICAgICAgLy8gbWF5IGNhdXNlIGlzc3VlcyB3aXRoIGRvdWJsZSB0YXBzXG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBtdWx0aUVsZW1lbnQgfHwgaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA/IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQgOiBudWxsLFxuICAgICAgICBzbmFwTGluZXM6IFtdLFxuICAgICAgICBvcmlnaW5TbmFwT2Zmc2V0OiBudWxsXG4gICAgICB9KTtcbiAgICAgIFNuYXBDYWNoZS5zZXRSZWZlcmVuY2VTbmFwUG9pbnRzKG51bGwpO1xuICAgICAgU25hcENhY2hlLnNldFZpc2libGVHYXBzKG51bGwpO1xuICAgICAgdGhpcy5zYXZlUG9pbnRlcihjaGlsZEV2ZW50LmNsaWVudFgsIGNoaWxkRXZlbnQuY2xpZW50WSwgXCJ1cFwiKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkOiBmYWxzZVxuICAgICAgfSk7IC8vIEhhbmRsZSBlbmQgb2YgZHJhZ2dpbmcgYSBwb2ludCBvZiBhIGxpbmVhciBlbGVtZW50LCBtaWdodCBjbG9zZSBhIGxvb3BcbiAgICAgIC8vIGFuZCBzZXRzIGJpbmRpbmcgZWxlbWVudFxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICBpZiAoIXBvaW50ZXJEb3duU3RhdGUuYm94U2VsZWN0aW9uLmhhc09jY3VycmVkICYmICgoX2IgPSAoX2EgPSBwb2ludGVyRG93blN0YXRlLmhpdCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5pZCkgIT09IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkKSB7XG4gICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnN0IGVkaXRpbmdMaW5lYXJFbGVtZW50ID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludGVyVXAoY2hpbGRFdmVudCwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgICBpZiAoZWRpdGluZ0xpbmVhckVsZW1lbnQgIT09IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudCxcbiAgICAgICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgaWYgKCgoX2QgPSAoX2MgPSBwb2ludGVyRG93blN0YXRlLmhpdCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmVsZW1lbnQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5pZCkgIT09IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCkge1xuICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRUxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7IC8vIHNldCBzZWxlY3RlZExpbmVhckVsZW1lbnQgdG8gbnVsbCBpZiB0aGVyZSBpcyBtb3JlIHRoYW4gb25lIGVsZW1lbnQgc2VsZWN0ZWQgc2luY2Ugd2UgZG9uJ3Qgd2FudCB0byBzaG93IGxpbmVhciBlbGVtZW50IGhhbmRsZXNcblxuICAgICAgICAgIGlmIChzZWxlY3RlZEVMZW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG51bGxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBsaW5lYXJFbGVtZW50RWRpdG9yID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludGVyVXAoY2hpbGRFdmVudCwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgIHN0YXJ0QmluZGluZ0VsZW1lbnQsXG4gICAgICAgICAgICBlbmRCaW5kaW5nRWxlbWVudFxuICAgICAgICAgIH0gPSBsaW5lYXJFbGVtZW50RWRpdG9yO1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnQobGluZWFyRWxlbWVudEVkaXRvci5lbGVtZW50SWQpO1xuXG4gICAgICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnQoZWxlbWVudCkpIHtcbiAgICAgICAgICAgIGJpbmRPclVuYmluZExpbmVhckVsZW1lbnQoZWxlbWVudCwgc3RhcnRCaW5kaW5nRWxlbWVudCwgZW5kQmluZGluZ0VsZW1lbnQpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChsaW5lYXJFbGVtZW50RWRpdG9yICE9PSB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBsaW5lYXJFbGVtZW50RWRpdG9yKSwge1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkUG9pbnRzSW5kaWNlczogbnVsbFxuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25Nb3ZlKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25VcCk7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlET1dOLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5RG93bik7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbktleVVwKTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHBlbmRpbmdJbWFnZUVsZW1lbnRJZDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5vblBvaW50ZXJVcEVtaXR0ZXIudHJpZ2dlcih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wsIHBvaW50ZXJEb3duU3RhdGUsIGNoaWxkRXZlbnQpO1xuXG4gICAgICBpZiAoKGRyYWdnaW5nRWxlbWVudCA9PT0gbnVsbCB8fCBkcmFnZ2luZ0VsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGRyYWdnaW5nRWxlbWVudC50eXBlKSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoY2hpbGRFdmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IHBvaW50cyA9IGRyYWdnaW5nRWxlbWVudC5wb2ludHM7XG4gICAgICAgIGxldCBkeCA9IHBvaW50ZXJDb29yZHMueCAtIGRyYWdnaW5nRWxlbWVudC54O1xuICAgICAgICBsZXQgZHkgPSBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueTsgLy8gQWxsb3dzIGRvdHMgdG8gYXZvaWQgYmVpbmcgZmxhZ2dlZCBhcyBpbmZpbml0ZWx5IHNtYWxsXG5cbiAgICAgICAgaWYgKGR4ID09PSBwb2ludHNbMF1bMF0gJiYgZHkgPT09IHBvaW50c1swXVsxXSkge1xuICAgICAgICAgIGR5ICs9IDAuMDAwMTtcbiAgICAgICAgICBkeCArPSAwLjAwMDE7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwcmVzc3VyZXMgPSBkcmFnZ2luZ0VsZW1lbnQuc2ltdWxhdGVQcmVzc3VyZSA/IFtdIDogWy4uLmRyYWdnaW5nRWxlbWVudC5wcmVzc3VyZXMsIGNoaWxkRXZlbnQucHJlc3N1cmVdO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dLFxuICAgICAgICAgIHByZXNzdXJlcyxcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnQ6IFtkeCwgZHldXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gZHJhZ2dpbmdFbGVtZW50O1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zKGltYWdlRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgICAgW2ltYWdlRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSBpbWFnZUVsZW1lbnQuaWQpKTtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0xpbmVhckVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSkge1xuICAgICAgICBpZiAoZHJhZ2dpbmdFbGVtZW50LnBvaW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhjaGlsZEV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoIXBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiBkcmFnZ2luZ0VsZW1lbnQgJiYgIW11bHRpRWxlbWVudCkge1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucG9pbnRzLCBbcG9pbnRlckNvb3Jkcy54IC0gZHJhZ2dpbmdFbGVtZW50LngsIHBvaW50ZXJDb29yZHMueSAtIGRyYWdnaW5nRWxlbWVudC55XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIG11bHRpRWxlbWVudDogZHJhZ2dpbmdFbGVtZW50LFxuICAgICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAocG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICFtdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgICBpZiAoaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSAmJiBpc0JpbmRpbmdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICAgICAgICBtYXliZUJpbmRMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZSwgcG9pbnRlckNvb3Jkcyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgICBzdGFydEJvdW5kRWxlbWVudDogbnVsbFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKCFhY3RpdmVUb29sLmxvY2tlZCkge1xuICAgICAgICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgIFtkcmFnZ2luZ0VsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH0pLCBwcmV2U3RhdGUpLFxuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zY2VuZSlcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiICYmIGRyYWdnaW5nRWxlbWVudCAmJiBpc0ludmlzaWJseVNtYWxsRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpKSB7XG4gICAgICAgIC8vIHJlbW92ZSBpbnZpc2libGUgZWxlbWVudCB3aGljaCB3YXMgYWRkZWQgaW4gb25Qb2ludGVyRG93blxuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbHRlcihlbCA9PiBlbC5pZCAhPT0gZHJhZ2dpbmdFbGVtZW50LmlkKSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQpIHtcbiAgICAgICAgICBjb25zdCBzY2VuZUNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhjaGlsZEV2ZW50LCB0aGlzLnN0YXRlKTsgLy8gd2hlbiBlZGl0aW5nIHRoZSBwb2ludHMgb2YgYSBsaW5lYXIgZWxlbWVudCwgd2UgY2hlY2sgaWYgdGhlXG4gICAgICAgICAgLy8gbGluZWFyIGVsZW1lbnQgc3RpbGwgaXMgaW4gdGhlIGZyYW1lIGFmdGVyd2FyZHNcbiAgICAgICAgICAvLyBpZiBub3QsIHRoZSBsaW5lYXIgZWxlbWVudCB3aWxsIGJlIHJlbW92ZWQgZnJvbSBpdHMgZnJhbWUgKGlmIGFueSlcblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICBjb25zdCBsaW5lYXJFbGVtZW50ID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCk7XG5cbiAgICAgICAgICAgIGlmIChsaW5lYXJFbGVtZW50ID09PSBudWxsIHx8IGxpbmVhckVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGxpbmVhckVsZW1lbnQuZnJhbWVJZCkge1xuICAgICAgICAgICAgICBjb25zdCBmcmFtZSA9IGdldENvbnRhaW5pbmdGcmFtZShsaW5lYXJFbGVtZW50KTtcblxuICAgICAgICAgICAgICBpZiAoZnJhbWUgJiYgbGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICAgIGlmICghZWxlbWVudE92ZXJsYXBzV2l0aEZyYW1lKGxpbmVhckVsZW1lbnQsIGZyYW1lKSkge1xuICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlIHRoZSBsaW5lYXIgZWxlbWVudCBmcm9tIGFsbCBncm91cHNcbiAgICAgICAgICAgICAgICAgIC8vIGJlZm9yZSByZW1vdmluZyBpdCBmcm9tIHRoZSBmcmFtZSBhcyB3ZWxsXG4gICAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGxpbmVhckVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZHM6IFtdXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHJlbW92ZUVsZW1lbnRzRnJvbUZyYW1lKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIFtsaW5lYXJFbGVtZW50XSwgdGhpcy5zdGF0ZSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyB1cGRhdGUgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBzZWxlY3RlZCBlbGVtZW50cyBhbmQgZnJhbWVzXG4gICAgICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3JkcyhzY2VuZUNvb3Jkcyk7XG4gICAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgbGV0IG5leHRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG5cbiAgICAgICAgICAgIGNvbnN0IHVwZGF0ZUdyb3VwSWRzQWZ0ZXJFZGl0aW5nR3JvdXAgPSBlbGVtZW50cyA9PiB7XG4gICAgICAgICAgICAgIGlmIChlbGVtZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBpbmRleCA9IGVsZW1lbnQuZ3JvdXBJZHMuaW5kZXhPZih0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkKTtcbiAgICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgICBncm91cElkczogZWxlbWVudC5ncm91cElkcy5zbGljZSgwLCBpbmRleClcbiAgICAgICAgICAgICAgICAgIH0sIGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBuZXh0RWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50Lmdyb3VwSWRzLmxlbmd0aCAmJiBnZXRFbGVtZW50c0luR3JvdXAobmV4dEVsZW1lbnRzLCBlbGVtZW50Lmdyb3VwSWRzW2VsZW1lbnQuZ3JvdXBJZHMubGVuZ3RoIC0gMV0pLmxlbmd0aCA8IDIpIHtcbiAgICAgICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZHM6IFtdXG4gICAgICAgICAgICAgICAgICAgIH0sIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICh0b3BMYXllckZyYW1lICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0b3BMYXllckZyYW1lLmlkXSkge1xuICAgICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvQWRkID0gc2VsZWN0ZWRFbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LmZyYW1lSWQgIT09IHRvcExheWVyRnJhbWUuaWQgJiYgaXNFbGVtZW50SW5GcmFtZShlbGVtZW50LCBuZXh0RWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcblxuICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHVwZGF0ZUdyb3VwSWRzQWZ0ZXJFZGl0aW5nR3JvdXAoZWxlbWVudHNUb0FkZCk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBuZXh0RWxlbWVudHMgPSBhZGRFbGVtZW50c1RvRnJhbWUobmV4dEVsZW1lbnRzLCBlbGVtZW50c1RvQWRkLCB0b3BMYXllckZyYW1lKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIXRvcExheWVyRnJhbWUpIHtcbiAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvUmVtb3ZlID0gc2VsZWN0ZWRFbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LmZyYW1lSWQgJiYgIWlzRWxlbWVudEluRnJhbWUoZWxlbWVudCwgbmV4dEVsZW1lbnRzLCB0aGlzLnN0YXRlKSk7XG4gICAgICAgICAgICAgICAgdXBkYXRlR3JvdXBJZHNBZnRlckVkaXRpbmdHcm91cChlbGVtZW50c1RvUmVtb3ZlKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBuZXh0RWxlbWVudHMgPSB1cGRhdGVGcmFtZU1lbWJlcnNoaXBPZlNlbGVjdGVkRWxlbWVudHMobmV4dEVsZW1lbnRzLCB0aGlzLnN0YXRlLCB0aGlzKTtcbiAgICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKG5leHRFbGVtZW50cyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpIHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50c0luc2lkZUZyYW1lID0gZ2V0RWxlbWVudHNJbk5ld0ZyYW1lKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGRyYWdnaW5nRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoYWRkRWxlbWVudHNUb0ZyYW1lKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGVsZW1lbnRzSW5zaWRlRnJhbWUsIGRyYWdnaW5nRWxlbWVudCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGdldE5vcm1hbGl6ZWREaW1lbnNpb25zKGRyYWdnaW5nRWxlbWVudCkpO1xuICAgICAgfVxuXG4gICAgICBpZiAocmVzaXppbmdFbGVtZW50KSB7XG4gICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHJlc2l6aW5nRWxlbWVudCAmJiBpc0ludmlzaWJseVNtYWxsRWxlbWVudChyZXNpemluZ0VsZW1lbnQpKSB7XG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSByZXNpemluZ0VsZW1lbnQuaWQpKTtcbiAgICAgIH0gLy8gaGFuZGxlIGZyYW1lIG1lbWJlcnNoaXAgZm9yIHJlc2l6aW5nIGZyYW1lcyBhbmQvb3Igc2VsZWN0ZWQgZWxlbWVudHNcblxuXG4gICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaXNSZXNpemluZykge1xuICAgICAgICBsZXQgbmV4dEVsZW1lbnRzID0gdXBkYXRlRnJhbWVNZW1iZXJzaGlwT2ZTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMuc3RhdGUsIHRoaXMpO1xuICAgICAgICBjb25zdCBzZWxlY3RlZEZyYW1lcyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKS5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG5cbiAgICAgICAgZm9yIChjb25zdCBmcmFtZSBvZiBzZWxlY3RlZEZyYW1lcykge1xuICAgICAgICAgIG5leHRFbGVtZW50cyA9IHJlcGxhY2VBbGxFbGVtZW50c0luRnJhbWUobmV4dEVsZW1lbnRzLCBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBmcmFtZSwgdGhpcy5zdGF0ZSksIGZyYW1lLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKG5leHRFbGVtZW50cyk7XG4gICAgICB9IC8vIENvZGUgYmVsb3cgaGFuZGxlcyBzZWxlY3Rpb24gd2hlbiBlbGVtZW50KHMpIHdlcmVuJ3RcbiAgICAgIC8vIGRyYWcgb3IgYWRkZWQgdG8gc2VsZWN0aW9uIG9uIHBvaW50ZXIgZG93biBwaGFzZS5cblxuXG4gICAgICBjb25zdCBoaXRFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudDtcblxuICAgICAgaWYgKCgoX2UgPSB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLmVsZW1lbnRJZCkgIT09IChoaXRFbGVtZW50ID09PSBudWxsIHx8IGhpdEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGhpdEVsZW1lbnQuaWQpICYmIGlzTGluZWFyRWxlbWVudChoaXRFbGVtZW50KSkge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVMZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpOyAvLyBzZXQgc2VsZWN0ZWRMaW5lYXJFbGVtZW50IHdoZW4gbm8gb3RoZXIgZWxlbWVudCBzZWxlY3RlZCBleGNlcHRcbiAgICAgICAgLy8gdGhlIG9uZSB3ZSd2ZSBoaXRcblxuICAgICAgICBpZiAoc2VsZWN0ZWRFTGVtZW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoaGl0RWxlbWVudCwgdGhpcy5zY2VuZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoaXNFcmFzZXJBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgY29uc3QgZHJhZ2dlZERpc3RhbmNlID0gZGlzdGFuY2UyZCh0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50LmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQuY2xpZW50WSwgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WSk7XG5cbiAgICAgICAgaWYgKGRyYWdnZWREaXN0YW5jZSA9PT0gMCkge1xuICAgICAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICBjbGllbnRYOiB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC5jbGllbnRYLFxuICAgICAgICAgICAgY2xpZW50WTogdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WVxuICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnRzID0gdGhpcy5nZXRFbGVtZW50c0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgICAgICBoaXRFbGVtZW50cy5mb3JFYWNoKGhpdEVsZW1lbnQgPT4gcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtoaXRFbGVtZW50LmlkXSA9IHtcbiAgICAgICAgICAgIGVyYXNlOiB0cnVlLFxuICAgICAgICAgICAgb3BhY2l0eTogaGl0RWxlbWVudC5vcGFjaXR5XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmVyYXNlRWxlbWVudHMocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAoT2JqZWN0LmtleXMocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZSkubGVuZ3RoKSB7XG4gICAgICAgIHRoaXMucmVzdG9yZVJlYWR5VG9FcmFzZUVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoaGl0RWxlbWVudCAmJiAhcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICFwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uICYmICggLy8gaWYgd2UncmUgZWRpdGluZyBhIGxpbmUsIHBvaW50ZXJ1cCBzaG91bGRuJ3Qgc3dpdGNoIHNlbGVjdGlvbiBpZlxuICAgICAgLy8gYm94IHNlbGVjdGVkXG4gICAgICAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCAhcG9pbnRlckRvd25TdGF0ZS5ib3hTZWxlY3Rpb24uaGFzT2NjdXJyZWQpKSB7XG4gICAgICAgIC8vIHdoZW4gaW5zaWRlIGxpbmUgZWRpdG9yLCBzaGlmdCBzZWxlY3RzIHBvaW50cyBpbnN0ZWFkXG4gICAgICAgIGlmIChjaGlsZEV2ZW50LnNoaWZ0S2V5ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdKSB7XG4gICAgICAgICAgICBpZiAoaXNTZWxlY3RlZFZpYUdyb3VwKHRoaXMuc3RhdGUsIGhpdEVsZW1lbnQpKSB7XG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoX3ByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oe30sIF9wcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTsgLy8gV2Ugd2FudCB0byB1bnNlbGVjdCBhbGwgZ3JvdXBzIGhpdEVsZW1lbnQgaXMgcGFydCBvZlxuICAgICAgICAgICAgICAgIC8vIGFzIHdlbGwgYXMgYWxsIGVsZW1lbnRzIHRoYXQgYXJlIHBhcnQgb2YgdGhlIGdyb3Vwc1xuICAgICAgICAgICAgICAgIC8vIGhpdEVsZW1lbnQgaXMgcGFydCBvZlxuXG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBncm91cGVkRWxlbWVudCBvZiBoaXRFbGVtZW50Lmdyb3VwSWRzLmZsYXRNYXAoZ3JvdXBJZCA9PiBnZXRFbGVtZW50c0luR3JvdXAodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZ3JvdXBJZCkpKSB7XG4gICAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tncm91cGVkRWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgX3ByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCBoaXRFbGVtZW50Lmdyb3VwSWRzLm1hcChnSWQgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgW2dJZF06IGZhbHNlXG4gICAgICAgICAgICAgICAgICB9KSkucmVkdWNlKChwcmV2LCBhY2MpID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldiksIGFjYyksIHt9KSksXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKG5leHRTZWxlY3RlZEVsZW1lbnRJZHMsIF9wcmV2U3RhdGUpXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgfSk7IC8vIGlmIG5vdCBncmFnZ2luZyBhIGxpbmVhciBlbGVtZW50IHBvaW50IChvdXRzaWRlIGVkaXRvcilcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoISgoX2YgPSB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkgPT09IG51bGwgfHwgX2YgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9mLmlzRHJhZ2dpbmcpKSB7XG4gICAgICAgICAgICAgIC8vIHJlbW92ZSBlbGVtZW50IGZyb20gc2VsZWN0aW9uIHdoaWxlXG4gICAgICAgICAgICAgIC8vIGtlZXBpbmcgcHJldiBlbGVtZW50cyBzZWxlY3RlZFxuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgbmV3U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7XG4gICAgICAgICAgICAgICAgZGVsZXRlIG5ld1NlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXdTZWxlY3RlZEVsZW1lbnRzID0gZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB7XG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5ld1NlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV3U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgICAgIC8vIHNldCBzZWxlY3RlZExpbmVhckVsZW1lbnQgb25seSBpZiB0aGF0cyB0aGUgb25seSBlbGVtZW50IHNlbGVjdGVkXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG5ld1NlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmIGlzTGluZWFyRWxlbWVudChuZXdTZWxlY3RlZEVsZW1lbnRzWzBdKSA/IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKG5ld1NlbGVjdGVkRWxlbWVudHNbMF0sIHRoaXMuc2NlbmUpIDogcHJldlN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKGhpdEVsZW1lbnQuZnJhbWVJZCAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmZyYW1lSWRdKSB7XG4gICAgICAgICAgICAvLyB3aGVuIGhpdEVsZW1lbnQgaXMgcGFydCBvZiBhIHNlbGVjdGVkIGZyYW1lLCBkZXNlbGVjdCB0aGUgZnJhbWVcbiAgICAgICAgICAgIC8vIHRvIGF2b2lkIGZyYW1lIGFuZCBjb250YWluaW5nIGVsZW1lbnRzIHNlbGVjdGVkIHNpbXVsdGFuZW91c2x5XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgfSk7IC8vIGRlc2VsZWN0IHRoZSBmcmFtZVxuXG4gICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuZnJhbWVJZF07IC8vIGRlc2VsZWN0IGdyb3VwcyBjb250YWluaW5nIHRoZSBmcmFtZVxuXG4gICAgICAgICAgICAgICgoX2IgPSAoX2EgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnQoaGl0RWxlbWVudC5mcmFtZUlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmdyb3VwSWRzKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiBbXSkuZmxhdE1hcChnaWQgPT4gZ2V0RWxlbWVudHNJbkdyb3VwKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGdpZCkpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dFNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogaGl0RWxlbWVudC5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGFkZCBlbGVtZW50IHRvIHNlbGVjdGlvbiB3aGlsZSBrZWVwaW5nIHByZXYgZWxlbWVudHMgc2VsZWN0ZWRcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoX3ByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgX3ByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgICAgW2hpdEVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH0pLCBfcHJldlN0YXRlKVxuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBpc0xpbmVhckVsZW1lbnQoaGl0RWxlbWVudCkgJiYgLy8gRG9uJ3Qgc2V0IGBzZWxlY3RlZExpbmVhckVsZW1lbnRgIGlmIGl0cyBzYW1lIGFzIHRoZSBoaXRFbGVtZW50LCB0aGlzIGlzIG1haW5seSB0byBwcmV2ZW50IHJlc2V0dGluZyB0aGUgYGhvdmVyUG9pbnRJbmRleGAgdG8gLTEuXG4gICAgICAgICAgICAgIC8vIEZ1dHVyZSB3ZSBzaG91bGQgdXBkYXRlIHRoZSBBUEkgdG8gdGFrZSBjYXJlIG9mIHNldHRpbmcgdGhlIGNvcnJlY3QgYGhvdmVyUG9pbnRJbmRleGAgd2hlbiBpbml0aWFsaXplZFxuICAgICAgICAgICAgICAoKF9hID0gcHJldlN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnRJZCkgIT09IGhpdEVsZW1lbnQuaWQgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihoaXRFbGVtZW50LCB0aGlzLnNjZW5lKSA6IHByZXZTdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICF0aGlzLnN0YXRlLmlzUmVzaXppbmcgJiYgKGhpdEVsZW1lbnQgJiYgaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50KGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpIHx8ICFoaXRFbGVtZW50ICYmIHBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBEZXNlbGVjdCBzZWxlY3RlZCBlbGVtZW50c1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWFjdGl2ZVRvb2wubG9ja2VkICYmIGFjdGl2ZVRvb2wudHlwZSAhPT0gXCJmcmVlZHJhd1wiICYmIGRyYWdnaW5nRWxlbWVudCAmJiBkcmFnZ2luZ0VsZW1lbnQudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgW2RyYWdnaW5nRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICB9KSwgcHJldlN0YXRlKSxcbiAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGlzRW1iZWRkYWJsZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSAmJiAhZHJhZ2dpbmdFbGVtZW50LmxpbmsgPyBcImVkaXRvclwiIDogcHJldlN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cFxuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgfHwgaXNTb21lRWxlbWVudFNlbGVjdGVkKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCB8fCBpc1Jlc2l6aW5nIHx8IGlzUm90YXRpbmcpIHtcbiAgICAgICAgKGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgPyBiaW5kT3JVbmJpbmRTZWxlY3RlZEVsZW1lbnRzIDogdW5iaW5kTGluZWFyRWxlbWVudHMpKHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIikge1xuICAgICAgICB0aGlzLmxhc2VyUGF0aE1hbmFnZXIuZW5kUGF0aCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICghYWN0aXZlVG9vbC5sb2NrZWQgJiYgYWN0aXZlVG9vbC50eXBlICE9PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoaGl0RWxlbWVudCAmJiB0aGlzLmxhc3RQb2ludGVyVXBFdmVudCAmJiB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50ICYmIHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LnRpbWVTdGFtcCAtIHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQudGltZVN0YW1wIDwgMzAwICYmIGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA8PSAxICYmIGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKGhpdEVsZW1lbnQpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgbWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID4gNTApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzdWdnZXN0ZWRCaW5kaW5ncyA9IGdldEVsaWdpYmxlRWxlbWVudHNGb3JCaW5kaW5nKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgc3VnZ2VzdGVkQmluZGluZ3NcbiAgICB9KTtcbiAgfVxuXG4gIGNsZWFyU2VsZWN0aW9uKGhpdEVsZW1lbnQpIHtcbiAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgcHJldlN0YXRlKSxcbiAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGwsXG4gICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgIC8vIENvbnRpbnVlIGVkaXRpbmcgdGhlIHNhbWUgZ3JvdXAgaWYgdGhlIHVzZXIgc2VsZWN0ZWQgYSBkaWZmZXJlbnRcbiAgICAgIC8vIGVsZW1lbnQgZnJvbSBpdFxuICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCAmJiBoaXRFbGVtZW50ICE9IG51bGwgJiYgaXNFbGVtZW50SW5Hcm91cChoaXRFbGVtZW50LCBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQpID8gcHJldlN0YXRlLmVkaXRpbmdHcm91cElkIDogbnVsbFxuICAgIH0pKTtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbCxcbiAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1xuICAgIH0pO1xuICB9XG5cbiAgZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbih4LCB5LCBhcHBTdGF0ZSwgY29udGFpbmVyKSB7XG4gICAgaWYgKGNvbnRhaW5lcikge1xuICAgICAgbGV0IGVsZW1lbnRDZW50ZXJYID0gY29udGFpbmVyLnggKyBjb250YWluZXIud2lkdGggLyAyO1xuICAgICAgbGV0IGVsZW1lbnRDZW50ZXJZID0gY29udGFpbmVyLnkgKyBjb250YWluZXIuaGVpZ2h0IC8gMjtcbiAgICAgIGNvbnN0IGVsZW1lbnRDZW50ZXIgPSBnZXRDb250YWluZXJDZW50ZXIoY29udGFpbmVyLCBhcHBTdGF0ZSk7XG5cbiAgICAgIGlmIChlbGVtZW50Q2VudGVyKSB7XG4gICAgICAgIGVsZW1lbnRDZW50ZXJYID0gZWxlbWVudENlbnRlci54O1xuICAgICAgICBlbGVtZW50Q2VudGVyWSA9IGVsZW1lbnRDZW50ZXIueTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGlzdGFuY2VUb0NlbnRlciA9IE1hdGguaHlwb3QoeCAtIGVsZW1lbnRDZW50ZXJYLCB5IC0gZWxlbWVudENlbnRlclkpO1xuICAgICAgY29uc3QgaXNTbmFwcGVkVG9DZW50ZXIgPSBkaXN0YW5jZVRvQ2VudGVyIDwgVEVYVF9UT19DRU5URVJfU05BUF9USFJFU0hPTEQ7XG5cbiAgICAgIGlmIChpc1NuYXBwZWRUb0NlbnRlcikge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogdmlld3BvcnRYLFxuICAgICAgICAgIHk6IHZpZXdwb3J0WVxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IGVsZW1lbnRDZW50ZXJYLFxuICAgICAgICAgIHNjZW5lWTogZWxlbWVudENlbnRlcllcbiAgICAgICAgfSwgYXBwU3RhdGUpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHZpZXdwb3J0WCxcbiAgICAgICAgICB2aWV3cG9ydFksXG4gICAgICAgICAgZWxlbWVudENlbnRlclgsXG4gICAgICAgICAgZWxlbWVudENlbnRlcllcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBnZXRDYW52YXNPZmZzZXRzKCkge1xuICAgIHZhciBfYTtcblxuICAgIGlmICgoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jdXJyZW50KSB7XG4gICAgICBjb25zdCBleGNhbGlkcmF3Q29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICBjb25zdCB7XG4gICAgICAgIGxlZnQsXG4gICAgICAgIHRvcFxuICAgICAgfSA9IGV4Y2FsaWRyYXdDb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBvZmZzZXRMZWZ0OiBsZWZ0LFxuICAgICAgICBvZmZzZXRUb3A6IHRvcFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgb2Zmc2V0TGVmdDogMCxcbiAgICAgIG9mZnNldFRvcDogMFxuICAgIH07XG4gIH1cblxuICB1cGRhdGVMYW5ndWFnZSgpIHtcbiAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgY29uc3QgY3VycmVudExhbmcgPSBsYW5ndWFnZXMuZmluZChsYW5nID0+IGxhbmcuY29kZSA9PT0gdGhpcy5wcm9wcy5sYW5nQ29kZSkgfHwgZGVmYXVsdExhbmc7XG4gICAgICB5aWVsZCBzZXRMYW5ndWFnZShjdXJyZW50TGFuZyk7XG4gICAgICB0aGlzLnNldEFwcFN0YXRlKHt9KTtcbiAgICB9KTtcbiAgfVxuXG59XG5cbkFwcC5kZWZhdWx0UHJvcHMgPSB7XG4gIC8vIG5lZWRlZCBmb3IgdGVzdHMgdG8gcGFzcyBzaW5jZSB3ZSBkaXJlY3RseSByZW5kZXIgQXBwIGluIG1hbnkgdGVzdHNcbiAgVUlPcHRpb25zOiBERUZBVUxUX1VJX09QVElPTlNcbn07XG5cbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gRU5WLlRFU1QgfHwgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09IFwicHJvZHVjdGlvblwiKSB7XG4gIHdpbmRvdy5oID0gd2luZG93LmggfHwge307XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHdpbmRvdy5oLCB7XG4gICAgZWxlbWVudHM6IHtcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcblxuICAgICAgZ2V0KCkge1xuICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgcmV0dXJuIChfYSA9IHRoaXMuYXBwKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Euc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG4gICAgICB9LFxuXG4gICAgICBzZXQoZWxlbWVudHMpIHtcbiAgICAgICAgdmFyIF9hO1xuXG4gICAgICAgIHJldHVybiAoX2EgPSB0aGlzLmFwcCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgICB9XG5cbiAgICB9XG4gIH0pO1xufVxuXG5leHBvcnQgZGVmYXVsdCBBcHA7Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../components/App.tsx\n");
2511
2511
 
2512
2512
  /***/ }),
2513
2513
 
@@ -3904,7 +3904,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
3904
3904
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
3905
3905
 
3906
3906
  "use strict";
3907
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"actionSetEmbeddableAsActiveTool\": () => (/* binding */ actionSetEmbeddableAsActiveTool),\n/* harmony export */ \"createPlaceholderEmbeddableLabel\": () => (/* binding */ createPlaceholderEmbeddableLabel),\n/* harmony export */ \"embeddableURLValidator\": () => (/* binding */ embeddableURLValidator),\n/* harmony export */ \"extractSrc\": () => (/* binding */ extractSrc),\n/* harmony export */ \"getEmbedLink\": () => (/* binding */ getEmbedLink),\n/* harmony export */ \"isEmbeddableOrLabel\": () => (/* binding */ isEmbeddableOrLabel)\n/* harmony export */ });\n/* harmony import */ var _actions_register__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../actions/register */ \"../../actions/register.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../i18n */ \"../../i18n.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _cursor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../cursor */ \"../../cursor.ts\");\n/* harmony import */ var _newElement__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./newElement */ \"../../element/newElement.ts\");\n/* harmony import */ var _textElement__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _typeChecks__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./typeChecks */ \"../../element/typeChecks.ts\");\n\n\n\n\n\n\n\n\nconst embeddedLinkCache = new Map();\nconst RE_YOUTUBE = /^(?:http(?:s)?:\\/\\/)?(?:www\\.)?youtu(?:be\\.com|\\.be)\\/(embed\\/|watch\\?v=|shorts\\/|playlist\\?list=|embed\\/videoseries\\?list=)?([a-zA-Z0-9_-]+)(?:\\?t=|&t=|\\?start=|&start=)?([a-zA-Z0-9_-]+)?[^\\s]*$/;\nconst RE_VIMEO = /^(?:http(?:s)?:\\/\\/)?(?:(?:w){3}.)?(?:player\\.)?vimeo\\.com\\/(?:video\\/)?([^?\\s]+)(?:\\?.*)?$/;\nconst RE_FIGMA = /^https:\\/\\/(?:www\\.)?figma\\.com/;\nconst RE_GH_GIST = /^https:\\/\\/gist\\.github\\.com/;\nconst RE_GH_GIST_EMBED = /^<script[\\s\\S]*?\\ssrc=[\"'](https:\\/\\/gist.github.com\\/.*?)\\.js[\"']/i; // not anchored to start to allow <blockquote> twitter embeds\n\nconst RE_TWITTER = /(?:http(?:s)?:\\/\\/)?(?:(?:w){3}.)?twitter.com/;\nconst RE_TWITTER_EMBED = /^<blockquote[\\s\\S]*?\\shref=[\"'](https:\\/\\/twitter.com\\/[^\"']*)/i;\nconst RE_VALTOWN = /^https:\\/\\/(?:www\\.)?val.town\\/(v|embed)\\/[a-zA-Z_$][0-9a-zA-Z_$]+\\.[a-zA-Z_$][0-9a-zA-Z_$]+/;\nconst RE_GENERIC_EMBED = /^<(?:iframe|blockquote)[\\s\\S]*?\\s(?:src|href)=[\"']([^\"']*)[\"'][\\s\\S]*?>$/i;\nconst RE_GIPHY = /giphy.com\\/(?:clips|embed|gifs)\\/[a-zA-Z0-9]*?-?([a-zA-Z0-9]+)(?:[^a-zA-Z0-9]|$)/;\nconst ALLOWED_DOMAINS = new Set([\"youtube.com\", \"youtu.be\", \"vimeo.com\", \"player.vimeo.com\", \"figma.com\", \"link.excalidraw.com\", \"gist.github.com\", \"twitter.com\", \"*.simplepdf.eu\", \"stackblitz.com\", \"val.town\", \"giphy.com\", \"dddice.com\"]);\n\nconst createSrcDoc = body => {\n return `<html><body>${body}</body></html>`;\n};\n\nconst getEmbedLink = link => {\n if (!link) {\n return null;\n }\n\n if (embeddedLinkCache.has(link)) {\n return embeddedLinkCache.get(link);\n }\n\n const originalLink = link;\n let type = \"generic\";\n let aspectRatio = {\n w: 560,\n h: 840\n };\n const ytLink = link.match(RE_YOUTUBE);\n\n if (ytLink === null || ytLink === void 0 ? void 0 : ytLink[2]) {\n const time = ytLink[3] ? `&start=${ytLink[3]}` : ``;\n const isPortrait = link.includes(\"shorts\");\n type = \"video\";\n\n switch (ytLink[1]) {\n case \"embed/\":\n case \"watch?v=\":\n case \"shorts/\":\n link = `https://www.youtube.com/embed/${ytLink[2]}?enablejsapi=1${time}`;\n break;\n\n case \"playlist?list=\":\n case \"embed/videoseries?list=\":\n link = `https://www.youtube.com/embed/videoseries?list=${ytLink[2]}&enablejsapi=1${time}`;\n break;\n\n default:\n link = `https://www.youtube.com/embed/${ytLink[2]}?enablejsapi=1${time}`;\n break;\n }\n\n aspectRatio = isPortrait ? {\n w: 315,\n h: 560\n } : {\n w: 560,\n h: 315\n };\n embeddedLinkCache.set(originalLink, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type\n };\n }\n\n const vimeoLink = link.match(RE_VIMEO);\n\n if (vimeoLink === null || vimeoLink === void 0 ? void 0 : vimeoLink[1]) {\n const target = vimeoLink === null || vimeoLink === void 0 ? void 0 : vimeoLink[1];\n const warning = !/^\\d+$/.test(target) ? (0,_i18n__WEBPACK_IMPORTED_MODULE_2__.t)(\"toast.unrecognizedLinkFormat\") : undefined;\n type = \"video\";\n link = `https://player.vimeo.com/video/${target}?api=1`;\n aspectRatio = {\n w: 560,\n h: 315\n }; //warning deliberately ommited so it is displayed only once per link\n //same link next time will be served from cache\n\n embeddedLinkCache.set(originalLink, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type,\n warning\n };\n }\n\n const figmaLink = link.match(RE_FIGMA);\n\n if (figmaLink) {\n type = \"generic\";\n link = `https://www.figma.com/embed?embed_host=share&url=${encodeURIComponent(link)}`;\n aspectRatio = {\n w: 550,\n h: 550\n };\n embeddedLinkCache.set(originalLink, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type\n };\n }\n\n const valLink = link.match(RE_VALTOWN);\n\n if (valLink) {\n link = valLink[1] === \"embed\" ? valLink[0] : valLink[0].replace(\"/v\", \"/embed\");\n embeddedLinkCache.set(originalLink, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type\n };\n }\n\n if (RE_TWITTER.test(link)) {\n let ret; // assume embed code\n\n if (/<blockquote/.test(link)) {\n const srcDoc = createSrcDoc(link);\n ret = {\n type: \"document\",\n srcdoc: () => srcDoc,\n aspectRatio: {\n w: 480,\n h: 480\n }\n }; // assume regular tweet url\n } else {\n ret = {\n type: \"document\",\n srcdoc: theme => createSrcDoc(`<blockquote class=\"twitter-tweet\" data-dnt=\"true\" data-theme=\"${theme}\"><a href=\"${link}\"></a></blockquote> <script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>`),\n aspectRatio: {\n w: 480,\n h: 480\n }\n };\n }\n\n embeddedLinkCache.set(originalLink, ret);\n return ret;\n }\n\n if (RE_GH_GIST.test(link)) {\n let ret; // assume embed code\n\n if (/<script>/.test(link)) {\n const srcDoc = createSrcDoc(link);\n ret = {\n type: \"document\",\n srcdoc: () => srcDoc,\n aspectRatio: {\n w: 550,\n h: 720\n }\n }; // assume regular url\n } else {\n ret = {\n type: \"document\",\n srcdoc: () => createSrcDoc(`\n <script src=\"${link}.js\"></script>\n <style type=\"text/css\">\n * { margin: 0px; }\n table, .gist { height: 100%; }\n .gist .gist-file { height: calc(100vh - 2px); padding: 0px; display: grid; grid-template-rows: 1fr auto; }\n </style>\n `),\n aspectRatio: {\n w: 550,\n h: 720\n }\n };\n }\n\n embeddedLinkCache.set(link, ret);\n return ret;\n }\n\n embeddedLinkCache.set(link, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type\n };\n};\nconst isEmbeddableOrLabel = element => {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_7__.isEmbeddableElement)(element)) {\n return true;\n }\n\n if (element.type === \"text\") {\n const container = (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getContainerElement)(element);\n\n if (container && (0,_typeChecks__WEBPACK_IMPORTED_MODULE_7__.isEmbeddableElement)(container)) {\n return true;\n }\n }\n\n return false;\n};\nconst createPlaceholderEmbeddableLabel = element => {\n var _a;\n\n const text = !element.link || (element === null || element === void 0 ? void 0 : element.link) === \"\" ? \"Empty Web-Embed\" : element.link;\n const fontSize = Math.max(Math.min(element.width / 2, element.width / text.length), element.width / 30);\n const fontFamily = _constants__WEBPACK_IMPORTED_MODULE_1__.FONT_FAMILY.Helvetica;\n const fontString = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.getFontString)({\n fontSize,\n fontFamily\n });\n return (0,_newElement__WEBPACK_IMPORTED_MODULE_5__.newTextElement)({\n x: element.x + element.width / 2,\n y: element.y + element.height / 2,\n strokeColor: element.strokeColor !== \"transparent\" ? element.strokeColor : \"black\",\n backgroundColor: \"transparent\",\n fontFamily,\n fontSize,\n text: (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.wrapText)(text, fontString, element.width - 20),\n textAlign: \"center\",\n verticalAlign: _constants__WEBPACK_IMPORTED_MODULE_1__.VERTICAL_ALIGN.MIDDLE,\n angle: (_a = element.angle) !== null && _a !== void 0 ? _a : 0\n });\n};\nconst actionSetEmbeddableAsActiveTool = (0,_actions_register__WEBPACK_IMPORTED_MODULE_0__.register)({\n name: \"setEmbeddableAsActiveTool\",\n trackEvent: {\n category: \"toolbar\"\n },\n perform: (elements, appState, _, app) => {\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.updateActiveTool)(appState, {\n type: \"embeddable\"\n });\n (0,_cursor__WEBPACK_IMPORTED_MODULE_4__.setCursorForShape)(app.canvas, Object.assign(Object.assign({}, appState), {\n activeTool: nextActiveTool\n }));\n return {\n elements,\n appState: Object.assign(Object.assign({}, appState), {\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_3__.updateActiveTool)(appState, {\n type: \"embeddable\"\n })\n }),\n commitToHistory: false\n };\n }\n});\n\nconst validateHostname = (url,\n/** using a Set assumes it already contains normalized bare domains */\nallowedHostnames) => {\n try {\n const {\n hostname\n } = new URL(url);\n const bareDomain = hostname.replace(/^www\\./, \"\");\n const bareDomainWithFirstSubdomainWildcarded = bareDomain.replace(/^([^.]+)/, \"*\");\n\n if (allowedHostnames instanceof Set) {\n return ALLOWED_DOMAINS.has(bareDomain) || ALLOWED_DOMAINS.has(bareDomainWithFirstSubdomainWildcarded);\n }\n\n if (bareDomain === allowedHostnames.replace(/^www\\./, \"\")) {\n return true;\n }\n } catch (error) {// ignore\n }\n\n return false;\n};\n\nconst extractSrc = htmlString => {\n const twitterMatch = htmlString.match(RE_TWITTER_EMBED);\n\n if (twitterMatch && twitterMatch.length === 2) {\n return twitterMatch[1];\n }\n\n const gistMatch = htmlString.match(RE_GH_GIST_EMBED);\n\n if (gistMatch && gistMatch.length === 2) {\n return gistMatch[1];\n }\n\n if (RE_GIPHY.test(htmlString)) {\n return `https://giphy.com/embed/${RE_GIPHY.exec(htmlString)[1]}`;\n }\n\n const match = htmlString.match(RE_GENERIC_EMBED);\n\n if (match && match.length === 2) {\n return match[1];\n }\n\n return htmlString;\n};\nconst embeddableURLValidator = (url, validateEmbeddable) => {\n if (!url) {\n return false;\n }\n\n if (validateEmbeddable != null) {\n if (typeof validateEmbeddable === \"function\") {\n const ret = validateEmbeddable(url); // if return value is undefined, leave validation to default\n\n if (typeof ret === \"boolean\") {\n return ret;\n }\n } else if (typeof validateEmbeddable === \"boolean\") {\n return validateEmbeddable;\n } else if (validateEmbeddable instanceof RegExp) {\n return validateEmbeddable.test(url);\n } else if (Array.isArray(validateEmbeddable)) {\n for (const domain of validateEmbeddable) {\n if (domain instanceof RegExp) {\n if (url.match(domain)) {\n return true;\n }\n } else if (validateHostname(url, domain)) {\n return true;\n }\n }\n\n return false;\n }\n }\n\n return validateHostname(url, ALLOWED_DOMAINS);\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUFJLDBEQUFpQiwyQ0FBMkM7QUFDaEU7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLDhDQUE4QztBQUM5QyxvQkFBb0Isd0RBQWdCO0FBQ3BDO0FBQ0EsU0FBUztBQUNULE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJLGVBQWU7QUFDbkI7O0FBRUE7QUFDQTs7QUFFTztBQUNQOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzQ0FBc0MsNkJBQTZCO0FBQ25FOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ087QUFDUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDJDQUEyQzs7QUFFM0M7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2VsZW1lbnQvZW1iZWRkYWJsZS50cz9iZjkzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlZ2lzdGVyIH0gZnJvbSBcIi4uL2FjdGlvbnMvcmVnaXN0ZXJcIjtcbmltcG9ydCB7IEZPTlRfRkFNSUxZLCBWRVJUSUNBTF9BTElHTiB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IHQgfSBmcm9tIFwiLi4vaTE4blwiO1xuaW1wb3J0IHsgZ2V0Rm9udFN0cmluZywgdXBkYXRlQWN0aXZlVG9vbCB9IGZyb20gXCIuLi91dGlsc1wiO1xuaW1wb3J0IHsgc2V0Q3Vyc29yRm9yU2hhcGUgfSBmcm9tIFwiLi4vY3Vyc29yXCI7XG5pbXBvcnQgeyBuZXdUZXh0RWxlbWVudCB9IGZyb20gXCIuL25ld0VsZW1lbnRcIjtcbmltcG9ydCB7IGdldENvbnRhaW5lckVsZW1lbnQsIHdyYXBUZXh0IH0gZnJvbSBcIi4vdGV4dEVsZW1lbnRcIjtcbmltcG9ydCB7IGlzRW1iZWRkYWJsZUVsZW1lbnQgfSBmcm9tIFwiLi90eXBlQ2hlY2tzXCI7XG5jb25zdCBlbWJlZGRlZExpbmtDYWNoZSA9IG5ldyBNYXAoKTtcbmNvbnN0IFJFX1lPVVRVQkUgPSAvXig/Omh0dHAoPzpzKT86XFwvXFwvKT8oPzp3d3dcXC4pP3lvdXR1KD86YmVcXC5jb218XFwuYmUpXFwvKGVtYmVkXFwvfHdhdGNoXFw/dj18c2hvcnRzXFwvfHBsYXlsaXN0XFw/bGlzdD18ZW1iZWRcXC92aWRlb3Nlcmllc1xcP2xpc3Q9KT8oW2EtekEtWjAtOV8tXSspKD86XFw/dD18JnQ9fFxcP3N0YXJ0PXwmc3RhcnQ9KT8oW2EtekEtWjAtOV8tXSspP1teXFxzXSokLztcbmNvbnN0IFJFX1ZJTUVPID0gL14oPzpodHRwKD86cyk/OlxcL1xcLyk/KD86KD86dyl7M30uKT8oPzpwbGF5ZXJcXC4pP3ZpbWVvXFwuY29tXFwvKD86dmlkZW9cXC8pPyhbXj9cXHNdKykoPzpcXD8uKik/JC87XG5jb25zdCBSRV9GSUdNQSA9IC9eaHR0cHM6XFwvXFwvKD86d3d3XFwuKT9maWdtYVxcLmNvbS87XG5jb25zdCBSRV9HSF9HSVNUID0gL15odHRwczpcXC9cXC9naXN0XFwuZ2l0aHViXFwuY29tLztcbmNvbnN0IFJFX0dIX0dJU1RfRU1CRUQgPSAvXjxzY3JpcHRbXFxzXFxTXSo/XFxzc3JjPVtcIiddKGh0dHBzOlxcL1xcL2dpc3QuZ2l0aHViLmNvbVxcLy4qPylcXC5qc1tcIiddL2k7IC8vIG5vdCBhbmNob3JlZCB0byBzdGFydCB0byBhbGxvdyA8YmxvY2txdW90ZT4gdHdpdHRlciBlbWJlZHNcblxuY29uc3QgUkVfVFdJVFRFUiA9IC8oPzpodHRwKD86cyk/OlxcL1xcLyk/KD86KD86dyl7M30uKT90d2l0dGVyLmNvbS87XG5jb25zdCBSRV9UV0lUVEVSX0VNQkVEID0gL148YmxvY2txdW90ZVtcXHNcXFNdKj9cXHNocmVmPVtcIiddKGh0dHBzOlxcL1xcL3R3aXR0ZXIuY29tXFwvW15cIiddKikvaTtcbmNvbnN0IFJFX1ZBTFRPV04gPSAvXmh0dHBzOlxcL1xcLyg/Ond3d1xcLik/dmFsLnRvd25cXC8odnxlbWJlZClcXC9bYS16QS1aXyRdWzAtOWEtekEtWl8kXStcXC5bYS16QS1aXyRdWzAtOWEtekEtWl8kXSsvO1xuY29uc3QgUkVfR0VORVJJQ19FTUJFRCA9IC9ePCg/OmlmcmFtZXxibG9ja3F1b3RlKVtcXHNcXFNdKj9cXHMoPzpzcmN8aHJlZik9W1wiJ10oW15cIiddKilbXCInXVtcXHNcXFNdKj8+JC9pO1xuY29uc3QgUkVfR0lQSFkgPSAvZ2lwaHkuY29tXFwvKD86Y2xpcHN8ZW1iZWR8Z2lmcylcXC9bYS16QS1aMC05XSo/LT8oW2EtekEtWjAtOV0rKSg/OlteYS16QS1aMC05XXwkKS87XG5jb25zdCBBTExPV0VEX0RPTUFJTlMgPSBuZXcgU2V0KFtcInlvdXR1YmUuY29tXCIsIFwieW91dHUuYmVcIiwgXCJ2aW1lby5jb21cIiwgXCJwbGF5ZXIudmltZW8uY29tXCIsIFwiZmlnbWEuY29tXCIsIFwibGluay5leGNhbGlkcmF3LmNvbVwiLCBcImdpc3QuZ2l0aHViLmNvbVwiLCBcInR3aXR0ZXIuY29tXCIsIFwiKi5zaW1wbGVwZGYuZXVcIiwgXCJzdGFja2JsaXR6LmNvbVwiLCBcInZhbC50b3duXCIsIFwiZ2lwaHkuY29tXCIsIFwiZGRkaWNlLmNvbVwiXSk7XG5cbmNvbnN0IGNyZWF0ZVNyY0RvYyA9IGJvZHkgPT4ge1xuICByZXR1cm4gYDxodG1sPjxib2R5PiR7Ym9keX08L2JvZHk+PC9odG1sPmA7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0RW1iZWRMaW5rID0gbGluayA9PiB7XG4gIGlmICghbGluaykge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgaWYgKGVtYmVkZGVkTGlua0NhY2hlLmhhcyhsaW5rKSkge1xuICAgIHJldHVybiBlbWJlZGRlZExpbmtDYWNoZS5nZXQobGluayk7XG4gIH1cblxuICBjb25zdCBvcmlnaW5hbExpbmsgPSBsaW5rO1xuICBsZXQgdHlwZSA9IFwiZ2VuZXJpY1wiO1xuICBsZXQgYXNwZWN0UmF0aW8gPSB7XG4gICAgdzogNTYwLFxuICAgIGg6IDg0MFxuICB9O1xuICBjb25zdCB5dExpbmsgPSBsaW5rLm1hdGNoKFJFX1lPVVRVQkUpO1xuXG4gIGlmICh5dExpbmsgPT09IG51bGwgfHwgeXRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiB5dExpbmtbMl0pIHtcbiAgICBjb25zdCB0aW1lID0geXRMaW5rWzNdID8gYCZzdGFydD0ke3l0TGlua1szXX1gIDogYGA7XG4gICAgY29uc3QgaXNQb3J0cmFpdCA9IGxpbmsuaW5jbHVkZXMoXCJzaG9ydHNcIik7XG4gICAgdHlwZSA9IFwidmlkZW9cIjtcblxuICAgIHN3aXRjaCAoeXRMaW5rWzFdKSB7XG4gICAgICBjYXNlIFwiZW1iZWQvXCI6XG4gICAgICBjYXNlIFwid2F0Y2g/dj1cIjpcbiAgICAgIGNhc2UgXCJzaG9ydHMvXCI6XG4gICAgICAgIGxpbmsgPSBgaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvJHt5dExpbmtbMl19P2VuYWJsZWpzYXBpPTEke3RpbWV9YDtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgXCJwbGF5bGlzdD9saXN0PVwiOlxuICAgICAgY2FzZSBcImVtYmVkL3ZpZGVvc2VyaWVzP2xpc3Q9XCI6XG4gICAgICAgIGxpbmsgPSBgaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvdmlkZW9zZXJpZXM/bGlzdD0ke3l0TGlua1syXX0mZW5hYmxlanNhcGk9MSR7dGltZX1gO1xuICAgICAgICBicmVhaztcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgbGluayA9IGBodHRwczovL3d3dy55b3V0dWJlLmNvbS9lbWJlZC8ke3l0TGlua1syXX0/ZW5hYmxlanNhcGk9MSR7dGltZX1gO1xuICAgICAgICBicmVhaztcbiAgICB9XG5cbiAgICBhc3BlY3RSYXRpbyA9IGlzUG9ydHJhaXQgPyB7XG4gICAgICB3OiAzMTUsXG4gICAgICBoOiA1NjBcbiAgICB9IDoge1xuICAgICAgdzogNTYwLFxuICAgICAgaDogMzE1XG4gICAgfTtcbiAgICBlbWJlZGRlZExpbmtDYWNoZS5zZXQob3JpZ2luYWxMaW5rLCB7XG4gICAgICBsaW5rLFxuICAgICAgYXNwZWN0UmF0aW8sXG4gICAgICB0eXBlXG4gICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxpbmssXG4gICAgICBhc3BlY3RSYXRpbyxcbiAgICAgIHR5cGVcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgdmltZW9MaW5rID0gbGluay5tYXRjaChSRV9WSU1FTyk7XG5cbiAgaWYgKHZpbWVvTGluayA9PT0gbnVsbCB8fCB2aW1lb0xpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHZpbWVvTGlua1sxXSkge1xuICAgIGNvbnN0IHRhcmdldCA9IHZpbWVvTGluayA9PT0gbnVsbCB8fCB2aW1lb0xpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHZpbWVvTGlua1sxXTtcbiAgICBjb25zdCB3YXJuaW5nID0gIS9eXFxkKyQvLnRlc3QodGFyZ2V0KSA/IHQoXCJ0b2FzdC51bnJlY29nbml6ZWRMaW5rRm9ybWF0XCIpIDogdW5kZWZpbmVkO1xuICAgIHR5cGUgPSBcInZpZGVvXCI7XG4gICAgbGluayA9IGBodHRwczovL3BsYXllci52aW1lby5jb20vdmlkZW8vJHt0YXJnZXR9P2FwaT0xYDtcbiAgICBhc3BlY3RSYXRpbyA9IHtcbiAgICAgIHc6IDU2MCxcbiAgICAgIGg6IDMxNVxuICAgIH07IC8vd2FybmluZyBkZWxpYmVyYXRlbHkgb21taXRlZCBzbyBpdCBpcyBkaXNwbGF5ZWQgb25seSBvbmNlIHBlciBsaW5rXG4gICAgLy9zYW1lIGxpbmsgbmV4dCB0aW1lIHdpbGwgYmUgc2VydmVkIGZyb20gY2FjaGVcblxuICAgIGVtYmVkZGVkTGlua0NhY2hlLnNldChvcmlnaW5hbExpbmssIHtcbiAgICAgIGxpbmssXG4gICAgICBhc3BlY3RSYXRpbyxcbiAgICAgIHR5cGVcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgbGluayxcbiAgICAgIGFzcGVjdFJhdGlvLFxuICAgICAgdHlwZSxcbiAgICAgIHdhcm5pbmdcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgZmlnbWFMaW5rID0gbGluay5tYXRjaChSRV9GSUdNQSk7XG5cbiAgaWYgKGZpZ21hTGluaykge1xuICAgIHR5cGUgPSBcImdlbmVyaWNcIjtcbiAgICBsaW5rID0gYGh0dHBzOi8vd3d3LmZpZ21hLmNvbS9lbWJlZD9lbWJlZF9ob3N0PXNoYXJlJnVybD0ke2VuY29kZVVSSUNvbXBvbmVudChsaW5rKX1gO1xuICAgIGFzcGVjdFJhdGlvID0ge1xuICAgICAgdzogNTUwLFxuICAgICAgaDogNTUwXG4gICAgfTtcbiAgICBlbWJlZGRlZExpbmtDYWNoZS5zZXQob3JpZ2luYWxMaW5rLCB7XG4gICAgICBsaW5rLFxuICAgICAgYXNwZWN0UmF0aW8sXG4gICAgICB0eXBlXG4gICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxpbmssXG4gICAgICBhc3BlY3RSYXRpbyxcbiAgICAgIHR5cGVcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgdmFsTGluayA9IGxpbmsubWF0Y2goUkVfVkFMVE9XTik7XG5cbiAgaWYgKHZhbExpbmspIHtcbiAgICBsaW5rID0gdmFsTGlua1sxXSA9PT0gXCJlbWJlZFwiID8gdmFsTGlua1swXSA6IHZhbExpbmtbMF0ucmVwbGFjZShcIi92XCIsIFwiL2VtYmVkXCIpO1xuICAgIGVtYmVkZGVkTGlua0NhY2hlLnNldChvcmlnaW5hbExpbmssIHtcbiAgICAgIGxpbmssXG4gICAgICBhc3BlY3RSYXRpbyxcbiAgICAgIHR5cGVcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgbGluayxcbiAgICAgIGFzcGVjdFJhdGlvLFxuICAgICAgdHlwZVxuICAgIH07XG4gIH1cblxuICBpZiAoUkVfVFdJVFRFUi50ZXN0KGxpbmspKSB7XG4gICAgbGV0IHJldDsgLy8gYXNzdW1lIGVtYmVkIGNvZGVcblxuICAgIGlmICgvPGJsb2NrcXVvdGUvLnRlc3QobGluaykpIHtcbiAgICAgIGNvbnN0IHNyY0RvYyA9IGNyZWF0ZVNyY0RvYyhsaW5rKTtcbiAgICAgIHJldCA9IHtcbiAgICAgICAgdHlwZTogXCJkb2N1bWVudFwiLFxuICAgICAgICBzcmNkb2M6ICgpID0+IHNyY0RvYyxcbiAgICAgICAgYXNwZWN0UmF0aW86IHtcbiAgICAgICAgICB3OiA0ODAsXG4gICAgICAgICAgaDogNDgwXG4gICAgICAgIH1cbiAgICAgIH07IC8vIGFzc3VtZSByZWd1bGFyIHR3ZWV0IHVybFxuICAgIH0gZWxzZSB7XG4gICAgICByZXQgPSB7XG4gICAgICAgIHR5cGU6IFwiZG9jdW1lbnRcIixcbiAgICAgICAgc3JjZG9jOiB0aGVtZSA9PiBjcmVhdGVTcmNEb2MoYDxibG9ja3F1b3RlIGNsYXNzPVwidHdpdHRlci10d2VldFwiIGRhdGEtZG50PVwidHJ1ZVwiIGRhdGEtdGhlbWU9XCIke3RoZW1lfVwiPjxhIGhyZWY9XCIke2xpbmt9XCI+PC9hPjwvYmxvY2txdW90ZT4gPHNjcmlwdCBhc3luYyBzcmM9XCJodHRwczovL3BsYXRmb3JtLnR3aXR0ZXIuY29tL3dpZGdldHMuanNcIiBjaGFyc2V0PVwidXRmLThcIj48L3NjcmlwdD5gKSxcbiAgICAgICAgYXNwZWN0UmF0aW86IHtcbiAgICAgICAgICB3OiA0ODAsXG4gICAgICAgICAgaDogNDgwXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfVxuXG4gICAgZW1iZWRkZWRMaW5rQ2FjaGUuc2V0KG9yaWdpbmFsTGluaywgcmV0KTtcbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgaWYgKFJFX0dIX0dJU1QudGVzdChsaW5rKSkge1xuICAgIGxldCByZXQ7IC8vIGFzc3VtZSBlbWJlZCBjb2RlXG5cbiAgICBpZiAoLzxzY3JpcHQ+Ly50ZXN0KGxpbmspKSB7XG4gICAgICBjb25zdCBzcmNEb2MgPSBjcmVhdGVTcmNEb2MobGluayk7XG4gICAgICByZXQgPSB7XG4gICAgICAgIHR5cGU6IFwiZG9jdW1lbnRcIixcbiAgICAgICAgc3JjZG9jOiAoKSA9PiBzcmNEb2MsXG4gICAgICAgIGFzcGVjdFJhdGlvOiB7XG4gICAgICAgICAgdzogNTUwLFxuICAgICAgICAgIGg6IDcyMFxuICAgICAgICB9XG4gICAgICB9OyAvLyBhc3N1bWUgcmVndWxhciB1cmxcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0ID0ge1xuICAgICAgICB0eXBlOiBcImRvY3VtZW50XCIsXG4gICAgICAgIHNyY2RvYzogKCkgPT4gY3JlYXRlU3JjRG9jKGBcbiAgICAgICAgICA8c2NyaXB0IHNyYz1cIiR7bGlua30uanNcIj48L3NjcmlwdD5cbiAgICAgICAgICA8c3R5bGUgdHlwZT1cInRleHQvY3NzXCI+XG4gICAgICAgICAgICAqIHsgbWFyZ2luOiAwcHg7IH1cbiAgICAgICAgICAgIHRhYmxlLCAuZ2lzdCB7IGhlaWdodDogMTAwJTsgfVxuICAgICAgICAgICAgLmdpc3QgLmdpc3QtZmlsZSB7IGhlaWdodDogY2FsYygxMDB2aCAtIDJweCk7IHBhZGRpbmc6IDBweDsgZGlzcGxheTogZ3JpZDsgZ3JpZC10ZW1wbGF0ZS1yb3dzOiAxZnIgYXV0bzsgfVxuICAgICAgICAgIDwvc3R5bGU+XG4gICAgICAgIGApLFxuICAgICAgICBhc3BlY3RSYXRpbzoge1xuICAgICAgICAgIHc6IDU1MCxcbiAgICAgICAgICBoOiA3MjBcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9XG5cbiAgICBlbWJlZGRlZExpbmtDYWNoZS5zZXQobGluaywgcmV0KTtcbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgZW1iZWRkZWRMaW5rQ2FjaGUuc2V0KGxpbmssIHtcbiAgICBsaW5rLFxuICAgIGFzcGVjdFJhdGlvLFxuICAgIHR5cGVcbiAgfSk7XG4gIHJldHVybiB7XG4gICAgbGluayxcbiAgICBhc3BlY3RSYXRpbyxcbiAgICB0eXBlXG4gIH07XG59O1xuZXhwb3J0IGNvbnN0IGlzRW1iZWRkYWJsZU9yTGFiZWwgPSBlbGVtZW50ID0+IHtcbiAgaWYgKGlzRW1iZWRkYWJsZUVsZW1lbnQoZWxlbWVudCkpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGlmIChlbGVtZW50LnR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgY29uc3QgY29udGFpbmVyID0gZ2V0Q29udGFpbmVyRWxlbWVudChlbGVtZW50KTtcblxuICAgIGlmIChjb250YWluZXIgJiYgaXNFbWJlZGRhYmxlRWxlbWVudChjb250YWluZXIpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZmFsc2U7XG59O1xuZXhwb3J0IGNvbnN0IGNyZWF0ZVBsYWNlaG9sZGVyRW1iZWRkYWJsZUxhYmVsID0gZWxlbWVudCA9PiB7XG4gIHZhciBfYTtcblxuICBjb25zdCB0ZXh0ID0gIWVsZW1lbnQubGluayB8fCAoZWxlbWVudCA9PT0gbnVsbCB8fCBlbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbGVtZW50LmxpbmspID09PSBcIlwiID8gXCJFbXB0eSBXZWItRW1iZWRcIiA6IGVsZW1lbnQubGluaztcbiAgY29uc3QgZm9udFNpemUgPSBNYXRoLm1heChNYXRoLm1pbihlbGVtZW50LndpZHRoIC8gMiwgZWxlbWVudC53aWR0aCAvIHRleHQubGVuZ3RoKSwgZWxlbWVudC53aWR0aCAvIDMwKTtcbiAgY29uc3QgZm9udEZhbWlseSA9IEZPTlRfRkFNSUxZLkhlbHZldGljYTtcbiAgY29uc3QgZm9udFN0cmluZyA9IGdldEZvbnRTdHJpbmcoe1xuICAgIGZvbnRTaXplLFxuICAgIGZvbnRGYW1pbHlcbiAgfSk7XG4gIHJldHVybiBuZXdUZXh0RWxlbWVudCh7XG4gICAgeDogZWxlbWVudC54ICsgZWxlbWVudC53aWR0aCAvIDIsXG4gICAgeTogZWxlbWVudC55ICsgZWxlbWVudC5oZWlnaHQgLyAyLFxuICAgIHN0cm9rZUNvbG9yOiBlbGVtZW50LnN0cm9rZUNvbG9yICE9PSBcInRyYW5zcGFyZW50XCIgPyBlbGVtZW50LnN0cm9rZUNvbG9yIDogXCJibGFja1wiLFxuICAgIGJhY2tncm91bmRDb2xvcjogXCJ0cmFuc3BhcmVudFwiLFxuICAgIGZvbnRGYW1pbHksXG4gICAgZm9udFNpemUsXG4gICAgdGV4dDogd3JhcFRleHQodGV4dCwgZm9udFN0cmluZywgZWxlbWVudC53aWR0aCAtIDIwKSxcbiAgICB0ZXh0QWxpZ246IFwiY2VudGVyXCIsXG4gICAgdmVydGljYWxBbGlnbjogVkVSVElDQUxfQUxJR04uTUlERExFLFxuICAgIGFuZ2xlOiAoX2EgPSBlbGVtZW50LmFuZ2xlKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiAwXG4gIH0pO1xufTtcbmV4cG9ydCBjb25zdCBhY3Rpb25TZXRFbWJlZGRhYmxlQXNBY3RpdmVUb29sID0gcmVnaXN0ZXIoe1xuICBuYW1lOiBcInNldEVtYmVkZGFibGVBc0FjdGl2ZVRvb2xcIixcbiAgdHJhY2tFdmVudDoge1xuICAgIGNhdGVnb3J5OiBcInRvb2xiYXJcIlxuICB9LFxuICBwZXJmb3JtOiAoZWxlbWVudHMsIGFwcFN0YXRlLCBfLCBhcHApID0+IHtcbiAgICBjb25zdCBuZXh0QWN0aXZlVG9vbCA9IHVwZGF0ZUFjdGl2ZVRvb2woYXBwU3RhdGUsIHtcbiAgICAgIHR5cGU6IFwiZW1iZWRkYWJsZVwiXG4gICAgfSk7XG4gICAgc2V0Q3Vyc29yRm9yU2hhcGUoYXBwLmNhbnZhcywgT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBhcHBTdGF0ZSksIHtcbiAgICAgIGFjdGl2ZVRvb2w6IG5leHRBY3RpdmVUb29sXG4gICAgfSkpO1xuICAgIHJldHVybiB7XG4gICAgICBlbGVtZW50cyxcbiAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGFwcFN0YXRlKSwge1xuICAgICAgICBhY3RpdmVUb29sOiB1cGRhdGVBY3RpdmVUb29sKGFwcFN0YXRlLCB7XG4gICAgICAgICAgdHlwZTogXCJlbWJlZGRhYmxlXCJcbiAgICAgICAgfSlcbiAgICAgIH0pLFxuICAgICAgY29tbWl0VG9IaXN0b3J5OiBmYWxzZVxuICAgIH07XG4gIH1cbn0pO1xuXG5jb25zdCB2YWxpZGF0ZUhvc3RuYW1lID0gKHVybCxcbi8qKiB1c2luZyBhIFNldCBhc3N1bWVzIGl0IGFscmVhZHkgY29udGFpbnMgbm9ybWFsaXplZCBiYXJlIGRvbWFpbnMgKi9cbmFsbG93ZWRIb3N0bmFtZXMpID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCB7XG4gICAgICBob3N0bmFtZVxuICAgIH0gPSBuZXcgVVJMKHVybCk7XG4gICAgY29uc3QgYmFyZURvbWFpbiA9IGhvc3RuYW1lLnJlcGxhY2UoL153d3dcXC4vLCBcIlwiKTtcbiAgICBjb25zdCBiYXJlRG9tYWluV2l0aEZpcnN0U3ViZG9tYWluV2lsZGNhcmRlZCA9IGJhcmVEb21haW4ucmVwbGFjZSgvXihbXi5dKykvLCBcIipcIik7XG5cbiAgICBpZiAoYWxsb3dlZEhvc3RuYW1lcyBpbnN0YW5jZW9mIFNldCkge1xuICAgICAgcmV0dXJuIEFMTE9XRURfRE9NQUlOUy5oYXMoYmFyZURvbWFpbikgfHwgQUxMT1dFRF9ET01BSU5TLmhhcyhiYXJlRG9tYWluV2l0aEZpcnN0U3ViZG9tYWluV2lsZGNhcmRlZCk7XG4gICAgfVxuXG4gICAgaWYgKGJhcmVEb21haW4gPT09IGFsbG93ZWRIb3N0bmFtZXMucmVwbGFjZSgvXnd3d1xcLi8sIFwiXCIpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7Ly8gaWdub3JlXG4gIH1cblxuICByZXR1cm4gZmFsc2U7XG59O1xuXG5leHBvcnQgY29uc3QgZXh0cmFjdFNyYyA9IGh0bWxTdHJpbmcgPT4ge1xuICBjb25zdCB0d2l0dGVyTWF0Y2ggPSBodG1sU3RyaW5nLm1hdGNoKFJFX1RXSVRURVJfRU1CRUQpO1xuXG4gIGlmICh0d2l0dGVyTWF0Y2ggJiYgdHdpdHRlck1hdGNoLmxlbmd0aCA9PT0gMikge1xuICAgIHJldHVybiB0d2l0dGVyTWF0Y2hbMV07XG4gIH1cblxuICBjb25zdCBnaXN0TWF0Y2ggPSBodG1sU3RyaW5nLm1hdGNoKFJFX0dIX0dJU1RfRU1CRUQpO1xuXG4gIGlmIChnaXN0TWF0Y2ggJiYgZ2lzdE1hdGNoLmxlbmd0aCA9PT0gMikge1xuICAgIHJldHVybiBnaXN0TWF0Y2hbMV07XG4gIH1cblxuICBpZiAoUkVfR0lQSFkudGVzdChodG1sU3RyaW5nKSkge1xuICAgIHJldHVybiBgaHR0cHM6Ly9naXBoeS5jb20vZW1iZWQvJHtSRV9HSVBIWS5leGVjKGh0bWxTdHJpbmcpWzFdfWA7XG4gIH1cblxuICBjb25zdCBtYXRjaCA9IGh0bWxTdHJpbmcubWF0Y2goUkVfR0VORVJJQ19FTUJFRCk7XG5cbiAgaWYgKG1hdGNoICYmIG1hdGNoLmxlbmd0aCA9PT0gMikge1xuICAgIHJldHVybiBtYXRjaFsxXTtcbiAgfVxuXG4gIHJldHVybiBodG1sU3RyaW5nO1xufTtcbmV4cG9ydCBjb25zdCBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yID0gKHVybCwgdmFsaWRhdGVFbWJlZGRhYmxlKSA9PiB7XG4gIGlmICghdXJsKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgaWYgKHZhbGlkYXRlRW1iZWRkYWJsZSAhPSBudWxsKSB7XG4gICAgaWYgKHR5cGVvZiB2YWxpZGF0ZUVtYmVkZGFibGUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgY29uc3QgcmV0ID0gdmFsaWRhdGVFbWJlZGRhYmxlKHVybCk7IC8vIGlmIHJldHVybiB2YWx1ZSBpcyB1bmRlZmluZWQsIGxlYXZlIHZhbGlkYXRpb24gdG8gZGVmYXVsdFxuXG4gICAgICBpZiAodHlwZW9mIHJldCA9PT0gXCJib29sZWFuXCIpIHtcbiAgICAgICAgcmV0dXJuIHJldDtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWxpZGF0ZUVtYmVkZGFibGUgPT09IFwiYm9vbGVhblwiKSB7XG4gICAgICByZXR1cm4gdmFsaWRhdGVFbWJlZGRhYmxlO1xuICAgIH0gZWxzZSBpZiAodmFsaWRhdGVFbWJlZGRhYmxlIGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICByZXR1cm4gdmFsaWRhdGVFbWJlZGRhYmxlLnRlc3QodXJsKTtcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkodmFsaWRhdGVFbWJlZGRhYmxlKSkge1xuICAgICAgZm9yIChjb25zdCBkb21haW4gb2YgdmFsaWRhdGVFbWJlZGRhYmxlKSB7XG4gICAgICAgIGlmIChkb21haW4gaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgICAgICBpZiAodXJsLm1hdGNoKGRvbWFpbikpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh2YWxpZGF0ZUhvc3RuYW1lKHVybCwgZG9tYWluKSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdmFsaWRhdGVIb3N0bmFtZSh1cmwsIEFMTE9XRURfRE9NQUlOUyk7XG59OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../element/embeddable.ts\n");
3907
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"actionSetEmbeddableAsActiveTool\": () => (/* binding */ actionSetEmbeddableAsActiveTool),\n/* harmony export */ \"createPlaceholderEmbeddableLabel\": () => (/* binding */ createPlaceholderEmbeddableLabel),\n/* harmony export */ \"embeddableURLValidator\": () => (/* binding */ embeddableURLValidator),\n/* harmony export */ \"extractSrc\": () => (/* binding */ extractSrc),\n/* harmony export */ \"getEmbedLink\": () => (/* binding */ getEmbedLink),\n/* harmony export */ \"isEmbeddableOrLabel\": () => (/* binding */ isEmbeddableOrLabel)\n/* harmony export */ });\n/* harmony import */ var _actions_register__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../actions/register */ \"../../actions/register.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../i18n */ \"../../i18n.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _cursor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../cursor */ \"../../cursor.ts\");\n/* harmony import */ var _newElement__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./newElement */ \"../../element/newElement.ts\");\n/* harmony import */ var _textElement__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _typeChecks__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./typeChecks */ \"../../element/typeChecks.ts\");\n\n\n\n\n\n\n\n\nconst embeddedLinkCache = new Map();\nconst RE_YOUTUBE = /^(?:http(?:s)?:\\/\\/)?(?:www\\.)?youtu(?:be\\.com|\\.be)\\/(embed\\/|watch\\?v=|shorts\\/|playlist\\?list=|embed\\/videoseries\\?list=)?([a-zA-Z0-9_-]+)(?:\\?t=|&t=|\\?start=|&start=)?([a-zA-Z0-9_-]+)?[^\\s]*$/;\nconst RE_VIMEO = /^(?:http(?:s)?:\\/\\/)?(?:(?:w){3}\\.)?(?:player\\.)?vimeo\\.com\\/(?:video\\/)?([^?\\s]+)(?:\\?.*)?$/;\nconst RE_FIGMA = /^https:\\/\\/(?:www\\.)?figma\\.com/;\nconst RE_GH_GIST = /^https:\\/\\/gist\\.github\\.com/;\nconst RE_GH_GIST_EMBED = /https?:\\/\\/gist\\.github\\.com\\/([\\w_-]+)\\/([\\w_-]+)\\.js[\"']/i; // not anchored to start to allow <blockquote> twitter embeds\n\nconst RE_TWITTER = /(?:https?:\\/\\/)?(?:(?:w){3}\\.)?(?:twitter|x)\\.com/;\nconst RE_TWITTER_EMBED = /^<blockquote[\\s\\S]*?\\shref=[\"'](https?:\\/\\/(?:twitter|x)\\.com\\/[^\"']*)/i;\nconst RE_VALTOWN = /^https:\\/\\/(?:www\\.)?val\\.town\\/(v|embed)\\/[a-zA-Z_$][0-9a-zA-Z_$]+\\.[a-zA-Z_$][0-9a-zA-Z_$]+/;\nconst RE_GENERIC_EMBED = /^<(?:iframe|blockquote)[\\s\\S]*?\\s(?:src|href)=[\"']([^\"']*)[\"'][\\s\\S]*?>$/i;\nconst RE_GIPHY = /giphy.com\\/(?:clips|embed|gifs)\\/[a-zA-Z0-9]*?-?([a-zA-Z0-9]+)(?:[^a-zA-Z0-9]|$)/;\nconst ALLOWED_DOMAINS = new Set([\"youtube.com\", \"youtu.be\", \"vimeo.com\", \"player.vimeo.com\", \"figma.com\", \"link.excalidraw.com\", \"gist.github.com\", \"twitter.com\", \"*.simplepdf.eu\", \"stackblitz.com\", \"val.town\", \"giphy.com\", \"dddice.com\"]);\n\nconst createSrcDoc = body => {\n return `<html><body>${body}</body></html>`;\n};\n\nconst getEmbedLink = link => {\n if (!link) {\n return null;\n }\n\n if (embeddedLinkCache.has(link)) {\n return embeddedLinkCache.get(link);\n }\n\n const originalLink = link;\n let type = \"generic\";\n let aspectRatio = {\n w: 560,\n h: 840\n };\n const ytLink = link.match(RE_YOUTUBE);\n\n if (ytLink === null || ytLink === void 0 ? void 0 : ytLink[2]) {\n const time = ytLink[3] ? `&start=${ytLink[3]}` : ``;\n const isPortrait = link.includes(\"shorts\");\n type = \"video\";\n\n switch (ytLink[1]) {\n case \"embed/\":\n case \"watch?v=\":\n case \"shorts/\":\n link = `https://www.youtube.com/embed/${ytLink[2]}?enablejsapi=1${time}`;\n break;\n\n case \"playlist?list=\":\n case \"embed/videoseries?list=\":\n link = `https://www.youtube.com/embed/videoseries?list=${ytLink[2]}&enablejsapi=1${time}`;\n break;\n\n default:\n link = `https://www.youtube.com/embed/${ytLink[2]}?enablejsapi=1${time}`;\n break;\n }\n\n aspectRatio = isPortrait ? {\n w: 315,\n h: 560\n } : {\n w: 560,\n h: 315\n };\n embeddedLinkCache.set(originalLink, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type\n };\n }\n\n const vimeoLink = link.match(RE_VIMEO);\n\n if (vimeoLink === null || vimeoLink === void 0 ? void 0 : vimeoLink[1]) {\n const target = vimeoLink === null || vimeoLink === void 0 ? void 0 : vimeoLink[1];\n const warning = !/^\\d+$/.test(target) ? (0,_i18n__WEBPACK_IMPORTED_MODULE_2__.t)(\"toast.unrecognizedLinkFormat\") : undefined;\n type = \"video\";\n link = `https://player.vimeo.com/video/${target}?api=1`;\n aspectRatio = {\n w: 560,\n h: 315\n }; //warning deliberately ommited so it is displayed only once per link\n //same link next time will be served from cache\n\n embeddedLinkCache.set(originalLink, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type,\n warning\n };\n }\n\n const figmaLink = link.match(RE_FIGMA);\n\n if (figmaLink) {\n type = \"generic\";\n link = `https://www.figma.com/embed?embed_host=share&url=${encodeURIComponent(link)}`;\n aspectRatio = {\n w: 550,\n h: 550\n };\n embeddedLinkCache.set(originalLink, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type\n };\n }\n\n const valLink = link.match(RE_VALTOWN);\n\n if (valLink) {\n link = valLink[1] === \"embed\" ? valLink[0] : valLink[0].replace(\"/v\", \"/embed\");\n embeddedLinkCache.set(originalLink, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type\n };\n }\n\n if (RE_TWITTER.test(link)) {\n // the embed srcdoc still supports twitter.com domain only\n link = link.replace(/\\bx.com\\b/, \"twitter.com\");\n const ret = {\n type: \"document\",\n srcdoc: theme => createSrcDoc(`<blockquote class=\"twitter-tweet\" data-dnt=\"true\" data-theme=\"${theme}\"><a href=\"${link}\"></a></blockquote> <script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>`),\n aspectRatio: {\n w: 480,\n h: 480\n },\n sandbox: {\n allowSameOrigin: true\n }\n };\n embeddedLinkCache.set(originalLink, ret);\n return ret;\n }\n\n if (RE_GH_GIST.test(link)) {\n const ret = {\n type: \"document\",\n srcdoc: () => createSrcDoc(`\n <script src=\"${link}.js\"></script>\n <style type=\"text/css\">\n * { margin: 0px; }\n table, .gist { height: 100%; }\n .gist .gist-file { height: calc(100vh - 2px); padding: 0px; display: grid; grid-template-rows: 1fr auto; }\n </style>\n `),\n aspectRatio: {\n w: 550,\n h: 720\n }\n };\n embeddedLinkCache.set(link, ret);\n return ret;\n }\n\n embeddedLinkCache.set(link, {\n link,\n aspectRatio,\n type\n });\n return {\n link,\n aspectRatio,\n type\n };\n};\nconst isEmbeddableOrLabel = element => {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_7__.isEmbeddableElement)(element)) {\n return true;\n }\n\n if (element.type === \"text\") {\n const container = (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getContainerElement)(element);\n\n if (container && (0,_typeChecks__WEBPACK_IMPORTED_MODULE_7__.isEmbeddableElement)(container)) {\n return true;\n }\n }\n\n return false;\n};\nconst createPlaceholderEmbeddableLabel = element => {\n var _a;\n\n const text = !element.link || (element === null || element === void 0 ? void 0 : element.link) === \"\" ? \"Empty Web-Embed\" : element.link;\n const fontSize = Math.max(Math.min(element.width / 2, element.width / text.length), element.width / 30);\n const fontFamily = _constants__WEBPACK_IMPORTED_MODULE_1__.FONT_FAMILY.Helvetica;\n const fontString = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.getFontString)({\n fontSize,\n fontFamily\n });\n return (0,_newElement__WEBPACK_IMPORTED_MODULE_5__.newTextElement)({\n x: element.x + element.width / 2,\n y: element.y + element.height / 2,\n strokeColor: element.strokeColor !== \"transparent\" ? element.strokeColor : \"black\",\n backgroundColor: \"transparent\",\n fontFamily,\n fontSize,\n text: (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.wrapText)(text, fontString, element.width - 20),\n textAlign: \"center\",\n verticalAlign: _constants__WEBPACK_IMPORTED_MODULE_1__.VERTICAL_ALIGN.MIDDLE,\n angle: (_a = element.angle) !== null && _a !== void 0 ? _a : 0\n });\n};\nconst actionSetEmbeddableAsActiveTool = (0,_actions_register__WEBPACK_IMPORTED_MODULE_0__.register)({\n name: \"setEmbeddableAsActiveTool\",\n trackEvent: {\n category: \"toolbar\"\n },\n perform: (elements, appState, _, app) => {\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.updateActiveTool)(appState, {\n type: \"embeddable\"\n });\n (0,_cursor__WEBPACK_IMPORTED_MODULE_4__.setCursorForShape)(app.canvas, Object.assign(Object.assign({}, appState), {\n activeTool: nextActiveTool\n }));\n return {\n elements,\n appState: Object.assign(Object.assign({}, appState), {\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_3__.updateActiveTool)(appState, {\n type: \"embeddable\"\n })\n }),\n commitToHistory: false\n };\n }\n});\n\nconst validateHostname = (url,\n/** using a Set assumes it already contains normalized bare domains */\nallowedHostnames) => {\n try {\n const {\n hostname\n } = new URL(url);\n const bareDomain = hostname.replace(/^www\\./, \"\");\n const bareDomainWithFirstSubdomainWildcarded = bareDomain.replace(/^([^.]+)/, \"*\");\n\n if (allowedHostnames instanceof Set) {\n return ALLOWED_DOMAINS.has(bareDomain) || ALLOWED_DOMAINS.has(bareDomainWithFirstSubdomainWildcarded);\n }\n\n if (bareDomain === allowedHostnames.replace(/^www\\./, \"\")) {\n return true;\n }\n } catch (error) {// ignore\n }\n\n return false;\n};\n\nconst extractSrc = htmlString => {\n const twitterMatch = htmlString.match(RE_TWITTER_EMBED);\n\n if (twitterMatch && twitterMatch.length === 2) {\n return twitterMatch[1];\n }\n\n const gistMatch = htmlString.match(RE_GH_GIST_EMBED);\n\n if (gistMatch && gistMatch.length === 3) {\n return `https://gist.github.com/${gistMatch[1]}/${gistMatch[2]}`;\n }\n\n if (RE_GIPHY.test(htmlString)) {\n return `https://giphy.com/embed/${RE_GIPHY.exec(htmlString)[1]}`;\n }\n\n const match = htmlString.match(RE_GENERIC_EMBED);\n\n if (match && match.length === 2) {\n return match[1];\n }\n\n return htmlString;\n};\nconst embeddableURLValidator = (url, validateEmbeddable) => {\n if (!url) {\n return false;\n }\n\n if (validateEmbeddable != null) {\n if (typeof validateEmbeddable === \"function\") {\n const ret = validateEmbeddable(url); // if return value is undefined, leave validation to default\n\n if (typeof ret === \"boolean\") {\n return ret;\n }\n } else if (typeof validateEmbeddable === \"boolean\") {\n return validateEmbeddable;\n } else if (validateEmbeddable instanceof RegExp) {\n return validateEmbeddable.test(url);\n } else if (Array.isArray(validateEmbeddable)) {\n for (const domain of validateEmbeddable) {\n if (domain instanceof RegExp) {\n if (url.match(domain)) {\n return true;\n }\n } else if (validateHostname(url, domain)) {\n return true;\n }\n }\n\n return false;\n }\n }\n\n return validateHostname(url, ALLOWED_DOMAINS);\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSSxlQUFlO0FBQ25COztBQUVBO0FBQ0E7O0FBRU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxzQ0FBc0MsYUFBYSxHQUFHLGFBQWE7QUFDbkU7O0FBRUE7QUFDQSxzQ0FBc0MsNkJBQTZCO0FBQ25FOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ087QUFDUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDJDQUEyQzs7QUFFM0M7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2VsZW1lbnQvZW1iZWRkYWJsZS50cz9iZjkzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlZ2lzdGVyIH0gZnJvbSBcIi4uL2FjdGlvbnMvcmVnaXN0ZXJcIjtcbmltcG9ydCB7IEZPTlRfRkFNSUxZLCBWRVJUSUNBTF9BTElHTiB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IHQgfSBmcm9tIFwiLi4vaTE4blwiO1xuaW1wb3J0IHsgZ2V0Rm9udFN0cmluZywgdXBkYXRlQWN0aXZlVG9vbCB9IGZyb20gXCIuLi91dGlsc1wiO1xuaW1wb3J0IHsgc2V0Q3Vyc29yRm9yU2hhcGUgfSBmcm9tIFwiLi4vY3Vyc29yXCI7XG5pbXBvcnQgeyBuZXdUZXh0RWxlbWVudCB9IGZyb20gXCIuL25ld0VsZW1lbnRcIjtcbmltcG9ydCB7IGdldENvbnRhaW5lckVsZW1lbnQsIHdyYXBUZXh0IH0gZnJvbSBcIi4vdGV4dEVsZW1lbnRcIjtcbmltcG9ydCB7IGlzRW1iZWRkYWJsZUVsZW1lbnQgfSBmcm9tIFwiLi90eXBlQ2hlY2tzXCI7XG5jb25zdCBlbWJlZGRlZExpbmtDYWNoZSA9IG5ldyBNYXAoKTtcbmNvbnN0IFJFX1lPVVRVQkUgPSAvXig/Omh0dHAoPzpzKT86XFwvXFwvKT8oPzp3d3dcXC4pP3lvdXR1KD86YmVcXC5jb218XFwuYmUpXFwvKGVtYmVkXFwvfHdhdGNoXFw/dj18c2hvcnRzXFwvfHBsYXlsaXN0XFw/bGlzdD18ZW1iZWRcXC92aWRlb3Nlcmllc1xcP2xpc3Q9KT8oW2EtekEtWjAtOV8tXSspKD86XFw/dD18JnQ9fFxcP3N0YXJ0PXwmc3RhcnQ9KT8oW2EtekEtWjAtOV8tXSspP1teXFxzXSokLztcbmNvbnN0IFJFX1ZJTUVPID0gL14oPzpodHRwKD86cyk/OlxcL1xcLyk/KD86KD86dyl7M31cXC4pPyg/OnBsYXllclxcLik/dmltZW9cXC5jb21cXC8oPzp2aWRlb1xcLyk/KFteP1xcc10rKSg/OlxcPy4qKT8kLztcbmNvbnN0IFJFX0ZJR01BID0gL15odHRwczpcXC9cXC8oPzp3d3dcXC4pP2ZpZ21hXFwuY29tLztcbmNvbnN0IFJFX0dIX0dJU1QgPSAvXmh0dHBzOlxcL1xcL2dpc3RcXC5naXRodWJcXC5jb20vO1xuY29uc3QgUkVfR0hfR0lTVF9FTUJFRCA9IC9odHRwcz86XFwvXFwvZ2lzdFxcLmdpdGh1YlxcLmNvbVxcLyhbXFx3Xy1dKylcXC8oW1xcd18tXSspXFwuanNbXCInXS9pOyAvLyBub3QgYW5jaG9yZWQgdG8gc3RhcnQgdG8gYWxsb3cgPGJsb2NrcXVvdGU+IHR3aXR0ZXIgZW1iZWRzXG5cbmNvbnN0IFJFX1RXSVRURVIgPSAvKD86aHR0cHM/OlxcL1xcLyk/KD86KD86dyl7M31cXC4pPyg/OnR3aXR0ZXJ8eClcXC5jb20vO1xuY29uc3QgUkVfVFdJVFRFUl9FTUJFRCA9IC9ePGJsb2NrcXVvdGVbXFxzXFxTXSo/XFxzaHJlZj1bXCInXShodHRwcz86XFwvXFwvKD86dHdpdHRlcnx4KVxcLmNvbVxcL1teXCInXSopL2k7XG5jb25zdCBSRV9WQUxUT1dOID0gL15odHRwczpcXC9cXC8oPzp3d3dcXC4pP3ZhbFxcLnRvd25cXC8odnxlbWJlZClcXC9bYS16QS1aXyRdWzAtOWEtekEtWl8kXStcXC5bYS16QS1aXyRdWzAtOWEtekEtWl8kXSsvO1xuY29uc3QgUkVfR0VORVJJQ19FTUJFRCA9IC9ePCg/OmlmcmFtZXxibG9ja3F1b3RlKVtcXHNcXFNdKj9cXHMoPzpzcmN8aHJlZik9W1wiJ10oW15cIiddKilbXCInXVtcXHNcXFNdKj8+JC9pO1xuY29uc3QgUkVfR0lQSFkgPSAvZ2lwaHkuY29tXFwvKD86Y2xpcHN8ZW1iZWR8Z2lmcylcXC9bYS16QS1aMC05XSo/LT8oW2EtekEtWjAtOV0rKSg/OlteYS16QS1aMC05XXwkKS87XG5jb25zdCBBTExPV0VEX0RPTUFJTlMgPSBuZXcgU2V0KFtcInlvdXR1YmUuY29tXCIsIFwieW91dHUuYmVcIiwgXCJ2aW1lby5jb21cIiwgXCJwbGF5ZXIudmltZW8uY29tXCIsIFwiZmlnbWEuY29tXCIsIFwibGluay5leGNhbGlkcmF3LmNvbVwiLCBcImdpc3QuZ2l0aHViLmNvbVwiLCBcInR3aXR0ZXIuY29tXCIsIFwiKi5zaW1wbGVwZGYuZXVcIiwgXCJzdGFja2JsaXR6LmNvbVwiLCBcInZhbC50b3duXCIsIFwiZ2lwaHkuY29tXCIsIFwiZGRkaWNlLmNvbVwiXSk7XG5cbmNvbnN0IGNyZWF0ZVNyY0RvYyA9IGJvZHkgPT4ge1xuICByZXR1cm4gYDxodG1sPjxib2R5PiR7Ym9keX08L2JvZHk+PC9odG1sPmA7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0RW1iZWRMaW5rID0gbGluayA9PiB7XG4gIGlmICghbGluaykge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgaWYgKGVtYmVkZGVkTGlua0NhY2hlLmhhcyhsaW5rKSkge1xuICAgIHJldHVybiBlbWJlZGRlZExpbmtDYWNoZS5nZXQobGluayk7XG4gIH1cblxuICBjb25zdCBvcmlnaW5hbExpbmsgPSBsaW5rO1xuICBsZXQgdHlwZSA9IFwiZ2VuZXJpY1wiO1xuICBsZXQgYXNwZWN0UmF0aW8gPSB7XG4gICAgdzogNTYwLFxuICAgIGg6IDg0MFxuICB9O1xuICBjb25zdCB5dExpbmsgPSBsaW5rLm1hdGNoKFJFX1lPVVRVQkUpO1xuXG4gIGlmICh5dExpbmsgPT09IG51bGwgfHwgeXRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiB5dExpbmtbMl0pIHtcbiAgICBjb25zdCB0aW1lID0geXRMaW5rWzNdID8gYCZzdGFydD0ke3l0TGlua1szXX1gIDogYGA7XG4gICAgY29uc3QgaXNQb3J0cmFpdCA9IGxpbmsuaW5jbHVkZXMoXCJzaG9ydHNcIik7XG4gICAgdHlwZSA9IFwidmlkZW9cIjtcblxuICAgIHN3aXRjaCAoeXRMaW5rWzFdKSB7XG4gICAgICBjYXNlIFwiZW1iZWQvXCI6XG4gICAgICBjYXNlIFwid2F0Y2g/dj1cIjpcbiAgICAgIGNhc2UgXCJzaG9ydHMvXCI6XG4gICAgICAgIGxpbmsgPSBgaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvJHt5dExpbmtbMl19P2VuYWJsZWpzYXBpPTEke3RpbWV9YDtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgXCJwbGF5bGlzdD9saXN0PVwiOlxuICAgICAgY2FzZSBcImVtYmVkL3ZpZGVvc2VyaWVzP2xpc3Q9XCI6XG4gICAgICAgIGxpbmsgPSBgaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvdmlkZW9zZXJpZXM/bGlzdD0ke3l0TGlua1syXX0mZW5hYmxlanNhcGk9MSR7dGltZX1gO1xuICAgICAgICBicmVhaztcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgbGluayA9IGBodHRwczovL3d3dy55b3V0dWJlLmNvbS9lbWJlZC8ke3l0TGlua1syXX0/ZW5hYmxlanNhcGk9MSR7dGltZX1gO1xuICAgICAgICBicmVhaztcbiAgICB9XG5cbiAgICBhc3BlY3RSYXRpbyA9IGlzUG9ydHJhaXQgPyB7XG4gICAgICB3OiAzMTUsXG4gICAgICBoOiA1NjBcbiAgICB9IDoge1xuICAgICAgdzogNTYwLFxuICAgICAgaDogMzE1XG4gICAgfTtcbiAgICBlbWJlZGRlZExpbmtDYWNoZS5zZXQob3JpZ2luYWxMaW5rLCB7XG4gICAgICBsaW5rLFxuICAgICAgYXNwZWN0UmF0aW8sXG4gICAgICB0eXBlXG4gICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxpbmssXG4gICAgICBhc3BlY3RSYXRpbyxcbiAgICAgIHR5cGVcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgdmltZW9MaW5rID0gbGluay5tYXRjaChSRV9WSU1FTyk7XG5cbiAgaWYgKHZpbWVvTGluayA9PT0gbnVsbCB8fCB2aW1lb0xpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHZpbWVvTGlua1sxXSkge1xuICAgIGNvbnN0IHRhcmdldCA9IHZpbWVvTGluayA9PT0gbnVsbCB8fCB2aW1lb0xpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHZpbWVvTGlua1sxXTtcbiAgICBjb25zdCB3YXJuaW5nID0gIS9eXFxkKyQvLnRlc3QodGFyZ2V0KSA/IHQoXCJ0b2FzdC51bnJlY29nbml6ZWRMaW5rRm9ybWF0XCIpIDogdW5kZWZpbmVkO1xuICAgIHR5cGUgPSBcInZpZGVvXCI7XG4gICAgbGluayA9IGBodHRwczovL3BsYXllci52aW1lby5jb20vdmlkZW8vJHt0YXJnZXR9P2FwaT0xYDtcbiAgICBhc3BlY3RSYXRpbyA9IHtcbiAgICAgIHc6IDU2MCxcbiAgICAgIGg6IDMxNVxuICAgIH07IC8vd2FybmluZyBkZWxpYmVyYXRlbHkgb21taXRlZCBzbyBpdCBpcyBkaXNwbGF5ZWQgb25seSBvbmNlIHBlciBsaW5rXG4gICAgLy9zYW1lIGxpbmsgbmV4dCB0aW1lIHdpbGwgYmUgc2VydmVkIGZyb20gY2FjaGVcblxuICAgIGVtYmVkZGVkTGlua0NhY2hlLnNldChvcmlnaW5hbExpbmssIHtcbiAgICAgIGxpbmssXG4gICAgICBhc3BlY3RSYXRpbyxcbiAgICAgIHR5cGVcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgbGluayxcbiAgICAgIGFzcGVjdFJhdGlvLFxuICAgICAgdHlwZSxcbiAgICAgIHdhcm5pbmdcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgZmlnbWFMaW5rID0gbGluay5tYXRjaChSRV9GSUdNQSk7XG5cbiAgaWYgKGZpZ21hTGluaykge1xuICAgIHR5cGUgPSBcImdlbmVyaWNcIjtcbiAgICBsaW5rID0gYGh0dHBzOi8vd3d3LmZpZ21hLmNvbS9lbWJlZD9lbWJlZF9ob3N0PXNoYXJlJnVybD0ke2VuY29kZVVSSUNvbXBvbmVudChsaW5rKX1gO1xuICAgIGFzcGVjdFJhdGlvID0ge1xuICAgICAgdzogNTUwLFxuICAgICAgaDogNTUwXG4gICAgfTtcbiAgICBlbWJlZGRlZExpbmtDYWNoZS5zZXQob3JpZ2luYWxMaW5rLCB7XG4gICAgICBsaW5rLFxuICAgICAgYXNwZWN0UmF0aW8sXG4gICAgICB0eXBlXG4gICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxpbmssXG4gICAgICBhc3BlY3RSYXRpbyxcbiAgICAgIHR5cGVcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgdmFsTGluayA9IGxpbmsubWF0Y2goUkVfVkFMVE9XTik7XG5cbiAgaWYgKHZhbExpbmspIHtcbiAgICBsaW5rID0gdmFsTGlua1sxXSA9PT0gXCJlbWJlZFwiID8gdmFsTGlua1swXSA6IHZhbExpbmtbMF0ucmVwbGFjZShcIi92XCIsIFwiL2VtYmVkXCIpO1xuICAgIGVtYmVkZGVkTGlua0NhY2hlLnNldChvcmlnaW5hbExpbmssIHtcbiAgICAgIGxpbmssXG4gICAgICBhc3BlY3RSYXRpbyxcbiAgICAgIHR5cGVcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgbGluayxcbiAgICAgIGFzcGVjdFJhdGlvLFxuICAgICAgdHlwZVxuICAgIH07XG4gIH1cblxuICBpZiAoUkVfVFdJVFRFUi50ZXN0KGxpbmspKSB7XG4gICAgLy8gdGhlIGVtYmVkIHNyY2RvYyBzdGlsbCBzdXBwb3J0cyB0d2l0dGVyLmNvbSBkb21haW4gb25seVxuICAgIGxpbmsgPSBsaW5rLnJlcGxhY2UoL1xcYnguY29tXFxiLywgXCJ0d2l0dGVyLmNvbVwiKTtcbiAgICBjb25zdCByZXQgPSB7XG4gICAgICB0eXBlOiBcImRvY3VtZW50XCIsXG4gICAgICBzcmNkb2M6IHRoZW1lID0+IGNyZWF0ZVNyY0RvYyhgPGJsb2NrcXVvdGUgY2xhc3M9XCJ0d2l0dGVyLXR3ZWV0XCIgZGF0YS1kbnQ9XCJ0cnVlXCIgZGF0YS10aGVtZT1cIiR7dGhlbWV9XCI+PGEgaHJlZj1cIiR7bGlua31cIj48L2E+PC9ibG9ja3F1b3RlPiA8c2NyaXB0IGFzeW5jIHNyYz1cImh0dHBzOi8vcGxhdGZvcm0udHdpdHRlci5jb20vd2lkZ2V0cy5qc1wiIGNoYXJzZXQ9XCJ1dGYtOFwiPjwvc2NyaXB0PmApLFxuICAgICAgYXNwZWN0UmF0aW86IHtcbiAgICAgICAgdzogNDgwLFxuICAgICAgICBoOiA0ODBcbiAgICAgIH0sXG4gICAgICBzYW5kYm94OiB7XG4gICAgICAgIGFsbG93U2FtZU9yaWdpbjogdHJ1ZVxuICAgICAgfVxuICAgIH07XG4gICAgZW1iZWRkZWRMaW5rQ2FjaGUuc2V0KG9yaWdpbmFsTGluaywgcmV0KTtcbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgaWYgKFJFX0dIX0dJU1QudGVzdChsaW5rKSkge1xuICAgIGNvbnN0IHJldCA9IHtcbiAgICAgIHR5cGU6IFwiZG9jdW1lbnRcIixcbiAgICAgIHNyY2RvYzogKCkgPT4gY3JlYXRlU3JjRG9jKGBcbiAgICAgICAgICA8c2NyaXB0IHNyYz1cIiR7bGlua30uanNcIj48L3NjcmlwdD5cbiAgICAgICAgICA8c3R5bGUgdHlwZT1cInRleHQvY3NzXCI+XG4gICAgICAgICAgICAqIHsgbWFyZ2luOiAwcHg7IH1cbiAgICAgICAgICAgIHRhYmxlLCAuZ2lzdCB7IGhlaWdodDogMTAwJTsgfVxuICAgICAgICAgICAgLmdpc3QgLmdpc3QtZmlsZSB7IGhlaWdodDogY2FsYygxMDB2aCAtIDJweCk7IHBhZGRpbmc6IDBweDsgZGlzcGxheTogZ3JpZDsgZ3JpZC10ZW1wbGF0ZS1yb3dzOiAxZnIgYXV0bzsgfVxuICAgICAgICAgIDwvc3R5bGU+XG4gICAgICAgIGApLFxuICAgICAgYXNwZWN0UmF0aW86IHtcbiAgICAgICAgdzogNTUwLFxuICAgICAgICBoOiA3MjBcbiAgICAgIH1cbiAgICB9O1xuICAgIGVtYmVkZGVkTGlua0NhY2hlLnNldChsaW5rLCByZXQpO1xuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICBlbWJlZGRlZExpbmtDYWNoZS5zZXQobGluaywge1xuICAgIGxpbmssXG4gICAgYXNwZWN0UmF0aW8sXG4gICAgdHlwZVxuICB9KTtcbiAgcmV0dXJuIHtcbiAgICBsaW5rLFxuICAgIGFzcGVjdFJhdGlvLFxuICAgIHR5cGVcbiAgfTtcbn07XG5leHBvcnQgY29uc3QgaXNFbWJlZGRhYmxlT3JMYWJlbCA9IGVsZW1lbnQgPT4ge1xuICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChlbGVtZW50KSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgaWYgKGVsZW1lbnQudHlwZSA9PT0gXCJ0ZXh0XCIpIHtcbiAgICBjb25zdCBjb250YWluZXIgPSBnZXRDb250YWluZXJFbGVtZW50KGVsZW1lbnQpO1xuXG4gICAgaWYgKGNvbnRhaW5lciAmJiBpc0VtYmVkZGFibGVFbGVtZW50KGNvbnRhaW5lcikpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn07XG5leHBvcnQgY29uc3QgY3JlYXRlUGxhY2Vob2xkZXJFbWJlZGRhYmxlTGFiZWwgPSBlbGVtZW50ID0+IHtcbiAgdmFyIF9hO1xuXG4gIGNvbnN0IHRleHQgPSAhZWxlbWVudC5saW5rIHx8IChlbGVtZW50ID09PSBudWxsIHx8IGVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVsZW1lbnQubGluaykgPT09IFwiXCIgPyBcIkVtcHR5IFdlYi1FbWJlZFwiIDogZWxlbWVudC5saW5rO1xuICBjb25zdCBmb250U2l6ZSA9IE1hdGgubWF4KE1hdGgubWluKGVsZW1lbnQud2lkdGggLyAyLCBlbGVtZW50LndpZHRoIC8gdGV4dC5sZW5ndGgpLCBlbGVtZW50LndpZHRoIC8gMzApO1xuICBjb25zdCBmb250RmFtaWx5ID0gRk9OVF9GQU1JTFkuSGVsdmV0aWNhO1xuICBjb25zdCBmb250U3RyaW5nID0gZ2V0Rm9udFN0cmluZyh7XG4gICAgZm9udFNpemUsXG4gICAgZm9udEZhbWlseVxuICB9KTtcbiAgcmV0dXJuIG5ld1RleHRFbGVtZW50KHtcbiAgICB4OiBlbGVtZW50LnggKyBlbGVtZW50LndpZHRoIC8gMixcbiAgICB5OiBlbGVtZW50LnkgKyBlbGVtZW50LmhlaWdodCAvIDIsXG4gICAgc3Ryb2tlQ29sb3I6IGVsZW1lbnQuc3Ryb2tlQ29sb3IgIT09IFwidHJhbnNwYXJlbnRcIiA/IGVsZW1lbnQuc3Ryb2tlQ29sb3IgOiBcImJsYWNrXCIsXG4gICAgYmFja2dyb3VuZENvbG9yOiBcInRyYW5zcGFyZW50XCIsXG4gICAgZm9udEZhbWlseSxcbiAgICBmb250U2l6ZSxcbiAgICB0ZXh0OiB3cmFwVGV4dCh0ZXh0LCBmb250U3RyaW5nLCBlbGVtZW50LndpZHRoIC0gMjApLFxuICAgIHRleHRBbGlnbjogXCJjZW50ZXJcIixcbiAgICB2ZXJ0aWNhbEFsaWduOiBWRVJUSUNBTF9BTElHTi5NSURETEUsXG4gICAgYW5nbGU6IChfYSA9IGVsZW1lbnQuYW5nbGUpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IDBcbiAgfSk7XG59O1xuZXhwb3J0IGNvbnN0IGFjdGlvblNldEVtYmVkZGFibGVBc0FjdGl2ZVRvb2wgPSByZWdpc3Rlcih7XG4gIG5hbWU6IFwic2V0RW1iZWRkYWJsZUFzQWN0aXZlVG9vbFwiLFxuICB0cmFja0V2ZW50OiB7XG4gICAgY2F0ZWdvcnk6IFwidG9vbGJhclwiXG4gIH0sXG4gIHBlcmZvcm06IChlbGVtZW50cywgYXBwU3RhdGUsIF8sIGFwcCkgPT4ge1xuICAgIGNvbnN0IG5leHRBY3RpdmVUb29sID0gdXBkYXRlQWN0aXZlVG9vbChhcHBTdGF0ZSwge1xuICAgICAgdHlwZTogXCJlbWJlZGRhYmxlXCJcbiAgICB9KTtcbiAgICBzZXRDdXJzb3JGb3JTaGFwZShhcHAuY2FudmFzLCBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGFwcFN0YXRlKSwge1xuICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2xcbiAgICB9KSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGVsZW1lbnRzLFxuICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYXBwU3RhdGUpLCB7XG4gICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2woYXBwU3RhdGUsIHtcbiAgICAgICAgICB0eXBlOiBcImVtYmVkZGFibGVcIlxuICAgICAgICB9KVxuICAgICAgfSksXG4gICAgICBjb21taXRUb0hpc3Rvcnk6IGZhbHNlXG4gICAgfTtcbiAgfVxufSk7XG5cbmNvbnN0IHZhbGlkYXRlSG9zdG5hbWUgPSAodXJsLFxuLyoqIHVzaW5nIGEgU2V0IGFzc3VtZXMgaXQgYWxyZWFkeSBjb250YWlucyBub3JtYWxpemVkIGJhcmUgZG9tYWlucyAqL1xuYWxsb3dlZEhvc3RuYW1lcykgPT4ge1xuICB0cnkge1xuICAgIGNvbnN0IHtcbiAgICAgIGhvc3RuYW1lXG4gICAgfSA9IG5ldyBVUkwodXJsKTtcbiAgICBjb25zdCBiYXJlRG9tYWluID0gaG9zdG5hbWUucmVwbGFjZSgvXnd3d1xcLi8sIFwiXCIpO1xuICAgIGNvbnN0IGJhcmVEb21haW5XaXRoRmlyc3RTdWJkb21haW5XaWxkY2FyZGVkID0gYmFyZURvbWFpbi5yZXBsYWNlKC9eKFteLl0rKS8sIFwiKlwiKTtcblxuICAgIGlmIChhbGxvd2VkSG9zdG5hbWVzIGluc3RhbmNlb2YgU2V0KSB7XG4gICAgICByZXR1cm4gQUxMT1dFRF9ET01BSU5TLmhhcyhiYXJlRG9tYWluKSB8fCBBTExPV0VEX0RPTUFJTlMuaGFzKGJhcmVEb21haW5XaXRoRmlyc3RTdWJkb21haW5XaWxkY2FyZGVkKTtcbiAgICB9XG5cbiAgICBpZiAoYmFyZURvbWFpbiA9PT0gYWxsb3dlZEhvc3RuYW1lcy5yZXBsYWNlKC9ed3d3XFwuLywgXCJcIikpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHsvLyBpZ25vcmVcbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn07XG5cbmV4cG9ydCBjb25zdCBleHRyYWN0U3JjID0gaHRtbFN0cmluZyA9PiB7XG4gIGNvbnN0IHR3aXR0ZXJNYXRjaCA9IGh0bWxTdHJpbmcubWF0Y2goUkVfVFdJVFRFUl9FTUJFRCk7XG5cbiAgaWYgKHR3aXR0ZXJNYXRjaCAmJiB0d2l0dGVyTWF0Y2gubGVuZ3RoID09PSAyKSB7XG4gICAgcmV0dXJuIHR3aXR0ZXJNYXRjaFsxXTtcbiAgfVxuXG4gIGNvbnN0IGdpc3RNYXRjaCA9IGh0bWxTdHJpbmcubWF0Y2goUkVfR0hfR0lTVF9FTUJFRCk7XG5cbiAgaWYgKGdpc3RNYXRjaCAmJiBnaXN0TWF0Y2gubGVuZ3RoID09PSAzKSB7XG4gICAgcmV0dXJuIGBodHRwczovL2dpc3QuZ2l0aHViLmNvbS8ke2dpc3RNYXRjaFsxXX0vJHtnaXN0TWF0Y2hbMl19YDtcbiAgfVxuXG4gIGlmIChSRV9HSVBIWS50ZXN0KGh0bWxTdHJpbmcpKSB7XG4gICAgcmV0dXJuIGBodHRwczovL2dpcGh5LmNvbS9lbWJlZC8ke1JFX0dJUEhZLmV4ZWMoaHRtbFN0cmluZylbMV19YDtcbiAgfVxuXG4gIGNvbnN0IG1hdGNoID0gaHRtbFN0cmluZy5tYXRjaChSRV9HRU5FUklDX0VNQkVEKTtcblxuICBpZiAobWF0Y2ggJiYgbWF0Y2gubGVuZ3RoID09PSAyKSB7XG4gICAgcmV0dXJuIG1hdGNoWzFdO1xuICB9XG5cbiAgcmV0dXJuIGh0bWxTdHJpbmc7XG59O1xuZXhwb3J0IGNvbnN0IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IgPSAodXJsLCB2YWxpZGF0ZUVtYmVkZGFibGUpID0+IHtcbiAgaWYgKCF1cmwpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBpZiAodmFsaWRhdGVFbWJlZGRhYmxlICE9IG51bGwpIHtcbiAgICBpZiAodHlwZW9mIHZhbGlkYXRlRW1iZWRkYWJsZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICBjb25zdCByZXQgPSB2YWxpZGF0ZUVtYmVkZGFibGUodXJsKTsgLy8gaWYgcmV0dXJuIHZhbHVlIGlzIHVuZGVmaW5lZCwgbGVhdmUgdmFsaWRhdGlvbiB0byBkZWZhdWx0XG5cbiAgICAgIGlmICh0eXBlb2YgcmV0ID09PSBcImJvb2xlYW5cIikge1xuICAgICAgICByZXR1cm4gcmV0O1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbGlkYXRlRW1iZWRkYWJsZSA9PT0gXCJib29sZWFuXCIpIHtcbiAgICAgIHJldHVybiB2YWxpZGF0ZUVtYmVkZGFibGU7XG4gICAgfSBlbHNlIGlmICh2YWxpZGF0ZUVtYmVkZGFibGUgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgIHJldHVybiB2YWxpZGF0ZUVtYmVkZGFibGUudGVzdCh1cmwpO1xuICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheSh2YWxpZGF0ZUVtYmVkZGFibGUpKSB7XG4gICAgICBmb3IgKGNvbnN0IGRvbWFpbiBvZiB2YWxpZGF0ZUVtYmVkZGFibGUpIHtcbiAgICAgICAgaWYgKGRvbWFpbiBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICAgIGlmICh1cmwubWF0Y2goZG9tYWluKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHZhbGlkYXRlSG9zdG5hbWUodXJsLCBkb21haW4pKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB2YWxpZGF0ZUhvc3RuYW1lKHVybCwgQUxMT1dFRF9ET01BSU5TKTtcbn07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../element/embeddable.ts\n");
3908
3908
 
3909
3909
  /***/ }),
3910
3910
 
@@ -3959,7 +3959,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
3959
3959
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
3960
3960
 
3961
3961
  "use strict";
3962
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"deepCopyElement\": () => (/* binding */ deepCopyElement),\n/* harmony export */ \"duplicateElement\": () => (/* binding */ duplicateElement),\n/* harmony export */ \"duplicateElements\": () => (/* binding */ duplicateElements),\n/* harmony export */ \"newElement\": () => (/* binding */ newElement),\n/* harmony export */ \"newEmbeddableElement\": () => (/* binding */ newEmbeddableElement),\n/* harmony export */ \"newFrameElement\": () => (/* binding */ newFrameElement),\n/* harmony export */ \"newFreeDrawElement\": () => (/* binding */ newFreeDrawElement),\n/* harmony export */ \"newImageElement\": () => (/* binding */ newImageElement),\n/* harmony export */ \"newLinearElement\": () => (/* binding */ newLinearElement),\n/* harmony export */ \"newTextElement\": () => (/* binding */ newTextElement),\n/* harmony export */ \"refreshTextDimensions\": () => (/* binding */ refreshTextDimensions),\n/* harmony export */ \"regenerateId\": () => (/* binding */ regenerateId),\n/* harmony export */ \"updateTextElement\": () => (/* binding */ updateTextElement)\n/* harmony export */ });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _random__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../random */ \"../../random.ts\");\n/* harmony import */ var _mutateElement__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mutateElement */ \"../../element/mutateElement.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../groups */ \"../../groups.ts\");\n/* harmony import */ var ___WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! . */ \"../../element/index.ts\");\n/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../math */ \"../../math.ts\");\n/* harmony import */ var _bounds__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./bounds */ \"../../element/bounds.ts\");\n/* harmony import */ var _textElement__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\nvar __rest = undefined && undefined.__rest || function (s, e) {\n var t = {};\n\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];\n\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];\n }\n return t;\n};\n\n\n\n\n\n\n\n\n\n\n\nconst _newElementBase = (type, _a) => {\n var _b, _c;\n\n var {\n x,\n y,\n strokeColor = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.strokeColor,\n backgroundColor = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.backgroundColor,\n fillStyle = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.fillStyle,\n strokeWidth = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.strokeWidth,\n strokeStyle = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.strokeStyle,\n roughness = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.roughness,\n opacity = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.opacity,\n width = 0,\n height = 0,\n angle = 0,\n groupIds = [],\n frameId = null,\n roundness = null,\n boundElements = null,\n link = null,\n locked = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.locked\n } = _a,\n rest = __rest(_a, [\"x\", \"y\", \"strokeColor\", \"backgroundColor\", \"fillStyle\", \"strokeWidth\", \"strokeStyle\", \"roughness\", \"opacity\", \"width\", \"height\", \"angle\", \"groupIds\", \"frameId\", \"roundness\", \"boundElements\", \"link\", \"locked\"]); // assign type to guard against excess properties\n\n\n const element = {\n id: rest.id || (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomId)(),\n type,\n x,\n y,\n width,\n height,\n angle,\n strokeColor,\n backgroundColor,\n fillStyle,\n strokeWidth,\n strokeStyle,\n roughness,\n opacity,\n groupIds,\n frameId,\n roundness,\n seed: (_b = rest.seed) !== null && _b !== void 0 ? _b : (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomInteger)(),\n version: rest.version || 1,\n versionNonce: (_c = rest.versionNonce) !== null && _c !== void 0 ? _c : 0,\n isDeleted: false,\n boundElements,\n updated: (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getUpdatedTimestamp)(),\n link,\n locked\n };\n return element;\n};\n\nconst newElement = opts => _newElementBase(opts.type, opts);\nconst newEmbeddableElement = opts => {\n return Object.assign(Object.assign({}, _newElementBase(\"embeddable\", opts)), {\n validated: opts.validated\n });\n};\nconst newFrameElement = opts => {\n const frameElement = (0,_mutateElement__WEBPACK_IMPORTED_MODULE_2__.newElementWith)(Object.assign(Object.assign({}, _newElementBase(\"frame\", opts)), {\n type: \"frame\",\n name: (opts === null || opts === void 0 ? void 0 : opts.name) || null\n }), {});\n return frameElement;\n};\n/** computes element x/y offset based on textAlign/verticalAlign */\n\nconst getTextElementPositionOffsets = (opts, metrics) => {\n return {\n x: opts.textAlign === \"center\" ? metrics.width / 2 : opts.textAlign === \"right\" ? metrics.width : 0,\n y: opts.verticalAlign === \"middle\" ? metrics.height / 2 : 0\n };\n};\n\nconst newTextElement = opts => {\n const fontFamily = opts.fontFamily || _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_FONT_FAMILY;\n const fontSize = opts.fontSize || _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_FONT_SIZE;\n const lineHeight = opts.lineHeight || (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.getDefaultLineHeight)(fontFamily);\n const text = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.normalizeText)(opts.text);\n const metrics = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.measureText)(text, (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getFontString)({\n fontFamily,\n fontSize\n }), lineHeight);\n const textAlign = opts.textAlign || _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_TEXT_ALIGN;\n const verticalAlign = opts.verticalAlign || _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_VERTICAL_ALIGN;\n const offsets = getTextElementPositionOffsets({\n textAlign,\n verticalAlign\n }, metrics);\n const textElement = (0,_mutateElement__WEBPACK_IMPORTED_MODULE_2__.newElementWith)(Object.assign(Object.assign({}, _newElementBase(\"text\", opts)), {\n text,\n fontSize,\n fontFamily,\n textAlign,\n verticalAlign,\n x: opts.x - offsets.x,\n y: opts.y - offsets.y,\n width: metrics.width,\n height: metrics.height,\n baseline: metrics.baseline,\n containerId: opts.containerId || null,\n originalText: text,\n lineHeight\n }), {});\n return textElement;\n};\n\nconst getAdjustedDimensions = (element, nextText) => {\n const {\n width: nextWidth,\n height: nextHeight,\n baseline: nextBaseline\n } = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.measureText)(nextText, (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getFontString)(element), element.lineHeight);\n const {\n textAlign,\n verticalAlign\n } = element;\n let x;\n let y;\n\n if (textAlign === \"center\" && verticalAlign === _constants__WEBPACK_IMPORTED_MODULE_8__.VERTICAL_ALIGN.MIDDLE && !element.containerId) {\n const prevMetrics = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.measureText)(element.text, (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getFontString)(element), element.lineHeight);\n const offsets = getTextElementPositionOffsets(element, {\n width: nextWidth - prevMetrics.width,\n height: nextHeight - prevMetrics.height\n });\n x = element.x - offsets.x;\n y = element.y - offsets.y;\n } else {\n const [x1, y1, x2, y2] = (0,___WEBPACK_IMPORTED_MODULE_4__.getElementAbsoluteCoords)(element);\n const [nextX1, nextY1, nextX2, nextY2] = (0,_bounds__WEBPACK_IMPORTED_MODULE_6__.getResizedElementAbsoluteCoords)(element, nextWidth, nextHeight, false);\n const deltaX1 = (x1 - nextX1) / 2;\n const deltaY1 = (y1 - nextY1) / 2;\n const deltaX2 = (x2 - nextX2) / 2;\n const deltaY2 = (y2 - nextY2) / 2;\n [x, y] = (0,_math__WEBPACK_IMPORTED_MODULE_5__.adjustXYWithRotation)({\n s: true,\n e: textAlign === \"center\" || textAlign === \"left\",\n w: textAlign === \"center\" || textAlign === \"right\"\n }, element.x, element.y, element.angle, deltaX1, deltaY1, deltaX2, deltaY2);\n }\n\n return {\n width: nextWidth,\n height: nextHeight,\n baseline: nextBaseline,\n x: Number.isFinite(x) ? x : element.x,\n y: Number.isFinite(y) ? y : element.y\n };\n};\n\nconst refreshTextDimensions = (textElement, text = textElement.text) => {\n if (textElement.isDeleted) {\n return;\n }\n\n const container = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.getContainerElement)(textElement);\n\n if (container) {\n text = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.wrapText)(text, (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getFontString)(textElement), (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.getBoundTextMaxWidth)(container));\n }\n\n const dimensions = getAdjustedDimensions(textElement, text);\n return Object.assign({\n text\n }, dimensions);\n};\nconst updateTextElement = (textElement, {\n text,\n isDeleted,\n originalText\n}) => {\n return (0,_mutateElement__WEBPACK_IMPORTED_MODULE_2__.newElementWith)(textElement, Object.assign({\n originalText,\n isDeleted: isDeleted !== null && isDeleted !== void 0 ? isDeleted : textElement.isDeleted\n }, refreshTextDimensions(textElement, originalText)));\n};\nconst newFreeDrawElement = opts => {\n return Object.assign(Object.assign({}, _newElementBase(opts.type, opts)), {\n points: opts.points || [],\n pressures: [],\n simulatePressure: opts.simulatePressure,\n lastCommittedPoint: null\n });\n};\nconst newLinearElement = opts => {\n return Object.assign(Object.assign({}, _newElementBase(opts.type, opts)), {\n points: opts.points || [],\n lastCommittedPoint: null,\n startBinding: null,\n endBinding: null,\n startArrowhead: opts.startArrowhead || null,\n endArrowhead: opts.endArrowhead || null\n });\n};\nconst newImageElement = opts => {\n var _a, _b, _c;\n\n return Object.assign(Object.assign({}, _newElementBase(\"image\", opts)), {\n // in the future we'll support changing stroke color for some SVG elements,\n // and `transparent` will likely mean \"use original colors of the image\"\n strokeColor: \"transparent\",\n status: (_a = opts.status) !== null && _a !== void 0 ? _a : \"pending\",\n fileId: (_b = opts.fileId) !== null && _b !== void 0 ? _b : null,\n scale: (_c = opts.scale) !== null && _c !== void 0 ? _c : [1, 1]\n });\n}; // Simplified deep clone for the purpose of cloning ExcalidrawElement.\n//\n// Only clones plain objects and arrays. Doesn't clone Date, RegExp, Map, Set,\n// Typed arrays and other non-null objects.\n//\n// Adapted from https://github.com/lukeed/klona\n//\n// The reason for `deepCopyElement()` wrapper is type safety (only allow\n// passing ExcalidrawElement as the top-level argument).\n\nconst _deepCopyElement = (val, depth = 0) => {\n // only clone non-primitives\n if (val == null || typeof val !== \"object\") {\n return val;\n }\n\n const objectType = Object.prototype.toString.call(val);\n\n if (objectType === \"[object Object]\") {\n const tmp = typeof val.constructor === \"function\" ? Object.create(Object.getPrototypeOf(val)) : {};\n\n for (const key in val) {\n if (val.hasOwnProperty(key)) {\n // don't copy non-serializable objects like these caches. They'll be\n // populated when the element is rendered.\n if (depth === 0 && (key === \"shape\" || key === \"canvas\")) {\n continue;\n }\n\n tmp[key] = _deepCopyElement(val[key], depth + 1);\n }\n }\n\n return tmp;\n }\n\n if (Array.isArray(val)) {\n let k = val.length;\n const arr = new Array(k);\n\n while (k--) {\n arr[k] = _deepCopyElement(val[k], depth + 1);\n }\n\n return arr;\n } // we're not cloning non-array & non-plain-object objects because we\n // don't support them on excalidraw elements yet. If we do, we need to make\n // sure we start cloning them, so let's warn about it.\n\n\n if (true) {\n if (objectType !== \"[object Object]\" && objectType !== \"[object Array]\" && objectType.startsWith(\"[object \")) {\n console.warn(`_deepCloneElement: unexpected object type ${objectType}. This value will not be cloned!`);\n }\n }\n\n return val;\n};\n/**\n * Clones ExcalidrawElement data structure. Does not regenerate id, nonce, or\n * any value. The purpose is to to break object references for immutability\n * reasons, whenever we want to keep the original element, but ensure it's not\n * mutated.\n *\n * Only clones plain objects and arrays. Doesn't clone Date, RegExp, Map, Set,\n * Typed arrays and other non-null objects.\n */\n\n\nconst deepCopyElement = val => {\n return _deepCopyElement(val);\n};\n/**\n * utility wrapper to generate new id. In test env it reuses the old + postfix\n * for test assertions.\n */\n\nconst regenerateId = (\n/** supply null if no previous id exists */\npreviousId) => {\n var _a, _b;\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_0__.isTestEnv)() && previousId) {\n let nextId = `${previousId}_copy`; // `window.h` may not be defined in some unit tests\n\n if ((_b = (_a = window.h) === null || _a === void 0 ? void 0 : _a.app) === null || _b === void 0 ? void 0 : _b.getSceneElementsIncludingDeleted().find(el => el.id === nextId)) {\n nextId += \"_copy\";\n }\n\n return nextId;\n }\n\n return (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomId)();\n};\n/**\n * Duplicate an element, often used in the alt-drag operation.\n * Note that this method has gotten a bit complicated since the\n * introduction of gruoping/ungrouping elements.\n * @param editingGroupId The current group being edited. The new\n * element will inherit this group and its\n * parents.\n * @param groupIdMapForOperation A Map that maps old group IDs to\n * duplicated ones. If you are duplicating\n * multiple elements at once, share this map\n * amongst all of them\n * @param element Element to duplicate\n * @param overrides Any element properties to override\n */\n\nconst duplicateElement = (editingGroupId, groupIdMapForOperation, element, overrides) => {\n let copy = deepCopyElement(element);\n copy.id = regenerateId(copy.id);\n copy.boundElements = null;\n copy.updated = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getUpdatedTimestamp)();\n copy.seed = (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomInteger)();\n copy.groupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getNewGroupIdsForDuplication)(copy.groupIds, editingGroupId, groupId => {\n if (!groupIdMapForOperation.has(groupId)) {\n groupIdMapForOperation.set(groupId, regenerateId(groupId));\n }\n\n return groupIdMapForOperation.get(groupId);\n });\n\n if (overrides) {\n copy = Object.assign(copy, overrides);\n }\n\n return copy;\n};\n/**\n * Clones elements, regenerating their ids (including bindings) and group ids.\n *\n * If bindings don't exist in the elements array, they are removed. Therefore,\n * it's advised to supply the whole elements array, or sets of elements that\n * are encapsulated (such as library items), if the purpose is to retain\n * bindings to the cloned elements intact.\n *\n * NOTE by default does not randomize or regenerate anything except the id.\n */\n\nconst duplicateElements = (elements, opts) => {\n const clonedElements = [];\n const origElementsMap = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements); // used for for migrating old ids to new ids\n\n const elementNewIdsMap = new Map();\n\n const maybeGetNewId = id => {\n // if we've already migrated the element id, return the new one directly\n if (elementNewIdsMap.has(id)) {\n return elementNewIdsMap.get(id);\n } // if we haven't migrated the element id, but an old element with the same\n // id exists, generate a new id for it and return it\n\n\n if (origElementsMap.has(id)) {\n const newId = regenerateId(id);\n elementNewIdsMap.set(id, newId);\n return newId;\n } // if old element doesn't exist, return null to mark it for removal\n\n\n return null;\n };\n\n const groupNewIdsMap = new Map();\n\n for (const element of elements) {\n const clonedElement = _deepCopyElement(element);\n\n clonedElement.id = maybeGetNewId(element.id);\n\n if (opts === null || opts === void 0 ? void 0 : opts.randomizeSeed) {\n clonedElement.seed = (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomInteger)();\n (0,_mutateElement__WEBPACK_IMPORTED_MODULE_2__.bumpVersion)(clonedElement);\n }\n\n if (clonedElement.groupIds) {\n clonedElement.groupIds = clonedElement.groupIds.map(groupId => {\n if (!groupNewIdsMap.has(groupId)) {\n groupNewIdsMap.set(groupId, regenerateId(groupId));\n }\n\n return groupNewIdsMap.get(groupId);\n });\n }\n\n if (\"containerId\" in clonedElement && clonedElement.containerId) {\n const newContainerId = maybeGetNewId(clonedElement.containerId);\n clonedElement.containerId = newContainerId;\n }\n\n if (\"boundElements\" in clonedElement && clonedElement.boundElements) {\n clonedElement.boundElements = clonedElement.boundElements.reduce((acc, binding) => {\n const newBindingId = maybeGetNewId(binding.id);\n\n if (newBindingId) {\n acc.push(Object.assign(Object.assign({}, binding), {\n id: newBindingId\n }));\n }\n\n return acc;\n }, []);\n }\n\n if (\"endBinding\" in clonedElement && clonedElement.endBinding) {\n const newEndBindingId = maybeGetNewId(clonedElement.endBinding.elementId);\n clonedElement.endBinding = newEndBindingId ? Object.assign(Object.assign({}, clonedElement.endBinding), {\n elementId: newEndBindingId\n }) : null;\n }\n\n if (\"startBinding\" in clonedElement && clonedElement.startBinding) {\n const newEndBindingId = maybeGetNewId(clonedElement.startBinding.elementId);\n clonedElement.startBinding = newEndBindingId ? Object.assign(Object.assign({}, clonedElement.startBinding), {\n elementId: newEndBindingId\n }) : null;\n }\n\n if (clonedElement.frameId) {\n clonedElement.frameId = maybeGetNewId(clonedElement.frameId);\n }\n\n clonedElements.push(clonedElement);\n }\n\n return clonedElements;\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QTtBQUNBLDJCQUEyQixzREFBYTtBQUN4QyxNQUFNLDJEQUFXO0FBQ2pCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsaURBQWlEO0FBQ2pEO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQSxpRkFBaUY7QUFDakY7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBLG1GQUFtRjtBQUNuRjtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2VsZW1lbnQvbmV3RWxlbWVudC50cz80ZDdiIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX3Jlc3QgPSB0aGlzICYmIHRoaXMuX19yZXN0IHx8IGZ1bmN0aW9uIChzLCBlKSB7XG4gIHZhciB0ID0ge307XG5cbiAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApICYmIGUuaW5kZXhPZihwKSA8IDApIHRbcF0gPSBzW3BdO1xuXG4gIGlmIChzICE9IG51bGwgJiYgdHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMgPT09IFwiZnVuY3Rpb25cIikgZm9yICh2YXIgaSA9IDAsIHAgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHMpOyBpIDwgcC5sZW5ndGg7IGkrKykge1xuICAgIGlmIChlLmluZGV4T2YocFtpXSkgPCAwICYmIE9iamVjdC5wcm90b3R5cGUucHJvcGVydHlJc0VudW1lcmFibGUuY2FsbChzLCBwW2ldKSkgdFtwW2ldXSA9IHNbcFtpXV07XG4gIH1cbiAgcmV0dXJuIHQ7XG59O1xuXG5pbXBvcnQgeyBhcnJheVRvTWFwLCBnZXRGb250U3RyaW5nLCBnZXRVcGRhdGVkVGltZXN0YW1wLCBpc1Rlc3RFbnYgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IHJhbmRvbUludGVnZXIsIHJhbmRvbUlkIH0gZnJvbSBcIi4uL3JhbmRvbVwiO1xuaW1wb3J0IHsgYnVtcFZlcnNpb24sIG5ld0VsZW1lbnRXaXRoIH0gZnJvbSBcIi4vbXV0YXRlRWxlbWVudFwiO1xuaW1wb3J0IHsgZ2V0TmV3R3JvdXBJZHNGb3JEdXBsaWNhdGlvbiB9IGZyb20gXCIuLi9ncm91cHNcIjtcbmltcG9ydCB7IGdldEVsZW1lbnRBYnNvbHV0ZUNvb3JkcyB9IGZyb20gXCIuXCI7XG5pbXBvcnQgeyBhZGp1c3RYWVdpdGhSb3RhdGlvbiB9IGZyb20gXCIuLi9tYXRoXCI7XG5pbXBvcnQgeyBnZXRSZXNpemVkRWxlbWVudEFic29sdXRlQ29vcmRzIH0gZnJvbSBcIi4vYm91bmRzXCI7XG5pbXBvcnQgeyBnZXRDb250YWluZXJFbGVtZW50LCBtZWFzdXJlVGV4dCwgbm9ybWFsaXplVGV4dCwgd3JhcFRleHQsIGdldEJvdW5kVGV4dE1heFdpZHRoLCBnZXREZWZhdWx0TGluZUhlaWdodCB9IGZyb20gXCIuL3RleHRFbGVtZW50XCI7XG5pbXBvcnQgeyBERUZBVUxUX0VMRU1FTlRfUFJPUFMsIERFRkFVTFRfRk9OVF9GQU1JTFksIERFRkFVTFRfRk9OVF9TSVpFLCBERUZBVUxUX1RFWFRfQUxJR04sIERFRkFVTFRfVkVSVElDQUxfQUxJR04sIFZFUlRJQ0FMX0FMSUdOIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuXG5jb25zdCBfbmV3RWxlbWVudEJhc2UgPSAodHlwZSwgX2EpID0+IHtcbiAgdmFyIF9iLCBfYztcblxuICB2YXIge1xuICAgIHgsXG4gICAgeSxcbiAgICBzdHJva2VDb2xvciA9IERFRkFVTFRfRUxFTUVOVF9QUk9QUy5zdHJva2VDb2xvcixcbiAgICBiYWNrZ3JvdW5kQ29sb3IgPSBERUZBVUxUX0VMRU1FTlRfUFJPUFMuYmFja2dyb3VuZENvbG9yLFxuICAgIGZpbGxTdHlsZSA9IERFRkFVTFRfRUxFTUVOVF9QUk9QUy5maWxsU3R5bGUsXG4gICAgc3Ryb2tlV2lkdGggPSBERUZBVUxUX0VMRU1FTlRfUFJPUFMuc3Ryb2tlV2lkdGgsXG4gICAgc3Ryb2tlU3R5bGUgPSBERUZBVUxUX0VMRU1FTlRfUFJPUFMuc3Ryb2tlU3R5bGUsXG4gICAgcm91Z2huZXNzID0gREVGQVVMVF9FTEVNRU5UX1BST1BTLnJvdWdobmVzcyxcbiAgICBvcGFjaXR5ID0gREVGQVVMVF9FTEVNRU5UX1BST1BTLm9wYWNpdHksXG4gICAgd2lkdGggPSAwLFxuICAgIGhlaWdodCA9IDAsXG4gICAgYW5nbGUgPSAwLFxuICAgIGdyb3VwSWRzID0gW10sXG4gICAgZnJhbWVJZCA9IG51bGwsXG4gICAgcm91bmRuZXNzID0gbnVsbCxcbiAgICBib3VuZEVsZW1lbnRzID0gbnVsbCxcbiAgICBsaW5rID0gbnVsbCxcbiAgICBsb2NrZWQgPSBERUZBVUxUX0VMRU1FTlRfUFJPUFMubG9ja2VkXG4gIH0gPSBfYSxcbiAgICAgIHJlc3QgPSBfX3Jlc3QoX2EsIFtcInhcIiwgXCJ5XCIsIFwic3Ryb2tlQ29sb3JcIiwgXCJiYWNrZ3JvdW5kQ29sb3JcIiwgXCJmaWxsU3R5bGVcIiwgXCJzdHJva2VXaWR0aFwiLCBcInN0cm9rZVN0eWxlXCIsIFwicm91Z2huZXNzXCIsIFwib3BhY2l0eVwiLCBcIndpZHRoXCIsIFwiaGVpZ2h0XCIsIFwiYW5nbGVcIiwgXCJncm91cElkc1wiLCBcImZyYW1lSWRcIiwgXCJyb3VuZG5lc3NcIiwgXCJib3VuZEVsZW1lbnRzXCIsIFwibGlua1wiLCBcImxvY2tlZFwiXSk7IC8vIGFzc2lnbiB0eXBlIHRvIGd1YXJkIGFnYWluc3QgZXhjZXNzIHByb3BlcnRpZXNcblxuXG4gIGNvbnN0IGVsZW1lbnQgPSB7XG4gICAgaWQ6IHJlc3QuaWQgfHwgcmFuZG9tSWQoKSxcbiAgICB0eXBlLFxuICAgIHgsXG4gICAgeSxcbiAgICB3aWR0aCxcbiAgICBoZWlnaHQsXG4gICAgYW5nbGUsXG4gICAgc3Ryb2tlQ29sb3IsXG4gICAgYmFja2dyb3VuZENvbG9yLFxuICAgIGZpbGxTdHlsZSxcbiAgICBzdHJva2VXaWR0aCxcbiAgICBzdHJva2VTdHlsZSxcbiAgICByb3VnaG5lc3MsXG4gICAgb3BhY2l0eSxcbiAgICBncm91cElkcyxcbiAgICBmcmFtZUlkLFxuICAgIHJvdW5kbmVzcyxcbiAgICBzZWVkOiAoX2IgPSByZXN0LnNlZWQpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IHJhbmRvbUludGVnZXIoKSxcbiAgICB2ZXJzaW9uOiByZXN0LnZlcnNpb24gfHwgMSxcbiAgICB2ZXJzaW9uTm9uY2U6IChfYyA9IHJlc3QudmVyc2lvbk5vbmNlKSAhPT0gbnVsbCAmJiBfYyAhPT0gdm9pZCAwID8gX2MgOiAwLFxuICAgIGlzRGVsZXRlZDogZmFsc2UsXG4gICAgYm91bmRFbGVtZW50cyxcbiAgICB1cGRhdGVkOiBnZXRVcGRhdGVkVGltZXN0YW1wKCksXG4gICAgbGluayxcbiAgICBsb2NrZWRcbiAgfTtcbiAgcmV0dXJuIGVsZW1lbnQ7XG59O1xuXG5leHBvcnQgY29uc3QgbmV3RWxlbWVudCA9IG9wdHMgPT4gX25ld0VsZW1lbnRCYXNlKG9wdHMudHlwZSwgb3B0cyk7XG5leHBvcnQgY29uc3QgbmV3RW1iZWRkYWJsZUVsZW1lbnQgPSBvcHRzID0+IHtcbiAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgX25ld0VsZW1lbnRCYXNlKFwiZW1iZWRkYWJsZVwiLCBvcHRzKSksIHtcbiAgICB2YWxpZGF0ZWQ6IG9wdHMudmFsaWRhdGVkXG4gIH0pO1xufTtcbmV4cG9ydCBjb25zdCBuZXdGcmFtZUVsZW1lbnQgPSBvcHRzID0+IHtcbiAgY29uc3QgZnJhbWVFbGVtZW50ID0gbmV3RWxlbWVudFdpdGgoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfbmV3RWxlbWVudEJhc2UoXCJmcmFtZVwiLCBvcHRzKSksIHtcbiAgICB0eXBlOiBcImZyYW1lXCIsXG4gICAgbmFtZTogKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5uYW1lKSB8fCBudWxsXG4gIH0pLCB7fSk7XG4gIHJldHVybiBmcmFtZUVsZW1lbnQ7XG59O1xuLyoqIGNvbXB1dGVzIGVsZW1lbnQgeC95IG9mZnNldCBiYXNlZCBvbiB0ZXh0QWxpZ24vdmVydGljYWxBbGlnbiAqL1xuXG5jb25zdCBnZXRUZXh0RWxlbWVudFBvc2l0aW9uT2Zmc2V0cyA9IChvcHRzLCBtZXRyaWNzKSA9PiB7XG4gIHJldHVybiB7XG4gICAgeDogb3B0cy50ZXh0QWxpZ24gPT09IFwiY2VudGVyXCIgPyBtZXRyaWNzLndpZHRoIC8gMiA6IG9wdHMudGV4dEFsaWduID09PSBcInJpZ2h0XCIgPyBtZXRyaWNzLndpZHRoIDogMCxcbiAgICB5OiBvcHRzLnZlcnRpY2FsQWxpZ24gPT09IFwibWlkZGxlXCIgPyBtZXRyaWNzLmhlaWdodCAvIDIgOiAwXG4gIH07XG59O1xuXG5leHBvcnQgY29uc3QgbmV3VGV4dEVsZW1lbnQgPSBvcHRzID0+IHtcbiAgY29uc3QgZm9udEZhbWlseSA9IG9wdHMuZm9udEZhbWlseSB8fCBERUZBVUxUX0ZPTlRfRkFNSUxZO1xuICBjb25zdCBmb250U2l6ZSA9IG9wdHMuZm9udFNpemUgfHwgREVGQVVMVF9GT05UX1NJWkU7XG4gIGNvbnN0IGxpbmVIZWlnaHQgPSBvcHRzLmxpbmVIZWlnaHQgfHwgZ2V0RGVmYXVsdExpbmVIZWlnaHQoZm9udEZhbWlseSk7XG4gIGNvbnN0IHRleHQgPSBub3JtYWxpemVUZXh0KG9wdHMudGV4dCk7XG4gIGNvbnN0IG1ldHJpY3MgPSBtZWFzdXJlVGV4dCh0ZXh0LCBnZXRGb250U3RyaW5nKHtcbiAgICBmb250RmFtaWx5LFxuICAgIGZvbnRTaXplXG4gIH0pLCBsaW5lSGVpZ2h0KTtcbiAgY29uc3QgdGV4dEFsaWduID0gb3B0cy50ZXh0QWxpZ24gfHwgREVGQVVMVF9URVhUX0FMSUdOO1xuICBjb25zdCB2ZXJ0aWNhbEFsaWduID0gb3B0cy52ZXJ0aWNhbEFsaWduIHx8IERFRkFVTFRfVkVSVElDQUxfQUxJR047XG4gIGNvbnN0IG9mZnNldHMgPSBnZXRUZXh0RWxlbWVudFBvc2l0aW9uT2Zmc2V0cyh7XG4gICAgdGV4dEFsaWduLFxuICAgIHZlcnRpY2FsQWxpZ25cbiAgfSwgbWV0cmljcyk7XG4gIGNvbnN0IHRleHRFbGVtZW50ID0gbmV3RWxlbWVudFdpdGgoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfbmV3RWxlbWVudEJhc2UoXCJ0ZXh0XCIsIG9wdHMpKSwge1xuICAgIHRleHQsXG4gICAgZm9udFNpemUsXG4gICAgZm9udEZhbWlseSxcbiAgICB0ZXh0QWxpZ24sXG4gICAgdmVydGljYWxBbGlnbixcbiAgICB4OiBvcHRzLnggLSBvZmZzZXRzLngsXG4gICAgeTogb3B0cy55IC0gb2Zmc2V0cy55LFxuICAgIHdpZHRoOiBtZXRyaWNzLndpZHRoLFxuICAgIGhlaWdodDogbWV0cmljcy5oZWlnaHQsXG4gICAgYmFzZWxpbmU6IG1ldHJpY3MuYmFzZWxpbmUsXG4gICAgY29udGFpbmVySWQ6IG9wdHMuY29udGFpbmVySWQgfHwgbnVsbCxcbiAgICBvcmlnaW5hbFRleHQ6IHRleHQsXG4gICAgbGluZUhlaWdodFxuICB9KSwge30pO1xuICByZXR1cm4gdGV4dEVsZW1lbnQ7XG59O1xuXG5jb25zdCBnZXRBZGp1c3RlZERpbWVuc2lvbnMgPSAoZWxlbWVudCwgbmV4dFRleHQpID0+IHtcbiAgY29uc3Qge1xuICAgIHdpZHRoOiBuZXh0V2lkdGgsXG4gICAgaGVpZ2h0OiBuZXh0SGVpZ2h0LFxuICAgIGJhc2VsaW5lOiBuZXh0QmFzZWxpbmVcbiAgfSA9IG1lYXN1cmVUZXh0KG5leHRUZXh0LCBnZXRGb250U3RyaW5nKGVsZW1lbnQpLCBlbGVtZW50LmxpbmVIZWlnaHQpO1xuICBjb25zdCB7XG4gICAgdGV4dEFsaWduLFxuICAgIHZlcnRpY2FsQWxpZ25cbiAgfSA9IGVsZW1lbnQ7XG4gIGxldCB4O1xuICBsZXQgeTtcblxuICBpZiAodGV4dEFsaWduID09PSBcImNlbnRlclwiICYmIHZlcnRpY2FsQWxpZ24gPT09IFZFUlRJQ0FMX0FMSUdOLk1JRERMRSAmJiAhZWxlbWVudC5jb250YWluZXJJZCkge1xuICAgIGNvbnN0IHByZXZNZXRyaWNzID0gbWVhc3VyZVRleHQoZWxlbWVudC50ZXh0LCBnZXRGb250U3RyaW5nKGVsZW1lbnQpLCBlbGVtZW50LmxpbmVIZWlnaHQpO1xuICAgIGNvbnN0IG9mZnNldHMgPSBnZXRUZXh0RWxlbWVudFBvc2l0aW9uT2Zmc2V0cyhlbGVtZW50LCB7XG4gICAgICB3aWR0aDogbmV4dFdpZHRoIC0gcHJldk1ldHJpY3Mud2lkdGgsXG4gICAgICBoZWlnaHQ6IG5leHRIZWlnaHQgLSBwcmV2TWV0cmljcy5oZWlnaHRcbiAgICB9KTtcbiAgICB4ID0gZWxlbWVudC54IC0gb2Zmc2V0cy54O1xuICAgIHkgPSBlbGVtZW50LnkgLSBvZmZzZXRzLnk7XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgW3gxLCB5MSwgeDIsIHkyXSA9IGdldEVsZW1lbnRBYnNvbHV0ZUNvb3JkcyhlbGVtZW50KTtcbiAgICBjb25zdCBbbmV4dFgxLCBuZXh0WTEsIG5leHRYMiwgbmV4dFkyXSA9IGdldFJlc2l6ZWRFbGVtZW50QWJzb2x1dGVDb29yZHMoZWxlbWVudCwgbmV4dFdpZHRoLCBuZXh0SGVpZ2h0LCBmYWxzZSk7XG4gICAgY29uc3QgZGVsdGFYMSA9ICh4MSAtIG5leHRYMSkgLyAyO1xuICAgIGNvbnN0IGRlbHRhWTEgPSAoeTEgLSBuZXh0WTEpIC8gMjtcbiAgICBjb25zdCBkZWx0YVgyID0gKHgyIC0gbmV4dFgyKSAvIDI7XG4gICAgY29uc3QgZGVsdGFZMiA9ICh5MiAtIG5leHRZMikgLyAyO1xuICAgIFt4LCB5XSA9IGFkanVzdFhZV2l0aFJvdGF0aW9uKHtcbiAgICAgIHM6IHRydWUsXG4gICAgICBlOiB0ZXh0QWxpZ24gPT09IFwiY2VudGVyXCIgfHwgdGV4dEFsaWduID09PSBcImxlZnRcIixcbiAgICAgIHc6IHRleHRBbGlnbiA9PT0gXCJjZW50ZXJcIiB8fCB0ZXh0QWxpZ24gPT09IFwicmlnaHRcIlxuICAgIH0sIGVsZW1lbnQueCwgZWxlbWVudC55LCBlbGVtZW50LmFuZ2xlLCBkZWx0YVgxLCBkZWx0YVkxLCBkZWx0YVgyLCBkZWx0YVkyKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgd2lkdGg6IG5leHRXaWR0aCxcbiAgICBoZWlnaHQ6IG5leHRIZWlnaHQsXG4gICAgYmFzZWxpbmU6IG5leHRCYXNlbGluZSxcbiAgICB4OiBOdW1iZXIuaXNGaW5pdGUoeCkgPyB4IDogZWxlbWVudC54LFxuICAgIHk6IE51bWJlci5pc0Zpbml0ZSh5KSA/IHkgOiBlbGVtZW50LnlcbiAgfTtcbn07XG5cbmV4cG9ydCBjb25zdCByZWZyZXNoVGV4dERpbWVuc2lvbnMgPSAodGV4dEVsZW1lbnQsIHRleHQgPSB0ZXh0RWxlbWVudC50ZXh0KSA9PiB7XG4gIGlmICh0ZXh0RWxlbWVudC5pc0RlbGV0ZWQpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBjb250YWluZXIgPSBnZXRDb250YWluZXJFbGVtZW50KHRleHRFbGVtZW50KTtcblxuICBpZiAoY29udGFpbmVyKSB7XG4gICAgdGV4dCA9IHdyYXBUZXh0KHRleHQsIGdldEZvbnRTdHJpbmcodGV4dEVsZW1lbnQpLCBnZXRCb3VuZFRleHRNYXhXaWR0aChjb250YWluZXIpKTtcbiAgfVxuXG4gIGNvbnN0IGRpbWVuc2lvbnMgPSBnZXRBZGp1c3RlZERpbWVuc2lvbnModGV4dEVsZW1lbnQsIHRleHQpO1xuICByZXR1cm4gT2JqZWN0LmFzc2lnbih7XG4gICAgdGV4dFxuICB9LCBkaW1lbnNpb25zKTtcbn07XG5leHBvcnQgY29uc3QgdXBkYXRlVGV4dEVsZW1lbnQgPSAodGV4dEVsZW1lbnQsIHtcbiAgdGV4dCxcbiAgaXNEZWxldGVkLFxuICBvcmlnaW5hbFRleHRcbn0pID0+IHtcbiAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKHRleHRFbGVtZW50LCBPYmplY3QuYXNzaWduKHtcbiAgICBvcmlnaW5hbFRleHQsXG4gICAgaXNEZWxldGVkOiBpc0RlbGV0ZWQgIT09IG51bGwgJiYgaXNEZWxldGVkICE9PSB2b2lkIDAgPyBpc0RlbGV0ZWQgOiB0ZXh0RWxlbWVudC5pc0RlbGV0ZWRcbiAgfSwgcmVmcmVzaFRleHREaW1lbnNpb25zKHRleHRFbGVtZW50LCBvcmlnaW5hbFRleHQpKSk7XG59O1xuZXhwb3J0IGNvbnN0IG5ld0ZyZWVEcmF3RWxlbWVudCA9IG9wdHMgPT4ge1xuICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfbmV3RWxlbWVudEJhc2Uob3B0cy50eXBlLCBvcHRzKSksIHtcbiAgICBwb2ludHM6IG9wdHMucG9pbnRzIHx8IFtdLFxuICAgIHByZXNzdXJlczogW10sXG4gICAgc2ltdWxhdGVQcmVzc3VyZTogb3B0cy5zaW11bGF0ZVByZXNzdXJlLFxuICAgIGxhc3RDb21taXR0ZWRQb2ludDogbnVsbFxuICB9KTtcbn07XG5leHBvcnQgY29uc3QgbmV3TGluZWFyRWxlbWVudCA9IG9wdHMgPT4ge1xuICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfbmV3RWxlbWVudEJhc2Uob3B0cy50eXBlLCBvcHRzKSksIHtcbiAgICBwb2ludHM6IG9wdHMucG9pbnRzIHx8IFtdLFxuICAgIGxhc3RDb21taXR0ZWRQb2ludDogbnVsbCxcbiAgICBzdGFydEJpbmRpbmc6IG51bGwsXG4gICAgZW5kQmluZGluZzogbnVsbCxcbiAgICBzdGFydEFycm93aGVhZDogb3B0cy5zdGFydEFycm93aGVhZCB8fCBudWxsLFxuICAgIGVuZEFycm93aGVhZDogb3B0cy5lbmRBcnJvd2hlYWQgfHwgbnVsbFxuICB9KTtcbn07XG5leHBvcnQgY29uc3QgbmV3SW1hZ2VFbGVtZW50ID0gb3B0cyA9PiB7XG4gIHZhciBfYSwgX2IsIF9jO1xuXG4gIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIF9uZXdFbGVtZW50QmFzZShcImltYWdlXCIsIG9wdHMpKSwge1xuICAgIC8vIGluIHRoZSBmdXR1cmUgd2UnbGwgc3VwcG9ydCBjaGFuZ2luZyBzdHJva2UgY29sb3IgZm9yIHNvbWUgU1ZHIGVsZW1lbnRzLFxuICAgIC8vIGFuZCBgdHJhbnNwYXJlbnRgIHdpbGwgbGlrZWx5IG1lYW4gXCJ1c2Ugb3JpZ2luYWwgY29sb3JzIG9mIHRoZSBpbWFnZVwiXG4gICAgc3Ryb2tlQ29sb3I6IFwidHJhbnNwYXJlbnRcIixcbiAgICBzdGF0dXM6IChfYSA9IG9wdHMuc3RhdHVzKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBcInBlbmRpbmdcIixcbiAgICBmaWxlSWQ6IChfYiA9IG9wdHMuZmlsZUlkKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiBudWxsLFxuICAgIHNjYWxlOiAoX2MgPSBvcHRzLnNjYWxlKSAhPT0gbnVsbCAmJiBfYyAhPT0gdm9pZCAwID8gX2MgOiBbMSwgMV1cbiAgfSk7XG59OyAvLyBTaW1wbGlmaWVkIGRlZXAgY2xvbmUgZm9yIHRoZSBwdXJwb3NlIG9mIGNsb25pbmcgRXhjYWxpZHJhd0VsZW1lbnQuXG4vL1xuLy8gT25seSBjbG9uZXMgcGxhaW4gb2JqZWN0cyBhbmQgYXJyYXlzLiBEb2Vzbid0IGNsb25lIERhdGUsIFJlZ0V4cCwgTWFwLCBTZXQsXG4vLyBUeXBlZCBhcnJheXMgYW5kIG90aGVyIG5vbi1udWxsIG9iamVjdHMuXG4vL1xuLy8gQWRhcHRlZCBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9sdWtlZWQva2xvbmFcbi8vXG4vLyBUaGUgcmVhc29uIGZvciBgZGVlcENvcHlFbGVtZW50KClgIHdyYXBwZXIgaXMgdHlwZSBzYWZldHkgKG9ubHkgYWxsb3dcbi8vIHBhc3NpbmcgRXhjYWxpZHJhd0VsZW1lbnQgYXMgdGhlIHRvcC1sZXZlbCBhcmd1bWVudCkuXG5cbmNvbnN0IF9kZWVwQ29weUVsZW1lbnQgPSAodmFsLCBkZXB0aCA9IDApID0+IHtcbiAgLy8gb25seSBjbG9uZSBub24tcHJpbWl0aXZlc1xuICBpZiAodmFsID09IG51bGwgfHwgdHlwZW9mIHZhbCAhPT0gXCJvYmplY3RcIikge1xuICAgIHJldHVybiB2YWw7XG4gIH1cblxuICBjb25zdCBvYmplY3RUeXBlID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbCk7XG5cbiAgaWYgKG9iamVjdFR5cGUgPT09IFwiW29iamVjdCBPYmplY3RdXCIpIHtcbiAgICBjb25zdCB0bXAgPSB0eXBlb2YgdmFsLmNvbnN0cnVjdG9yID09PSBcImZ1bmN0aW9uXCIgPyBPYmplY3QuY3JlYXRlKE9iamVjdC5nZXRQcm90b3R5cGVPZih2YWwpKSA6IHt9O1xuXG4gICAgZm9yIChjb25zdCBrZXkgaW4gdmFsKSB7XG4gICAgICBpZiAodmFsLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgLy8gZG9uJ3QgY29weSBub24tc2VyaWFsaXphYmxlIG9iamVjdHMgbGlrZSB0aGVzZSBjYWNoZXMuIFRoZXknbGwgYmVcbiAgICAgICAgLy8gcG9wdWxhdGVkIHdoZW4gdGhlIGVsZW1lbnQgaXMgcmVuZGVyZWQuXG4gICAgICAgIGlmIChkZXB0aCA9PT0gMCAmJiAoa2V5ID09PSBcInNoYXBlXCIgfHwga2V5ID09PSBcImNhbnZhc1wiKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdG1wW2tleV0gPSBfZGVlcENvcHlFbGVtZW50KHZhbFtrZXldLCBkZXB0aCArIDEpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0bXA7XG4gIH1cblxuICBpZiAoQXJyYXkuaXNBcnJheSh2YWwpKSB7XG4gICAgbGV0IGsgPSB2YWwubGVuZ3RoO1xuICAgIGNvbnN0IGFyciA9IG5ldyBBcnJheShrKTtcblxuICAgIHdoaWxlIChrLS0pIHtcbiAgICAgIGFycltrXSA9IF9kZWVwQ29weUVsZW1lbnQodmFsW2tdLCBkZXB0aCArIDEpO1xuICAgIH1cblxuICAgIHJldHVybiBhcnI7XG4gIH0gLy8gd2UncmUgbm90IGNsb25pbmcgbm9uLWFycmF5ICYgbm9uLXBsYWluLW9iamVjdCBvYmplY3RzIGJlY2F1c2Ugd2VcbiAgLy8gZG9uJ3Qgc3VwcG9ydCB0aGVtIG9uIGV4Y2FsaWRyYXcgZWxlbWVudHMgeWV0LiBJZiB3ZSBkbywgd2UgbmVlZCB0byBtYWtlXG4gIC8vIHN1cmUgd2Ugc3RhcnQgY2xvbmluZyB0aGVtLCBzbyBsZXQncyB3YXJuIGFib3V0IGl0LlxuXG5cbiAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICAgIGlmIChvYmplY3RUeXBlICE9PSBcIltvYmplY3QgT2JqZWN0XVwiICYmIG9iamVjdFR5cGUgIT09IFwiW29iamVjdCBBcnJheV1cIiAmJiBvYmplY3RUeXBlLnN0YXJ0c1dpdGgoXCJbb2JqZWN0IFwiKSkge1xuICAgICAgY29uc29sZS53YXJuKGBfZGVlcENsb25lRWxlbWVudDogdW5leHBlY3RlZCBvYmplY3QgdHlwZSAke29iamVjdFR5cGV9LiBUaGlzIHZhbHVlIHdpbGwgbm90IGJlIGNsb25lZCFgKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdmFsO1xufTtcbi8qKlxuICogQ2xvbmVzIEV4Y2FsaWRyYXdFbGVtZW50IGRhdGEgc3RydWN0dXJlLiBEb2VzIG5vdCByZWdlbmVyYXRlIGlkLCBub25jZSwgb3JcbiAqIGFueSB2YWx1ZS4gVGhlIHB1cnBvc2UgaXMgdG8gdG8gYnJlYWsgb2JqZWN0IHJlZmVyZW5jZXMgZm9yIGltbXV0YWJpbGl0eVxuICogcmVhc29ucywgd2hlbmV2ZXIgd2Ugd2FudCB0byBrZWVwIHRoZSBvcmlnaW5hbCBlbGVtZW50LCBidXQgZW5zdXJlIGl0J3Mgbm90XG4gKiBtdXRhdGVkLlxuICpcbiAqIE9ubHkgY2xvbmVzIHBsYWluIG9iamVjdHMgYW5kIGFycmF5cy4gRG9lc24ndCBjbG9uZSBEYXRlLCBSZWdFeHAsIE1hcCwgU2V0LFxuICogVHlwZWQgYXJyYXlzIGFuZCBvdGhlciBub24tbnVsbCBvYmplY3RzLlxuICovXG5cblxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5RWxlbWVudCA9IHZhbCA9PiB7XG4gIHJldHVybiBfZGVlcENvcHlFbGVtZW50KHZhbCk7XG59O1xuLyoqXG4gKiB1dGlsaXR5IHdyYXBwZXIgdG8gZ2VuZXJhdGUgbmV3IGlkLiBJbiB0ZXN0IGVudiBpdCByZXVzZXMgdGhlIG9sZCArIHBvc3RmaXhcbiAqIGZvciB0ZXN0IGFzc2VydGlvbnMuXG4gKi9cblxuZXhwb3J0IGNvbnN0IHJlZ2VuZXJhdGVJZCA9IChcbi8qKiBzdXBwbHkgbnVsbCBpZiBubyBwcmV2aW91cyBpZCBleGlzdHMgKi9cbnByZXZpb3VzSWQpID0+IHtcbiAgdmFyIF9hLCBfYjtcblxuICBpZiAoaXNUZXN0RW52KCkgJiYgcHJldmlvdXNJZCkge1xuICAgIGxldCBuZXh0SWQgPSBgJHtwcmV2aW91c0lkfV9jb3B5YDsgLy8gYHdpbmRvdy5oYCBtYXkgbm90IGJlIGRlZmluZWQgaW4gc29tZSB1bml0IHRlc3RzXG5cbiAgICBpZiAoKF9iID0gKF9hID0gd2luZG93LmgpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5hcHApID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5nZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbmQoZWwgPT4gZWwuaWQgPT09IG5leHRJZCkpIHtcbiAgICAgIG5leHRJZCArPSBcIl9jb3B5XCI7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5leHRJZDtcbiAgfVxuXG4gIHJldHVybiByYW5kb21JZCgpO1xufTtcbi8qKlxuICogRHVwbGljYXRlIGFuIGVsZW1lbnQsIG9mdGVuIHVzZWQgaW4gdGhlIGFsdC1kcmFnIG9wZXJhdGlvbi5cbiAqIE5vdGUgdGhhdCB0aGlzIG1ldGhvZCBoYXMgZ290dGVuIGEgYml0IGNvbXBsaWNhdGVkIHNpbmNlIHRoZVxuICogaW50cm9kdWN0aW9uIG9mIGdydW9waW5nL3VuZ3JvdXBpbmcgZWxlbWVudHMuXG4gKiBAcGFyYW0gZWRpdGluZ0dyb3VwSWQgVGhlIGN1cnJlbnQgZ3JvdXAgYmVpbmcgZWRpdGVkLiBUaGUgbmV3XG4gKiAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudCB3aWxsIGluaGVyaXQgdGhpcyBncm91cCBhbmQgaXRzXG4gKiAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50cy5cbiAqIEBwYXJhbSBncm91cElkTWFwRm9yT3BlcmF0aW9uIEEgTWFwIHRoYXQgbWFwcyBvbGQgZ3JvdXAgSURzIHRvXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdXBsaWNhdGVkIG9uZXMuIElmIHlvdSBhcmUgZHVwbGljYXRpbmdcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpcGxlIGVsZW1lbnRzIGF0IG9uY2UsIHNoYXJlIHRoaXMgbWFwXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbW9uZ3N0IGFsbCBvZiB0aGVtXG4gKiBAcGFyYW0gZWxlbWVudCBFbGVtZW50IHRvIGR1cGxpY2F0ZVxuICogQHBhcmFtIG92ZXJyaWRlcyBBbnkgZWxlbWVudCBwcm9wZXJ0aWVzIHRvIG92ZXJyaWRlXG4gKi9cblxuZXhwb3J0IGNvbnN0IGR1cGxpY2F0ZUVsZW1lbnQgPSAoZWRpdGluZ0dyb3VwSWQsIGdyb3VwSWRNYXBGb3JPcGVyYXRpb24sIGVsZW1lbnQsIG92ZXJyaWRlcykgPT4ge1xuICBsZXQgY29weSA9IGRlZXBDb3B5RWxlbWVudChlbGVtZW50KTtcbiAgY29weS5pZCA9IHJlZ2VuZXJhdGVJZChjb3B5LmlkKTtcbiAgY29weS5ib3VuZEVsZW1lbnRzID0gbnVsbDtcbiAgY29weS51cGRhdGVkID0gZ2V0VXBkYXRlZFRpbWVzdGFtcCgpO1xuICBjb3B5LnNlZWQgPSByYW5kb21JbnRlZ2VyKCk7XG4gIGNvcHkuZ3JvdXBJZHMgPSBnZXROZXdHcm91cElkc0ZvckR1cGxpY2F0aW9uKGNvcHkuZ3JvdXBJZHMsIGVkaXRpbmdHcm91cElkLCBncm91cElkID0+IHtcbiAgICBpZiAoIWdyb3VwSWRNYXBGb3JPcGVyYXRpb24uaGFzKGdyb3VwSWQpKSB7XG4gICAgICBncm91cElkTWFwRm9yT3BlcmF0aW9uLnNldChncm91cElkLCByZWdlbmVyYXRlSWQoZ3JvdXBJZCkpO1xuICAgIH1cblxuICAgIHJldHVybiBncm91cElkTWFwRm9yT3BlcmF0aW9uLmdldChncm91cElkKTtcbiAgfSk7XG5cbiAgaWYgKG92ZXJyaWRlcykge1xuICAgIGNvcHkgPSBPYmplY3QuYXNzaWduKGNvcHksIG92ZXJyaWRlcyk7XG4gIH1cblxuICByZXR1cm4gY29weTtcbn07XG4vKipcbiAqIENsb25lcyBlbGVtZW50cywgcmVnZW5lcmF0aW5nIHRoZWlyIGlkcyAoaW5jbHVkaW5nIGJpbmRpbmdzKSBhbmQgZ3JvdXAgaWRzLlxuICpcbiAqIElmIGJpbmRpbmdzIGRvbid0IGV4aXN0IGluIHRoZSBlbGVtZW50cyBhcnJheSwgdGhleSBhcmUgcmVtb3ZlZC4gVGhlcmVmb3JlLFxuICogaXQncyBhZHZpc2VkIHRvIHN1cHBseSB0aGUgd2hvbGUgZWxlbWVudHMgYXJyYXksIG9yIHNldHMgb2YgZWxlbWVudHMgdGhhdFxuICogYXJlIGVuY2Fwc3VsYXRlZCAoc3VjaCBhcyBsaWJyYXJ5IGl0ZW1zKSwgaWYgdGhlIHB1cnBvc2UgaXMgdG8gcmV0YWluXG4gKiBiaW5kaW5ncyB0byB0aGUgY2xvbmVkIGVsZW1lbnRzIGludGFjdC5cbiAqXG4gKiBOT1RFIGJ5IGRlZmF1bHQgZG9lcyBub3QgcmFuZG9taXplIG9yIHJlZ2VuZXJhdGUgYW55dGhpbmcgZXhjZXB0IHRoZSBpZC5cbiAqL1xuXG5leHBvcnQgY29uc3QgZHVwbGljYXRlRWxlbWVudHMgPSAoZWxlbWVudHMsIG9wdHMpID0+IHtcbiAgY29uc3QgY2xvbmVkRWxlbWVudHMgPSBbXTtcbiAgY29uc3Qgb3JpZ0VsZW1lbnRzTWFwID0gYXJyYXlUb01hcChlbGVtZW50cyk7IC8vIHVzZWQgZm9yIGZvciBtaWdyYXRpbmcgb2xkIGlkcyB0byBuZXcgaWRzXG5cbiAgY29uc3QgZWxlbWVudE5ld0lkc01hcCA9IG5ldyBNYXAoKTtcblxuICBjb25zdCBtYXliZUdldE5ld0lkID0gaWQgPT4ge1xuICAgIC8vIGlmIHdlJ3ZlIGFscmVhZHkgbWlncmF0ZWQgdGhlIGVsZW1lbnQgaWQsIHJldHVybiB0aGUgbmV3IG9uZSBkaXJlY3RseVxuICAgIGlmIChlbGVtZW50TmV3SWRzTWFwLmhhcyhpZCkpIHtcbiAgICAgIHJldHVybiBlbGVtZW50TmV3SWRzTWFwLmdldChpZCk7XG4gICAgfSAvLyBpZiB3ZSBoYXZlbid0IG1pZ3JhdGVkIHRoZSBlbGVtZW50IGlkLCBidXQgYW4gb2xkIGVsZW1lbnQgd2l0aCB0aGUgc2FtZVxuICAgIC8vIGlkIGV4aXN0cywgZ2VuZXJhdGUgYSBuZXcgaWQgZm9yIGl0IGFuZCByZXR1cm4gaXRcblxuXG4gICAgaWYgKG9yaWdFbGVtZW50c01hcC5oYXMoaWQpKSB7XG4gICAgICBjb25zdCBuZXdJZCA9IHJlZ2VuZXJhdGVJZChpZCk7XG4gICAgICBlbGVtZW50TmV3SWRzTWFwLnNldChpZCwgbmV3SWQpO1xuICAgICAgcmV0dXJuIG5ld0lkO1xuICAgIH0gLy8gaWYgb2xkIGVsZW1lbnQgZG9lc24ndCBleGlzdCwgcmV0dXJuIG51bGwgdG8gbWFyayBpdCBmb3IgcmVtb3ZhbFxuXG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfTtcblxuICBjb25zdCBncm91cE5ld0lkc01hcCA9IG5ldyBNYXAoKTtcblxuICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZWxlbWVudHMpIHtcbiAgICBjb25zdCBjbG9uZWRFbGVtZW50ID0gX2RlZXBDb3B5RWxlbWVudChlbGVtZW50KTtcblxuICAgIGNsb25lZEVsZW1lbnQuaWQgPSBtYXliZUdldE5ld0lkKGVsZW1lbnQuaWQpO1xuXG4gICAgaWYgKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yYW5kb21pemVTZWVkKSB7XG4gICAgICBjbG9uZWRFbGVtZW50LnNlZWQgPSByYW5kb21JbnRlZ2VyKCk7XG4gICAgICBidW1wVmVyc2lvbihjbG9uZWRFbGVtZW50KTtcbiAgICB9XG5cbiAgICBpZiAoY2xvbmVkRWxlbWVudC5ncm91cElkcykge1xuICAgICAgY2xvbmVkRWxlbWVudC5ncm91cElkcyA9IGNsb25lZEVsZW1lbnQuZ3JvdXBJZHMubWFwKGdyb3VwSWQgPT4ge1xuICAgICAgICBpZiAoIWdyb3VwTmV3SWRzTWFwLmhhcyhncm91cElkKSkge1xuICAgICAgICAgIGdyb3VwTmV3SWRzTWFwLnNldChncm91cElkLCByZWdlbmVyYXRlSWQoZ3JvdXBJZCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGdyb3VwTmV3SWRzTWFwLmdldChncm91cElkKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChcImNvbnRhaW5lcklkXCIgaW4gY2xvbmVkRWxlbWVudCAmJiBjbG9uZWRFbGVtZW50LmNvbnRhaW5lcklkKSB7XG4gICAgICBjb25zdCBuZXdDb250YWluZXJJZCA9IG1heWJlR2V0TmV3SWQoY2xvbmVkRWxlbWVudC5jb250YWluZXJJZCk7XG4gICAgICBjbG9uZWRFbGVtZW50LmNvbnRhaW5lcklkID0gbmV3Q29udGFpbmVySWQ7XG4gICAgfVxuXG4gICAgaWYgKFwiYm91bmRFbGVtZW50c1wiIGluIGNsb25lZEVsZW1lbnQgJiYgY2xvbmVkRWxlbWVudC5ib3VuZEVsZW1lbnRzKSB7XG4gICAgICBjbG9uZWRFbGVtZW50LmJvdW5kRWxlbWVudHMgPSBjbG9uZWRFbGVtZW50LmJvdW5kRWxlbWVudHMucmVkdWNlKChhY2MsIGJpbmRpbmcpID0+IHtcbiAgICAgICAgY29uc3QgbmV3QmluZGluZ0lkID0gbWF5YmVHZXROZXdJZChiaW5kaW5nLmlkKTtcblxuICAgICAgICBpZiAobmV3QmluZGluZ0lkKSB7XG4gICAgICAgICAgYWNjLnB1c2goT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBiaW5kaW5nKSwge1xuICAgICAgICAgICAgaWQ6IG5ld0JpbmRpbmdJZFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCBbXSk7XG4gICAgfVxuXG4gICAgaWYgKFwiZW5kQmluZGluZ1wiIGluIGNsb25lZEVsZW1lbnQgJiYgY2xvbmVkRWxlbWVudC5lbmRCaW5kaW5nKSB7XG4gICAgICBjb25zdCBuZXdFbmRCaW5kaW5nSWQgPSBtYXliZUdldE5ld0lkKGNsb25lZEVsZW1lbnQuZW5kQmluZGluZy5lbGVtZW50SWQpO1xuICAgICAgY2xvbmVkRWxlbWVudC5lbmRCaW5kaW5nID0gbmV3RW5kQmluZGluZ0lkID8gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBjbG9uZWRFbGVtZW50LmVuZEJpbmRpbmcpLCB7XG4gICAgICAgIGVsZW1lbnRJZDogbmV3RW5kQmluZGluZ0lkXG4gICAgICB9KSA6IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKFwic3RhcnRCaW5kaW5nXCIgaW4gY2xvbmVkRWxlbWVudCAmJiBjbG9uZWRFbGVtZW50LnN0YXJ0QmluZGluZykge1xuICAgICAgY29uc3QgbmV3RW5kQmluZGluZ0lkID0gbWF5YmVHZXROZXdJZChjbG9uZWRFbGVtZW50LnN0YXJ0QmluZGluZy5lbGVtZW50SWQpO1xuICAgICAgY2xvbmVkRWxlbWVudC5zdGFydEJpbmRpbmcgPSBuZXdFbmRCaW5kaW5nSWQgPyBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGNsb25lZEVsZW1lbnQuc3RhcnRCaW5kaW5nKSwge1xuICAgICAgICBlbGVtZW50SWQ6IG5ld0VuZEJpbmRpbmdJZFxuICAgICAgfSkgOiBudWxsO1xuICAgIH1cblxuICAgIGlmIChjbG9uZWRFbGVtZW50LmZyYW1lSWQpIHtcbiAgICAgIGNsb25lZEVsZW1lbnQuZnJhbWVJZCA9IG1heWJlR2V0TmV3SWQoY2xvbmVkRWxlbWVudC5mcmFtZUlkKTtcbiAgICB9XG5cbiAgICBjbG9uZWRFbGVtZW50cy5wdXNoKGNsb25lZEVsZW1lbnQpO1xuICB9XG5cbiAgcmV0dXJuIGNsb25lZEVsZW1lbnRzO1xufTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../element/newElement.ts\n");
3962
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"deepCopyElement\": () => (/* binding */ deepCopyElement),\n/* harmony export */ \"duplicateElement\": () => (/* binding */ duplicateElement),\n/* harmony export */ \"duplicateElements\": () => (/* binding */ duplicateElements),\n/* harmony export */ \"newElement\": () => (/* binding */ newElement),\n/* harmony export */ \"newEmbeddableElement\": () => (/* binding */ newEmbeddableElement),\n/* harmony export */ \"newFrameElement\": () => (/* binding */ newFrameElement),\n/* harmony export */ \"newFreeDrawElement\": () => (/* binding */ newFreeDrawElement),\n/* harmony export */ \"newImageElement\": () => (/* binding */ newImageElement),\n/* harmony export */ \"newLinearElement\": () => (/* binding */ newLinearElement),\n/* harmony export */ \"newTextElement\": () => (/* binding */ newTextElement),\n/* harmony export */ \"refreshTextDimensions\": () => (/* binding */ refreshTextDimensions),\n/* harmony export */ \"regenerateId\": () => (/* binding */ regenerateId),\n/* harmony export */ \"updateTextElement\": () => (/* binding */ updateTextElement)\n/* harmony export */ });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _random__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../random */ \"../../random.ts\");\n/* harmony import */ var _mutateElement__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mutateElement */ \"../../element/mutateElement.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../groups */ \"../../groups.ts\");\n/* harmony import */ var ___WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! . */ \"../../element/index.ts\");\n/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../math */ \"../../math.ts\");\n/* harmony import */ var _bounds__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./bounds */ \"../../element/bounds.ts\");\n/* harmony import */ var _textElement__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\nvar __rest = undefined && undefined.__rest || function (s, e) {\n var t = {};\n\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];\n\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];\n }\n return t;\n};\n\n\n\n\n\n\n\n\n\n\n\nconst _newElementBase = (type, _a) => {\n var _b, _c;\n\n var {\n x,\n y,\n strokeColor = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.strokeColor,\n backgroundColor = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.backgroundColor,\n fillStyle = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.fillStyle,\n strokeWidth = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.strokeWidth,\n strokeStyle = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.strokeStyle,\n roughness = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.roughness,\n opacity = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.opacity,\n width = 0,\n height = 0,\n angle = 0,\n groupIds = [],\n frameId = null,\n roundness = null,\n boundElements = null,\n link = null,\n locked = _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_ELEMENT_PROPS.locked\n } = _a,\n rest = __rest(_a, [\"x\", \"y\", \"strokeColor\", \"backgroundColor\", \"fillStyle\", \"strokeWidth\", \"strokeStyle\", \"roughness\", \"opacity\", \"width\", \"height\", \"angle\", \"groupIds\", \"frameId\", \"roundness\", \"boundElements\", \"link\", \"locked\"]); // assign type to guard against excess properties\n\n\n const element = {\n id: rest.id || (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomId)(),\n type,\n x,\n y,\n width,\n height,\n angle,\n strokeColor,\n backgroundColor,\n fillStyle,\n strokeWidth,\n strokeStyle,\n roughness,\n opacity,\n groupIds,\n frameId,\n roundness,\n seed: (_b = rest.seed) !== null && _b !== void 0 ? _b : (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomInteger)(),\n version: rest.version || 1,\n versionNonce: (_c = rest.versionNonce) !== null && _c !== void 0 ? _c : 0,\n isDeleted: false,\n boundElements,\n updated: (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getUpdatedTimestamp)(),\n link,\n locked,\n customData: rest.customData\n };\n return element;\n};\n\nconst newElement = opts => _newElementBase(opts.type, opts);\nconst newEmbeddableElement = opts => {\n return Object.assign(Object.assign({}, _newElementBase(\"embeddable\", opts)), {\n validated: opts.validated\n });\n};\nconst newFrameElement = opts => {\n const frameElement = (0,_mutateElement__WEBPACK_IMPORTED_MODULE_2__.newElementWith)(Object.assign(Object.assign({}, _newElementBase(\"frame\", opts)), {\n type: \"frame\",\n name: (opts === null || opts === void 0 ? void 0 : opts.name) || null\n }), {});\n return frameElement;\n};\n/** computes element x/y offset based on textAlign/verticalAlign */\n\nconst getTextElementPositionOffsets = (opts, metrics) => {\n return {\n x: opts.textAlign === \"center\" ? metrics.width / 2 : opts.textAlign === \"right\" ? metrics.width : 0,\n y: opts.verticalAlign === \"middle\" ? metrics.height / 2 : 0\n };\n};\n\nconst newTextElement = opts => {\n const fontFamily = opts.fontFamily || _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_FONT_FAMILY;\n const fontSize = opts.fontSize || _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_FONT_SIZE;\n const lineHeight = opts.lineHeight || (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.getDefaultLineHeight)(fontFamily);\n const text = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.normalizeText)(opts.text);\n const metrics = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.measureText)(text, (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getFontString)({\n fontFamily,\n fontSize\n }), lineHeight);\n const textAlign = opts.textAlign || _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_TEXT_ALIGN;\n const verticalAlign = opts.verticalAlign || _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_VERTICAL_ALIGN;\n const offsets = getTextElementPositionOffsets({\n textAlign,\n verticalAlign\n }, metrics);\n const textElement = (0,_mutateElement__WEBPACK_IMPORTED_MODULE_2__.newElementWith)(Object.assign(Object.assign({}, _newElementBase(\"text\", opts)), {\n text,\n fontSize,\n fontFamily,\n textAlign,\n verticalAlign,\n x: opts.x - offsets.x,\n y: opts.y - offsets.y,\n width: metrics.width,\n height: metrics.height,\n baseline: metrics.baseline,\n containerId: opts.containerId || null,\n originalText: text,\n lineHeight\n }), {});\n return textElement;\n};\n\nconst getAdjustedDimensions = (element, nextText) => {\n const {\n width: nextWidth,\n height: nextHeight,\n baseline: nextBaseline\n } = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.measureText)(nextText, (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getFontString)(element), element.lineHeight);\n const {\n textAlign,\n verticalAlign\n } = element;\n let x;\n let y;\n\n if (textAlign === \"center\" && verticalAlign === _constants__WEBPACK_IMPORTED_MODULE_8__.VERTICAL_ALIGN.MIDDLE && !element.containerId) {\n const prevMetrics = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.measureText)(element.text, (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getFontString)(element), element.lineHeight);\n const offsets = getTextElementPositionOffsets(element, {\n width: nextWidth - prevMetrics.width,\n height: nextHeight - prevMetrics.height\n });\n x = element.x - offsets.x;\n y = element.y - offsets.y;\n } else {\n const [x1, y1, x2, y2] = (0,___WEBPACK_IMPORTED_MODULE_4__.getElementAbsoluteCoords)(element);\n const [nextX1, nextY1, nextX2, nextY2] = (0,_bounds__WEBPACK_IMPORTED_MODULE_6__.getResizedElementAbsoluteCoords)(element, nextWidth, nextHeight, false);\n const deltaX1 = (x1 - nextX1) / 2;\n const deltaY1 = (y1 - nextY1) / 2;\n const deltaX2 = (x2 - nextX2) / 2;\n const deltaY2 = (y2 - nextY2) / 2;\n [x, y] = (0,_math__WEBPACK_IMPORTED_MODULE_5__.adjustXYWithRotation)({\n s: true,\n e: textAlign === \"center\" || textAlign === \"left\",\n w: textAlign === \"center\" || textAlign === \"right\"\n }, element.x, element.y, element.angle, deltaX1, deltaY1, deltaX2, deltaY2);\n }\n\n return {\n width: nextWidth,\n height: nextHeight,\n baseline: nextBaseline,\n x: Number.isFinite(x) ? x : element.x,\n y: Number.isFinite(y) ? y : element.y\n };\n};\n\nconst refreshTextDimensions = (textElement, text = textElement.text) => {\n if (textElement.isDeleted) {\n return;\n }\n\n const container = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.getContainerElement)(textElement);\n\n if (container) {\n text = (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.wrapText)(text, (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getFontString)(textElement), (0,_textElement__WEBPACK_IMPORTED_MODULE_7__.getBoundTextMaxWidth)(container));\n }\n\n const dimensions = getAdjustedDimensions(textElement, text);\n return Object.assign({\n text\n }, dimensions);\n};\nconst updateTextElement = (textElement, {\n text,\n isDeleted,\n originalText\n}) => {\n return (0,_mutateElement__WEBPACK_IMPORTED_MODULE_2__.newElementWith)(textElement, Object.assign({\n originalText,\n isDeleted: isDeleted !== null && isDeleted !== void 0 ? isDeleted : textElement.isDeleted\n }, refreshTextDimensions(textElement, originalText)));\n};\nconst newFreeDrawElement = opts => {\n return Object.assign(Object.assign({}, _newElementBase(opts.type, opts)), {\n points: opts.points || [],\n pressures: [],\n simulatePressure: opts.simulatePressure,\n lastCommittedPoint: null\n });\n};\nconst newLinearElement = opts => {\n return Object.assign(Object.assign({}, _newElementBase(opts.type, opts)), {\n points: opts.points || [],\n lastCommittedPoint: null,\n startBinding: null,\n endBinding: null,\n startArrowhead: opts.startArrowhead || null,\n endArrowhead: opts.endArrowhead || null\n });\n};\nconst newImageElement = opts => {\n var _a, _b, _c;\n\n return Object.assign(Object.assign({}, _newElementBase(\"image\", opts)), {\n // in the future we'll support changing stroke color for some SVG elements,\n // and `transparent` will likely mean \"use original colors of the image\"\n strokeColor: \"transparent\",\n status: (_a = opts.status) !== null && _a !== void 0 ? _a : \"pending\",\n fileId: (_b = opts.fileId) !== null && _b !== void 0 ? _b : null,\n scale: (_c = opts.scale) !== null && _c !== void 0 ? _c : [1, 1]\n });\n}; // Simplified deep clone for the purpose of cloning ExcalidrawElement.\n//\n// Only clones plain objects and arrays. Doesn't clone Date, RegExp, Map, Set,\n// Typed arrays and other non-null objects.\n//\n// Adapted from https://github.com/lukeed/klona\n//\n// The reason for `deepCopyElement()` wrapper is type safety (only allow\n// passing ExcalidrawElement as the top-level argument).\n\nconst _deepCopyElement = (val, depth = 0) => {\n // only clone non-primitives\n if (val == null || typeof val !== \"object\") {\n return val;\n }\n\n const objectType = Object.prototype.toString.call(val);\n\n if (objectType === \"[object Object]\") {\n const tmp = typeof val.constructor === \"function\" ? Object.create(Object.getPrototypeOf(val)) : {};\n\n for (const key in val) {\n if (val.hasOwnProperty(key)) {\n // don't copy non-serializable objects like these caches. They'll be\n // populated when the element is rendered.\n if (depth === 0 && (key === \"shape\" || key === \"canvas\")) {\n continue;\n }\n\n tmp[key] = _deepCopyElement(val[key], depth + 1);\n }\n }\n\n return tmp;\n }\n\n if (Array.isArray(val)) {\n let k = val.length;\n const arr = new Array(k);\n\n while (k--) {\n arr[k] = _deepCopyElement(val[k], depth + 1);\n }\n\n return arr;\n } // we're not cloning non-array & non-plain-object objects because we\n // don't support them on excalidraw elements yet. If we do, we need to make\n // sure we start cloning them, so let's warn about it.\n\n\n if (true) {\n if (objectType !== \"[object Object]\" && objectType !== \"[object Array]\" && objectType.startsWith(\"[object \")) {\n console.warn(`_deepCloneElement: unexpected object type ${objectType}. This value will not be cloned!`);\n }\n }\n\n return val;\n};\n/**\n * Clones ExcalidrawElement data structure. Does not regenerate id, nonce, or\n * any value. The purpose is to to break object references for immutability\n * reasons, whenever we want to keep the original element, but ensure it's not\n * mutated.\n *\n * Only clones plain objects and arrays. Doesn't clone Date, RegExp, Map, Set,\n * Typed arrays and other non-null objects.\n */\n\n\nconst deepCopyElement = val => {\n return _deepCopyElement(val);\n};\n/**\n * utility wrapper to generate new id. In test env it reuses the old + postfix\n * for test assertions.\n */\n\nconst regenerateId = (\n/** supply null if no previous id exists */\npreviousId) => {\n var _a, _b;\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_0__.isTestEnv)() && previousId) {\n let nextId = `${previousId}_copy`; // `window.h` may not be defined in some unit tests\n\n if ((_b = (_a = window.h) === null || _a === void 0 ? void 0 : _a.app) === null || _b === void 0 ? void 0 : _b.getSceneElementsIncludingDeleted().find(el => el.id === nextId)) {\n nextId += \"_copy\";\n }\n\n return nextId;\n }\n\n return (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomId)();\n};\n/**\n * Duplicate an element, often used in the alt-drag operation.\n * Note that this method has gotten a bit complicated since the\n * introduction of gruoping/ungrouping elements.\n * @param editingGroupId The current group being edited. The new\n * element will inherit this group and its\n * parents.\n * @param groupIdMapForOperation A Map that maps old group IDs to\n * duplicated ones. If you are duplicating\n * multiple elements at once, share this map\n * amongst all of them\n * @param element Element to duplicate\n * @param overrides Any element properties to override\n */\n\nconst duplicateElement = (editingGroupId, groupIdMapForOperation, element, overrides) => {\n let copy = deepCopyElement(element);\n copy.id = regenerateId(copy.id);\n copy.boundElements = null;\n copy.updated = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getUpdatedTimestamp)();\n copy.seed = (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomInteger)();\n copy.groupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getNewGroupIdsForDuplication)(copy.groupIds, editingGroupId, groupId => {\n if (!groupIdMapForOperation.has(groupId)) {\n groupIdMapForOperation.set(groupId, regenerateId(groupId));\n }\n\n return groupIdMapForOperation.get(groupId);\n });\n\n if (overrides) {\n copy = Object.assign(copy, overrides);\n }\n\n return copy;\n};\n/**\n * Clones elements, regenerating their ids (including bindings) and group ids.\n *\n * If bindings don't exist in the elements array, they are removed. Therefore,\n * it's advised to supply the whole elements array, or sets of elements that\n * are encapsulated (such as library items), if the purpose is to retain\n * bindings to the cloned elements intact.\n *\n * NOTE by default does not randomize or regenerate anything except the id.\n */\n\nconst duplicateElements = (elements, opts) => {\n const clonedElements = [];\n const origElementsMap = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements); // used for for migrating old ids to new ids\n\n const elementNewIdsMap = new Map();\n\n const maybeGetNewId = id => {\n // if we've already migrated the element id, return the new one directly\n if (elementNewIdsMap.has(id)) {\n return elementNewIdsMap.get(id);\n } // if we haven't migrated the element id, but an old element with the same\n // id exists, generate a new id for it and return it\n\n\n if (origElementsMap.has(id)) {\n const newId = regenerateId(id);\n elementNewIdsMap.set(id, newId);\n return newId;\n } // if old element doesn't exist, return null to mark it for removal\n\n\n return null;\n };\n\n const groupNewIdsMap = new Map();\n\n for (const element of elements) {\n const clonedElement = _deepCopyElement(element);\n\n clonedElement.id = maybeGetNewId(element.id);\n\n if (opts === null || opts === void 0 ? void 0 : opts.randomizeSeed) {\n clonedElement.seed = (0,_random__WEBPACK_IMPORTED_MODULE_1__.randomInteger)();\n (0,_mutateElement__WEBPACK_IMPORTED_MODULE_2__.bumpVersion)(clonedElement);\n }\n\n if (clonedElement.groupIds) {\n clonedElement.groupIds = clonedElement.groupIds.map(groupId => {\n if (!groupNewIdsMap.has(groupId)) {\n groupNewIdsMap.set(groupId, regenerateId(groupId));\n }\n\n return groupNewIdsMap.get(groupId);\n });\n }\n\n if (\"containerId\" in clonedElement && clonedElement.containerId) {\n const newContainerId = maybeGetNewId(clonedElement.containerId);\n clonedElement.containerId = newContainerId;\n }\n\n if (\"boundElements\" in clonedElement && clonedElement.boundElements) {\n clonedElement.boundElements = clonedElement.boundElements.reduce((acc, binding) => {\n const newBindingId = maybeGetNewId(binding.id);\n\n if (newBindingId) {\n acc.push(Object.assign(Object.assign({}, binding), {\n id: newBindingId\n }));\n }\n\n return acc;\n }, []);\n }\n\n if (\"endBinding\" in clonedElement && clonedElement.endBinding) {\n const newEndBindingId = maybeGetNewId(clonedElement.endBinding.elementId);\n clonedElement.endBinding = newEndBindingId ? Object.assign(Object.assign({}, clonedElement.endBinding), {\n elementId: newEndBindingId\n }) : null;\n }\n\n if (\"startBinding\" in clonedElement && clonedElement.startBinding) {\n const newEndBindingId = maybeGetNewId(clonedElement.startBinding.elementId);\n clonedElement.startBinding = newEndBindingId ? Object.assign(Object.assign({}, clonedElement.startBinding), {\n elementId: newEndBindingId\n }) : null;\n }\n\n if (clonedElement.frameId) {\n clonedElement.frameId = maybeGetNewId(clonedElement.frameId);\n }\n\n clonedElements.push(clonedElement);\n }\n\n return clonedElements;\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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OztBQUVBO0FBQ0EsMkJBQTJCLHNEQUFhO0FBQ3hDLE1BQU0sMkRBQVc7QUFDakI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxpREFBaUQ7QUFDakQ7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBLGlGQUFpRjtBQUNqRjtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0EsbUZBQW1GO0FBQ25GO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vZWxlbWVudC9uZXdFbGVtZW50LnRzPzRkN2IiXSwic291cmNlc0NvbnRlbnQiOlsidmFyIF9fcmVzdCA9IHRoaXMgJiYgdGhpcy5fX3Jlc3QgfHwgZnVuY3Rpb24gKHMsIGUpIHtcbiAgdmFyIHQgPSB7fTtcblxuICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkgJiYgZS5pbmRleE9mKHApIDwgMCkgdFtwXSA9IHNbcF07XG5cbiAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKSBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKGUuaW5kZXhPZihwW2ldKSA8IDAgJiYgT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKHMsIHBbaV0pKSB0W3BbaV1dID0gc1twW2ldXTtcbiAgfVxuICByZXR1cm4gdDtcbn07XG5cbmltcG9ydCB7IGFycmF5VG9NYXAsIGdldEZvbnRTdHJpbmcsIGdldFVwZGF0ZWRUaW1lc3RhbXAsIGlzVGVzdEVudiB9IGZyb20gXCIuLi91dGlsc1wiO1xuaW1wb3J0IHsgcmFuZG9tSW50ZWdlciwgcmFuZG9tSWQgfSBmcm9tIFwiLi4vcmFuZG9tXCI7XG5pbXBvcnQgeyBidW1wVmVyc2lvbiwgbmV3RWxlbWVudFdpdGggfSBmcm9tIFwiLi9tdXRhdGVFbGVtZW50XCI7XG5pbXBvcnQgeyBnZXROZXdHcm91cElkc0ZvckR1cGxpY2F0aW9uIH0gZnJvbSBcIi4uL2dyb3Vwc1wiO1xuaW1wb3J0IHsgZ2V0RWxlbWVudEFic29sdXRlQ29vcmRzIH0gZnJvbSBcIi5cIjtcbmltcG9ydCB7IGFkanVzdFhZV2l0aFJvdGF0aW9uIH0gZnJvbSBcIi4uL21hdGhcIjtcbmltcG9ydCB7IGdldFJlc2l6ZWRFbGVtZW50QWJzb2x1dGVDb29yZHMgfSBmcm9tIFwiLi9ib3VuZHNcIjtcbmltcG9ydCB7IGdldENvbnRhaW5lckVsZW1lbnQsIG1lYXN1cmVUZXh0LCBub3JtYWxpemVUZXh0LCB3cmFwVGV4dCwgZ2V0Qm91bmRUZXh0TWF4V2lkdGgsIGdldERlZmF1bHRMaW5lSGVpZ2h0IH0gZnJvbSBcIi4vdGV4dEVsZW1lbnRcIjtcbmltcG9ydCB7IERFRkFVTFRfRUxFTUVOVF9QUk9QUywgREVGQVVMVF9GT05UX0ZBTUlMWSwgREVGQVVMVF9GT05UX1NJWkUsIERFRkFVTFRfVEVYVF9BTElHTiwgREVGQVVMVF9WRVJUSUNBTF9BTElHTiwgVkVSVElDQUxfQUxJR04gfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5cbmNvbnN0IF9uZXdFbGVtZW50QmFzZSA9ICh0eXBlLCBfYSkgPT4ge1xuICB2YXIgX2IsIF9jO1xuXG4gIHZhciB7XG4gICAgeCxcbiAgICB5LFxuICAgIHN0cm9rZUNvbG9yID0gREVGQVVMVF9FTEVNRU5UX1BST1BTLnN0cm9rZUNvbG9yLFxuICAgIGJhY2tncm91bmRDb2xvciA9IERFRkFVTFRfRUxFTUVOVF9QUk9QUy5iYWNrZ3JvdW5kQ29sb3IsXG4gICAgZmlsbFN0eWxlID0gREVGQVVMVF9FTEVNRU5UX1BST1BTLmZpbGxTdHlsZSxcbiAgICBzdHJva2VXaWR0aCA9IERFRkFVTFRfRUxFTUVOVF9QUk9QUy5zdHJva2VXaWR0aCxcbiAgICBzdHJva2VTdHlsZSA9IERFRkFVTFRfRUxFTUVOVF9QUk9QUy5zdHJva2VTdHlsZSxcbiAgICByb3VnaG5lc3MgPSBERUZBVUxUX0VMRU1FTlRfUFJPUFMucm91Z2huZXNzLFxuICAgIG9wYWNpdHkgPSBERUZBVUxUX0VMRU1FTlRfUFJPUFMub3BhY2l0eSxcbiAgICB3aWR0aCA9IDAsXG4gICAgaGVpZ2h0ID0gMCxcbiAgICBhbmdsZSA9IDAsXG4gICAgZ3JvdXBJZHMgPSBbXSxcbiAgICBmcmFtZUlkID0gbnVsbCxcbiAgICByb3VuZG5lc3MgPSBudWxsLFxuICAgIGJvdW5kRWxlbWVudHMgPSBudWxsLFxuICAgIGxpbmsgPSBudWxsLFxuICAgIGxvY2tlZCA9IERFRkFVTFRfRUxFTUVOVF9QUk9QUy5sb2NrZWRcbiAgfSA9IF9hLFxuICAgICAgcmVzdCA9IF9fcmVzdChfYSwgW1wieFwiLCBcInlcIiwgXCJzdHJva2VDb2xvclwiLCBcImJhY2tncm91bmRDb2xvclwiLCBcImZpbGxTdHlsZVwiLCBcInN0cm9rZVdpZHRoXCIsIFwic3Ryb2tlU3R5bGVcIiwgXCJyb3VnaG5lc3NcIiwgXCJvcGFjaXR5XCIsIFwid2lkdGhcIiwgXCJoZWlnaHRcIiwgXCJhbmdsZVwiLCBcImdyb3VwSWRzXCIsIFwiZnJhbWVJZFwiLCBcInJvdW5kbmVzc1wiLCBcImJvdW5kRWxlbWVudHNcIiwgXCJsaW5rXCIsIFwibG9ja2VkXCJdKTsgLy8gYXNzaWduIHR5cGUgdG8gZ3VhcmQgYWdhaW5zdCBleGNlc3MgcHJvcGVydGllc1xuXG5cbiAgY29uc3QgZWxlbWVudCA9IHtcbiAgICBpZDogcmVzdC5pZCB8fCByYW5kb21JZCgpLFxuICAgIHR5cGUsXG4gICAgeCxcbiAgICB5LFxuICAgIHdpZHRoLFxuICAgIGhlaWdodCxcbiAgICBhbmdsZSxcbiAgICBzdHJva2VDb2xvcixcbiAgICBiYWNrZ3JvdW5kQ29sb3IsXG4gICAgZmlsbFN0eWxlLFxuICAgIHN0cm9rZVdpZHRoLFxuICAgIHN0cm9rZVN0eWxlLFxuICAgIHJvdWdobmVzcyxcbiAgICBvcGFjaXR5LFxuICAgIGdyb3VwSWRzLFxuICAgIGZyYW1lSWQsXG4gICAgcm91bmRuZXNzLFxuICAgIHNlZWQ6IChfYiA9IHJlc3Quc2VlZCkgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogcmFuZG9tSW50ZWdlcigpLFxuICAgIHZlcnNpb246IHJlc3QudmVyc2lvbiB8fCAxLFxuICAgIHZlcnNpb25Ob25jZTogKF9jID0gcmVzdC52ZXJzaW9uTm9uY2UpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IDAsXG4gICAgaXNEZWxldGVkOiBmYWxzZSxcbiAgICBib3VuZEVsZW1lbnRzLFxuICAgIHVwZGF0ZWQ6IGdldFVwZGF0ZWRUaW1lc3RhbXAoKSxcbiAgICBsaW5rLFxuICAgIGxvY2tlZCxcbiAgICBjdXN0b21EYXRhOiByZXN0LmN1c3RvbURhdGFcbiAgfTtcbiAgcmV0dXJuIGVsZW1lbnQ7XG59O1xuXG5leHBvcnQgY29uc3QgbmV3RWxlbWVudCA9IG9wdHMgPT4gX25ld0VsZW1lbnRCYXNlKG9wdHMudHlwZSwgb3B0cyk7XG5leHBvcnQgY29uc3QgbmV3RW1iZWRkYWJsZUVsZW1lbnQgPSBvcHRzID0+IHtcbiAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgX25ld0VsZW1lbnRCYXNlKFwiZW1iZWRkYWJsZVwiLCBvcHRzKSksIHtcbiAgICB2YWxpZGF0ZWQ6IG9wdHMudmFsaWRhdGVkXG4gIH0pO1xufTtcbmV4cG9ydCBjb25zdCBuZXdGcmFtZUVsZW1lbnQgPSBvcHRzID0+IHtcbiAgY29uc3QgZnJhbWVFbGVtZW50ID0gbmV3RWxlbWVudFdpdGgoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfbmV3RWxlbWVudEJhc2UoXCJmcmFtZVwiLCBvcHRzKSksIHtcbiAgICB0eXBlOiBcImZyYW1lXCIsXG4gICAgbmFtZTogKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5uYW1lKSB8fCBudWxsXG4gIH0pLCB7fSk7XG4gIHJldHVybiBmcmFtZUVsZW1lbnQ7XG59O1xuLyoqIGNvbXB1dGVzIGVsZW1lbnQgeC95IG9mZnNldCBiYXNlZCBvbiB0ZXh0QWxpZ24vdmVydGljYWxBbGlnbiAqL1xuXG5jb25zdCBnZXRUZXh0RWxlbWVudFBvc2l0aW9uT2Zmc2V0cyA9IChvcHRzLCBtZXRyaWNzKSA9PiB7XG4gIHJldHVybiB7XG4gICAgeDogb3B0cy50ZXh0QWxpZ24gPT09IFwiY2VudGVyXCIgPyBtZXRyaWNzLndpZHRoIC8gMiA6IG9wdHMudGV4dEFsaWduID09PSBcInJpZ2h0XCIgPyBtZXRyaWNzLndpZHRoIDogMCxcbiAgICB5OiBvcHRzLnZlcnRpY2FsQWxpZ24gPT09IFwibWlkZGxlXCIgPyBtZXRyaWNzLmhlaWdodCAvIDIgOiAwXG4gIH07XG59O1xuXG5leHBvcnQgY29uc3QgbmV3VGV4dEVsZW1lbnQgPSBvcHRzID0+IHtcbiAgY29uc3QgZm9udEZhbWlseSA9IG9wdHMuZm9udEZhbWlseSB8fCBERUZBVUxUX0ZPTlRfRkFNSUxZO1xuICBjb25zdCBmb250U2l6ZSA9IG9wdHMuZm9udFNpemUgfHwgREVGQVVMVF9GT05UX1NJWkU7XG4gIGNvbnN0IGxpbmVIZWlnaHQgPSBvcHRzLmxpbmVIZWlnaHQgfHwgZ2V0RGVmYXVsdExpbmVIZWlnaHQoZm9udEZhbWlseSk7XG4gIGNvbnN0IHRleHQgPSBub3JtYWxpemVUZXh0KG9wdHMudGV4dCk7XG4gIGNvbnN0IG1ldHJpY3MgPSBtZWFzdXJlVGV4dCh0ZXh0LCBnZXRGb250U3RyaW5nKHtcbiAgICBmb250RmFtaWx5LFxuICAgIGZvbnRTaXplXG4gIH0pLCBsaW5lSGVpZ2h0KTtcbiAgY29uc3QgdGV4dEFsaWduID0gb3B0cy50ZXh0QWxpZ24gfHwgREVGQVVMVF9URVhUX0FMSUdOO1xuICBjb25zdCB2ZXJ0aWNhbEFsaWduID0gb3B0cy52ZXJ0aWNhbEFsaWduIHx8IERFRkFVTFRfVkVSVElDQUxfQUxJR047XG4gIGNvbnN0IG9mZnNldHMgPSBnZXRUZXh0RWxlbWVudFBvc2l0aW9uT2Zmc2V0cyh7XG4gICAgdGV4dEFsaWduLFxuICAgIHZlcnRpY2FsQWxpZ25cbiAgfSwgbWV0cmljcyk7XG4gIGNvbnN0IHRleHRFbGVtZW50ID0gbmV3RWxlbWVudFdpdGgoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfbmV3RWxlbWVudEJhc2UoXCJ0ZXh0XCIsIG9wdHMpKSwge1xuICAgIHRleHQsXG4gICAgZm9udFNpemUsXG4gICAgZm9udEZhbWlseSxcbiAgICB0ZXh0QWxpZ24sXG4gICAgdmVydGljYWxBbGlnbixcbiAgICB4OiBvcHRzLnggLSBvZmZzZXRzLngsXG4gICAgeTogb3B0cy55IC0gb2Zmc2V0cy55LFxuICAgIHdpZHRoOiBtZXRyaWNzLndpZHRoLFxuICAgIGhlaWdodDogbWV0cmljcy5oZWlnaHQsXG4gICAgYmFzZWxpbmU6IG1ldHJpY3MuYmFzZWxpbmUsXG4gICAgY29udGFpbmVySWQ6IG9wdHMuY29udGFpbmVySWQgfHwgbnVsbCxcbiAgICBvcmlnaW5hbFRleHQ6IHRleHQsXG4gICAgbGluZUhlaWdodFxuICB9KSwge30pO1xuICByZXR1cm4gdGV4dEVsZW1lbnQ7XG59O1xuXG5jb25zdCBnZXRBZGp1c3RlZERpbWVuc2lvbnMgPSAoZWxlbWVudCwgbmV4dFRleHQpID0+IHtcbiAgY29uc3Qge1xuICAgIHdpZHRoOiBuZXh0V2lkdGgsXG4gICAgaGVpZ2h0OiBuZXh0SGVpZ2h0LFxuICAgIGJhc2VsaW5lOiBuZXh0QmFzZWxpbmVcbiAgfSA9IG1lYXN1cmVUZXh0KG5leHRUZXh0LCBnZXRGb250U3RyaW5nKGVsZW1lbnQpLCBlbGVtZW50LmxpbmVIZWlnaHQpO1xuICBjb25zdCB7XG4gICAgdGV4dEFsaWduLFxuICAgIHZlcnRpY2FsQWxpZ25cbiAgfSA9IGVsZW1lbnQ7XG4gIGxldCB4O1xuICBsZXQgeTtcblxuICBpZiAodGV4dEFsaWduID09PSBcImNlbnRlclwiICYmIHZlcnRpY2FsQWxpZ24gPT09IFZFUlRJQ0FMX0FMSUdOLk1JRERMRSAmJiAhZWxlbWVudC5jb250YWluZXJJZCkge1xuICAgIGNvbnN0IHByZXZNZXRyaWNzID0gbWVhc3VyZVRleHQoZWxlbWVudC50ZXh0LCBnZXRGb250U3RyaW5nKGVsZW1lbnQpLCBlbGVtZW50LmxpbmVIZWlnaHQpO1xuICAgIGNvbnN0IG9mZnNldHMgPSBnZXRUZXh0RWxlbWVudFBvc2l0aW9uT2Zmc2V0cyhlbGVtZW50LCB7XG4gICAgICB3aWR0aDogbmV4dFdpZHRoIC0gcHJldk1ldHJpY3Mud2lkdGgsXG4gICAgICBoZWlnaHQ6IG5leHRIZWlnaHQgLSBwcmV2TWV0cmljcy5oZWlnaHRcbiAgICB9KTtcbiAgICB4ID0gZWxlbWVudC54IC0gb2Zmc2V0cy54O1xuICAgIHkgPSBlbGVtZW50LnkgLSBvZmZzZXRzLnk7XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgW3gxLCB5MSwgeDIsIHkyXSA9IGdldEVsZW1lbnRBYnNvbHV0ZUNvb3JkcyhlbGVtZW50KTtcbiAgICBjb25zdCBbbmV4dFgxLCBuZXh0WTEsIG5leHRYMiwgbmV4dFkyXSA9IGdldFJlc2l6ZWRFbGVtZW50QWJzb2x1dGVDb29yZHMoZWxlbWVudCwgbmV4dFdpZHRoLCBuZXh0SGVpZ2h0LCBmYWxzZSk7XG4gICAgY29uc3QgZGVsdGFYMSA9ICh4MSAtIG5leHRYMSkgLyAyO1xuICAgIGNvbnN0IGRlbHRhWTEgPSAoeTEgLSBuZXh0WTEpIC8gMjtcbiAgICBjb25zdCBkZWx0YVgyID0gKHgyIC0gbmV4dFgyKSAvIDI7XG4gICAgY29uc3QgZGVsdGFZMiA9ICh5MiAtIG5leHRZMikgLyAyO1xuICAgIFt4LCB5XSA9IGFkanVzdFhZV2l0aFJvdGF0aW9uKHtcbiAgICAgIHM6IHRydWUsXG4gICAgICBlOiB0ZXh0QWxpZ24gPT09IFwiY2VudGVyXCIgfHwgdGV4dEFsaWduID09PSBcImxlZnRcIixcbiAgICAgIHc6IHRleHRBbGlnbiA9PT0gXCJjZW50ZXJcIiB8fCB0ZXh0QWxpZ24gPT09IFwicmlnaHRcIlxuICAgIH0sIGVsZW1lbnQueCwgZWxlbWVudC55LCBlbGVtZW50LmFuZ2xlLCBkZWx0YVgxLCBkZWx0YVkxLCBkZWx0YVgyLCBkZWx0YVkyKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgd2lkdGg6IG5leHRXaWR0aCxcbiAgICBoZWlnaHQ6IG5leHRIZWlnaHQsXG4gICAgYmFzZWxpbmU6IG5leHRCYXNlbGluZSxcbiAgICB4OiBOdW1iZXIuaXNGaW5pdGUoeCkgPyB4IDogZWxlbWVudC54LFxuICAgIHk6IE51bWJlci5pc0Zpbml0ZSh5KSA/IHkgOiBlbGVtZW50LnlcbiAgfTtcbn07XG5cbmV4cG9ydCBjb25zdCByZWZyZXNoVGV4dERpbWVuc2lvbnMgPSAodGV4dEVsZW1lbnQsIHRleHQgPSB0ZXh0RWxlbWVudC50ZXh0KSA9PiB7XG4gIGlmICh0ZXh0RWxlbWVudC5pc0RlbGV0ZWQpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBjb250YWluZXIgPSBnZXRDb250YWluZXJFbGVtZW50KHRleHRFbGVtZW50KTtcblxuICBpZiAoY29udGFpbmVyKSB7XG4gICAgdGV4dCA9IHdyYXBUZXh0KHRleHQsIGdldEZvbnRTdHJpbmcodGV4dEVsZW1lbnQpLCBnZXRCb3VuZFRleHRNYXhXaWR0aChjb250YWluZXIpKTtcbiAgfVxuXG4gIGNvbnN0IGRpbWVuc2lvbnMgPSBnZXRBZGp1c3RlZERpbWVuc2lvbnModGV4dEVsZW1lbnQsIHRleHQpO1xuICByZXR1cm4gT2JqZWN0LmFzc2lnbih7XG4gICAgdGV4dFxuICB9LCBkaW1lbnNpb25zKTtcbn07XG5leHBvcnQgY29uc3QgdXBkYXRlVGV4dEVsZW1lbnQgPSAodGV4dEVsZW1lbnQsIHtcbiAgdGV4dCxcbiAgaXNEZWxldGVkLFxuICBvcmlnaW5hbFRleHRcbn0pID0+IHtcbiAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKHRleHRFbGVtZW50LCBPYmplY3QuYXNzaWduKHtcbiAgICBvcmlnaW5hbFRleHQsXG4gICAgaXNEZWxldGVkOiBpc0RlbGV0ZWQgIT09IG51bGwgJiYgaXNEZWxldGVkICE9PSB2b2lkIDAgPyBpc0RlbGV0ZWQgOiB0ZXh0RWxlbWVudC5pc0RlbGV0ZWRcbiAgfSwgcmVmcmVzaFRleHREaW1lbnNpb25zKHRleHRFbGVtZW50LCBvcmlnaW5hbFRleHQpKSk7XG59O1xuZXhwb3J0IGNvbnN0IG5ld0ZyZWVEcmF3RWxlbWVudCA9IG9wdHMgPT4ge1xuICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfbmV3RWxlbWVudEJhc2Uob3B0cy50eXBlLCBvcHRzKSksIHtcbiAgICBwb2ludHM6IG9wdHMucG9pbnRzIHx8IFtdLFxuICAgIHByZXNzdXJlczogW10sXG4gICAgc2ltdWxhdGVQcmVzc3VyZTogb3B0cy5zaW11bGF0ZVByZXNzdXJlLFxuICAgIGxhc3RDb21taXR0ZWRQb2ludDogbnVsbFxuICB9KTtcbn07XG5leHBvcnQgY29uc3QgbmV3TGluZWFyRWxlbWVudCA9IG9wdHMgPT4ge1xuICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfbmV3RWxlbWVudEJhc2Uob3B0cy50eXBlLCBvcHRzKSksIHtcbiAgICBwb2ludHM6IG9wdHMucG9pbnRzIHx8IFtdLFxuICAgIGxhc3RDb21taXR0ZWRQb2ludDogbnVsbCxcbiAgICBzdGFydEJpbmRpbmc6IG51bGwsXG4gICAgZW5kQmluZGluZzogbnVsbCxcbiAgICBzdGFydEFycm93aGVhZDogb3B0cy5zdGFydEFycm93aGVhZCB8fCBudWxsLFxuICAgIGVuZEFycm93aGVhZDogb3B0cy5lbmRBcnJvd2hlYWQgfHwgbnVsbFxuICB9KTtcbn07XG5leHBvcnQgY29uc3QgbmV3SW1hZ2VFbGVtZW50ID0gb3B0cyA9PiB7XG4gIHZhciBfYSwgX2IsIF9jO1xuXG4gIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIF9uZXdFbGVtZW50QmFzZShcImltYWdlXCIsIG9wdHMpKSwge1xuICAgIC8vIGluIHRoZSBmdXR1cmUgd2UnbGwgc3VwcG9ydCBjaGFuZ2luZyBzdHJva2UgY29sb3IgZm9yIHNvbWUgU1ZHIGVsZW1lbnRzLFxuICAgIC8vIGFuZCBgdHJhbnNwYXJlbnRgIHdpbGwgbGlrZWx5IG1lYW4gXCJ1c2Ugb3JpZ2luYWwgY29sb3JzIG9mIHRoZSBpbWFnZVwiXG4gICAgc3Ryb2tlQ29sb3I6IFwidHJhbnNwYXJlbnRcIixcbiAgICBzdGF0dXM6IChfYSA9IG9wdHMuc3RhdHVzKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBcInBlbmRpbmdcIixcbiAgICBmaWxlSWQ6IChfYiA9IG9wdHMuZmlsZUlkKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiBudWxsLFxuICAgIHNjYWxlOiAoX2MgPSBvcHRzLnNjYWxlKSAhPT0gbnVsbCAmJiBfYyAhPT0gdm9pZCAwID8gX2MgOiBbMSwgMV1cbiAgfSk7XG59OyAvLyBTaW1wbGlmaWVkIGRlZXAgY2xvbmUgZm9yIHRoZSBwdXJwb3NlIG9mIGNsb25pbmcgRXhjYWxpZHJhd0VsZW1lbnQuXG4vL1xuLy8gT25seSBjbG9uZXMgcGxhaW4gb2JqZWN0cyBhbmQgYXJyYXlzLiBEb2Vzbid0IGNsb25lIERhdGUsIFJlZ0V4cCwgTWFwLCBTZXQsXG4vLyBUeXBlZCBhcnJheXMgYW5kIG90aGVyIG5vbi1udWxsIG9iamVjdHMuXG4vL1xuLy8gQWRhcHRlZCBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9sdWtlZWQva2xvbmFcbi8vXG4vLyBUaGUgcmVhc29uIGZvciBgZGVlcENvcHlFbGVtZW50KClgIHdyYXBwZXIgaXMgdHlwZSBzYWZldHkgKG9ubHkgYWxsb3dcbi8vIHBhc3NpbmcgRXhjYWxpZHJhd0VsZW1lbnQgYXMgdGhlIHRvcC1sZXZlbCBhcmd1bWVudCkuXG5cbmNvbnN0IF9kZWVwQ29weUVsZW1lbnQgPSAodmFsLCBkZXB0aCA9IDApID0+IHtcbiAgLy8gb25seSBjbG9uZSBub24tcHJpbWl0aXZlc1xuICBpZiAodmFsID09IG51bGwgfHwgdHlwZW9mIHZhbCAhPT0gXCJvYmplY3RcIikge1xuICAgIHJldHVybiB2YWw7XG4gIH1cblxuICBjb25zdCBvYmplY3RUeXBlID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbCk7XG5cbiAgaWYgKG9iamVjdFR5cGUgPT09IFwiW29iamVjdCBPYmplY3RdXCIpIHtcbiAgICBjb25zdCB0bXAgPSB0eXBlb2YgdmFsLmNvbnN0cnVjdG9yID09PSBcImZ1bmN0aW9uXCIgPyBPYmplY3QuY3JlYXRlKE9iamVjdC5nZXRQcm90b3R5cGVPZih2YWwpKSA6IHt9O1xuXG4gICAgZm9yIChjb25zdCBrZXkgaW4gdmFsKSB7XG4gICAgICBpZiAodmFsLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgLy8gZG9uJ3QgY29weSBub24tc2VyaWFsaXphYmxlIG9iamVjdHMgbGlrZSB0aGVzZSBjYWNoZXMuIFRoZXknbGwgYmVcbiAgICAgICAgLy8gcG9wdWxhdGVkIHdoZW4gdGhlIGVsZW1lbnQgaXMgcmVuZGVyZWQuXG4gICAgICAgIGlmIChkZXB0aCA9PT0gMCAmJiAoa2V5ID09PSBcInNoYXBlXCIgfHwga2V5ID09PSBcImNhbnZhc1wiKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdG1wW2tleV0gPSBfZGVlcENvcHlFbGVtZW50KHZhbFtrZXldLCBkZXB0aCArIDEpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0bXA7XG4gIH1cblxuICBpZiAoQXJyYXkuaXNBcnJheSh2YWwpKSB7XG4gICAgbGV0IGsgPSB2YWwubGVuZ3RoO1xuICAgIGNvbnN0IGFyciA9IG5ldyBBcnJheShrKTtcblxuICAgIHdoaWxlIChrLS0pIHtcbiAgICAgIGFycltrXSA9IF9kZWVwQ29weUVsZW1lbnQodmFsW2tdLCBkZXB0aCArIDEpO1xuICAgIH1cblxuICAgIHJldHVybiBhcnI7XG4gIH0gLy8gd2UncmUgbm90IGNsb25pbmcgbm9uLWFycmF5ICYgbm9uLXBsYWluLW9iamVjdCBvYmplY3RzIGJlY2F1c2Ugd2VcbiAgLy8gZG9uJ3Qgc3VwcG9ydCB0aGVtIG9uIGV4Y2FsaWRyYXcgZWxlbWVudHMgeWV0LiBJZiB3ZSBkbywgd2UgbmVlZCB0byBtYWtlXG4gIC8vIHN1cmUgd2Ugc3RhcnQgY2xvbmluZyB0aGVtLCBzbyBsZXQncyB3YXJuIGFib3V0IGl0LlxuXG5cbiAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICAgIGlmIChvYmplY3RUeXBlICE9PSBcIltvYmplY3QgT2JqZWN0XVwiICYmIG9iamVjdFR5cGUgIT09IFwiW29iamVjdCBBcnJheV1cIiAmJiBvYmplY3RUeXBlLnN0YXJ0c1dpdGgoXCJbb2JqZWN0IFwiKSkge1xuICAgICAgY29uc29sZS53YXJuKGBfZGVlcENsb25lRWxlbWVudDogdW5leHBlY3RlZCBvYmplY3QgdHlwZSAke29iamVjdFR5cGV9LiBUaGlzIHZhbHVlIHdpbGwgbm90IGJlIGNsb25lZCFgKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdmFsO1xufTtcbi8qKlxuICogQ2xvbmVzIEV4Y2FsaWRyYXdFbGVtZW50IGRhdGEgc3RydWN0dXJlLiBEb2VzIG5vdCByZWdlbmVyYXRlIGlkLCBub25jZSwgb3JcbiAqIGFueSB2YWx1ZS4gVGhlIHB1cnBvc2UgaXMgdG8gdG8gYnJlYWsgb2JqZWN0IHJlZmVyZW5jZXMgZm9yIGltbXV0YWJpbGl0eVxuICogcmVhc29ucywgd2hlbmV2ZXIgd2Ugd2FudCB0byBrZWVwIHRoZSBvcmlnaW5hbCBlbGVtZW50LCBidXQgZW5zdXJlIGl0J3Mgbm90XG4gKiBtdXRhdGVkLlxuICpcbiAqIE9ubHkgY2xvbmVzIHBsYWluIG9iamVjdHMgYW5kIGFycmF5cy4gRG9lc24ndCBjbG9uZSBEYXRlLCBSZWdFeHAsIE1hcCwgU2V0LFxuICogVHlwZWQgYXJyYXlzIGFuZCBvdGhlciBub24tbnVsbCBvYmplY3RzLlxuICovXG5cblxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5RWxlbWVudCA9IHZhbCA9PiB7XG4gIHJldHVybiBfZGVlcENvcHlFbGVtZW50KHZhbCk7XG59O1xuLyoqXG4gKiB1dGlsaXR5IHdyYXBwZXIgdG8gZ2VuZXJhdGUgbmV3IGlkLiBJbiB0ZXN0IGVudiBpdCByZXVzZXMgdGhlIG9sZCArIHBvc3RmaXhcbiAqIGZvciB0ZXN0IGFzc2VydGlvbnMuXG4gKi9cblxuZXhwb3J0IGNvbnN0IHJlZ2VuZXJhdGVJZCA9IChcbi8qKiBzdXBwbHkgbnVsbCBpZiBubyBwcmV2aW91cyBpZCBleGlzdHMgKi9cbnByZXZpb3VzSWQpID0+IHtcbiAgdmFyIF9hLCBfYjtcblxuICBpZiAoaXNUZXN0RW52KCkgJiYgcHJldmlvdXNJZCkge1xuICAgIGxldCBuZXh0SWQgPSBgJHtwcmV2aW91c0lkfV9jb3B5YDsgLy8gYHdpbmRvdy5oYCBtYXkgbm90IGJlIGRlZmluZWQgaW4gc29tZSB1bml0IHRlc3RzXG5cbiAgICBpZiAoKF9iID0gKF9hID0gd2luZG93LmgpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5hcHApID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5nZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbmQoZWwgPT4gZWwuaWQgPT09IG5leHRJZCkpIHtcbiAgICAgIG5leHRJZCArPSBcIl9jb3B5XCI7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5leHRJZDtcbiAgfVxuXG4gIHJldHVybiByYW5kb21JZCgpO1xufTtcbi8qKlxuICogRHVwbGljYXRlIGFuIGVsZW1lbnQsIG9mdGVuIHVzZWQgaW4gdGhlIGFsdC1kcmFnIG9wZXJhdGlvbi5cbiAqIE5vdGUgdGhhdCB0aGlzIG1ldGhvZCBoYXMgZ290dGVuIGEgYml0IGNvbXBsaWNhdGVkIHNpbmNlIHRoZVxuICogaW50cm9kdWN0aW9uIG9mIGdydW9waW5nL3VuZ3JvdXBpbmcgZWxlbWVudHMuXG4gKiBAcGFyYW0gZWRpdGluZ0dyb3VwSWQgVGhlIGN1cnJlbnQgZ3JvdXAgYmVpbmcgZWRpdGVkLiBUaGUgbmV3XG4gKiAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudCB3aWxsIGluaGVyaXQgdGhpcyBncm91cCBhbmQgaXRzXG4gKiAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50cy5cbiAqIEBwYXJhbSBncm91cElkTWFwRm9yT3BlcmF0aW9uIEEgTWFwIHRoYXQgbWFwcyBvbGQgZ3JvdXAgSURzIHRvXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdXBsaWNhdGVkIG9uZXMuIElmIHlvdSBhcmUgZHVwbGljYXRpbmdcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpcGxlIGVsZW1lbnRzIGF0IG9uY2UsIHNoYXJlIHRoaXMgbWFwXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbW9uZ3N0IGFsbCBvZiB0aGVtXG4gKiBAcGFyYW0gZWxlbWVudCBFbGVtZW50IHRvIGR1cGxpY2F0ZVxuICogQHBhcmFtIG92ZXJyaWRlcyBBbnkgZWxlbWVudCBwcm9wZXJ0aWVzIHRvIG92ZXJyaWRlXG4gKi9cblxuZXhwb3J0IGNvbnN0IGR1cGxpY2F0ZUVsZW1lbnQgPSAoZWRpdGluZ0dyb3VwSWQsIGdyb3VwSWRNYXBGb3JPcGVyYXRpb24sIGVsZW1lbnQsIG92ZXJyaWRlcykgPT4ge1xuICBsZXQgY29weSA9IGRlZXBDb3B5RWxlbWVudChlbGVtZW50KTtcbiAgY29weS5pZCA9IHJlZ2VuZXJhdGVJZChjb3B5LmlkKTtcbiAgY29weS5ib3VuZEVsZW1lbnRzID0gbnVsbDtcbiAgY29weS51cGRhdGVkID0gZ2V0VXBkYXRlZFRpbWVzdGFtcCgpO1xuICBjb3B5LnNlZWQgPSByYW5kb21JbnRlZ2VyKCk7XG4gIGNvcHkuZ3JvdXBJZHMgPSBnZXROZXdHcm91cElkc0ZvckR1cGxpY2F0aW9uKGNvcHkuZ3JvdXBJZHMsIGVkaXRpbmdHcm91cElkLCBncm91cElkID0+IHtcbiAgICBpZiAoIWdyb3VwSWRNYXBGb3JPcGVyYXRpb24uaGFzKGdyb3VwSWQpKSB7XG4gICAgICBncm91cElkTWFwRm9yT3BlcmF0aW9uLnNldChncm91cElkLCByZWdlbmVyYXRlSWQoZ3JvdXBJZCkpO1xuICAgIH1cblxuICAgIHJldHVybiBncm91cElkTWFwRm9yT3BlcmF0aW9uLmdldChncm91cElkKTtcbiAgfSk7XG5cbiAgaWYgKG92ZXJyaWRlcykge1xuICAgIGNvcHkgPSBPYmplY3QuYXNzaWduKGNvcHksIG92ZXJyaWRlcyk7XG4gIH1cblxuICByZXR1cm4gY29weTtcbn07XG4vKipcbiAqIENsb25lcyBlbGVtZW50cywgcmVnZW5lcmF0aW5nIHRoZWlyIGlkcyAoaW5jbHVkaW5nIGJpbmRpbmdzKSBhbmQgZ3JvdXAgaWRzLlxuICpcbiAqIElmIGJpbmRpbmdzIGRvbid0IGV4aXN0IGluIHRoZSBlbGVtZW50cyBhcnJheSwgdGhleSBhcmUgcmVtb3ZlZC4gVGhlcmVmb3JlLFxuICogaXQncyBhZHZpc2VkIHRvIHN1cHBseSB0aGUgd2hvbGUgZWxlbWVudHMgYXJyYXksIG9yIHNldHMgb2YgZWxlbWVudHMgdGhhdFxuICogYXJlIGVuY2Fwc3VsYXRlZCAoc3VjaCBhcyBsaWJyYXJ5IGl0ZW1zKSwgaWYgdGhlIHB1cnBvc2UgaXMgdG8gcmV0YWluXG4gKiBiaW5kaW5ncyB0byB0aGUgY2xvbmVkIGVsZW1lbnRzIGludGFjdC5cbiAqXG4gKiBOT1RFIGJ5IGRlZmF1bHQgZG9lcyBub3QgcmFuZG9taXplIG9yIHJlZ2VuZXJhdGUgYW55dGhpbmcgZXhjZXB0IHRoZSBpZC5cbiAqL1xuXG5leHBvcnQgY29uc3QgZHVwbGljYXRlRWxlbWVudHMgPSAoZWxlbWVudHMsIG9wdHMpID0+IHtcbiAgY29uc3QgY2xvbmVkRWxlbWVudHMgPSBbXTtcbiAgY29uc3Qgb3JpZ0VsZW1lbnRzTWFwID0gYXJyYXlUb01hcChlbGVtZW50cyk7IC8vIHVzZWQgZm9yIGZvciBtaWdyYXRpbmcgb2xkIGlkcyB0byBuZXcgaWRzXG5cbiAgY29uc3QgZWxlbWVudE5ld0lkc01hcCA9IG5ldyBNYXAoKTtcblxuICBjb25zdCBtYXliZUdldE5ld0lkID0gaWQgPT4ge1xuICAgIC8vIGlmIHdlJ3ZlIGFscmVhZHkgbWlncmF0ZWQgdGhlIGVsZW1lbnQgaWQsIHJldHVybiB0aGUgbmV3IG9uZSBkaXJlY3RseVxuICAgIGlmIChlbGVtZW50TmV3SWRzTWFwLmhhcyhpZCkpIHtcbiAgICAgIHJldHVybiBlbGVtZW50TmV3SWRzTWFwLmdldChpZCk7XG4gICAgfSAvLyBpZiB3ZSBoYXZlbid0IG1pZ3JhdGVkIHRoZSBlbGVtZW50IGlkLCBidXQgYW4gb2xkIGVsZW1lbnQgd2l0aCB0aGUgc2FtZVxuICAgIC8vIGlkIGV4aXN0cywgZ2VuZXJhdGUgYSBuZXcgaWQgZm9yIGl0IGFuZCByZXR1cm4gaXRcblxuXG4gICAgaWYgKG9yaWdFbGVtZW50c01hcC5oYXMoaWQpKSB7XG4gICAgICBjb25zdCBuZXdJZCA9IHJlZ2VuZXJhdGVJZChpZCk7XG4gICAgICBlbGVtZW50TmV3SWRzTWFwLnNldChpZCwgbmV3SWQpO1xuICAgICAgcmV0dXJuIG5ld0lkO1xuICAgIH0gLy8gaWYgb2xkIGVsZW1lbnQgZG9lc24ndCBleGlzdCwgcmV0dXJuIG51bGwgdG8gbWFyayBpdCBmb3IgcmVtb3ZhbFxuXG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfTtcblxuICBjb25zdCBncm91cE5ld0lkc01hcCA9IG5ldyBNYXAoKTtcblxuICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZWxlbWVudHMpIHtcbiAgICBjb25zdCBjbG9uZWRFbGVtZW50ID0gX2RlZXBDb3B5RWxlbWVudChlbGVtZW50KTtcblxuICAgIGNsb25lZEVsZW1lbnQuaWQgPSBtYXliZUdldE5ld0lkKGVsZW1lbnQuaWQpO1xuXG4gICAgaWYgKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yYW5kb21pemVTZWVkKSB7XG4gICAgICBjbG9uZWRFbGVtZW50LnNlZWQgPSByYW5kb21JbnRlZ2VyKCk7XG4gICAgICBidW1wVmVyc2lvbihjbG9uZWRFbGVtZW50KTtcbiAgICB9XG5cbiAgICBpZiAoY2xvbmVkRWxlbWVudC5ncm91cElkcykge1xuICAgICAgY2xvbmVkRWxlbWVudC5ncm91cElkcyA9IGNsb25lZEVsZW1lbnQuZ3JvdXBJZHMubWFwKGdyb3VwSWQgPT4ge1xuICAgICAgICBpZiAoIWdyb3VwTmV3SWRzTWFwLmhhcyhncm91cElkKSkge1xuICAgICAgICAgIGdyb3VwTmV3SWRzTWFwLnNldChncm91cElkLCByZWdlbmVyYXRlSWQoZ3JvdXBJZCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGdyb3VwTmV3SWRzTWFwLmdldChncm91cElkKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChcImNvbnRhaW5lcklkXCIgaW4gY2xvbmVkRWxlbWVudCAmJiBjbG9uZWRFbGVtZW50LmNvbnRhaW5lcklkKSB7XG4gICAgICBjb25zdCBuZXdDb250YWluZXJJZCA9IG1heWJlR2V0TmV3SWQoY2xvbmVkRWxlbWVudC5jb250YWluZXJJZCk7XG4gICAgICBjbG9uZWRFbGVtZW50LmNvbnRhaW5lcklkID0gbmV3Q29udGFpbmVySWQ7XG4gICAgfVxuXG4gICAgaWYgKFwiYm91bmRFbGVtZW50c1wiIGluIGNsb25lZEVsZW1lbnQgJiYgY2xvbmVkRWxlbWVudC5ib3VuZEVsZW1lbnRzKSB7XG4gICAgICBjbG9uZWRFbGVtZW50LmJvdW5kRWxlbWVudHMgPSBjbG9uZWRFbGVtZW50LmJvdW5kRWxlbWVudHMucmVkdWNlKChhY2MsIGJpbmRpbmcpID0+IHtcbiAgICAgICAgY29uc3QgbmV3QmluZGluZ0lkID0gbWF5YmVHZXROZXdJZChiaW5kaW5nLmlkKTtcblxuICAgICAgICBpZiAobmV3QmluZGluZ0lkKSB7XG4gICAgICAgICAgYWNjLnB1c2goT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBiaW5kaW5nKSwge1xuICAgICAgICAgICAgaWQ6IG5ld0JpbmRpbmdJZFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCBbXSk7XG4gICAgfVxuXG4gICAgaWYgKFwiZW5kQmluZGluZ1wiIGluIGNsb25lZEVsZW1lbnQgJiYgY2xvbmVkRWxlbWVudC5lbmRCaW5kaW5nKSB7XG4gICAgICBjb25zdCBuZXdFbmRCaW5kaW5nSWQgPSBtYXliZUdldE5ld0lkKGNsb25lZEVsZW1lbnQuZW5kQmluZGluZy5lbGVtZW50SWQpO1xuICAgICAgY2xvbmVkRWxlbWVudC5lbmRCaW5kaW5nID0gbmV3RW5kQmluZGluZ0lkID8gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBjbG9uZWRFbGVtZW50LmVuZEJpbmRpbmcpLCB7XG4gICAgICAgIGVsZW1lbnRJZDogbmV3RW5kQmluZGluZ0lkXG4gICAgICB9KSA6IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKFwic3RhcnRCaW5kaW5nXCIgaW4gY2xvbmVkRWxlbWVudCAmJiBjbG9uZWRFbGVtZW50LnN0YXJ0QmluZGluZykge1xuICAgICAgY29uc3QgbmV3RW5kQmluZGluZ0lkID0gbWF5YmVHZXROZXdJZChjbG9uZWRFbGVtZW50LnN0YXJ0QmluZGluZy5lbGVtZW50SWQpO1xuICAgICAgY2xvbmVkRWxlbWVudC5zdGFydEJpbmRpbmcgPSBuZXdFbmRCaW5kaW5nSWQgPyBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGNsb25lZEVsZW1lbnQuc3RhcnRCaW5kaW5nKSwge1xuICAgICAgICBlbGVtZW50SWQ6IG5ld0VuZEJpbmRpbmdJZFxuICAgICAgfSkgOiBudWxsO1xuICAgIH1cblxuICAgIGlmIChjbG9uZWRFbGVtZW50LmZyYW1lSWQpIHtcbiAgICAgIGNsb25lZEVsZW1lbnQuZnJhbWVJZCA9IG1heWJlR2V0TmV3SWQoY2xvbmVkRWxlbWVudC5mcmFtZUlkKTtcbiAgICB9XG5cbiAgICBjbG9uZWRFbGVtZW50cy5wdXNoKGNsb25lZEVsZW1lbnQpO1xuICB9XG5cbiAgcmV0dXJuIGNsb25lZEVsZW1lbnRzO1xufTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../element/newElement.ts\n");
3963
3963
 
3964
3964
  /***/ }),
3965
3965