@dwelle/excalidraw 0.4.0-ab25481 → 0.4.0-ab8616b

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.
@@ -2151,7 +2151,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
2151
2151
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2152
2152
 
2153
2153
  "use strict";
2154
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"trackEvent\": () => (/* binding */ trackEvent)\n/* harmony export */ });\nconst trackEvent = (category, action, label, value) => {\n try {\n // place here categories that you want to track as events\n // KEEP IN MIND THE PRICING\n const ALLOWED_CATEGORIES_TO_TRACK = []; // Uncomment the next line to track locally\n // console.log(\"Track Event\", { category, action, label, value });\n\n if (typeof window === \"undefined\" || ({\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PORTAL_URL\":\"\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"https://app.excalidraw.com\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_ENABLE_SW\":\"\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_DISABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3000\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_PKG_NAME\":\"@dwelle/excalidraw\",\"VITE_PKG_VERSION\":\"0.4.0-ab25481\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).VITE_WORKER_ID) {\n return;\n }\n\n if (!ALLOWED_CATEGORIES_TO_TRACK.includes(category)) {\n return;\n }\n\n if (window.sa_event) {\n window.sa_event(action, {\n category,\n label,\n value\n });\n }\n } catch (error) {\n console.error(\"error during analytics\", error);\n }\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vYW5hbHl0aWNzLnRzLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QyxvQ0FBb0MsZ0NBQWdDOztBQUVwRSx5Q0FBeUMseXFDQUFXO0FBQ3BEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2FuYWx5dGljcy50cz81NjYxIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCB0cmFja0V2ZW50ID0gKGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSkgPT4ge1xuICB0cnkge1xuICAgIC8vIHBsYWNlIGhlcmUgY2F0ZWdvcmllcyB0aGF0IHlvdSB3YW50IHRvIHRyYWNrIGFzIGV2ZW50c1xuICAgIC8vIEtFRVAgSU4gTUlORCBUSEUgUFJJQ0lOR1xuICAgIGNvbnN0IEFMTE9XRURfQ0FURUdPUklFU19UT19UUkFDSyA9IFtdOyAvLyBVbmNvbW1lbnQgdGhlIG5leHQgbGluZSB0byB0cmFjayBsb2NhbGx5XG4gICAgLy8gY29uc29sZS5sb2coXCJUcmFjayBFdmVudFwiLCB7IGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSB9KTtcblxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSBcInVuZGVmaW5lZFwiIHx8IHByb2Nlc3MuZW52LlZJVEVfV09SS0VSX0lEKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFBTExPV0VEX0NBVEVHT1JJRVNfVE9fVFJBQ0suaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5zYV9ldmVudCkge1xuICAgICAgd2luZG93LnNhX2V2ZW50KGFjdGlvbiwge1xuICAgICAgICBjYXRlZ29yeSxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIHZhbHVlXG4gICAgICB9KTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcImVycm9yIGR1cmluZyBhbmFseXRpY3NcIiwgZXJyb3IpO1xuICB9XG59OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../analytics.ts\n");
2154
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"trackEvent\": () => (/* binding */ trackEvent)\n/* harmony export */ });\nconst trackEvent = (category, action, label, value) => {\n try {\n // place here categories that you want to track as events\n // KEEP IN MIND THE PRICING\n const ALLOWED_CATEGORIES_TO_TRACK = []; // Uncomment the next line to track locally\n // console.log(\"Track Event\", { category, action, label, value });\n\n if (typeof window === \"undefined\" || ({\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PORTAL_URL\":\"\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"https://app.excalidraw.com\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_ENABLE_SW\":\"\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_DISABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3000\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_PKG_NAME\":\"@dwelle/excalidraw\",\"VITE_PKG_VERSION\":\"0.4.0-ab8616b\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).VITE_WORKER_ID) {\n return;\n }\n\n if (!ALLOWED_CATEGORIES_TO_TRACK.includes(category)) {\n return;\n }\n\n if (window.sa_event) {\n window.sa_event(action, {\n category,\n label,\n value\n });\n }\n } catch (error) {\n console.error(\"error during analytics\", error);\n }\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vYW5hbHl0aWNzLnRzLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QyxvQ0FBb0MsZ0NBQWdDOztBQUVwRSx5Q0FBeUMseXFDQUFXO0FBQ3BEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2FuYWx5dGljcy50cz81NjYxIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCB0cmFja0V2ZW50ID0gKGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSkgPT4ge1xuICB0cnkge1xuICAgIC8vIHBsYWNlIGhlcmUgY2F0ZWdvcmllcyB0aGF0IHlvdSB3YW50IHRvIHRyYWNrIGFzIGV2ZW50c1xuICAgIC8vIEtFRVAgSU4gTUlORCBUSEUgUFJJQ0lOR1xuICAgIGNvbnN0IEFMTE9XRURfQ0FURUdPUklFU19UT19UUkFDSyA9IFtdOyAvLyBVbmNvbW1lbnQgdGhlIG5leHQgbGluZSB0byB0cmFjayBsb2NhbGx5XG4gICAgLy8gY29uc29sZS5sb2coXCJUcmFjayBFdmVudFwiLCB7IGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSB9KTtcblxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSBcInVuZGVmaW5lZFwiIHx8IHByb2Nlc3MuZW52LlZJVEVfV09SS0VSX0lEKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFBTExPV0VEX0NBVEVHT1JJRVNfVE9fVFJBQ0suaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5zYV9ldmVudCkge1xuICAgICAgd2luZG93LnNhX2V2ZW50KGFjdGlvbiwge1xuICAgICAgICBjYXRlZ29yeSxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIHZhbHVlXG4gICAgICB9KTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcImVycm9yIGR1cmluZyBhbmFseXRpY3NcIiwgZXJyb3IpO1xuICB9XG59OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../analytics.ts\n");
2155
2155
 
2156
2156
  /***/ }),
2157
2157
 
@@ -2239,7 +2239,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
2239
2239
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2240
2240
 
2241
2241
  "use strict";
2242
- 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 */ \"../../../node_modules/react/jsx-runtime.js\");\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_68__ = __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 _renderer_renderElement__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ../renderer/renderElement */ \"../../renderer/renderElement.ts\");\n/* harmony import */ var _scene__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ../scene */ \"../../scene/index.ts\");\n/* harmony import */ var _scene_Scene__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ../scene/Scene */ \"../../scene/Scene.ts\");\n/* harmony import */ var _scene_zoom__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ../scene/zoom */ \"../../scene/zoom.ts\");\n/* harmony import */ var _shapes__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ../shapes */ \"../../shapes.tsx\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _element_embeddable__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ../element/embeddable */ \"../../element/embeddable.ts\");\n/* harmony import */ var _ContextMenu__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./ContextMenu */ \"../../components/ContextMenu.tsx\");\n/* harmony import */ var _LayerUI__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./LayerUI */ \"../../components/LayerUI.tsx\");\n/* harmony import */ var _Toast__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ./Toast */ \"../../components/Toast.tsx\");\n/* harmony import */ var _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ../actions/actionToggleViewMode */ \"../../actions/actionToggleViewMode.tsx\");\n/* harmony import */ var _data_blob__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ../data/blob */ \"../../data/blob.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! ../element/image */ \"../../element/image.ts\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! lodash.throttle */ \"../../../node_modules/lodash.throttle/index.js\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_42___default = /*#__PURE__*/__webpack_require__.n(lodash_throttle__WEBPACK_IMPORTED_MODULE_42__);\n/* harmony import */ var _data_filesystem__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ../data/filesystem */ \"../../data/filesystem.ts\");\n/* harmony import */ var _element_textElement__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ../element/textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _element_collision__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! ../element/collision */ \"../../element/collision.ts\");\n/* harmony import */ var _element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! ../element/Hyperlink */ \"../../element/Hyperlink.tsx\");\n/* harmony import */ var _data_url__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! ../data/url */ \"../../data/url.ts\");\n/* harmony import */ var _element_transformHandles__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! ../element/transformHandles */ \"../../element/transformHandles.ts\");\n/* harmony import */ var _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! ../actions/actionElementLock */ \"../../actions/actionElementLock.ts\");\n/* harmony import */ var _scene_Fonts__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! ../scene/Fonts */ \"../../scene/Fonts.ts\");\n/* harmony import */ var _frame__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! ../frame */ \"../../frame.ts\");\n/* harmony import */ var _scene_selection__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! ../scene/selection */ \"../../scene/selection.ts\");\n/* harmony import */ var _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! ../actions/actionClipboard */ \"../../actions/actionClipboard.tsx\");\n/* harmony import */ var _actions_actionFrame__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ../actions/actionFrame */ \"../../actions/actionFrame.ts\");\n/* harmony import */ var _actions_actionCanvas__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ../actions/actionCanvas */ \"../../actions/actionCanvas.tsx\");\n/* harmony import */ var _jotai__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! ../jotai */ \"../../jotai.ts\");\n/* harmony import */ var _ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ./ActiveConfirmDialog */ \"../../components/ActiveConfirmDialog.tsx\");\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 _emitter__WEBPACK_IMPORTED_MODULE_67__ = __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\nconst AppContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst AppPropsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst deviceContextInitialValue = {\n isSmScreen: false,\n isMobile: false,\n isTouchScreen: false,\n canDeviceFitSidebar: false,\n isLandscape: 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);\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 var _a;\n\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.lastPointerDown = null;\n this.lastPointerUp = null;\n this.lastViewportPosition = {\n x: 0,\n y: 0\n };\n this.onChangeEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_67__.Emitter();\n this.onPointerDownEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_67__.Emitter();\n this.onPointerUpEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_67__.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_35__.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_34__.viewportCoordsToSceneCoords)({\n clientX: box.x,\n clientY: box.y\n }, this.state);\n const boxSceneBottomRight = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.sceneCoordsToViewportCoords)({\n sceneX: f.x,\n sceneY: f.y\n }, this.state);\n const {\n x: x2\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.sceneCoordsToViewportCoords)({\n sceneX: f.x + f.width,\n sceneY: f.y + f.height\n }, this.state);\n const FRAME_NAME_GAP = 20;\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: `translateY(-${FRAME_NAME_EDIT_PADDING}px)`,\n color: \"var(--color-gray-80)\",\n overflow: \"hidden\",\n maxWidth: `${Math.min(x2 - x1 - FRAME_NAME_EDIT_PADDING, 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 top: `${y1 - FRAME_NAME_GAP - this.state.offsetTop}px`,\n left: `${x1 - this.state.offsetLeft - (this.state.editingFrame === f.id ? FRAME_NAME_EDIT_PADDING : 0)}px`,\n zIndex: 2,\n fontSize: \"14px\",\n color: isDarkTheme ? \"var(--color-gray-60)\" : \"var(--color-gray-50)\",\n width: \"max-content\",\n maxWidth: `${x2 - x1 + FRAME_NAME_EDIT_PADDING * 2}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) => __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__.exportAsImage)(type, elements, this.state, this.files, {\n exportBackground: this.state.exportBackground,\n name: this.state.name,\n viewBackgroundColor: this.state.viewBackgroundColor\n }).catch(_utils__WEBPACK_IMPORTED_MODULE_34__.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_40__.isImageFileHandle)(fileHandle)) {\n this.setState({\n fileHandle\n });\n }\n });\n\n this.openEyeDropper = ({\n type\n }) => {\n _jotai__WEBPACK_IMPORTED_MODULE_56__.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_34__.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_34__.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_34__.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 _b;\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: ((_b = scene.appState) === null || _b === void 0 ? void 0 : _b.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_30__.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\n if ((initialData === null || initialData === void 0 ? void 0 : initialData.scrollX) != null) {\n scene.appState.scrollX = initialData.scrollX;\n }\n\n if ((initialData === null || initialData === void 0 ? void 0 : initialData.scrollY) != null) {\n scene.appState.scrollY = initialData.scrollY;\n }\n\n this.resetHistory();\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n commitToHistory: true\n }));\n });\n\n this.refreshDeviceState = container => {\n const {\n width,\n height\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 this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.updateObject)(this.device, {\n isLandscape: width > height,\n isSmScreen: width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_SM_MAX_WIDTH,\n isMobile: 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 canDeviceFitSidebar: width > sidebarBreakpoint\n });\n };\n\n this.onResize = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.withBatchedUpdates)(() => {\n this.scene.getElementsIncludingDeleted().forEach(element => _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element));\n this.setState({});\n });\n\n this.onFontsLoadingDone = event => {\n const loadedFontFaces = event.fontfaces;\n this.fonts.onFontsLoaded(loadedFontFaces);\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_34__.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_34__.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_34__.isWritableElement)(event.target)) {\n return;\n }\n\n this.cutAll();\n event.preventDefault();\n event.stopPropagation();\n });\n this.onCopy = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.isWritableElement)(event.target)) {\n return;\n }\n\n this.copyAll();\n event.preventDefault();\n event.stopPropagation();\n });\n\n this.cutAll = () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, \"keyboard\");\n };\n\n this.copyAll = () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, \"keyboard\");\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_52__.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_52__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n } else {\n gesture.pointers.clear();\n }\n };\n\n this.pasteFromClipboard = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.withBatchedUpdates)(event => __awaiter(this, void 0, void 0, function* () {\n var _c, _d, _e;\n\n const isPlainPaste = !!(IS_PLAIN_PASTE && event); // #686\n\n const target = document.activeElement;\n const isExcalidrawActive = (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.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_34__.isWritableElement)(target))) {\n return;\n } // 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\n let file = (_d = event === null || event === void 0 ? void 0 : event.clipboardData) === null || _d === void 0 ? void 0 : _d.files[0];\n const data = yield (0,_clipboard__WEBPACK_IMPORTED_MODULE_11__.parseClipboard)(event, isPlainPaste);\n\n if (!file && data.text && !isPlainPaste) {\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_40__.SVGStringToFile)(string);\n }\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state); // prefer spreadsheet data over image file (MS Office/Libre Office)\n\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.isSupportedImageFile)(file) && !data.spreadsheet) {\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_52__.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_35__.extractSrc)(data.text);\n\n if (!isPlainPaste && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.embeddableURLValidator)(maybeUrl, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(maybeUrl) || ((_e = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.getEmbedLink)(maybeUrl)) === null || _e === void 0 ? void 0 : _e.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_47__.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_34__.distance)(minX, maxX) / 2;\n const elementsCenterY = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_44__.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_52__.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.canDeviceFitSidebar && _jotai__WEBPACK_IMPORTED_MODULE_56__.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\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.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_34__.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 = () => {\n this.setState(prevState => {\n return {\n penMode: !prevState.penMode\n };\n });\n };\n\n this.onHandToolToggle = () => {\n this.actionManager.executeAction(_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_55__.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_32__.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_30__.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_55__.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_30__.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_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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_44__.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_44__.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_33__.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.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_30__.hasBackground)(this.state.activeTool.type) || selectedElements.some(element => (0,_scene__WEBPACK_IMPORTED_MODULE_30__.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[_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_56__.jotaiStore.set(_ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_57__.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_34__.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_34__.withBatchedUpdates)(event => {\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE) {\n if (this.state.viewModeEnabled) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (this.state.activeTool.type === \"selection\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursorForShape)(this.interactiveCanvas, this.state);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_52__.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 });\n\n this.setActiveTool = tool => {\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.updateActiveTool)(this.state, tool);\n\n if (nextActiveTool.type === \"hand\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (!isHoldingSpace) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_34__.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 }\n\n if (nextActiveTool.type !== \"selection\") {\n this.setState(prevState => ({\n activeTool: nextActiveTool,\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_52__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n snapLines: [],\n originSnapOffset: null\n }));\n } else {\n this.setState({\n activeTool: nextActiveTool,\n snapLines: [],\n originSnapOffset: null,\n activeEmbeddable: null\n });\n }\n };\n\n this.setCursor = cursor => {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, cursor);\n };\n\n this.resetCursor = () => {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_52__.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_34__.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_32__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_30__.getNormalizedZoom)(initialScale * event.scale)\n }, state)));\n }\n }); // fires only on Safari\n\n this.onGestureEnd = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_44__.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_44__.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_44__.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_44__.getApproxMinLineWidth)((0,_utils__WEBPACK_IMPORTED_MODULE_34__.getFontString)(fontString), lineHeight);\n const minHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_44__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n let {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_44__.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_34__.isTransparent)(container.backgroundColor) || (0,_element_collision__WEBPACK_IMPORTED_MODULE_45__.isHittingElementNotConsideringBoundingBox)(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY])) {\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_44__.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_46__.isPointHittingLink)(element, this.state, [scenePointer.x, scenePointer.y], this.device.isMobile);\n });\n };\n\n this.redirectToLink = (event, isTouchScreen) => {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDown.clientX, this.lastPointerDown.clientY, this.lastPointerUp.clientX, this.lastPointerUp.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_34__.viewportCoordsToSceneCoords)(this.lastPointerDown, this.state);\n const lastPointerDownHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerDownCoords.x, lastPointerDownCoords.y], this.device.isMobile);\n const lastPointerUpCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)(this.lastPointerUp, this.state);\n const lastPointerUpHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerUpCoords.x, lastPointerUpCoords.y], this.device.isMobile);\n\n if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {\n let url = this.hitLinkElement.link;\n\n if (url) {\n url = (0,_data_url__WEBPACK_IMPORTED_MODULE_47__.normalizeLink)(url);\n let customEvent;\n\n if (this.props.onLinkOpen) {\n customEvent = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_47__.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_51__.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_30__.getNormalizedZoom)(initialScale * scaleFactor) : this.state.zoom.value;\n this.setState(state => {\n const zoomState = (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_32__.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_30__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.showHyperlinkTooltip)(this.hitLinkElement, this.state);\n } else {\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (isOverScrollBar) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_34__.updateObject)(this.device, {\n isTouchScreen: true\n });\n }\n\n if (isPanning) {\n return;\n }\n\n this.lastPointerDown = event;\n this.setState({\n lastPointerDownWith: event.pointerType,\n cursorButton: \"down\"\n });\n this.savePointer(event.clientX, event.clientY, \"down\");\n\n if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) {\n return;\n } // only handle left mouse button or touch\n\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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.viewportCoordsToSceneCoords)(event, this.state);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(pendingImageElement, {\n x,\n y\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 if (this.state.activeTool.customType === \"comment\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursorForShape)(this.interactiveCanvas, this.state);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n } else if (this.state.activeTool.type === \"frame\") {\n this.createFrameElementOnPointerDown(pointerDownState);\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) {\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.lastPointerUp = event;\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)({\n clientX: event.clientX,\n clientY: event.clientY\n }, this.state);\n const clicklength = event.timeStamp - ((_b = (_a = this.lastPointerDown) === null || _a === void 0 ? void 0 : _a.timeStamp) !== null && _b !== void 0 ? _b : 0);\n\n if (this.device.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_46__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_34__.withBatchedUpdates)(lastPointerUp = () => {\n lastPointerUp = null;\n isPanning = false;\n\n if (!isHoldingSpace) {\n if (this.state.viewModeEnabled) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_34__.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_52__.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_52__.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_51__.getFrameElements)(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_44__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n\n if (!this.state.activeTool.locked) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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.lastPointerDown) === 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_35__.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 }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDown) === 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 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_52__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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.lastPointerDown) === 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.lastPointerDown) === 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 _f, _g, _h, _j; // 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_40__.isSupportedImageFile)(imageFile)) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.unsupportedFileType\"));\n }\n\n const mimeType = imageFile.type;\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_40__.SVGStringToFile)(yield (0,_element_image__WEBPACK_IMPORTED_MODULE_41__.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 ((_g = (_f = this.props).generateIdForFile) === null || _g === void 0 ? void 0 : _g.call(_f, imageFile)) || (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.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_40__.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 = (_h = this.files[fileId]) === null || _h === void 0 ? void 0 : _h.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_40__.dataURLToFile)(dataURL);\n this.setImagePreviewCursor(resizedFile || imageFile);\n }\n\n const dataURL = ((_j = this.files[fileId]) === null || _j === void 0 ? void 0 : _j.dataURL) || (yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.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 _k;\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 && ((_k = this.state.draggingElement) === null || _k === void 0 ? void 0 : _k.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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 this.scene.addNewElement(imageElement);\n\n try {\n 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 }\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_40__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: cursorImageSizePx\n });\n let previewDataURL = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.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_41__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, `url(${previewDataURL}) 4 4, auto`);\n }\n });\n\n this.onImageAction = ({\n insertOnCanvasDirectly\n } = {\n insertOnCanvasDirectly: false\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_34__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const imageFile = yield (0,_data_filesystem__WEBPACK_IMPORTED_MODULE_43__.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 });\n\n if (insertOnCanvasDirectly) {\n this.insertImageElement(imageElement, imageFile);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_52__.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_34__.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_41__.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_41__.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_42___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 _l, _m, _o, _p; // must be retrieved first, in the same frame\n\n\n const {\n file,\n fileHandle\n } = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.getFileFromEvent)(event);\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)(event, this.state);\n\n try {\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.isSupportedImageFile)(file)) {\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_52__.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_40__.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 ((_m = (_l = event.dataTransfer) === null || _l === void 0 ? void 0 : _l.types) === null || _m === void 0 ? void 0 : _m.includes(\"text/plain\")) {\n const text = (_o = event.dataTransfer) === null || _o === void 0 ? void 0 : _o.getData(\"text\");\n\n if (text && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.embeddableURLValidator)(text, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(text) || ((_p = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.getEmbedLink)(text)) === null || _p === void 0 ? void 0 : _p.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_47__.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_40__.normalizeFile)(file);\n\n try {\n const ret = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.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 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_34__.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_34__.distance)(pointerDownState.origin.x, pointerCoords.x), (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.distance)(pointerDownState.originInGrid.x, gridX), (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_51__.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_51__.getFrameElements)(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_30__.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_51__.getFrameElements)(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_51__.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_39__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n }\n\n return [_actions_actionClipboard__WEBPACK_IMPORTED_MODULE_53__.actionPaste, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSelectAll, _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_49__.actionUnlockAllElements, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_39__.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_53__.actionPaste, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_54__.actionSelectAllElementsInFrame, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_54__.actionRemoveAllElementsFromFrame, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.CONTEXT_MENU_SEPARATOR, ...options, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyStyles, _actions__WEBPACK_IMPORTED_MODULE_5__.actionPasteStyles, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionAddToLibrary, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipHorizontal, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipVertical, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDeleteSelected];\n };\n\n this.handleWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_32__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_30__.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 pointer = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)({\n clientX: x,\n clientY: y\n }, this.state);\n\n if (isNaN(pointer.x) || isNaN(pointer.y)) {// sometimes the pointer goes off screen\n }\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_34__.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 excalidrawRef,\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_68__.nanoid)();\n this.library = new _data_library__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this);\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_31__[\"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 (excalidrawRef) {\n const readyPromise = \"current\" in excalidrawRef && ((_a = excalidrawRef.current) === null || _a === void 0 ? void 0 : _a.readyPromise) || (0,_utils__WEBPACK_IMPORTED_MODULE_34__.resolvablePromise)();\n const api = {\n ready: true,\n readyPromise,\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 app: this,\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 excalidrawRef === \"function\") {\n excalidrawRef(api);\n } else {\n excalidrawRef.current = api;\n }\n\n readyPromise.resolve(api);\n }\n\n this.excalidrawContainerValue = {\n container: this.excalidrawContainerRef.current,\n id: this.id\n };\n this.fonts = new _scene_Fonts__WEBPACK_IMPORTED_MODULE_50__.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_34__.sceneCoordsToViewportCoords)({\n sceneX: el.x,\n sceneY: el.y\n }, this.state);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.getEmbedLink)((0,_data_url__WEBPACK_IMPORTED_MODULE_47__.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 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--zen-mode\": this.state.zenModeEnabled,\n \"excalidraw--mobile\": this.device.isMobile\n }),\n style: {\n [\"--ui-pointerEvents\"]: this.state.selectionElement || this.state.draggingElement || this.state.resizingElement || this.state.editingElement && !(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? _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__.jsx)(_LayerUI__WEBPACK_IMPORTED_MODULE_37__[\"default\"], Object.assign({\n onHomeButtonClick: this.props.onHomeButtonClick || (() => {}),\n canvas: this.canvas,\n interactiveCanvas: this.interactiveCanvas,\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 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 onImageAction: this.onImageAction,\n renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === \"selection\" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,\n app: this,\n renderTopRightUI: renderTopRightUI\n }, {\n children: this.props.children\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 }), selectedElements.length === 1 && !this.state.contextMenu && this.state.showHyperlinkPopup && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.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_38__.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_36__.ContextMenu, {\n items: this.state.contextMenu.items,\n top: this.state.contextMenu.top,\n left: this.state.contextMenu.left,\n actionManager: this.actionManager\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 canvasBackgroundColor: this.state.viewBackgroundColor\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, _b;\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 (this.excalidrawContainerRef.current && // 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_34__.isTestEnv)()) {\n this.refreshDeviceState(this.excalidrawContainerRef.current);\n }\n\n if (\"ResizeObserver\" in window && ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current)) {\n this.resizeObserver = new ResizeObserver(() => {\n // recompute device dimensions state\n // ---------------------------------------------------------------------\n this.refreshDeviceState(this.excalidrawContainerRef.current); // refresh offsets\n // ---------------------------------------------------------------------\n\n this.updateDOMRect();\n });\n (_b = this.resizeObserver) === null || _b === void 0 ? void 0 : _b.observe(this.excalidrawContainerRef.current);\n } else if (window.matchMedia) {\n const mdScreenQuery = window.matchMedia(`(max-width: ${_constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_PORTRAIT}px), (max-height: ${_constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_HEIGHT_LANDSCAPE}px) and (max-width: ${_constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_LANDSCAPE}px)`);\n const smScreenQuery = window.matchMedia(`(max-width: ${_constants__WEBPACK_IMPORTED_MODULE_12__.MQ_SM_MAX_WIDTH}px)`);\n const canDeviceFitSidebarMediaQuery = window.matchMedia(`(min-width: ${// NOTE this won't update if a different breakpoint is supplied\n // after mount\n this.props.UIOptions.dockedSidebarBreakpoint != null ? this.props.UIOptions.dockedSidebarBreakpoint : _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_RIGHT_SIDEBAR_MIN_WIDTH}px)`);\n\n const handler = () => {\n this.excalidrawContainerRef.current.getBoundingClientRect();\n this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.updateObject)(this.device, {\n isSmScreen: smScreenQuery.matches,\n isMobile: mdScreenQuery.matches,\n canDeviceFitSidebar: canDeviceFitSidebarMediaQuery.matches\n });\n };\n\n mdScreenQuery.addListener(handler);\n\n this.detachIsMobileMqHandler = () => mdScreenQuery.removeListener(handler);\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_44__.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_31__[\"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 _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache.destroy();\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.destroy();\n (0,_renderer_renderElement__WEBPACK_IMPORTED_MODULE_29__.clearRenderCache)();\n this.onChangeEmitter.destroy();\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_31__[\"default\"]();\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.library = new _data_library__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this); // @ts-ignore\n\n this.canvas = null;\n this.interactiveCanvas = null; // @ts-ignore\n\n this.rc = null; // @ts-ignore\n\n this.excalidrawContainerRef.current = undefined;\n this.nearestScrollableContainer = undefined;\n this.excalidrawContainerValue = {\n container: null,\n id: \"unmounted\"\n };\n _scene__WEBPACK_IMPORTED_MODULE_30__.isSomeElementSelected.clearCache();\n _groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements.clearCache();\n touchTimeout = 0;\n }\n\n removeEventListeners() {\n var _a, _b, _c, _d, _e, _f, _g;\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 (_f = (_e = document.fonts) === null || _e === void 0 ? void 0 : _e.removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_e, \"loadingdone\", this.onFontsLoadingDone);\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 (_g = this.detachIsMobileMqHandler) === null || _g === void 0 ? void 0 : _g.call(this);\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\", this.onFontsLoadingDone); // 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_34__.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 (this.excalidrawContainerRef.current && prevProps.UIOptions.dockedSidebarBreakpoint !== this.props.UIOptions.dockedSidebarBreakpoint) {\n this.refreshDeviceState(this.excalidrawContainerRef.current);\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_34__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n\n if (this.state.activeTool.type === \"eraser\" && prevState.theme !== this.state.theme) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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.UIOptions.canvasActions && this.state.openMenu === \"canvas\") {\n this.setState({\n openMenu: 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_34__.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, this.props.id);\n this.onChangeEmitter.trigger(this.scene.getElementsIncludingDeleted(), this.state, this.files);\n }\n }\n\n static resetTapTwice() {\n didTapTwice = false;\n }\n\n addTextFromPaste(text, isPlainPaste = false) {\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_44__.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_44__.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_52__.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.isMobile) {\n this.setToast({\n message: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"toast.pasteAsSingleElement\", {\n shortcut: (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_34__.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_34__.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_52__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_30__.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_51__.getContainingFrame)(element);\n return containingFrame && this.state.frameRendering.enabled && this.state.frameRendering.clip ? (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_44__.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_45__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n } else if ((0,_element_transformHandles__WEBPACK_IMPORTED_MODULE_48__.shouldShowBoundingBox)([element], this.state) && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_34__.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_30__.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_34__.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_34__.withBatchedUpdates)(() => {\n isDraggingScrollBar = false;\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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 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_30__.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_44__.bindTextToShapeAfterDuplication)(nextElements, elementsToAppend, oldIdToDuplicatedId);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, \"duplicatesServeAsOld\");\n (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_30__.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_30__.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_34__.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 });\n this.onPointerUpEmitter.trigger(this.state.activeTool, pointerDownState, childEvent); // 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 if ((draggingElement === null || draggingElement === void 0 ? void 0 : draggingElement.type) === \"freedraw\") {\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n this.setState(prevState => ({\n draggingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_34__.updateActiveTool)(this.state, {\n type: \"selection\"\n }),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_52__.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().slice(0, -1));\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_34__.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_51__.getContainingFrame)(linearElement);\n\n if (frame && linearElement) {\n if (!(0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_51__.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_51__.isElementInFrame)(element, nextElements, this.state));\n\n if (this.state.editingGroupId) {\n updateGroupIdsAfterEditingGroup(elementsToAdd);\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_51__.isElementInFrame)(element, nextElements, this.state));\n updateGroupIdsAfterEditingGroup(elementsToRemove);\n }\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_51__.getElementsInNewFrame)(this.scene.getElementsIncludingDeleted(), draggingElement);\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_51__.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_51__.replaceAllElementsInFrame)(nextElements, (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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.lastPointerDown.clientX, this.lastPointerDown.clientY, this.lastPointerUp.clientX, this.lastPointerUp.clientY);\n\n if (draggedDistance === 0) {\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)({\n clientX: this.lastPointerUp.clientX,\n clientY: this.lastPointerUp.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_52__.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_30__.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_52__.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_52__.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_52__.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_30__.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.locked && activeTool.type !== \"freedraw\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n this.setState({\n draggingElement: null,\n suggestedBindings: [],\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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.lastPointerUp && this.lastPointerDown && this.lastPointerUp.timeStamp - this.lastPointerDown.timeStamp < 300 && gesture.pointers.size <= 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, this.lastPointerUp, 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_52__.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_52__.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_44__.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_34__.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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O0FBRUE7QUFDQTs7QUFFQTtBQUNBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsR0FBRztBQUNIOztBQUVBLGlFQUFlLEdBQUciLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vY29tcG9uZW50cy9BcHAudHN4PzA2MjQiXSwic291cmNlc0NvbnRlbnQiOlsidmFyIF9fYXdhaXRlciA9IHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xuICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7XG4gICAgICByZXNvbHZlKHZhbHVlKTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZWplY3QoZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7XG4gICAgICByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTtcbiAgICB9XG5cbiAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XG4gIH0pO1xufTtcblxuaW1wb3J0IHsganN4IGFzIF9qc3gsIGpzeHMgYXMgX2pzeHMsIEZyYWdtZW50IGFzIF9GcmFnbWVudCB9IGZyb20gXCJyZWFjdC9qc3gtcnVudGltZVwiO1xuaW1wb3J0IFJlYWN0LCB7IHVzZUNvbnRleHQgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCB7IGZsdXNoU3luYyB9IGZyb20gXCJyZWFjdC1kb21cIjtcbmltcG9ydCByb3VnaCBmcm9tIFwicm91Z2hqcy9iaW4vcm91Z2hcIjtcbmltcG9ydCBjbHN4IGZyb20gXCJjbHN4XCI7XG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tIFwibmFub2lkXCI7XG5pbXBvcnQgeyBhY3Rpb25BZGRUb0xpYnJhcnksIGFjdGlvbkJyaW5nRm9yd2FyZCwgYWN0aW9uQnJpbmdUb0Zyb250LCBhY3Rpb25Db3B5LCBhY3Rpb25Db3B5QXNQbmcsIGFjdGlvbkNvcHlBc1N2ZywgY29weVRleHQsIGFjdGlvbkNvcHlTdHlsZXMsIGFjdGlvbkN1dCwgYWN0aW9uRGVsZXRlU2VsZWN0ZWQsIGFjdGlvbkR1cGxpY2F0ZVNlbGVjdGlvbiwgYWN0aW9uRmluYWxpemUsIGFjdGlvbkZsaXBIb3Jpem9udGFsLCBhY3Rpb25GbGlwVmVydGljYWwsIGFjdGlvbkdyb3VwLCBhY3Rpb25QYXN0ZVN0eWxlcywgYWN0aW9uU2VsZWN0QWxsLCBhY3Rpb25TZW5kQmFja3dhcmQsIGFjdGlvblNlbmRUb0JhY2ssIGFjdGlvblRvZ2dsZUdyaWRNb2RlLCBhY3Rpb25Ub2dnbGVTdGF0cywgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVW5iaW5kVGV4dCwgYWN0aW9uQmluZFRleHQsIGFjdGlvblVuZ3JvdXAsIGFjdGlvbkxpbmssIGFjdGlvblRvZ2dsZUVsZW1lbnRMb2NrLCBhY3Rpb25Ub2dnbGVMaW5lYXJFZGl0b3IsIGFjdGlvblRvZ2dsZU9iamVjdHNTbmFwTW9kZSB9IGZyb20gXCIuLi9hY3Rpb25zXCI7XG5pbXBvcnQgeyBjcmVhdGVSZWRvQWN0aW9uLCBjcmVhdGVVbmRvQWN0aW9uIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uSGlzdG9yeVwiO1xuaW1wb3J0IHsgQWN0aW9uTWFuYWdlciB9IGZyb20gXCIuLi9hY3Rpb25zL21hbmFnZXJcIjtcbmltcG9ydCB7IGFjdGlvbnMgfSBmcm9tIFwiLi4vYWN0aW9ucy9yZWdpc3RlclwiO1xuaW1wb3J0IHsgdHJhY2tFdmVudCB9IGZyb20gXCIuLi9hbmFseXRpY3NcIjtcbmltcG9ydCB7IGdldERlZmF1bHRBcHBTdGF0ZSwgaXNFcmFzZXJBY3RpdmUsIGlzSGFuZFRvb2xBY3RpdmUgfSBmcm9tIFwiLi4vYXBwU3RhdGVcIjtcbmltcG9ydCB7IHBhcnNlQ2xpcGJvYXJkIH0gZnJvbSBcIi4uL2NsaXBib2FyZFwiO1xuaW1wb3J0IHsgQVBQX05BTUUsIENVUlNPUl9UWVBFLCBERUZBVUxUX01BWF9JTUFHRV9XSURUSF9PUl9IRUlHSFQsIERFRkFVTFRfVUlfT1BUSU9OUywgREVGQVVMVF9WRVJUSUNBTF9BTElHTiwgRFJBR0dJTkdfVEhSRVNIT0xELCBFTEVNRU5UX1JFQURZX1RPX0VSQVNFX09QQUNJVFksIEVMRU1FTlRfU0hJRlRfVFJBTlNMQVRFX0FNT1VOVCwgRUxFTUVOVF9UUkFOU0xBVEVfQU1PVU5ULCBFTlYsIEVWRU5ULCBGUkFNRV9TVFlMRSwgR1JJRF9TSVpFLCBJTUFHRV9NSU1FX1RZUEVTLCBJTUFHRV9SRU5ERVJfVElNRU9VVCwgaXNBbmRyb2lkLCBpc0JyYXZlLCBMSU5FX0NPTkZJUk1fVEhSRVNIT0xELCBNQVhfQUxMT1dFRF9GSUxFX0JZVEVTLCBNSU1FX1RZUEVTLCBNUV9NQVhfSEVJR0hUX0xBTkRTQ0FQRSwgTVFfTUFYX1dJRFRIX0xBTkRTQ0FQRSwgTVFfTUFYX1dJRFRIX1BPUlRSQUlULCBNUV9SSUdIVF9TSURFQkFSX01JTl9XSURUSCwgTVFfU01fTUFYX1dJRFRILCBQT0lOVEVSX0JVVFRPTiwgUk9VTkRORVNTLCBTQ1JPTExfVElNRU9VVCwgVEFQX1RXSUNFX1RJTUVPVVQsIFRFWFRfVE9fQ0VOVEVSX1NOQVBfVEhSRVNIT0xELCBUSEVNRSwgVEhFTUVfRklMVEVSLCBUT1VDSF9DVFhfTUVOVV9USU1FT1VULCBWRVJUSUNBTF9BTElHTiwgWU9VVFVCRV9TVEFURVMsIFpPT01fU1RFUCwgUE9JTlRFUl9FVkVOVFMgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBleHBvcnRBc0ltYWdlLCBsb2FkRnJvbUJsb2IgfSBmcm9tIFwiLi4vZGF0YVwiO1xuaW1wb3J0IExpYnJhcnksIHsgZGlzdHJpYnV0ZUxpYnJhcnlJdGVtc09uU3F1YXJlR3JpZCB9IGZyb20gXCIuLi9kYXRhL2xpYnJhcnlcIjtcbmltcG9ydCB7IHJlc3RvcmUsIHJlc3RvcmVFbGVtZW50cyB9IGZyb20gXCIuLi9kYXRhL3Jlc3RvcmVcIjtcbmltcG9ydCB7IGRyYWdOZXdFbGVtZW50LCBkcmFnU2VsZWN0ZWRFbGVtZW50cywgZHVwbGljYXRlRWxlbWVudCwgZ2V0Q29tbW9uQm91bmRzLCBnZXRDdXJzb3JGb3JSZXNpemluZ0VsZW1lbnQsIGdldERyYWdPZmZzZXRYWSwgZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLCBnZXROb3JtYWxpemVkRGltZW5zaW9ucywgZ2V0UmVzaXplQXJyb3dEaXJlY3Rpb24sIGdldFJlc2l6ZU9mZnNldFhZLCBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUsIGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzLCBoaXRUZXN0LCBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQsIGlzSW52aXNpYmx5U21hbGxFbGVtZW50LCBpc05vbkRlbGV0ZWRFbGVtZW50LCBpc1RleHRFbGVtZW50LCBuZXdFbGVtZW50LCBuZXdMaW5lYXJFbGVtZW50LCBuZXdUZXh0RWxlbWVudCwgbmV3SW1hZ2VFbGVtZW50LCB0ZXh0V3lzaXd5ZywgdHJhbnNmb3JtRWxlbWVudHMsIHVwZGF0ZVRleHRFbGVtZW50LCByZWRyYXdUZXh0Qm91bmRpbmdCb3ggfSBmcm9tIFwiLi4vZWxlbWVudFwiO1xuaW1wb3J0IHsgYmluZE9yVW5iaW5kTGluZWFyRWxlbWVudCwgYmluZE9yVW5iaW5kU2VsZWN0ZWRFbGVtZW50cywgZml4QmluZGluZ3NBZnRlckRlbGV0aW9uLCBmaXhCaW5kaW5nc0FmdGVyRHVwbGljYXRpb24sIGdldEVsaWdpYmxlRWxlbWVudHNGb3JCaW5kaW5nLCBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcsIGlzQmluZGluZ0VuYWJsZWQsIGlzTGluZWFyRWxlbWVudFNpbXBsZUFuZEFscmVhZHlCb3VuZCwgbWF5YmVCaW5kTGluZWFyRWxlbWVudCwgc2hvdWxkRW5hYmxlQmluZGluZ0ZvclBvaW50ZXJFdmVudCwgdW5iaW5kTGluZWFyRWxlbWVudHMsIHVwZGF0ZUJvdW5kRWxlbWVudHMgfSBmcm9tIFwiLi4vZWxlbWVudC9iaW5kaW5nXCI7XG5pbXBvcnQgeyBMaW5lYXJFbGVtZW50RWRpdG9yIH0gZnJvbSBcIi4uL2VsZW1lbnQvbGluZWFyRWxlbWVudEVkaXRvclwiO1xuaW1wb3J0IHsgbXV0YXRlRWxlbWVudCwgbmV3RWxlbWVudFdpdGggfSBmcm9tIFwiLi4vZWxlbWVudC9tdXRhdGVFbGVtZW50XCI7XG5pbXBvcnQgeyBkZWVwQ29weUVsZW1lbnQsIGR1cGxpY2F0ZUVsZW1lbnRzLCBuZXdGcmFtZUVsZW1lbnQsIG5ld0ZyZWVEcmF3RWxlbWVudCwgbmV3RW1iZWRkYWJsZUVsZW1lbnQgfSBmcm9tIFwiLi4vZWxlbWVudC9uZXdFbGVtZW50XCI7XG5pbXBvcnQgeyBoYXNCb3VuZFRleHRFbGVtZW50LCBpc0Fycm93RWxlbWVudCwgaXNCaW5kaW5nRWxlbWVudCwgaXNCaW5kaW5nRWxlbWVudFR5cGUsIGlzQm91bmRUb0NvbnRhaW5lciwgaXNGcmFtZUVsZW1lbnQsIGlzSW1hZ2VFbGVtZW50LCBpc0VtYmVkZGFibGVFbGVtZW50LCBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50LCBpc0xpbmVhckVsZW1lbnQsIGlzTGluZWFyRWxlbWVudFR5cGUsIGlzVXNpbmdBZGFwdGl2ZVJhZGl1cyB9IGZyb20gXCIuLi9lbGVtZW50L3R5cGVDaGVja3NcIjtcbmltcG9ydCB7IGdldENlbnRlciwgZ2V0RGlzdGFuY2UgfSBmcm9tIFwiLi4vZ2VzdHVyZVwiO1xuaW1wb3J0IHsgZWRpdEdyb3VwRm9yU2VsZWN0ZWRFbGVtZW50LCBnZXRFbGVtZW50c0luR3JvdXAsIGdldFNlbGVjdGVkR3JvdXBJZEZvckVsZW1lbnQsIGdldFNlbGVjdGVkR3JvdXBJZHMsIGlzRWxlbWVudEluR3JvdXAsIGlzU2VsZWN0ZWRWaWFHcm91cCwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyB9IGZyb20gXCIuLi9ncm91cHNcIjtcbmltcG9ydCBIaXN0b3J5IGZyb20gXCIuLi9oaXN0b3J5XCI7XG5pbXBvcnQgeyBkZWZhdWx0TGFuZywgZ2V0TGFuZ3VhZ2UsIGxhbmd1YWdlcywgc2V0TGFuZ3VhZ2UsIHQgfSBmcm9tIFwiLi4vaTE4blwiO1xuaW1wb3J0IHsgQ09ERVMsIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIsIHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8sIHNob3VsZFJvdGF0ZVdpdGhEaXNjcmV0ZUFuZ2xlLCBpc0Fycm93S2V5LCBLRVlTIH0gZnJvbSBcIi4uL2tleXNcIjtcbmltcG9ydCB7IGlzRWxlbWVudEluVmlld3BvcnQgfSBmcm9tIFwiLi4vZWxlbWVudC9zaXplSGVscGVyc1wiO1xuaW1wb3J0IHsgZGlzdGFuY2UyZCwgZ2V0Q29ybmVyUmFkaXVzLCBnZXRHcmlkUG9pbnQsIGlzUGF0aEFMb29wIH0gZnJvbSBcIi4uL21hdGhcIjtcbmltcG9ydCB7IGNsZWFyUmVuZGVyQ2FjaGUgfSBmcm9tIFwiLi4vcmVuZGVyZXIvcmVuZGVyRWxlbWVudFwiO1xuaW1wb3J0IHsgY2FsY3VsYXRlU2Nyb2xsQ2VudGVyLCBnZXRFbGVtZW50c0F0UG9zaXRpb24sIGdldEVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLCBnZXROb3JtYWxpemVkWm9vbSwgZ2V0U2VsZWN0ZWRFbGVtZW50cywgaGFzQmFja2dyb3VuZCwgaXNPdmVyU2Nyb2xsQmFycywgaXNTb21lRWxlbWVudFNlbGVjdGVkIH0gZnJvbSBcIi4uL3NjZW5lXCI7XG5pbXBvcnQgU2NlbmUgZnJvbSBcIi4uL3NjZW5lL1NjZW5lXCI7XG5pbXBvcnQgeyBnZXRTdGF0ZUZvclpvb20gfSBmcm9tIFwiLi4vc2NlbmUvem9vbVwiO1xuaW1wb3J0IHsgZmluZFNoYXBlQnlLZXkgfSBmcm9tIFwiLi4vc2hhcGVzXCI7XG5pbXBvcnQgeyBkZWJvdW5jZSwgZGlzdGFuY2UsIGdldEZvbnRTdHJpbmcsIGdldE5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyLCBpc0lucHV0TGlrZSwgaXNUb29sSWNvbiwgaXNXcml0YWJsZUVsZW1lbnQsIHJlc2V0Q3Vyc29yLCByZXNvbHZhYmxlUHJvbWlzZSwgc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzLCBzZXRDdXJzb3IsIHNldEN1cnNvckZvclNoYXBlLCB0dXBsZVRvQ29vcnMsIHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcywgd2l0aEJhdGNoZWRVcGRhdGVzLCB3cmFwRXZlbnQsIHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZCwgdXBkYXRlT2JqZWN0LCBzZXRFcmFzZXJDdXJzb3IsIHVwZGF0ZUFjdGl2ZVRvb2wsIGdldFNob3J0Y3V0S2V5LCBpc1RyYW5zcGFyZW50LCBlYXNlVG9WYWx1ZXNSQUYsIG11dGVGU0Fib3J0RXJyb3IsIGlzVGVzdEVudiwgZWFzZU91dCB9IGZyb20gXCIuLi91dGlsc1wiO1xuaW1wb3J0IHsgZW1iZWRkYWJsZVVSTFZhbGlkYXRvciwgZXh0cmFjdFNyYywgZ2V0RW1iZWRMaW5rIH0gZnJvbSBcIi4uL2VsZW1lbnQvZW1iZWRkYWJsZVwiO1xuaW1wb3J0IHsgQ29udGV4dE1lbnUsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IgfSBmcm9tIFwiLi9Db250ZXh0TWVudVwiO1xuaW1wb3J0IExheWVyVUkgZnJvbSBcIi4vTGF5ZXJVSVwiO1xuaW1wb3J0IHsgVG9hc3QgfSBmcm9tIFwiLi9Ub2FzdFwiO1xuaW1wb3J0IHsgYWN0aW9uVG9nZ2xlVmlld01vZGUgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25Ub2dnbGVWaWV3TW9kZVwiO1xuaW1wb3J0IHsgZGF0YVVSTFRvRmlsZSwgZ2VuZXJhdGVJZEZyb21GaWxlLCBnZXREYXRhVVJMLCBnZXRGaWxlRnJvbUV2ZW50LCBpc0ltYWdlRmlsZUhhbmRsZSwgaXNTdXBwb3J0ZWRJbWFnZUZpbGUsIGxvYWRTY2VuZU9yTGlicmFyeUZyb21CbG9iLCBub3JtYWxpemVGaWxlLCBwYXJzZUxpYnJhcnlKU09OLCByZXNpemVJbWFnZUZpbGUsIFNWR1N0cmluZ1RvRmlsZSB9IGZyb20gXCIuLi9kYXRhL2Jsb2JcIjtcbmltcG9ydCB7IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cywgbG9hZEhUTUxJbWFnZUVsZW1lbnQsIG5vcm1hbGl6ZVNWRywgdXBkYXRlSW1hZ2VDYWNoZSBhcyBfdXBkYXRlSW1hZ2VDYWNoZSB9IGZyb20gXCIuLi9lbGVtZW50L2ltYWdlXCI7XG5pbXBvcnQgdGhyb3R0bGUgZnJvbSBcImxvZGFzaC50aHJvdHRsZVwiO1xuaW1wb3J0IHsgZmlsZU9wZW4gfSBmcm9tIFwiLi4vZGF0YS9maWxlc3lzdGVtXCI7XG5pbXBvcnQgeyBiaW5kVGV4dFRvU2hhcGVBZnRlckR1cGxpY2F0aW9uLCBnZXRBcHByb3hNaW5MaW5lSGVpZ2h0LCBnZXRBcHByb3hNaW5MaW5lV2lkdGgsIGdldEJvdW5kVGV4dEVsZW1lbnQsIGdldENvbnRhaW5lckNlbnRlciwgZ2V0Q29udGFpbmVyRWxlbWVudCwgZ2V0RGVmYXVsdExpbmVIZWlnaHQsIGdldExpbmVIZWlnaHRJblB4LCBnZXRUZXh0QmluZGFibGVDb250YWluZXJBdFBvc2l0aW9uLCBpc01lYXN1cmVUZXh0U3VwcG9ydGVkLCBpc1ZhbGlkVGV4dENvbnRhaW5lciB9IGZyb20gXCIuLi9lbGVtZW50L3RleHRFbGVtZW50XCI7XG5pbXBvcnQgeyBpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveCB9IGZyb20gXCIuLi9lbGVtZW50L2NvbGxpc2lvblwiO1xuaW1wb3J0IHsgc2hvd0h5cGVybGlua1Rvb2x0aXAsIGhpZGVIeXBlcmxpbmtUb29saXAsIEh5cGVybGluaywgaXNQb2ludEhpdHRpbmdMaW5rLCBpc1BvaW50SGl0dGluZ0xpbmtJY29uIH0gZnJvbSBcIi4uL2VsZW1lbnQvSHlwZXJsaW5rXCI7XG5pbXBvcnQgeyBpc0xvY2FsTGluaywgbm9ybWFsaXplTGluaywgdG9WYWxpZFVSTCB9IGZyb20gXCIuLi9kYXRhL3VybFwiO1xuaW1wb3J0IHsgc2hvdWxkU2hvd0JvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnQvdHJhbnNmb3JtSGFuZGxlc1wiO1xuaW1wb3J0IHsgYWN0aW9uVW5sb2NrQWxsRWxlbWVudHMgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25FbGVtZW50TG9ja1wiO1xuaW1wb3J0IHsgRm9udHMgfSBmcm9tIFwiLi4vc2NlbmUvRm9udHNcIjtcbmltcG9ydCB7IGdldEZyYW1lRWxlbWVudHMsIGlzQ3Vyc29ySW5GcmFtZSwgYmluZEVsZW1lbnRzVG9GcmFtZXNBZnRlckR1cGxpY2F0aW9uLCBhZGRFbGVtZW50c1RvRnJhbWUsIHJlcGxhY2VBbGxFbGVtZW50c0luRnJhbWUsIHJlbW92ZUVsZW1lbnRzRnJvbUZyYW1lLCBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSwgZ2V0RWxlbWVudHNJbk5ld0ZyYW1lLCBnZXRDb250YWluaW5nRnJhbWUsIGVsZW1lbnRPdmVybGFwc1dpdGhGcmFtZSwgdXBkYXRlRnJhbWVNZW1iZXJzaGlwT2ZTZWxlY3RlZEVsZW1lbnRzLCBpc0VsZW1lbnRJbkZyYW1lIH0gZnJvbSBcIi4uL2ZyYW1lXCI7XG5pbXBvcnQgeyBleGNsdWRlRWxlbWVudHNJbkZyYW1lc0Zyb21TZWxlY3Rpb24sIG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzIH0gZnJvbSBcIi4uL3NjZW5lL3NlbGVjdGlvblwiO1xuaW1wb3J0IHsgYWN0aW9uUGFzdGUgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25DbGlwYm9hcmRcIjtcbmltcG9ydCB7IGFjdGlvblJlbW92ZUFsbEVsZW1lbnRzRnJvbUZyYW1lLCBhY3Rpb25TZWxlY3RBbGxFbGVtZW50c0luRnJhbWUgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25GcmFtZVwiO1xuaW1wb3J0IHsgYWN0aW9uVG9nZ2xlSGFuZFRvb2wsIHpvb21Ub0ZpdCB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkNhbnZhc1wiO1xuaW1wb3J0IHsgam90YWlTdG9yZSB9IGZyb20gXCIuLi9qb3RhaVwiO1xuaW1wb3J0IHsgYWN0aXZlQ29uZmlybURpYWxvZ0F0b20gfSBmcm9tIFwiLi9BY3RpdmVDb25maXJtRGlhbG9nXCI7XG5pbXBvcnQgeyBnZXRTbmFwTGluZXNBdFBvaW50ZXIsIHNuYXBEcmFnZ2VkRWxlbWVudHMsIGlzQWN0aXZlVG9vbE5vbkxpbmVhclNuYXBwYWJsZSwgc25hcE5ld0VsZW1lbnQsIHNuYXBSZXNpemluZ0VsZW1lbnRzLCBpc1NuYXBwaW5nRW5hYmxlZCwgZ2V0VmlzaWJsZUdhcHMsIGdldFJlZmVyZW5jZVNuYXBQb2ludHMsIFNuYXBDYWNoZSB9IGZyb20gXCIuLi9zbmFwcGluZ1wiO1xuaW1wb3J0IHsgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkJvdW5kVGV4dFwiO1xuaW1wb3J0IEJyYXZlTWVhc3VyZVRleHRFcnJvciBmcm9tIFwiLi9CcmF2ZU1lYXN1cmVUZXh0RXJyb3JcIjtcbmltcG9ydCB7IGFjdGl2ZUV5ZURyb3BwZXJBdG9tIH0gZnJvbSBcIi4vRXllRHJvcHBlclwiO1xuaW1wb3J0IHsgY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzIH0gZnJvbSBcIi4uL2RhdGEvdHJhbnNmb3JtXCI7XG5pbXBvcnQgeyBpc1NpZGViYXJEb2NrZWRBdG9tIH0gZnJvbSBcIi4vU2lkZWJhci9TaWRlYmFyXCI7XG5pbXBvcnQgeyBTdGF0aWNDYW52YXMsIEludGVyYWN0aXZlQ2FudmFzIH0gZnJvbSBcIi4vY2FudmFzZXNcIjtcbmltcG9ydCB7IFJlbmRlcmVyIH0gZnJvbSBcIi4uL3NjZW5lL1JlbmRlcmVyXCI7XG5pbXBvcnQgeyBTaGFwZUNhY2hlIH0gZnJvbSBcIi4uL3NjZW5lL1NoYXBlQ2FjaGVcIjtcbmltcG9ydCB7IEVtaXR0ZXIgfSBmcm9tIFwiLi4vZW1pdHRlclwiO1xuY29uc3QgQXBwQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQobnVsbCk7XG5jb25zdCBBcHBQcm9wc0NvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuY29uc3QgZGV2aWNlQ29udGV4dEluaXRpYWxWYWx1ZSA9IHtcbiAgaXNTbVNjcmVlbjogZmFsc2UsXG4gIGlzTW9iaWxlOiBmYWxzZSxcbiAgaXNUb3VjaFNjcmVlbjogZmFsc2UsXG4gIGNhbkRldmljZUZpdFNpZGViYXI6IGZhbHNlLFxuICBpc0xhbmRzY2FwZTogZmFsc2Vcbn07XG5jb25zdCBEZXZpY2VDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChkZXZpY2VDb250ZXh0SW5pdGlhbFZhbHVlKTtcbkRldmljZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkRldmljZUNvbnRleHRcIjtcbmV4cG9ydCBjb25zdCBFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoe1xuICBjb250YWluZXI6IG51bGwsXG4gIGlkOiBudWxsXG59KTtcbkV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoW10pO1xuRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXREZWZhdWx0QXBwU3RhdGUoKSksIHtcbiAgd2lkdGg6IDAsXG4gIGhlaWdodDogMCxcbiAgb2Zmc2V0TGVmdDogMCxcbiAgb2Zmc2V0VG9wOiAwXG59KSk7XG5FeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dCgoKSA9PiB7XG4gIGNvbnNvbGUud2FybihcInVuaXRpYWxpemVkIEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQgY29udGV4dCFcIik7XG59KTtcbkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQobnVsbCk7XG5FeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dFwiO1xuZXhwb3J0IGNvbnN0IHVzZUFwcCA9ICgpID0+IHVzZUNvbnRleHQoQXBwQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlQXBwUHJvcHMgPSAoKSA9PiB1c2VDb250ZXh0KEFwcFByb3BzQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRGV2aWNlID0gKCkgPT4gdXNlQ29udGV4dChEZXZpY2VDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3Q29udGFpbmVyID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0VsZW1lbnRzID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3QXBwU3RhdGUgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdTZXRBcHBTdGF0ZSA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXIgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCk7XG5sZXQgZGlkVGFwVHdpY2UgPSBmYWxzZTtcbmxldCB0YXBwZWRUd2ljZVRpbWVyID0gMDtcbmxldCBpc0hvbGRpbmdTcGFjZSA9IGZhbHNlO1xubGV0IGlzUGFubmluZyA9IGZhbHNlO1xubGV0IGlzRHJhZ2dpbmdTY3JvbGxCYXIgPSBmYWxzZTtcbmxldCBjdXJyZW50U2Nyb2xsQmFycyA9IHtcbiAgaG9yaXpvbnRhbDogbnVsbCxcbiAgdmVydGljYWw6IG51bGxcbn07XG5sZXQgdG91Y2hUaW1lb3V0ID0gMDtcbmxldCBpbnZhbGlkYXRlQ29udGV4dE1lbnUgPSBmYWxzZTtcbi8qKlxuICogTWFwIG9mIHlvdXR1YmUgZW1iZWQgdmlkZW8gc3RhdGVzXG4gKi9cblxuY29uc3QgWU9VVFVCRV9WSURFT19TVEFURVMgPSBuZXcgTWFwKCk7XG5sZXQgSVNfUExBSU5fUEFTVEUgPSBmYWxzZTtcbmxldCBJU19QTEFJTl9QQVNURV9USU1FUiA9IDA7XG5sZXQgUExBSU5fUEFTVEVfVE9BU1RfU0hPV04gPSBmYWxzZTtcbmxldCBsYXN0UG9pbnRlclVwID0gbnVsbDtcbmNvbnN0IGdlc3R1cmUgPSB7XG4gIHBvaW50ZXJzOiBuZXcgTWFwKCksXG4gIGxhc3RDZW50ZXI6IG51bGwsXG4gIGluaXRpYWxEaXN0YW5jZTogbnVsbCxcbiAgaW5pdGlhbFNjYWxlOiBudWxsXG59O1xuXG5jbGFzcyBBcHAgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQge1xuICBjb25zdHJ1Y3Rvcihwcm9wcykge1xuICAgIHZhciBfYTtcblxuICAgIHN1cGVyKHByb3BzKTtcbiAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzID0gbnVsbDtcbiAgICB0aGlzLnVubW91bnRlZCA9IGZhbHNlO1xuICAgIHRoaXMuZGV2aWNlID0gZGV2aWNlQ29udGV4dEluaXRpYWxWYWx1ZTtcbiAgICB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYgPSBSZWFjdC5jcmVhdGVSZWYoKTtcbiAgICB0aGlzLmZpbGVzID0ge307XG4gICAgdGhpcy5pbWFnZUNhY2hlID0gbmV3IE1hcCgpO1xuICAgIHRoaXMuaUZyYW1lUmVmcyA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmxhc3RQb2ludGVyRG93biA9IG51bGw7XG4gICAgdGhpcy5sYXN0UG9pbnRlclVwID0gbnVsbDtcbiAgICB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uID0ge1xuICAgICAgeDogMCxcbiAgICAgIHk6IDBcbiAgICB9O1xuICAgIHRoaXMub25DaGFuZ2VFbWl0dGVyID0gbmV3IEVtaXR0ZXIoKTtcbiAgICB0aGlzLm9uUG9pbnRlckRvd25FbWl0dGVyID0gbmV3IEVtaXR0ZXIoKTtcbiAgICB0aGlzLm9uUG9pbnRlclVwRW1pdHRlciA9IG5ldyBFbWl0dGVyKCk7XG5cbiAgICB0aGlzLnVwZGF0ZUVtYmVkZGFibGVzID0gKCkgPT4ge1xuICAgICAgY29uc3QgZW1iZWRkYWJsZUVsZW1lbnRzID0gbmV3IE1hcCgpO1xuICAgICAgbGV0IHVwZGF0ZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsZW1lbnQgPT4ge1xuICAgICAgICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICAgIGVtYmVkZGFibGVFbGVtZW50cy5zZXQoZWxlbWVudC5pZCwgdHJ1ZSk7XG5cbiAgICAgICAgICBpZiAoZWxlbWVudC52YWxpZGF0ZWQgPT0gbnVsbCkge1xuICAgICAgICAgICAgdXBkYXRlZCA9IHRydWU7XG4gICAgICAgICAgICBjb25zdCB2YWxpZGF0ZWQgPSBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yKGVsZW1lbnQubGluaywgdGhpcy5wcm9wcy52YWxpZGF0ZUVtYmVkZGFibGUpO1xuICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgIHZhbGlkYXRlZFxuICAgICAgICAgICAgfSwgZmFsc2UpO1xuICAgICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSk7XG5cbiAgICAgIGlmICh1cGRhdGVkKSB7XG4gICAgICAgIHRoaXMuc2NlbmUuaW5mb3JtTXV0YXRpb24oKTtcbiAgICAgIH0gLy8gR0NcblxuXG4gICAgICB0aGlzLmlGcmFtZVJlZnMuZm9yRWFjaCgocmVmLCBpZCkgPT4ge1xuICAgICAgICBpZiAoIWVtYmVkZGFibGVFbGVtZW50cy5oYXMoaWQpKSB7XG4gICAgICAgICAgdGhpcy5pRnJhbWVSZWZzLmRlbGV0ZShpZCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLmdldEZyYW1lTmFtZURPTUlkID0gZnJhbWVFbGVtZW50ID0+IHtcbiAgICAgIHJldHVybiBgJHt0aGlzLmlkfS1mcmFtZS1uYW1lLSR7ZnJhbWVFbGVtZW50LmlkfWA7XG4gICAgfTtcblxuICAgIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUgPSB7XG4gICAgICBnZXQ6IGZyYW1lRWxlbWVudCA9PiB7XG4gICAgICAgIGxldCBib3VuZHMgPSB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLl9jYWNoZS5nZXQoZnJhbWVFbGVtZW50LmlkKTtcblxuICAgICAgICBpZiAoIWJvdW5kcyB8fCBib3VuZHMuem9vbSAhPT0gdGhpcy5zdGF0ZS56b29tLnZhbHVlIHx8IGJvdW5kcy52ZXJzaW9uTm9uY2UgIT09IGZyYW1lRWxlbWVudC52ZXJzaW9uTm9uY2UpIHtcbiAgICAgICAgICBjb25zdCBmcmFtZU5hbWVEaXYgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLmdldEZyYW1lTmFtZURPTUlkKGZyYW1lRWxlbWVudCkpO1xuXG4gICAgICAgICAgaWYgKGZyYW1lTmFtZURpdikge1xuICAgICAgICAgICAgY29uc3QgYm94ID0gZnJhbWVOYW1lRGl2LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICAgICAgY29uc3QgYm94U2NlbmVUb3BMZWZ0ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgICAgICAgY2xpZW50WDogYm94LngsXG4gICAgICAgICAgICAgIGNsaWVudFk6IGJveC55XG4gICAgICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICAgIGNvbnN0IGJveFNjZW5lQm90dG9tUmlnaHQgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgICBjbGllbnRYOiBib3gucmlnaHQsXG4gICAgICAgICAgICAgIGNsaWVudFk6IGJveC5ib3R0b21cbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgYm91bmRzID0ge1xuICAgICAgICAgICAgICB4OiBib3hTY2VuZVRvcExlZnQueCxcbiAgICAgICAgICAgICAgeTogYm94U2NlbmVUb3BMZWZ0LnksXG4gICAgICAgICAgICAgIHdpZHRoOiBib3hTY2VuZUJvdHRvbVJpZ2h0LnggLSBib3hTY2VuZVRvcExlZnQueCxcbiAgICAgICAgICAgICAgaGVpZ2h0OiBib3hTY2VuZUJvdHRvbVJpZ2h0LnkgLSBib3hTY2VuZVRvcExlZnQueSxcbiAgICAgICAgICAgICAgYW5nbGU6IDAsXG4gICAgICAgICAgICAgIHpvb206IHRoaXMuc3RhdGUuem9vbS52YWx1ZSxcbiAgICAgICAgICAgICAgdmVyc2lvbk5vbmNlOiBmcmFtZUVsZW1lbnQudmVyc2lvbk5vbmNlXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLl9jYWNoZS5zZXQoZnJhbWVFbGVtZW50LmlkLCBib3VuZHMpO1xuXG4gICAgICAgICAgICByZXR1cm4gYm91bmRzO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGJvdW5kcztcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogQHByaXZhdGVcbiAgICAgICAqL1xuICAgICAgX2NhY2hlOiBuZXcgTWFwKClcbiAgICB9O1xuXG4gICAgdGhpcy5yZW5kZXJGcmFtZU5hbWVzID0gKCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLnN0YXRlLmZyYW1lUmVuZGVyaW5nLmVuYWJsZWQgfHwgIXRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcubmFtZSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaXNEYXJrVGhlbWUgPSB0aGlzLnN0YXRlLnRoZW1lID09PSBcImRhcmtcIjtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRGcmFtZXMoKS5tYXAoKGYsIGluZGV4KSA9PiB7XG4gICAgICAgIGlmICghaXNFbGVtZW50SW5WaWV3cG9ydChmLCB0aGlzLmNhbnZhcy53aWR0aCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLCB0aGlzLmNhbnZhcy5oZWlnaHQgLyB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbywge1xuICAgICAgICAgIG9mZnNldExlZnQ6IHRoaXMuc3RhdGUub2Zmc2V0TGVmdCxcbiAgICAgICAgICBvZmZzZXRUb3A6IHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCxcbiAgICAgICAgICBzY3JvbGxZOiB0aGlzLnN0YXRlLnNjcm9sbFksXG4gICAgICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tXG4gICAgICAgIH0pKSB7XG4gICAgICAgICAgLy8gaWYgZnJhbWUgbm90IHZpc2libGUsIGRvbid0IHJlbmRlciBpdHMgbmFtZVxuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHgxLFxuICAgICAgICAgIHk6IHkxXG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogZi54LFxuICAgICAgICAgIHNjZW5lWTogZi55XG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogeDJcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBmLnggKyBmLndpZHRoLFxuICAgICAgICAgIHNjZW5lWTogZi55ICsgZi5oZWlnaHRcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IEZSQU1FX05BTUVfR0FQID0gMjA7XG4gICAgICAgIGNvbnN0IEZSQU1FX05BTUVfRURJVF9QQURESU5HID0gNjtcblxuICAgICAgICBjb25zdCByZXNldCA9ICgpID0+IHtcbiAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICBpZiAoKChfYSA9IGYubmFtZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRyaW0oKSkgPT09IFwiXCIpIHtcbiAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZiwge1xuICAgICAgICAgICAgICBuYW1lOiBudWxsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIGxldCBmcmFtZU5hbWVKU1g7XG5cbiAgICAgICAgaWYgKGYuaWQgPT09IHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lKSB7XG4gICAgICAgICAgY29uc3QgZnJhbWVOYW1lSW5FZGl0ID0gZi5uYW1lID09IG51bGwgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZTtcbiAgICAgICAgICBmcmFtZU5hbWVKU1ggPSBfanN4KFwiaW5wdXRcIiwge1xuICAgICAgICAgICAgYXV0b0ZvY3VzOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IGZyYW1lTmFtZUluRWRpdCxcbiAgICAgICAgICAgIG9uQ2hhbmdlOiBlID0+IHtcbiAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChmLCB7XG4gICAgICAgICAgICAgICAgbmFtZTogZS50YXJnZXQudmFsdWVcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25CbHVyOiAoKSA9PiByZXNldCgpLFxuICAgICAgICAgICAgb25LZXlEb3duOiBldmVudCA9PiB7XG4gICAgICAgICAgICAgIC8vIGZvciBzb21lIGluZXhwbGljYWJsZSByZWFzb24sIGBvbkJsdXJgIHRyaWdnZXJlZCBvbiBFU0NcbiAgICAgICAgICAgICAgLy8gZG9lcyBub3QgcmVzZXQgYHN0YXRlLmVkaXRpbmdGcmFtZWAgZGVzcGl0ZSBiZWluZyBjYWxsZWQsXG4gICAgICAgICAgICAgIC8vIGFuZCB3ZSBuZWVkIHRvIHJlc2V0IGl0IGhlcmUgYXMgd2VsbFxuICAgICAgICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkVTQ0FQRSB8fCBldmVudC5rZXkgPT09IEtFWVMuRU5URVIpIHtcbiAgICAgICAgICAgICAgICByZXNldCgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgYmFja2dyb3VuZDogdGhpcy5zdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yLFxuICAgICAgICAgICAgICBmaWx0ZXI6IGlzRGFya1RoZW1lID8gVEhFTUVfRklMVEVSIDogXCJub25lXCIsXG4gICAgICAgICAgICAgIHpJbmRleDogMixcbiAgICAgICAgICAgICAgYm9yZGVyOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgZGlzcGxheTogXCJibG9ja1wiLFxuICAgICAgICAgICAgICBwYWRkaW5nOiBgJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weGAsXG4gICAgICAgICAgICAgIGJvcmRlclJhZGl1czogNCxcbiAgICAgICAgICAgICAgYm94U2hhZG93OiBcImluc2V0IDAgMCAwIDFweCB2YXIoLS1jb2xvci1wcmltYXJ5KVwiLFxuICAgICAgICAgICAgICBmb250RmFtaWx5OiBcIkFzc2lzdGFudFwiLFxuICAgICAgICAgICAgICBmb250U2l6ZTogXCIxNHB4XCIsXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogYHRyYW5zbGF0ZVkoLSR7RlJBTUVfTkFNRV9FRElUX1BBRERJTkd9cHgpYCxcbiAgICAgICAgICAgICAgY29sb3I6IFwidmFyKC0tY29sb3ItZ3JheS04MClcIixcbiAgICAgICAgICAgICAgb3ZlcmZsb3c6IFwiaGlkZGVuXCIsXG4gICAgICAgICAgICAgIG1heFdpZHRoOiBgJHtNYXRoLm1pbih4MiAtIHgxIC0gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcsIGRvY3VtZW50LmJvZHkuY2xpZW50V2lkdGggLSB4MSAtIEZSQU1FX05BTUVfRURJVF9QQURESU5HKX1weGBcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzaXplOiBmcmFtZU5hbWVJbkVkaXQubGVuZ3RoICsgMSB8fCAxLFxuICAgICAgICAgICAgZGlyOiBcImF1dG9cIixcbiAgICAgICAgICAgIGF1dG9Db21wbGV0ZTogXCJvZmZcIixcbiAgICAgICAgICAgIGF1dG9DYXBpdGFsaXplOiBcIm9mZlwiLFxuICAgICAgICAgICAgYXV0b0NvcnJlY3Q6IFwib2ZmXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBmcmFtZU5hbWVKU1ggPSBmLm5hbWUgPT0gbnVsbCB8fCBmLm5hbWUudHJpbSgpID09PSBcIlwiID8gYEZyYW1lICR7aW5kZXggKyAxfWAgOiBmLm5hbWUudHJpbSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgaWQ6IHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQoZiksXG4gICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgIHBvc2l0aW9uOiBcImFic29sdXRlXCIsXG4gICAgICAgICAgICB0b3A6IGAke3kxIC0gRlJBTUVfTkFNRV9HQVAgLSB0aGlzLnN0YXRlLm9mZnNldFRvcH1weGAsXG4gICAgICAgICAgICBsZWZ0OiBgJHt4MSAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCAtICh0aGlzLnN0YXRlLmVkaXRpbmdGcmFtZSA9PT0gZi5pZCA/IEZSQU1FX05BTUVfRURJVF9QQURESU5HIDogMCl9cHhgLFxuICAgICAgICAgICAgekluZGV4OiAyLFxuICAgICAgICAgICAgZm9udFNpemU6IFwiMTRweFwiLFxuICAgICAgICAgICAgY29sb3I6IGlzRGFya1RoZW1lID8gXCJ2YXIoLS1jb2xvci1ncmF5LTYwKVwiIDogXCJ2YXIoLS1jb2xvci1ncmF5LTUwKVwiLFxuICAgICAgICAgICAgd2lkdGg6IFwibWF4LWNvbnRlbnRcIixcbiAgICAgICAgICAgIG1heFdpZHRoOiBgJHt4MiAtIHgxICsgRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgKiAyfXB4YCxcbiAgICAgICAgICAgIG92ZXJmbG93OiBmLmlkID09PSB0aGlzLnN0YXRlLmVkaXRpbmdGcmFtZSA/IFwidmlzaWJsZVwiIDogXCJoaWRkZW5cIixcbiAgICAgICAgICAgIHdoaXRlU3BhY2U6IFwibm93cmFwXCIsXG4gICAgICAgICAgICB0ZXh0T3ZlcmZsb3c6IFwiZWxsaXBzaXNcIixcbiAgICAgICAgICAgIGN1cnNvcjogQ1VSU09SX1RZUEUuTU9WRSxcbiAgICAgICAgICAgIHBvaW50ZXJFdmVudHM6IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkID8gUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5lbmFibGVkXG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblBvaW50ZXJEb3duOiBldmVudCA9PiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJEb3duKGV2ZW50KSxcbiAgICAgICAgICBvbldoZWVsOiBldmVudCA9PiB0aGlzLmhhbmRsZVdoZWVsKGV2ZW50KSxcbiAgICAgICAgICBvbkNvbnRleHRNZW51OiB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51LFxuICAgICAgICAgIG9uRG91YmxlQ2xpY2s6ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nRnJhbWU6IGYuaWRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBmcmFtZU5hbWVKU1hcbiAgICAgICAgfSksIGYuaWQpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZm9jdXNDb250YWluZXIgPSAoKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZm9jdXMoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5nZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCA9ICgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuICAgIH07XG5cbiAgICB0aGlzLmdldFNjZW5lRWxlbWVudHMgPSAoKSA9PiB7XG4gICAgICByZXR1cm4gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5vbkluc2VydEVsZW1lbnRzID0gZWxlbWVudHMgPT4ge1xuICAgICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSh7XG4gICAgICAgIGVsZW1lbnRzLFxuICAgICAgICBwb3NpdGlvbjogXCJjZW50ZXJcIixcbiAgICAgICAgZmlsZXM6IG51bGxcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLm9uRXhwb3J0SW1hZ2UgPSAodHlwZSwgZWxlbWVudHMpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRyYWNrRXZlbnQoXCJleHBvcnRcIiwgdHlwZSwgXCJ1aVwiKTtcbiAgICAgIGNvbnN0IGZpbGVIYW5kbGUgPSB5aWVsZCBleHBvcnRBc0ltYWdlKHR5cGUsIGVsZW1lbnRzLCB0aGlzLnN0YXRlLCB0aGlzLmZpbGVzLCB7XG4gICAgICAgIGV4cG9ydEJhY2tncm91bmQ6IHRoaXMuc3RhdGUuZXhwb3J0QmFja2dyb3VuZCxcbiAgICAgICAgbmFtZTogdGhpcy5zdGF0ZS5uYW1lLFxuICAgICAgICB2aWV3QmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLnZpZXdCYWNrZ3JvdW5kQ29sb3JcbiAgICAgIH0pLmNhdGNoKG11dGVGU0Fib3J0RXJyb3IpLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5leHBvcnRFbWJlZFNjZW5lICYmIGZpbGVIYW5kbGUgJiYgaXNJbWFnZUZpbGVIYW5kbGUoZmlsZUhhbmRsZSkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZmlsZUhhbmRsZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub3BlbkV5ZURyb3BwZXIgPSAoe1xuICAgICAgdHlwZVxuICAgIH0pID0+IHtcbiAgICAgIGpvdGFpU3RvcmUuc2V0KGFjdGl2ZUV5ZURyb3BwZXJBdG9tLCB7XG4gICAgICAgIHN3YXBQcmV2aWV3T25BbHQ6IHRydWUsXG4gICAgICAgIGNvbG9yUGlja2VyVHlwZTogdHlwZSA9PT0gXCJzdHJva2VcIiA/IFwiZWxlbWVudFN0cm9rZVwiIDogXCJlbGVtZW50QmFja2dyb3VuZFwiLFxuICAgICAgICBvblNlbGVjdDogKGNvbG9yLCBldmVudCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHNob3VsZFVwZGF0ZVN0cm9rZUNvbG9yID0gdHlwZSA9PT0gXCJiYWNrZ3JvdW5kXCIgJiYgZXZlbnQuYWx0S2V5IHx8IHR5cGUgPT09IFwic3Ryb2tlXCIgJiYgIWV2ZW50LmFsdEtleTtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgICAgaWYgKCFzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICAgICAgaWYgKHNob3VsZFVwZGF0ZVN0cm9rZUNvbG9yKSB7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCh7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGN1cnJlbnRJdGVtU3Ryb2tlQ29sb3I6IGNvbG9yXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KHtcbiAgICAgICAgICAgICAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAgICAgICAgICAgY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3I6IGNvbG9yXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVNjZW5lKHtcbiAgICAgICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbZWwuaWRdKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWwsIHtcbiAgICAgICAgICAgICAgICAgICAgW3Nob3VsZFVwZGF0ZVN0cm9rZUNvbG9yID8gXCJzdHJva2VDb2xvclwiIDogXCJiYWNrZ3JvdW5kQ29sb3JcIl06IGNvbG9yXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gZWw7XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGtlZXBPcGVuT25BbHQ6IGZhbHNlXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0ID0gd2l0aEJhdGNoZWRVcGRhdGVzKGFjdGlvblJlc3VsdCA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZiwgX2csIF9oLCBfajtcblxuICAgICAgaWYgKHRoaXMudW5tb3VudGVkIHx8IGFjdGlvblJlc3VsdCA9PT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsZXQgZWRpdGluZ0VsZW1lbnQgPSBudWxsO1xuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmVsZW1lbnRzKSB7XG4gICAgICAgIGFjdGlvblJlc3VsdC5lbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgIGlmICgoKF9hID0gdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmlkKSA9PT0gZWxlbWVudC5pZCAmJiB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICE9PSBlbGVtZW50ICYmIGlzTm9uRGVsZXRlZEVsZW1lbnQoZWxlbWVudCkpIHtcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50ID0gZWxlbWVudDtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhhY3Rpb25SZXN1bHQuZWxlbWVudHMpO1xuXG4gICAgICAgIGlmIChhY3Rpb25SZXN1bHQuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3Rpb25SZXN1bHQuZmlsZXMpIHtcbiAgICAgICAgdGhpcy5maWxlcyA9IGFjdGlvblJlc3VsdC5yZXBsYWNlRmlsZXMgPyBhY3Rpb25SZXN1bHQuZmlsZXMgOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZmlsZXMpLCBhY3Rpb25SZXN1bHQuZmlsZXMpO1xuICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmFwcFN0YXRlIHx8IGVkaXRpbmdFbGVtZW50IHx8IHRoaXMuc3RhdGUuY29udGV4dE1lbnUpIHtcbiAgICAgICAgaWYgKGFjdGlvblJlc3VsdC5jb21taXRUb0hpc3RvcnkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdmlld01vZGVFbmFibGVkID0gKChfYSA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnZpZXdNb2RlRW5hYmxlZCkgfHwgZmFsc2U7XG4gICAgICAgIGxldCB6ZW5Nb2RlRW5hYmxlZCA9ICgoX2IgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi56ZW5Nb2RlRW5hYmxlZCkgfHwgZmFsc2U7XG4gICAgICAgIGxldCBncmlkU2l6ZSA9ICgoX2MgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5ncmlkU2l6ZSkgfHwgbnVsbDtcbiAgICAgICAgY29uc3QgdGhlbWUgPSAoKF9kID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QudGhlbWUpIHx8IHRoaXMucHJvcHMudGhlbWUgfHwgVEhFTUUuTElHSFQ7XG4gICAgICAgIGxldCBuYW1lID0gKF9mID0gKF9lID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2UubmFtZSkgIT09IG51bGwgJiYgX2YgIT09IHZvaWQgMCA/IF9mIDogdGhpcy5zdGF0ZS5uYW1lO1xuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSAoX2ggPSAoX2cgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9nID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZy5lcnJvck1lc3NhZ2UpICE9PSBudWxsICYmIF9oICE9PSB2b2lkIDAgPyBfaCA6IHRoaXMuc3RhdGUuZXJyb3JNZXNzYWdlO1xuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICB2aWV3TW9kZUVuYWJsZWQgPSB0aGlzLnByb3BzLnZpZXdNb2RlRW5hYmxlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIHplbk1vZGVFbmFibGVkID0gdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICBncmlkU2l6ZSA9IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkID8gR1JJRF9TSVpFIDogbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5wcm9wcy5uYW1lICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgbmFtZSA9IHRoaXMucHJvcHMubmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGVkaXRpbmdFbGVtZW50ID0gZWRpdGluZ0VsZW1lbnQgfHwgKChfaiA9IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2ogPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9qLmVkaXRpbmdFbGVtZW50KSB8fCBudWxsO1xuXG4gICAgICAgIGlmIChlZGl0aW5nRWxlbWVudCA9PT0gbnVsbCB8fCBlZGl0aW5nRWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZWRpdGluZ0VsZW1lbnQuaXNEZWxldGVkKSB7XG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSA9PiB7XG4gICAgICAgICAgLy8gdXNpbmcgT2JqZWN0LmFzc2lnbiBpbnN0ZWFkIG9mIHNwcmVhZCB0byBmb29sIFRTIDQuMi4yKyBpbnRvXG4gICAgICAgICAgLy8gcmVnYXJkaW5nIHRoZSByZXN1bHRpbmcgdHlwZSBhcyBub3QgY29udGFpbmluZyB1bmRlZmluZWRcbiAgICAgICAgICAvLyAod2hpY2ggdGhlIGZvbGxvd2luZyBleHByZXNzaW9uIHdpbGwgbmV2ZXIgY29udGFpbilcbiAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihhY3Rpb25SZXN1bHQuYXBwU3RhdGUgfHwge30sIHtcbiAgICAgICAgICAgIC8vIE5PVEUgdGhpcyB3aWxsIHByZXZlbnQgb3BlbmluZyBjb250ZXh0IG1lbnUgdXNpbmcgYW4gYWN0aW9uXG4gICAgICAgICAgICAvLyBvciBwcm9ncmFtbWF0aWNhbGx5IGZyb20gdGhlIGhvc3QsIHNvIGl0IHdpbGwgbmVlZCB0byBiZVxuICAgICAgICAgICAgLy8gcmV3cml0dGVuIGxhdGVyXG4gICAgICAgICAgICBjb250ZXh0TWVudTogbnVsbCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50LFxuICAgICAgICAgICAgdmlld01vZGVFbmFibGVkLFxuICAgICAgICAgICAgemVuTW9kZUVuYWJsZWQsXG4gICAgICAgICAgICBncmlkU2l6ZSxcbiAgICAgICAgICAgIHRoZW1lLFxuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgaWYgKGFjdGlvblJlc3VsdC5zeW5jSGlzdG9yeSkge1xuICAgICAgICAgICAgdGhpcy5oaXN0b3J5LnNldEN1cnJlbnRTdGF0ZSh0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pOyAvLyBMaWZlY3ljbGVcblxuICAgIHRoaXMub25CbHVyID0gd2l0aEJhdGNoZWRVcGRhdGVzKCgpID0+IHtcbiAgICAgIGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogdHJ1ZVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLm9uVW5sb2FkID0gKCkgPT4ge1xuICAgICAgdGhpcy5vbkJsdXIoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5kaXNhYmxlRXZlbnQgPSBldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0SGlzdG9yeSA9ICgpID0+IHtcbiAgICAgIHRoaXMuaGlzdG9yeS5jbGVhcigpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmVzZXRzIHNjZW5lICYgaGlzdG9yeS5cbiAgICAgKiAhIERvIG5vdCB1c2UgdG8gY2xlYXIgc2NlbmUgdXNlciBhY3Rpb24gIVxuICAgICAqL1xuXG5cbiAgICB0aGlzLnJlc2V0U2NlbmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMob3B0cyA9PiB7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbXSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZ2V0RGVmYXVsdEFwcFN0YXRlKCkpLCB7XG4gICAgICAgIGlzTG9hZGluZzogKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yZXNldExvYWRpbmdTdGF0ZSkgPyBmYWxzZSA6IHN0YXRlLmlzTG9hZGluZyxcbiAgICAgICAgdGhlbWU6IHRoaXMuc3RhdGUudGhlbWVcbiAgICAgIH0pKTtcbiAgICAgIHRoaXMucmVzZXRIaXN0b3J5KCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmluaXRpYWxpemVTY2VuZSA9ICgpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfYjtcblxuICAgICAgaWYgKFwibGF1bmNoUXVldWVcIiBpbiB3aW5kb3cgJiYgXCJMYXVuY2hQYXJhbXNcIiBpbiB3aW5kb3cpIHtcbiAgICAgICAgd2luZG93LmxhdW5jaFF1ZXVlLnNldENvbnN1bWVyKGxhdW5jaFBhcmFtcyA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgICAgaWYgKCFsYXVuY2hQYXJhbXMuZmlsZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgZmlsZUhhbmRsZSA9IGxhdW5jaFBhcmFtcy5maWxlc1swXTtcbiAgICAgICAgICBjb25zdCBibG9iID0geWllbGQgZmlsZUhhbmRsZS5nZXRGaWxlKCk7XG4gICAgICAgICAgdGhpcy5sb2FkRmlsZVRvQ2FudmFzKG5ldyBGaWxlKFtibG9iXSwgYmxvYi5uYW1lIHx8IFwiXCIsIHtcbiAgICAgICAgICAgIHR5cGU6IGJsb2IudHlwZVxuICAgICAgICAgIH0pLCBmaWxlSGFuZGxlKTtcbiAgICAgICAgfSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5wcm9wcy50aGVtZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmlzTG9hZGluZykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0xvYWRpbmc6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGxldCBpbml0aWFsRGF0YSA9IG51bGw7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGluaXRpYWxEYXRhID0gKHlpZWxkIHRoaXMucHJvcHMuaW5pdGlhbERhdGEpIHx8IG51bGw7XG5cbiAgICAgICAgaWYgKGluaXRpYWxEYXRhID09PSBudWxsIHx8IGluaXRpYWxEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpbml0aWFsRGF0YS5saWJyYXJ5SXRlbXMpIHtcbiAgICAgICAgICB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSh7XG4gICAgICAgICAgICBsaWJyYXJ5SXRlbXM6IGluaXRpYWxEYXRhLmxpYnJhcnlJdGVtcyxcbiAgICAgICAgICAgIG1lcmdlOiB0cnVlXG4gICAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICBpbml0aWFsRGF0YSA9IHtcbiAgICAgICAgICBhcHBTdGF0ZToge1xuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlIHx8IFwiRW5jb3VudGVyZWQgYW4gZXJyb3IgZHVyaW5nIGltcG9ydGluZyBvciByZXN0b3Jpbmcgc2NlbmUgZGF0YVwiXG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzY2VuZSA9IHJlc3RvcmUoaW5pdGlhbERhdGEsIG51bGwsIG51bGwsIHtcbiAgICAgICAgcmVwYWlyQmluZGluZ3M6IHRydWVcbiAgICAgIH0pO1xuICAgICAgc2NlbmUuYXBwU3RhdGUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlKSwge1xuICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZSB8fCBzY2VuZS5hcHBTdGF0ZS50aGVtZSxcbiAgICAgICAgLy8gd2UncmUgZmFsbGluZyBiYWNrIHRvIGN1cnJlbnQgKHByZS1pbml0KSBzdGF0ZSB3aGVuIGRlY2lkaW5nXG4gICAgICAgIC8vIHdoZXRoZXIgdG8gb3BlbiB0aGUgbGlicmFyeSwgdG8gaGFuZGxlIGEgY2FzZSB3aGVyZSB3ZVxuICAgICAgICAvLyB1cGRhdGUgdGhlIHN0YXRlIG91dHNpZGUgb2YgaW5pdGlhbERhdGEgKGUuZy4gd2hlbiBsb2FkaW5nIHRoZSBhcHBcbiAgICAgICAgLy8gd2l0aCBhIGxpYnJhcnkgaW5zdGFsbCBsaW5rLCB3aGljaCBzaG91bGQgYXV0by1vcGVuIHRoZSBsaWJyYXJ5KVxuICAgICAgICBvcGVuU2lkZWJhcjogKChfYiA9IHNjZW5lLmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iub3BlblNpZGViYXIpIHx8IHRoaXMuc3RhdGUub3BlblNpZGViYXIsXG4gICAgICAgIGFjdGl2ZVRvb2w6IHNjZW5lLmFwcFN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiID8gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sKSwge1xuICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgfSkgOiBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sLFxuICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICB0b2FzdDogdGhpcy5zdGF0ZS50b2FzdFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEuc2Nyb2xsVG9Db250ZW50KSB7XG4gICAgICAgIHNjZW5lLmFwcFN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIGNhbGN1bGF0ZVNjcm9sbENlbnRlcihzY2VuZS5lbGVtZW50cywgT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIHtcbiAgICAgICAgICB3aWR0aDogdGhpcy5zdGF0ZS53aWR0aCxcbiAgICAgICAgICBoZWlnaHQ6IHRoaXMuc3RhdGUuaGVpZ2h0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0XG4gICAgICAgIH0pKSk7XG4gICAgICB9IC8vIEZvbnRGYWNlU2V0IGxvYWRpbmdkb25lIGV2ZW50IHdlIGxpc3RlbiBvbiBtYXkgbm90IGFsd2F5cyBmaXJlXG4gICAgICAvLyAobG9va2luZyBhdCB5b3UgU2FmYXJpKSwgc28gb24gaW5pdCB3ZSBtYW51YWxseSBsb2FkIGZvbnRzIGZvciBjdXJyZW50XG4gICAgICAvLyB0ZXh0IGVsZW1lbnRzIG9uIGNhbnZhcywgYW5kIHJlcmVuZGVyIHRoZW0gb25jZSBkb25lLiBUaGlzIGFsc29cbiAgICAgIC8vIHNlZW1zIGZhc3RlciBldmVuIGluIGJyb3dzZXJzIHRoYXQgZG8gZmlyZSB0aGUgbG9hZGluZ2RvbmUgZXZlbnQuXG5cblxuICAgICAgdGhpcy5mb250cy5sb2FkRm9udHNGb3JFbGVtZW50cyhzY2VuZS5lbGVtZW50cyk7XG5cbiAgICAgIGlmICgoaW5pdGlhbERhdGEgPT09IG51bGwgfHwgaW5pdGlhbERhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGluaXRpYWxEYXRhLnNjcm9sbFgpICE9IG51bGwpIHtcbiAgICAgICAgc2NlbmUuYXBwU3RhdGUuc2Nyb2xsWCA9IGluaXRpYWxEYXRhLnNjcm9sbFg7XG4gICAgICB9XG5cbiAgICAgIGlmICgoaW5pdGlhbERhdGEgPT09IG51bGwgfHwgaW5pdGlhbERhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGluaXRpYWxEYXRhLnNjcm9sbFkpICE9IG51bGwpIHtcbiAgICAgICAgc2NlbmUuYXBwU3RhdGUuc2Nyb2xsWSA9IGluaXRpYWxEYXRhLnNjcm9sbFk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMucmVzZXRIaXN0b3J5KCk7XG4gICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZSksIHtcbiAgICAgICAgY29tbWl0VG9IaXN0b3J5OiB0cnVlXG4gICAgICB9KSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnJlZnJlc2hEZXZpY2VTdGF0ZSA9IGNvbnRhaW5lciA9PiB7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHdpZHRoLFxuICAgICAgICBoZWlnaHRcbiAgICAgIH0gPSBjb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICBjb25zdCBzaWRlYmFyQnJlYWtwb2ludCA9IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50ICE9IG51bGwgPyB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCA6IE1RX1JJR0hUX1NJREVCQVJfTUlOX1dJRFRIO1xuICAgICAgdGhpcy5kZXZpY2UgPSB1cGRhdGVPYmplY3QodGhpcy5kZXZpY2UsIHtcbiAgICAgICAgaXNMYW5kc2NhcGU6IHdpZHRoID4gaGVpZ2h0LFxuICAgICAgICBpc1NtU2NyZWVuOiB3aWR0aCA8IE1RX1NNX01BWF9XSURUSCxcbiAgICAgICAgaXNNb2JpbGU6IHdpZHRoIDwgTVFfTUFYX1dJRFRIX1BPUlRSQUlUIHx8IGhlaWdodCA8IE1RX01BWF9IRUlHSFRfTEFORFNDQVBFICYmIHdpZHRoIDwgTVFfTUFYX1dJRFRIX0xBTkRTQ0FQRSxcbiAgICAgICAgY2FuRGV2aWNlRml0U2lkZWJhcjogd2lkdGggPiBzaWRlYmFyQnJlYWtwb2ludFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMub25SZXNpemUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoKCkgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5mb3JFYWNoKGVsZW1lbnQgPT4gU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCkpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7fSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLm9uRm9udHNMb2FkaW5nRG9uZSA9IGV2ZW50ID0+IHtcbiAgICAgIGNvbnN0IGxvYWRlZEZvbnRGYWNlcyA9IGV2ZW50LmZvbnRmYWNlcztcbiAgICAgIHRoaXMuZm9udHMub25Gb250c0xvYWRlZChsb2FkZWRGb250RmFjZXMpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlbmRlckludGVyYWN0aXZlU2NlbmVDYWxsYmFjayA9ICh7XG4gICAgICBhdExlYXN0T25lVmlzaWJsZUVsZW1lbnQsXG4gICAgICBzY3JvbGxCYXJzLFxuICAgICAgZWxlbWVudHNcbiAgICB9KSA9PiB7XG4gICAgICBpZiAoc2Nyb2xsQmFycykge1xuICAgICAgICBjdXJyZW50U2Nyb2xsQmFycyA9IHNjcm9sbEJhcnM7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNjcm9sbGVkT3V0c2lkZSA9IC8vIGhpZGUgd2hlbiBlZGl0aW5nIHRleHRcbiAgICAgIGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPyBmYWxzZSA6ICFhdExlYXN0T25lVmlzaWJsZUVsZW1lbnQgJiYgZWxlbWVudHMubGVuZ3RoID4gMDtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuc2Nyb2xsZWRPdXRzaWRlICE9PSBzY3JvbGxlZE91dHNpZGUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2Nyb2xsZWRPdXRzaWRlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNjaGVkdWxlSW1hZ2VSZWZyZXNoKCk7XG4gICAgfTtcblxuICAgIHRoaXMub25TY3JvbGwgPSBkZWJvdW5jZSgoKSA9PiB7XG4gICAgICBjb25zdCB7XG4gICAgICAgIG9mZnNldFRvcCxcbiAgICAgICAgb2Zmc2V0TGVmdFxuICAgICAgfSA9IHRoaXMuZ2V0Q2FudmFzT2Zmc2V0cygpO1xuICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSA9PiB7XG4gICAgICAgIGlmIChzdGF0ZS5vZmZzZXRMZWZ0ID09PSBvZmZzZXRMZWZ0ICYmIHN0YXRlLm9mZnNldFRvcCA9PT0gb2Zmc2V0VG9wKSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG9mZnNldFRvcCxcbiAgICAgICAgICBvZmZzZXRMZWZ0XG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9LCBTQ1JPTExfVElNRU9VVCk7IC8vIENvcHkvcGFzdGVcblxuICAgIHRoaXMub25DdXQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBpc0V4Y2FsaWRyYXdBY3RpdmUgPSAoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNvbnRhaW5zKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpO1xuXG4gICAgICBpZiAoIWlzRXhjYWxpZHJhd0FjdGl2ZSB8fCBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5jdXRBbGwoKTtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9KTtcbiAgICB0aGlzLm9uQ29weSA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IGlzRXhjYWxpZHJhd0FjdGl2ZSA9IChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY29udGFpbnMoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCk7XG5cbiAgICAgIGlmICghaXNFeGNhbGlkcmF3QWN0aXZlIHx8IGlzV3JpdGFibGVFbGVtZW50KGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmNvcHlBbGwoKTtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9KTtcblxuICAgIHRoaXMuY3V0QWxsID0gKCkgPT4ge1xuICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uQ3V0LCBcImtleWJvYXJkXCIpO1xuICAgIH07XG5cbiAgICB0aGlzLmNvcHlBbGwgPSAoKSA9PiB7XG4gICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25Db3B5LCBcImtleWJvYXJkXCIpO1xuICAgIH07XG5cbiAgICB0aGlzLm9uVG91Y2hTdGFydCA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIGZpeCBmb3IgQXBwbGUgUGVuY2lsIFNjcmliYmxlXG4gICAgICAvLyBPbiBBbmRyb2lkLCBwcmV2ZW50aW5nIHRoZSBldmVudCB3b3VsZCBkaXNhYmxlIGNvbnRleHRNZW51IG9uIHRhcC1ob2xkXG4gICAgICBpZiAoIWlzQW5kcm9pZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWRpZFRhcFR3aWNlKSB7XG4gICAgICAgIGRpZFRhcFR3aWNlID0gdHJ1ZTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRhcHBlZFR3aWNlVGltZXIpO1xuICAgICAgICB0YXBwZWRUd2ljZVRpbWVyID0gd2luZG93LnNldFRpbWVvdXQoQXBwLnJlc2V0VGFwVHdpY2UsIFRBUF9UV0lDRV9USU1FT1VUKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBpbnNlcnQgdGV4dCBvbmx5IGlmIHdlIHRhcHBlZCB0d2ljZSB3aXRoIGEgc2luZ2xlIGZpbmdlclxuICAgICAgLy8gZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDEgd2lsbCBhbHNvIHByZXZlbnQgaW5zZXJ0aW5nIHRleHQgd2hlbiB1c2VyJ3Mgem9vbWluZ1xuXG5cbiAgICAgIGlmIChkaWRUYXBUd2ljZSAmJiBldmVudC50b3VjaGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBjb25zdCB0b3VjaCA9IGV2ZW50LnRvdWNoZXNbMF07IC8vIEB0cy1pZ25vcmVcblxuICAgICAgICB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrKHtcbiAgICAgICAgICBjbGllbnRYOiB0b3VjaC5jbGllbnRYLFxuICAgICAgICAgIGNsaWVudFk6IHRvdWNoLmNsaWVudFlcbiAgICAgICAgfSk7XG4gICAgICAgIGRpZFRhcFR3aWNlID0gZmFsc2U7XG4gICAgICAgIGNsZWFyVGltZW91dCh0YXBwZWRUd2ljZVRpbWVyKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzQW5kcm9pZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5vblRvdWNoRW5kID0gZXZlbnQgPT4ge1xuICAgICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIoKTtcblxuICAgICAgaWYgKGV2ZW50LnRvdWNoZXMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczoge30sXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh0aGlzLnN0YXRlLnByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzLCB0aGlzLnN0YXRlKVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUucG9pbnRlcnMuY2xlYXIoKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5wYXN0ZUZyb21DbGlwYm9hcmQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdmFyIF9jLCBfZCwgX2U7XG5cbiAgICAgIGNvbnN0IGlzUGxhaW5QYXN0ZSA9ICEhKElTX1BMQUlOX1BBU1RFICYmIGV2ZW50KTsgLy8gIzY4NlxuXG4gICAgICBjb25zdCB0YXJnZXQgPSBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuICAgICAgY29uc3QgaXNFeGNhbGlkcmF3QWN0aXZlID0gKF9jID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5jb250YWlucyh0YXJnZXQpO1xuXG4gICAgICBpZiAoZXZlbnQgJiYgIWlzRXhjYWxpZHJhd0FjdGl2ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRVbmRlckN1cnNvciA9IGRvY3VtZW50LmVsZW1lbnRGcm9tUG9pbnQodGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LCB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnkpO1xuXG4gICAgICBpZiAoZXZlbnQgJiYgKCEoZWxlbWVudFVuZGVyQ3Vyc29yIGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQpIHx8IGlzV3JpdGFibGVFbGVtZW50KHRhcmdldCkpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gbXVzdCBiZSBjYWxsZWQgaW4gdGhlIHNhbWUgZnJhbWUgKHRodXMgYmVmb3JlIGFueSBhd2FpdHMpIGFzIHRoZSBwYXN0ZVxuICAgICAgLy8gZXZlbnQgZWxzZSBzb21lIGJyb3dzZXJzIChGRi4uLikgd2lsbCBjbGVhciB0aGUgY2xpcGJvYXJkRGF0YVxuICAgICAgLy8gKHNvbWV0aGluZyBzb21ldGhpbmcgc2VjdXJpdHkpXG5cblxuICAgICAgbGV0IGZpbGUgPSAoX2QgPSBldmVudCA9PT0gbnVsbCB8fCBldmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXZlbnQuY2xpcGJvYXJkRGF0YSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmZpbGVzWzBdO1xuICAgICAgY29uc3QgZGF0YSA9IHlpZWxkIHBhcnNlQ2xpcGJvYXJkKGV2ZW50LCBpc1BsYWluUGFzdGUpO1xuXG4gICAgICBpZiAoIWZpbGUgJiYgZGF0YS50ZXh0ICYmICFpc1BsYWluUGFzdGUpIHtcbiAgICAgICAgY29uc3Qgc3RyaW5nID0gZGF0YS50ZXh0LnRyaW0oKTtcblxuICAgICAgICBpZiAoc3RyaW5nLnN0YXJ0c1dpdGgoXCI8c3ZnXCIpICYmIHN0cmluZy5lbmRzV2l0aChcIjwvc3ZnPlwiKSkge1xuICAgICAgICAgIC8vIGlnbm9yZSBTVkcgdmFsaWRhdGlvbi9ub3JtYWxpemF0aW9uIHdoaWNoIHdpbGwgYmUgZG9uZSBkdXJpbmcgaW1hZ2VcbiAgICAgICAgICAvLyBpbml0aWFsaXphdGlvblxuICAgICAgICAgIGZpbGUgPSBTVkdTdHJpbmdUb0ZpbGUoc3RyaW5nKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgY2xpZW50WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgICBjbGllbnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnlcbiAgICAgIH0sIHRoaXMuc3RhdGUpOyAvLyBwcmVmZXIgc3ByZWFkc2hlZXQgZGF0YSBvdmVyIGltYWdlIGZpbGUgKE1TIE9mZmljZS9MaWJyZSBPZmZpY2UpXG5cbiAgICAgIGlmIChpc1N1cHBvcnRlZEltYWdlRmlsZShmaWxlKSAmJiAhZGF0YS5zcHJlYWRzaGVldCkge1xuICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSB0aGlzLmNyZWF0ZUltYWdlRWxlbWVudCh7XG4gICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgIHNjZW5lWVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5pbnNlcnRJbWFnZUVsZW1lbnQoaW1hZ2VFbGVtZW50LCBmaWxlKTtcbiAgICAgICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zKGltYWdlRWxlbWVudCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgW2ltYWdlRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICB9LCB0aGlzLnN0YXRlKVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5wcm9wcy5vblBhc3RlKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaWYgKCh5aWVsZCB0aGlzLnByb3BzLm9uUGFzdGUoZGF0YSwgZXZlbnQpKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGRhdGEuZXJyb3JNZXNzYWdlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZGF0YS5lcnJvck1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuc3ByZWFkc2hlZXQgJiYgIWlzUGxhaW5QYXN0ZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwYXN0ZURpYWxvZzoge1xuICAgICAgICAgICAgZGF0YTogZGF0YS5zcHJlYWRzaGVldCxcbiAgICAgICAgICAgIHNob3duOiB0cnVlXG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5lbGVtZW50cykge1xuICAgICAgICBjb25zdCBlbGVtZW50cyA9IGRhdGEucHJvZ3JhbW1hdGljQVBJID8gY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzKGRhdGEuZWxlbWVudHMpIDogZGF0YS5lbGVtZW50czsgLy8gVE9ETyByZW1vdmUgZm9ybWF0dGluZyBmcm9tIGVsZW1lbnRzIGlmIGlzUGxhaW5QYXN0ZVxuXG4gICAgICAgIHRoaXMuYWRkRWxlbWVudHNGcm9tUGFzdGVPckxpYnJhcnkoe1xuICAgICAgICAgIGVsZW1lbnRzLFxuICAgICAgICAgIGZpbGVzOiBkYXRhLmZpbGVzIHx8IG51bGwsXG4gICAgICAgICAgcG9zaXRpb246IFwiY3Vyc29yXCIsXG4gICAgICAgICAgcmV0YWluU2VlZDogaXNQbGFpblBhc3RlXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLnRleHQpIHtcbiAgICAgICAgY29uc3QgbWF5YmVVcmwgPSBleHRyYWN0U3JjKGRhdGEudGV4dCk7XG5cbiAgICAgICAgaWYgKCFpc1BsYWluUGFzdGUgJiYgZW1iZWRkYWJsZVVSTFZhbGlkYXRvcihtYXliZVVybCwgdGhpcy5wcm9wcy52YWxpZGF0ZUVtYmVkZGFibGUpICYmICgvXihodHRwfGh0dHBzKTpcXC9cXC9bXlxccy8kLj8jXS5bXlxcc10qJC8udGVzdChtYXliZVVybCkgfHwgKChfZSA9IGdldEVtYmVkTGluayhtYXliZVVybCkpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS50eXBlKSA9PT0gXCJ2aWRlb1wiKSkge1xuICAgICAgICAgIGNvbnN0IGVtYmVkZGFibGUgPSB0aGlzLmluc2VydEVtYmVkZGFibGVFbGVtZW50KHtcbiAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgIHNjZW5lWSxcbiAgICAgICAgICAgIGxpbms6IG5vcm1hbGl6ZUxpbmsobWF5YmVVcmwpXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBpZiAoZW1iZWRkYWJsZSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgIFtlbWJlZGRhYmxlLmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmFkZFRleHRGcm9tUGFzdGUoZGF0YS50ZXh0LCBpc1BsYWluUGFzdGUpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldEFjdGl2ZVRvb2woe1xuICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICB9KTtcbiAgICAgIGV2ZW50ID09PSBudWxsIHx8IGV2ZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH0pKTtcblxuICAgIHRoaXMuYWRkRWxlbWVudHNGcm9tUGFzdGVPckxpYnJhcnkgPSBvcHRzID0+IHtcbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gcmVzdG9yZUVsZW1lbnRzKG9wdHMuZWxlbWVudHMsIG51bGwsIHVuZGVmaW5lZCk7XG4gICAgICBjb25zdCBbbWluWCwgbWluWSwgbWF4WCwgbWF4WV0gPSBnZXRDb21tb25Cb3VuZHMoZWxlbWVudHMpO1xuICAgICAgY29uc3QgZWxlbWVudHNDZW50ZXJYID0gZGlzdGFuY2UobWluWCwgbWF4WCkgLyAyO1xuICAgICAgY29uc3QgZWxlbWVudHNDZW50ZXJZID0gZGlzdGFuY2UobWluWSwgbWF4WSkgLyAyO1xuICAgICAgY29uc3QgY2xpZW50WCA9IHR5cGVvZiBvcHRzLnBvc2l0aW9uID09PSBcIm9iamVjdFwiID8gb3B0cy5wb3NpdGlvbi5jbGllbnRYIDogb3B0cy5wb3NpdGlvbiA9PT0gXCJjdXJzb3JcIiA/IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCA6IHRoaXMuc3RhdGUud2lkdGggLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0O1xuICAgICAgY29uc3QgY2xpZW50WSA9IHR5cGVvZiBvcHRzLnBvc2l0aW9uID09PSBcIm9iamVjdFwiID8gb3B0cy5wb3NpdGlvbi5jbGllbnRZIDogb3B0cy5wb3NpdGlvbiA9PT0gXCJjdXJzb3JcIiA/IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSA6IHRoaXMuc3RhdGUuaGVpZ2h0IC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0VG9wO1xuICAgICAgY29uc3Qge1xuICAgICAgICB4LFxuICAgICAgICB5XG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgY2xpZW50WCxcbiAgICAgICAgY2xpZW50WVxuICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBkeCA9IHggLSBlbGVtZW50c0NlbnRlclg7XG4gICAgICBjb25zdCBkeSA9IHkgLSBlbGVtZW50c0NlbnRlclk7XG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChkeCwgZHksIHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgbmV3RWxlbWVudHMgPSBkdXBsaWNhdGVFbGVtZW50cyhlbGVtZW50cy5tYXAoZWxlbWVudCA9PiB7XG4gICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGVtZW50LCB7XG4gICAgICAgICAgeDogZWxlbWVudC54ICsgZ3JpZFggLSBtaW5YLFxuICAgICAgICAgIHk6IGVsZW1lbnQueSArIGdyaWRZIC0gbWluWVxuICAgICAgICB9KTtcbiAgICAgIH0pLCB7XG4gICAgICAgIHJhbmRvbWl6ZVNlZWQ6ICFvcHRzLnJldGFpblNlZWRcbiAgICAgIH0pO1xuICAgICAgY29uc3QgbmV4dEVsZW1lbnRzID0gWy4uLnRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIC4uLm5ld0VsZW1lbnRzXTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKG5leHRFbGVtZW50cyk7XG4gICAgICBuZXdFbGVtZW50cy5mb3JFYWNoKG5ld0VsZW1lbnQgPT4ge1xuICAgICAgICBpZiAoaXNUZXh0RWxlbWVudChuZXdFbGVtZW50KSAmJiBpc0JvdW5kVG9Db250YWluZXIobmV3RWxlbWVudCkpIHtcbiAgICAgICAgICBjb25zdCBjb250YWluZXIgPSBnZXRDb250YWluZXJFbGVtZW50KG5ld0VsZW1lbnQpO1xuICAgICAgICAgIHJlZHJhd1RleHRCb3VuZGluZ0JveChuZXdFbGVtZW50LCBjb250YWluZXIpO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgaWYgKG9wdHMuZmlsZXMpIHtcbiAgICAgICAgdGhpcy5maWxlcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5maWxlcyksIG9wdHMuZmlsZXMpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICBjb25zdCBuZXh0RWxlbWVudHNUb1NlbGVjdCA9IGV4Y2x1ZGVFbGVtZW50c0luRnJhbWVzRnJvbVNlbGVjdGlvbihuZXdFbGVtZW50cyk7XG4gICAgICB0aGlzLnNldFN0YXRlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAvLyBrZWVwIHNpZGViYXIgKHByZXN1bWFibHkgdGhlIGxpYnJhcnkpIG9wZW4gaWYgaXQncyBkb2NrZWQgYW5kXG4gICAgICAgIC8vIGNhbiBmaXQuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIE5vdGUsIHdlIHNob3VsZCBjbG9zZSB0aGUgc2lkZWJhciBvbmx5IGlmIHdlJ3JlIGRyb3BwaW5nIGl0ZW1zXG4gICAgICAgIC8vIGZyb20gbGlicmFyeSwgbm90IHdoZW4gcGFzdGluZyBmcm9tIGNsaXBib2FyZC4gQWxhcy5cbiAgICAgICAgb3BlblNpZGViYXI6IHRoaXMuc3RhdGUub3BlblNpZGViYXIgJiYgdGhpcy5kZXZpY2UuY2FuRGV2aWNlRml0U2lkZWJhciAmJiBqb3RhaVN0b3JlLmdldChpc1NpZGViYXJEb2NrZWRBdG9tKSA/IHRoaXMuc3RhdGUub3BlblNpZGViYXIgOiBudWxsXG4gICAgICB9KSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRFbGVtZW50c1RvU2VsZWN0LnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgaWYgKCFpc0JvdW5kVG9Db250YWluZXIoZWxlbWVudCkpIHtcbiAgICAgICAgICAgIGFjY1tlbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgfSwge30pXG4gICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCB0aGlzKSksICgpID0+IHtcbiAgICAgICAgaWYgKG9wdHMuZmlsZXMpIHtcbiAgICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnNldEFwcFN0YXRlID0gKHN0YXRlLCBjYWxsYmFjaykgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSwgY2FsbGJhY2spO1xuICAgIH07XG5cbiAgICB0aGlzLnJlbW92ZVBvaW50ZXIgPSBldmVudCA9PiB7XG4gICAgICBpZiAodG91Y2hUaW1lb3V0KSB7XG4gICAgICAgIHRoaXMucmVzZXRDb250ZXh0TWVudVRpbWVyKCk7XG4gICAgICB9XG5cbiAgICAgIGdlc3R1cmUucG9pbnRlcnMuZGVsZXRlKGV2ZW50LnBvaW50ZXJJZCk7XG4gICAgfTtcblxuICAgIHRoaXMudG9nZ2xlTG9jayA9IChzb3VyY2UgPSBcInVpXCIpID0+IHtcbiAgICAgIGlmICghdGhpcy5zdGF0ZS5hY3RpdmVUb29sLmxvY2tlZCkge1xuICAgICAgICB0cmFja0V2ZW50KFwidG9vbGJhclwiLCBcInRvZ2dsZUxvY2tcIiwgYCR7c291cmNlfSAoJHt0aGlzLmRldmljZS5pc01vYmlsZSA/IFwibW9iaWxlXCIgOiBcImRlc2t0b3BcIn0pYCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhY3RpdmVUb29sOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLmFjdGl2ZVRvb2wpLCB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHByZXZTdGF0ZS5hY3RpdmVUb29sLmxvY2tlZCA/IHtcbiAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgICB9IDogcHJldlN0YXRlLmFjdGl2ZVRvb2wpKSwge1xuICAgICAgICAgICAgbG9ja2VkOiAhcHJldlN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkXG4gICAgICAgICAgfSlcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnVwZGF0ZUZyYW1lUmVuZGVyaW5nID0gb3B0cyA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIHZhciBfYSwgX2IsIF9jLCBfZDtcblxuICAgICAgICBjb25zdCBuZXh0ID0gdHlwZW9mIG9wdHMgPT09IFwiZnVuY3Rpb25cIiA/IG9wdHMocHJldlN0YXRlLmZyYW1lUmVuZGVyaW5nKSA6IG9wdHM7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZnJhbWVSZW5kZXJpbmc6IHtcbiAgICAgICAgICAgIGVuYWJsZWQ6IChfYSA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5lbmFibGVkKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCxcbiAgICAgICAgICAgIGNsaXA6IChfYiA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5jbGlwKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcuY2xpcCxcbiAgICAgICAgICAgIG5hbWU6IChfYyA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5uYW1lKSAhPT0gbnVsbCAmJiBfYyAhPT0gdm9pZCAwID8gX2MgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcubmFtZSxcbiAgICAgICAgICAgIG91dGxpbmU6IChfZCA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5vdXRsaW5lKSAhPT0gbnVsbCAmJiBfZCAhPT0gdm9pZCAwID8gX2QgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcub3V0bGluZVxuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnRvZ2dsZVBlbk1vZGUgPSAoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgcGVuTW9kZTogIXByZXZTdGF0ZS5wZW5Nb2RlXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5vbkhhbmRUb29sVG9nZ2xlID0gKCkgPT4ge1xuICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uVG9nZ2xlSGFuZFRvb2wpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogWm9vbXMgb24gY2FudmFzIHZpZXdwb3J0IGNlbnRlclxuICAgICAqL1xuXG5cbiAgICB0aGlzLnpvb21DYW52YXMgPSAoXG4gICAgLyoqIGRlY2ltYWwgZnJhY3Rpb24gYmV0d2VlbiAwLjEgKDEwJSB6b29tKSBhbmQgMzAgKDMwMDAlIHpvb20pICovXG4gICAgdmFsdWUpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgdmlld3BvcnRYOiB0aGlzLnN0YXRlLndpZHRoIC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCxcbiAgICAgICAgdmlld3BvcnRZOiB0aGlzLnN0YXRlLmhlaWdodCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldFRvcCxcbiAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKHZhbHVlKVxuICAgICAgfSwgdGhpcy5zdGF0ZSkpKTtcbiAgICB9O1xuXG4gICAgdGhpcy5jYW5jZWxJblByb2dyZXNBbmltYXRpb24gPSBudWxsO1xuXG4gICAgdGhpcy5zY3JvbGxUb0NvbnRlbnQgPSAodGFyZ2V0ID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgb3B0cykgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgKF9hID0gdGhpcy5jYW5jZWxJblByb2dyZXNBbmltYXRpb24pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jYWxsKHRoaXMpOyAvLyBjb252ZXJ0IHByb3ZpZGVkIHRhcmdldCBpbnRvIEV4Y2FsaWRyYXdFbGVtZW50W10gaWYgbmVjZXNzYXJ5XG5cbiAgICAgIGNvbnN0IHRhcmdldEVsZW1lbnRzID0gQXJyYXkuaXNBcnJheSh0YXJnZXQpID8gdGFyZ2V0IDogW3RhcmdldF07XG4gICAgICBsZXQgem9vbSA9IHRoaXMuc3RhdGUuem9vbTtcbiAgICAgIGxldCBzY3JvbGxYID0gdGhpcy5zdGF0ZS5zY3JvbGxYO1xuICAgICAgbGV0IHNjcm9sbFkgPSB0aGlzLnN0YXRlLnNjcm9sbFk7XG5cbiAgICAgIGlmICgob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvQ29udGVudCkgfHwgKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5maXRUb1ZpZXdwb3J0KSkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgYXBwU3RhdGVcbiAgICAgICAgfSA9IHpvb21Ub0ZpdCh7XG4gICAgICAgICAgdGFyZ2V0RWxlbWVudHMsXG4gICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgZml0VG9WaWV3cG9ydDogISEob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvVmlld3BvcnQpLFxuICAgICAgICAgIHZpZXdwb3J0Wm9vbUZhY3Rvcjogb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnZpZXdwb3J0Wm9vbUZhY3RvclxuICAgICAgICB9KTtcbiAgICAgICAgem9vbSA9IGFwcFN0YXRlLnpvb207XG4gICAgICAgIHNjcm9sbFggPSBhcHBTdGF0ZS5zY3JvbGxYO1xuICAgICAgICBzY3JvbGxZID0gYXBwU3RhdGUuc2Nyb2xsWTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGNvbXB1dGUgb25seSB0aGUgdmlld3BvcnQgbG9jYXRpb24sIHdpdGhvdXQgYW55IHpvb20gYWRqdXN0bWVudFxuICAgICAgICBjb25zdCBzY3JvbGwgPSBjYWxjdWxhdGVTY3JvbGxDZW50ZXIodGFyZ2V0RWxlbWVudHMsIHRoaXMuc3RhdGUpO1xuICAgICAgICBzY3JvbGxYID0gc2Nyb2xsLnNjcm9sbFg7XG4gICAgICAgIHNjcm9sbFkgPSBzY3JvbGwuc2Nyb2xsWTtcbiAgICAgIH0gLy8gd2hlbiBhbmltYXRpbmcsIHdlIHVzZSBSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgdG8gcHJldmVudCB0aGUgYW5pbWF0aW9uXG4gICAgICAvLyBmcm9tIHNsb3dpbmcgZG93biBvdGhlciBwcm9jZXNzZXNcblxuXG4gICAgICBpZiAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmFuaW1hdGUpIHtcbiAgICAgICAgY29uc3Qgb3JpZ1Njcm9sbFggPSB0aGlzLnN0YXRlLnNjcm9sbFg7XG4gICAgICAgIGNvbnN0IG9yaWdTY3JvbGxZID0gdGhpcy5zdGF0ZS5zY3JvbGxZO1xuICAgICAgICBjb25zdCBvcmlnWm9vbSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgICAgY29uc3QgY2FuY2VsID0gZWFzZVRvVmFsdWVzUkFGKHtcbiAgICAgICAgICBmcm9tVmFsdWVzOiB7XG4gICAgICAgICAgICBzY3JvbGxYOiBvcmlnU2Nyb2xsWCxcbiAgICAgICAgICAgIHNjcm9sbFk6IG9yaWdTY3JvbGxZLFxuICAgICAgICAgICAgem9vbTogb3JpZ1pvb21cbiAgICAgICAgICB9LFxuICAgICAgICAgIHRvVmFsdWVzOiB7XG4gICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgIHpvb206IHpvb20udmFsdWVcbiAgICAgICAgICB9LFxuICAgICAgICAgIGludGVycG9sYXRlVmFsdWU6IChmcm9tLCB0bywgcHJvZ3Jlc3MsIGtleSkgPT4ge1xuICAgICAgICAgICAgLy8gZm9yIHpvb20sIHVzZSBkaWZmZXJlbnQgZWFzaW5nXG4gICAgICAgICAgICBpZiAoa2V5ID09PSBcInpvb21cIikge1xuICAgICAgICAgICAgICByZXR1cm4gZnJvbSAqIE1hdGgucG93KHRvIC8gZnJvbSwgZWFzZU91dChwcm9ncmVzcykpO1xuICAgICAgICAgICAgfSAvLyBoYW5kbGUgdXNpbmcgZGVmYXVsdFxuXG5cbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblN0ZXA6ICh7XG4gICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgIHpvb21cbiAgICAgICAgICB9KSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2Nyb2xsWCxcbiAgICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgICAgem9vbToge1xuICAgICAgICAgICAgICAgIHZhbHVlOiB6b29tXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgb25TdGFydDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogdHJ1ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvbkVuZDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgb25DYW5jZWw6ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIGR1cmF0aW9uOiAoX2IgPSBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZHVyYXRpb24pICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDUwMFxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9ICgpID0+IHtcbiAgICAgICAgICBjYW5jZWwoKTtcbiAgICAgICAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9IG51bGw7XG4gICAgICAgIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFksXG4gICAgICAgICAgem9vbVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICAgIC8qKiB1c2Ugd2hlbiBjaGFuZ2luZyBzY3JvbGxYL3Njcm9sbFkvem9vbSBiYXNlZCBvbiB1c2VyIGludGVyYWN0aW9uICovXG5cblxuICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzID0gc3RhdGUgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICAoX2EgPSB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwodGhpcyk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlKTtcbiAgICB9O1xuXG4gICAgdGhpcy5zZXRUb2FzdCA9IHRvYXN0ID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB0b2FzdFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzdG9yZUZpbGVGcm9tU2hhcmUgPSAoKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB3ZWJTaGFyZVRhcmdldENhY2hlID0geWllbGQgY2FjaGVzLm9wZW4oXCJ3ZWItc2hhcmUtdGFyZ2V0XCIpO1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IHlpZWxkIHdlYlNoYXJlVGFyZ2V0Q2FjaGUubWF0Y2goXCJzaGFyZWQtZmlsZVwiKTtcblxuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICBjb25zdCBibG9iID0geWllbGQgcmVzcG9uc2UuYmxvYigpO1xuICAgICAgICAgIGNvbnN0IGZpbGUgPSBuZXcgRmlsZShbYmxvYl0sIGJsb2IubmFtZSB8fCBcIlwiLCB7XG4gICAgICAgICAgICB0eXBlOiBibG9iLnR5cGVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLmxvYWRGaWxlVG9DYW52YXMoZmlsZSwgbnVsbCk7XG4gICAgICAgICAgeWllbGQgd2ViU2hhcmVUYXJnZXRDYWNoZS5kZWxldGUoXCJzaGFyZWQtZmlsZVwiKTtcbiAgICAgICAgICB3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUobnVsbCwgQVBQX05BTUUsIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICAvKiogYWRkcyBzdXBwbGllZCBmaWxlcyB0byBleGlzdGluZyBmaWxlcyBpbiB0aGUgYXBwU3RhdGUgKi9cblxuXG4gICAgdGhpcy5hZGRGaWxlcyA9IHdpdGhCYXRjaGVkVXBkYXRlcyhmaWxlcyA9PiB7XG4gICAgICBjb25zdCBmaWxlc01hcCA9IGZpbGVzLnJlZHVjZSgoYWNjLCBmaWxlRGF0YSkgPT4ge1xuICAgICAgICBhY2Muc2V0KGZpbGVEYXRhLmlkLCBmaWxlRGF0YSk7XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCBuZXcgTWFwKCkpO1xuICAgICAgdGhpcy5maWxlcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5maWxlcyksIE9iamVjdC5mcm9tRW50cmllcyhmaWxlc01hcCkpO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICBpZiAoaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChlbGVtZW50KSAmJiBmaWxlc01hcC5oYXMoZWxlbWVudC5maWxlSWQpKSB7XG4gICAgICAgICAgdGhpcy5pbWFnZUNhY2hlLmRlbGV0ZShlbGVtZW50LmZpbGVJZCk7XG4gICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICB9KTtcbiAgICB0aGlzLnVwZGF0ZVNjZW5lID0gd2l0aEJhdGNoZWRVcGRhdGVzKHNjZW5lRGF0YSA9PiB7XG4gICAgICBpZiAoc2NlbmVEYXRhLmNvbW1pdFRvSGlzdG9yeSkge1xuICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuYXBwU3RhdGUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShzY2VuZURhdGEuYXBwU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc2NlbmVEYXRhLmVsZW1lbnRzKSB7XG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHNjZW5lRGF0YS5lbGVtZW50cyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuY29sbGFib3JhdG9ycykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBjb2xsYWJvcmF0b3JzOiBzY2VuZURhdGEuY29sbGFib3JhdG9yc1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub25TY2VuZVVwZGF0ZWQgPSAoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHt9KTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHdoZXRoZXIgdGhlIG1lbnUgd2FzIHRvZ2dsZWQgb24gb3Igb2ZmXG4gICAgICovXG5cblxuICAgIHRoaXMudG9nZ2xlU2lkZWJhciA9ICh7XG4gICAgICBuYW1lLFxuICAgICAgdGFiLFxuICAgICAgZm9yY2VcbiAgICB9KSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGxldCBuZXh0TmFtZTtcblxuICAgICAgaWYgKGZvcmNlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbmV4dE5hbWUgPSAoKF9hID0gdGhpcy5zdGF0ZS5vcGVuU2lkZWJhcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm5hbWUpID09PSBuYW1lID8gbnVsbCA6IG5hbWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuZXh0TmFtZSA9IGZvcmNlID8gbmFtZSA6IG51bGw7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBvcGVuU2lkZWJhcjogbmV4dE5hbWUgPyB7XG4gICAgICAgICAgbmFtZTogbmV4dE5hbWUsXG4gICAgICAgICAgdGFiXG4gICAgICAgIH0gOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiAhIW5leHROYW1lO1xuICAgIH07XG5cbiAgICB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbiA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnggPSBldmVudC5jbGllbnRYO1xuICAgICAgdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55ID0gZXZlbnQuY2xpZW50WTtcbiAgICB9KTsgLy8gSW5wdXQgaGFuZGxpbmdcblxuICAgIHRoaXMub25LZXlEb3duID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIG5vcm1hbGl6ZSBgZXZlbnQua2V5YCB3aGVuIENhcHNMb2NrIGlzIHByZXNzZWQgIzIzNzJcbiAgICAgIGlmIChcIlByb3h5XCIgaW4gd2luZG93ICYmICghZXZlbnQuc2hpZnRLZXkgJiYgL15bQS1aXSQvLnRlc3QoZXZlbnQua2V5KSB8fCBldmVudC5zaGlmdEtleSAmJiAvXlthLXpdJC8udGVzdChldmVudC5rZXkpKSkge1xuICAgICAgICBldmVudCA9IG5ldyBQcm94eShldmVudCwge1xuICAgICAgICAgIGdldChldiwgcHJvcCkge1xuICAgICAgICAgICAgY29uc3QgdmFsdWUgPSBldltwcm9wXTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgIC8vIGZpeCBmb3IgUHJveGllcyBoaWphY2tpbmcgYHRoaXNgXG4gICAgICAgICAgICAgIHJldHVybiB2YWx1ZS5iaW5kKGV2KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHByb3AgPT09IFwia2V5XCIgPyAvLyBDYXBzTG9jayBpbnZlcnRzIGNhcGl0YWxpemF0aW9uIGJhc2VkIG9uIFNoaWZ0S2V5LCBzbyBpbnZlcnRcbiAgICAgICAgICAgIC8vIGl0IGJhY2tcbiAgICAgICAgICAgIGV2ZW50LnNoaWZ0S2V5ID8gZXYua2V5LnRvVXBwZXJDYXNlKCkgOiBldi5rZXkudG9Mb3dlckNhc2UoKSA6IHZhbHVlO1xuICAgICAgICAgIH1cblxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIGV2ZW50LmtleS50b0xvd2VyQ2FzZSgpID09PSBLRVlTLlYpIHtcbiAgICAgICAgSVNfUExBSU5fUEFTVEUgPSBldmVudC5zaGlmdEtleTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KElTX1BMQUlOX1BBU1RFX1RJTUVSKTsgLy8gcmVzZXQgKDEwMG1zIHRvIGJlIHNhZmUgdGhhdCB3ZSBpdCBydW5zIGFmdGVyIHRoZSBlbnN1aW5nXG4gICAgICAgIC8vIHBhc3RlIGV2ZW50KS4gVGhvdWdoLCB0ZWNobmljYWxseSB1bm5lY2Vzc2FyeSB0byByZXNldCBzaW5jZSB3ZVxuICAgICAgICAvLyAocmUpc2V0IHRoZSBmbGFnIGJlZm9yZSBlYWNoIHBhc3RlIGV2ZW50LlxuXG4gICAgICAgIElTX1BMQUlOX1BBU1RFX1RJTUVSID0gd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG4gICAgICAgIH0sIDEwMCk7XG4gICAgICB9IC8vIHByZXZlbnQgYnJvd3NlciB6b29tIGluIGlucHV0IGZpZWxkc1xuXG5cbiAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpKSB7XG4gICAgICAgIGlmIChldmVudC5jb2RlID09PSBDT0RFUy5NSU5VUyB8fCBldmVudC5jb2RlID09PSBDT0RFUy5FUVVBTCkge1xuICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IC8vIGJhaWwgaWZcblxuXG4gICAgICBpZiAoIC8vIGluc2lkZSBhbiBpbnB1dFxuICAgICAgaXNXcml0YWJsZUVsZW1lbnQoZXZlbnQudGFyZ2V0KSAmJiAvLyB1bmxlc3MgcHJlc3NpbmcgZXNjYXBlIChmaW5hbGl6ZSBhY3Rpb24pXG4gICAgICBldmVudC5rZXkgIT09IEtFWVMuRVNDQVBFIHx8IC8vIG9yIHVubGVzcyB1c2luZyBhcnJvd3MgKHRvIG1vdmUgYmV0d2VlbiBidXR0b25zKVxuICAgICAgaXNBcnJvd0tleShldmVudC5rZXkpICYmIGlzSW5wdXRMaWtlKGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlFVRVNUSU9OX01BUkspIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgb3BlbkRpYWxvZzogXCJoZWxwXCJcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5LnRvTG93ZXJDYXNlKCkgPT09IEtFWVMuRSAmJiBldmVudC5zaGlmdEtleSAmJiBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBvcGVuRGlhbG9nOiBcImltYWdlRXhwb3J0XCJcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX1VQIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX0RPV04pIHtcbiAgICAgICAgbGV0IG9mZnNldCA9IChldmVudC5zaGlmdEtleSA/IHRoaXMuc3RhdGUud2lkdGggOiB0aGlzLnN0YXRlLmhlaWdodCkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX0RPV04pIHtcbiAgICAgICAgICBvZmZzZXQgPSAtb2Zmc2V0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LnNoaWZ0S2V5KSB7XG4gICAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gKHtcbiAgICAgICAgICAgIHNjcm9sbFg6IHN0YXRlLnNjcm9sbFggKyBvZmZzZXRcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gKHtcbiAgICAgICAgICAgIHNjcm9sbFk6IHN0YXRlLnNjcm9sbFkgKyBvZmZzZXRcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuYWN0aW9uTWFuYWdlci5oYW5kbGVLZXlEb3duKGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiB0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0Fycm93S2V5KGV2ZW50LmtleSkpIHtcbiAgICAgICAgY29uc3Qgc3RlcCA9IHRoaXMuc3RhdGUuZ3JpZFNpemUgJiYgKGV2ZW50LnNoaWZ0S2V5ID8gRUxFTUVOVF9UUkFOU0xBVEVfQU1PVU5UIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSkgfHwgKGV2ZW50LnNoaWZ0S2V5ID8gRUxFTUVOVF9TSElGVF9UUkFOU0xBVEVfQU1PVU5UIDogRUxFTUVOVF9UUkFOU0xBVEVfQU1PVU5UKTtcbiAgICAgICAgbGV0IG9mZnNldFggPSAwO1xuICAgICAgICBsZXQgb2Zmc2V0WSA9IDA7XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19MRUZUKSB7XG4gICAgICAgICAgb2Zmc2V0WCA9IC1zdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19SSUdIVCkge1xuICAgICAgICAgIG9mZnNldFggPSBzdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19VUCkge1xuICAgICAgICAgIG9mZnNldFkgPSAtc3RlcDtcbiAgICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkgPT09IEtFWVMuQVJST1dfRE9XTikge1xuICAgICAgICAgIG9mZnNldFkgPSBzdGVwO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyxcbiAgICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZSxcbiAgICAgICAgICBpbmNsdWRlRWxlbWVudHNJbkZyYW1lczogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgeDogZWxlbWVudC54ICsgb2Zmc2V0WCxcbiAgICAgICAgICAgIHk6IGVsZW1lbnQueSArIG9mZnNldFlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB1cGRhdGVCb3VuZEVsZW1lbnRzKGVsZW1lbnQsIHtcbiAgICAgICAgICAgIHNpbXVsdGFuZW91c2x5VXBkYXRlZDogc2VsZWN0ZWRFbGVtZW50c1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkgPT09IEtFWVMuRU5URVIpIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnQgPSBzZWxlY3RlZEVsZW1lbnRzWzBdO1xuXG4gICAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgICAgICBpZiAoaXNMaW5lYXJFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkICE9PSBzZWxlY3RlZEVsZW1lbnRzWzBdLmlkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKHNlbGVjdGVkRWxlbWVudCwgdGhpcy5zY2VuZSlcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSBpZiAoaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnQpIHx8IGlzVmFsaWRUZXh0Q29udGFpbmVyKHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgIGxldCBjb250YWluZXI7XG5cbiAgICAgICAgICAgIGlmICghaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnQpKSB7XG4gICAgICAgICAgICAgIGNvbnRhaW5lciA9IHNlbGVjdGVkRWxlbWVudDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbWlkUG9pbnQgPSBnZXRDb250YWluZXJDZW50ZXIoc2VsZWN0ZWRFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICAgIGNvbnN0IHNjZW5lWCA9IG1pZFBvaW50Lng7XG4gICAgICAgICAgICBjb25zdCBzY2VuZVkgPSBtaWRQb2ludC55O1xuICAgICAgICAgICAgdGhpcy5zdGFydFRleHRFZGl0aW5nKHtcbiAgICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgICAgIGNvbnRhaW5lclxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaXNGcmFtZUVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogc2VsZWN0ZWRFbGVtZW50LmlkXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoIWV2ZW50LmN0cmxLZXkgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQubWV0YUtleSAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCA9PT0gbnVsbCkge1xuICAgICAgICBjb25zdCBzaGFwZSA9IGZpbmRTaGFwZUJ5S2V5KGV2ZW50LmtleSk7XG5cbiAgICAgICAgaWYgKHNoYXBlKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBzaGFwZSkge1xuICAgICAgICAgICAgdHJhY2tFdmVudChcInRvb2xiYXJcIiwgc2hhcGUsIGBrZXlib2FyZCAoJHt0aGlzLmRldmljZS5pc01vYmlsZSA/IFwibW9iaWxlXCIgOiBcImRlc2t0b3BcIn0pYCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgICAgIHR5cGU6IHNoYXBlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlEpIHtcbiAgICAgICAgICB0aGlzLnRvZ2dsZUxvY2soXCJrZXlib2FyZFwiKTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlNQQUNFICYmIGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMCkge1xuICAgICAgICBpc0hvbGRpbmdTcGFjZSA9IHRydWU7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCKTtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKChldmVudC5rZXkgPT09IEtFWVMuRyB8fCBldmVudC5rZXkgPT09IEtFWVMuUykgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgIXNlbGVjdGVkRWxlbWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5HICYmIChoYXNCYWNrZ3JvdW5kKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSB8fCBzZWxlY3RlZEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiBoYXNCYWNrZ3JvdW5kKGVsZW1lbnQudHlwZSkpKSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgb3BlblBvcHVwOiBcImVsZW1lbnRCYWNrZ3JvdW5kXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuUykge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgb3BlblBvcHVwOiBcImVsZW1lbnRTdHJva2VcIlxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiAoZXZlbnQua2V5ID09PSBLRVlTLkJBQ0tTUEFDRSB8fCBldmVudC5rZXkgPT09IEtFWVMuREVMRVRFKSkge1xuICAgICAgICBqb3RhaVN0b3JlLnNldChhY3RpdmVDb25maXJtRGlhbG9nQXRvbSwgXCJjbGVhckNhbnZhc1wiKTtcbiAgICAgIH0gLy8gZXllIGRyb3BwZXJcbiAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuICAgICAgY29uc3QgbG93ZXJDYXNlZCA9IGV2ZW50LmtleS50b0xvY2FsZUxvd2VyQ2FzZSgpO1xuICAgICAgY29uc3QgaXNQaWNraW5nU3Ryb2tlID0gbG93ZXJDYXNlZCA9PT0gS0VZUy5TICYmIGV2ZW50LnNoaWZ0S2V5O1xuICAgICAgY29uc3QgaXNQaWNraW5nQmFja2dyb3VuZCA9IGV2ZW50LmtleSA9PT0gS0VZUy5JIHx8IGxvd2VyQ2FzZWQgPT09IEtFWVMuRyAmJiBldmVudC5zaGlmdEtleTtcblxuICAgICAgaWYgKGlzUGlja2luZ1N0cm9rZSB8fCBpc1BpY2tpbmdCYWNrZ3JvdW5kKSB7XG4gICAgICAgIHRoaXMub3BlbkV5ZURyb3BwZXIoe1xuICAgICAgICAgIHR5cGU6IGlzUGlja2luZ1N0cm9rZSA/IFwic3Ryb2tlXCIgOiBcImJhY2tncm91bmRcIlxuICAgICAgICB9KTtcbiAgICAgIH0gLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAgIH0pO1xuICAgIHRoaXMub25XaGVlbCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICAvLyBwcmV2ZW50IGJyb3dzZXIgcGluY2ggem9vbSBvbiBET00gZWxlbWVudHNcbiAgICAgIGlmICghKGV2ZW50LnRhcmdldCBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50KSAmJiBldmVudC5jdHJsS2V5KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5vbktleVVwID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuU1BBQ0UpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpc0hvbGRpbmdTcGFjZSA9IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICF0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzQXJyb3dLZXkoZXZlbnQua2V5KSkge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgICAgICBpc0JpbmRpbmdFbmFibGVkKHRoaXMuc3RhdGUpID8gYmluZE9yVW5iaW5kU2VsZWN0ZWRFbGVtZW50cyhzZWxlY3RlZEVsZW1lbnRzKSA6IHVuYmluZExpbmVhckVsZW1lbnRzKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLnNldEFjdGl2ZVRvb2wgPSB0b29sID0+IHtcbiAgICAgIGNvbnN0IG5leHRBY3RpdmVUb29sID0gdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB0b29sKTtcblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgPT09IFwiaGFuZFwiKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCKTtcbiAgICAgIH0gZWxzZSBpZiAoIWlzSG9sZGluZ1NwYWNlKSB7XG4gICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNUb29sSWNvbihkb2N1bWVudC5hY3RpdmVFbGVtZW50KSkge1xuICAgICAgICB0aGlzLmZvY3VzQ29udGFpbmVyKCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghaXNMaW5lYXJFbGVtZW50VHlwZShuZXh0QWN0aXZlVG9vbC50eXBlKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChuZXh0QWN0aXZlVG9vbC50eXBlID09PSBcImltYWdlXCIpIHtcbiAgICAgICAgdGhpcy5vbkltYWdlQWN0aW9uKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChuZXh0QWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2wsXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgc25hcExpbmVzOiBbXSxcbiAgICAgICAgICBvcmlnaW5TbmFwT2Zmc2V0OiBudWxsXG4gICAgICAgIH0pKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IG5leHRBY3RpdmVUb29sLFxuICAgICAgICAgIHNuYXBMaW5lczogW10sXG4gICAgICAgICAgb3JpZ2luU25hcE9mZnNldDogbnVsbCxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLnNldEN1cnNvciA9IGN1cnNvciA9PiB7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgY3Vyc29yKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldEN1cnNvciA9ICgpID0+IHtcbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogcmV0dXJucyB3aGV0aGVyIHVzZXIgaXMgbWFraW5nIGEgZ2VzdHVyZSB3aXRoID49IDIgZmluZ2VycyAocG9pbnRzKVxuICAgICAqIG9uIG8gdG91Y2ggc2NyZWVuIChub3Qgb24gYSB0cmFja3BhZCkuIEN1cnJlbnRseSBvbmx5IHJlbGF0ZXMgdG8gRGFyd2luXG4gICAgICogKGlPUy9pUGFkT1MsTWFjT1MpLCBidXQgbWF5IHdvcmsgb24gb3RoZXIgZGV2aWNlcyBpbiB0aGUgZnV0dXJlIGlmXG4gICAgICogR2VzdHVyZUV2ZW50IGlzIHN0YW5kYXJkaXplZC5cbiAgICAgKi9cblxuXG4gICAgdGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUgPSAoKSA9PiB7XG4gICAgICAvLyB3ZSBkb24ndCB3YW50IHRvIGRlc2VsZWN0IHdoZW4gdXNpbmcgdHJhY2twYWQsIGFuZCBtdWx0aS1wb2ludCBnZXN0dXJlc1xuICAgICAgLy8gb25seSB3b3JrIG9uIHRvdWNoIHNjcmVlbnMsIHNvIGNoZWNraW5nIGZvciA+PSBwb2ludGVycyBtZWFucyB3ZSdyZSBvbiBhXG4gICAgICAvLyB0b3VjaHNjcmVlblxuICAgICAgcmV0dXJuIGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA+PSAyO1xuICAgIH07IC8vIGZpcmVzIG9ubHkgb24gU2FmYXJpXG5cblxuICAgIHRoaXMub25HZXN0dXJlU3RhcnQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gd2Ugb25seSB3YW50IHRvIGRlc2VsZWN0IG9uIHRvdWNoIHNjcmVlbnMgYmVjYXVzZSB1c2VyIG1heSBoYXZlIHNlbGVjdGVkXG4gICAgICAvLyBlbGVtZW50cyBieSBtaXN0YWtlIHdoaWxlIHpvb21pbmdcblxuICAgICAgaWYgKHRoaXMuaXNUb3VjaFNjcmVlbk11bHRpVG91Y2hHZXN0dXJlKCkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgfSk7IC8vIGZpcmVzIG9ubHkgb24gU2FmYXJpXG5cbiAgICB0aGlzLm9uR2VzdHVyZUNoYW5nZSA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyBvbkdlc3R1cmVDaGFuZ2Ugb25seSBoYXMgem9vbSBmYWN0b3IgYnV0IG5vdCB0aGUgY2VudGVyLlxuICAgICAgLy8gSWYgd2UncmUgb24gaVBhZCBvciBpUGhvbmUsIHRoZW4gd2UgcmVjb2duaXplIG11bHRpLXRvdWNoIGFuZCB3aWxsXG4gICAgICAvLyB6b29tIGluIGF0IHRoZSByaWdodCBsb2NhdGlvbiBpbiB0aGUgdG91Y2htb3ZlIGhhbmRsZXJcbiAgICAgIC8vIChoYW5kbGVDYW52YXNQb2ludGVyTW92ZSkuXG4gICAgICAvL1xuICAgICAgLy8gT24gTWFjYm9vayB0cmFja3BhZCwgd2UgZG9uJ3QgaGF2ZSB0aG9zZSBldmVudHMgc28gd2lsbCB6b29tIGluIGF0IHRoZVxuICAgICAgLy8gY3VycmVudCBsb2NhdGlvbiBpbnN0ZWFkLlxuICAgICAgLy9cbiAgICAgIC8vIEFzIHN1Y2gsIGJhaWwgZnJvbSB0aGlzIGhhbmRsZXIgb24gdG91Y2ggZGV2aWNlcy5cblxuICAgICAgaWYgKHRoaXMuaXNUb3VjaFNjcmVlbk11bHRpVG91Y2hHZXN0dXJlKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbml0aWFsU2NhbGUgPSBnZXN0dXJlLmluaXRpYWxTY2FsZTtcblxuICAgICAgaWYgKGluaXRpYWxTY2FsZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IE9iamVjdC5hc3NpZ24oe30sIGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgdmlld3BvcnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgICAgdmlld3BvcnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnksXG4gICAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKGluaXRpYWxTY2FsZSAqIGV2ZW50LnNjYWxlKVxuICAgICAgICB9LCBzdGF0ZSkpKTtcbiAgICAgIH1cbiAgICB9KTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuICAgIHRoaXMub25HZXN0dXJlRW5kID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIHJlc2VsZWN0IGVsZW1lbnRzIG9ubHkgb24gdG91Y2ggc2NyZWVucyAoc2VlIG9uR2VzdHVyZVN0YXJ0KVxuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczoge30sXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh0aGlzLnN0YXRlLnByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzLCB0aGlzLnN0YXRlKVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSBudWxsO1xuICAgIH0pO1xuXG4gICAgdGhpcy5zdGFydFRleHRFZGl0aW5nID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWSxcbiAgICAgIGluc2VydEF0UGFyZW50Q2VudGVyID0gdHJ1ZSxcbiAgICAgIGNvbnRhaW5lclxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgIGxldCBzaG91bGRCaW5kVG9Db250YWluZXIgPSBmYWxzZTtcbiAgICAgIGxldCBwYXJlbnRDZW50ZXJQb3NpdGlvbiA9IGluc2VydEF0UGFyZW50Q2VudGVyICYmIHRoaXMuZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwgdGhpcy5zdGF0ZSwgY29udGFpbmVyKTtcblxuICAgICAgaWYgKGNvbnRhaW5lciAmJiBwYXJlbnRDZW50ZXJQb3NpdGlvbikge1xuICAgICAgICBjb25zdCBib3VuZFRleHRFbGVtZW50VG9Db250YWluZXIgPSBnZXRCb3VuZFRleHRFbGVtZW50KGNvbnRhaW5lcik7XG5cbiAgICAgICAgaWYgKCFib3VuZFRleHRFbGVtZW50VG9Db250YWluZXIpIHtcbiAgICAgICAgICBzaG91bGRCaW5kVG9Db250YWluZXIgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxldCBleGlzdGluZ1RleHRFbGVtZW50ID0gbnVsbDtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBpZiAoaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnRzWzBdKSkge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBzZWxlY3RlZEVsZW1lbnRzWzBdO1xuICAgICAgICB9IGVsc2UgaWYgKGNvbnRhaW5lcikge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBnZXRCb3VuZFRleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSB0aGlzLmdldFRleHRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGV4aXN0aW5nVGV4dEVsZW1lbnQgPSB0aGlzLmdldFRleHRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZvbnRGYW1pbHkgPSAoZXhpc3RpbmdUZXh0RWxlbWVudCA9PT0gbnVsbCB8fCBleGlzdGluZ1RleHRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBleGlzdGluZ1RleHRFbGVtZW50LmZvbnRGYW1pbHkpIHx8IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250RmFtaWx5O1xuICAgICAgY29uc3QgbGluZUhlaWdodCA9IChleGlzdGluZ1RleHRFbGVtZW50ID09PSBudWxsIHx8IGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nVGV4dEVsZW1lbnQubGluZUhlaWdodCkgfHwgZ2V0RGVmYXVsdExpbmVIZWlnaHQoZm9udEZhbWlseSk7XG4gICAgICBjb25zdCBmb250U2l6ZSA9IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250U2l6ZTtcblxuICAgICAgaWYgKCFleGlzdGluZ1RleHRFbGVtZW50ICYmIHNob3VsZEJpbmRUb0NvbnRhaW5lciAmJiBjb250YWluZXIgJiYgIWlzQXJyb3dFbGVtZW50KGNvbnRhaW5lcikpIHtcbiAgICAgICAgY29uc3QgZm9udFN0cmluZyA9IHtcbiAgICAgICAgICBmb250U2l6ZSxcbiAgICAgICAgICBmb250RmFtaWx5XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IG1pbldpZHRoID0gZ2V0QXBwcm94TWluTGluZVdpZHRoKGdldEZvbnRTdHJpbmcoZm9udFN0cmluZyksIGxpbmVIZWlnaHQpO1xuICAgICAgICBjb25zdCBtaW5IZWlnaHQgPSBnZXRBcHByb3hNaW5MaW5lSGVpZ2h0KGZvbnRTaXplLCBsaW5lSGVpZ2h0KTtcbiAgICAgICAgY29uc3QgbmV3SGVpZ2h0ID0gTWF0aC5tYXgoY29udGFpbmVyLmhlaWdodCwgbWluSGVpZ2h0KTtcbiAgICAgICAgY29uc3QgbmV3V2lkdGggPSBNYXRoLm1heChjb250YWluZXIud2lkdGgsIG1pbldpZHRoKTtcbiAgICAgICAgbXV0YXRlRWxlbWVudChjb250YWluZXIsIHtcbiAgICAgICAgICBoZWlnaHQ6IG5ld0hlaWdodCxcbiAgICAgICAgICB3aWR0aDogbmV3V2lkdGhcbiAgICAgICAgfSk7XG4gICAgICAgIHNjZW5lWCA9IGNvbnRhaW5lci54ICsgbmV3V2lkdGggLyAyO1xuICAgICAgICBzY2VuZVkgPSBjb250YWluZXIueSArIG5ld0hlaWdodCAvIDI7XG5cbiAgICAgICAgaWYgKHBhcmVudENlbnRlclBvc2l0aW9uKSB7XG4gICAgICAgICAgcGFyZW50Q2VudGVyUG9zaXRpb24gPSB0aGlzLmdldFRleHRXeXNpd3lnU25hcHBlZFRvQ2VudGVyUG9zaXRpb24oc2NlbmVYLCBzY2VuZVksIHRoaXMuc3RhdGUsIGNvbnRhaW5lcik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSk7XG4gICAgICBjb25zdCBlbGVtZW50ID0gZXhpc3RpbmdUZXh0RWxlbWVudCA/IGV4aXN0aW5nVGV4dEVsZW1lbnQgOiBuZXdUZXh0RWxlbWVudCh7XG4gICAgICAgIHg6IHBhcmVudENlbnRlclBvc2l0aW9uID8gcGFyZW50Q2VudGVyUG9zaXRpb24uZWxlbWVudENlbnRlclggOiBzY2VuZVgsXG4gICAgICAgIHk6IHBhcmVudENlbnRlclBvc2l0aW9uID8gcGFyZW50Q2VudGVyUG9zaXRpb24uZWxlbWVudENlbnRlclkgOiBzY2VuZVksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICB0ZXh0OiBcIlwiLFxuICAgICAgICBmb250U2l6ZSxcbiAgICAgICAgZm9udEZhbWlseSxcbiAgICAgICAgdGV4dEFsaWduOiBwYXJlbnRDZW50ZXJQb3NpdGlvbiA/IFwiY2VudGVyXCIgOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtVGV4dEFsaWduLFxuICAgICAgICB2ZXJ0aWNhbEFsaWduOiBwYXJlbnRDZW50ZXJQb3NpdGlvbiA/IFZFUlRJQ0FMX0FMSUdOLk1JRERMRSA6IERFRkFVTFRfVkVSVElDQUxfQUxJR04sXG4gICAgICAgIGNvbnRhaW5lcklkOiBzaG91bGRCaW5kVG9Db250YWluZXIgPyBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuaWQgOiB1bmRlZmluZWQsXG4gICAgICAgIGdyb3VwSWRzOiAoX2EgPSBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuZ3JvdXBJZHMpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IFtdLFxuICAgICAgICBsaW5lSGVpZ2h0LFxuICAgICAgICBhbmdsZTogKF9iID0gY29udGFpbmVyID09PSBudWxsIHx8IGNvbnRhaW5lciA9PT0gdm9pZCAwID8gdm9pZCAwIDogY29udGFpbmVyLmFuZ2xlKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyICYmIGNvbnRhaW5lcikge1xuICAgICAgICBtdXRhdGVFbGVtZW50KGNvbnRhaW5lciwge1xuICAgICAgICAgIGJvdW5kRWxlbWVudHM6IChjb250YWluZXIuYm91bmRFbGVtZW50cyB8fCBbXSkuY29uY2F0KHtcbiAgICAgICAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgICAgICAgaWQ6IGVsZW1lbnQuaWRcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBlbGVtZW50XG4gICAgICB9KTtcblxuICAgICAgaWYgKCFleGlzdGluZ1RleHRFbGVtZW50KSB7XG4gICAgICAgIGlmIChjb250YWluZXIgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyKSB7XG4gICAgICAgICAgY29uc3QgY29udGFpbmVySW5kZXggPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRJbmRleChjb250YWluZXIuaWQpO1xuICAgICAgICAgIHRoaXMuc2NlbmUuaW5zZXJ0RWxlbWVudEF0SW5kZXgoZWxlbWVudCwgY29udGFpbmVySW5kZXggKyAxKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBlbGVtZW50XG4gICAgICB9KTtcbiAgICAgIHRoaXMuaGFuZGxlVGV4dFd5c2l3eWcoZWxlbWVudCwge1xuICAgICAgICBpc0V4aXN0aW5nRWxlbWVudDogISFleGlzdGluZ1RleHRFbGVtZW50XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNEb3VibGVDbGljayA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIGNhc2U6IGRvdWJsZS1jbGlja2luZyB3aXRoIGFycm93L2xpbmUgdG9vbCBzZWxlY3RlZCB3b3VsZCBib3RoIGNyZWF0ZVxuICAgICAgLy8gdGV4dCBhbmQgZW50ZXIgbXVsdGlFbGVtZW50IG1vZGVcbiAgICAgIGlmICh0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHdlIHNob3VsZCBvbmx5IGJlIGFibGUgdG8gZG91YmxlIGNsaWNrIHdoZW4gbW9kZSBpcyBzZWxlY3Rpb25cblxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNMaW5lYXJFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pKSB7XG4gICAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiAoIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgIT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpKSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKHNlbGVjdGVkRWxlbWVudHNbMF0sIHRoaXMuc2NlbmUpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgPT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICBsZXQge1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBzZWxlY3RlZEdyb3VwSWRzID0gZ2V0U2VsZWN0ZWRHcm91cElkcyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkR3JvdXBJZHMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkR3JvdXBJZCA9IGhpdEVsZW1lbnQgJiYgZ2V0U2VsZWN0ZWRHcm91cElkRm9yRWxlbWVudChoaXRFbGVtZW50LCB0aGlzLnN0YXRlLnNlbGVjdGVkR3JvdXBJZHMpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEdyb3VwSWQpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHNlbGVjdGVkR3JvdXBJZCxcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuXG4gICAgICBpZiAoIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICF0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSk7XG5cbiAgICAgICAgaWYgKGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IHtcbiAgICAgICAgICAgICAgZWxlbWVudDogaGl0RWxlbWVudCxcbiAgICAgICAgICAgICAgc3RhdGU6IFwiYWN0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjb250YWluZXIgPSBnZXRUZXh0QmluZGFibGVDb250YWluZXJBdFBvc2l0aW9uKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgICBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgaWYgKGhhc0JvdW5kVGV4dEVsZW1lbnQoY29udGFpbmVyKSB8fCAhaXNUcmFuc3BhcmVudChjb250YWluZXIuYmFja2dyb3VuZENvbG9yKSB8fCBpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveChjb250YWluZXIsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIFtzY2VuZVgsIHNjZW5lWV0pKSB7XG4gICAgICAgICAgICBjb25zdCBtaWRQb2ludCA9IGdldENvbnRhaW5lckNlbnRlcihjb250YWluZXIsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgc2NlbmVYID0gbWlkUG9pbnQueDtcbiAgICAgICAgICAgIHNjZW5lWSA9IG1pZFBvaW50Lnk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zdGFydFRleHRFZGl0aW5nKHtcbiAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgc2NlbmVZLFxuICAgICAgICAgIGluc2VydEF0UGFyZW50Q2VudGVyOiAhZXZlbnQuYWx0S2V5LFxuICAgICAgICAgIGNvbnRhaW5lclxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24gPSAoc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KSA9PiB7XG4gICAgICAvLyBSZXZlcnNpbmcgc28gd2UgdHJhdmVyc2UgdGhlIGVsZW1lbnRzIGluIGRlY3JlYXNpbmcgb3JkZXJcbiAgICAgIC8vIG9mIHotaW5kZXhcbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5zbGljZSgpLnJldmVyc2UoKTtcbiAgICAgIGxldCBoaXRFbGVtZW50SW5kZXggPSBJbmZpbml0eTtcbiAgICAgIHJldHVybiBlbGVtZW50cy5maW5kKChlbGVtZW50LCBpbmRleCkgPT4ge1xuICAgICAgICBpZiAoaGl0RWxlbWVudCAmJiBlbGVtZW50LmlkID09PSBoaXRFbGVtZW50LmlkKSB7XG4gICAgICAgICAgaGl0RWxlbWVudEluZGV4ID0gaW5kZXg7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlbWVudC5saW5rICYmIGluZGV4IDw9IGhpdEVsZW1lbnRJbmRleCAmJiBpc1BvaW50SGl0dGluZ0xpbmsoZWxlbWVudCwgdGhpcy5zdGF0ZSwgW3NjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueV0sIHRoaXMuZGV2aWNlLmlzTW9iaWxlKTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnJlZGlyZWN0VG9MaW5rID0gKGV2ZW50LCBpc1RvdWNoU2NyZWVuKSA9PiB7XG4gICAgICBjb25zdCBkcmFnZ2VkRGlzdGFuY2UgPSBkaXN0YW5jZTJkKHRoaXMubGFzdFBvaW50ZXJEb3duLmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJEb3duLmNsaWVudFksIHRoaXMubGFzdFBvaW50ZXJVcC5jbGllbnRYLCB0aGlzLmxhc3RQb2ludGVyVXAuY2xpZW50WSk7XG5cbiAgICAgIGlmICghdGhpcy5oaXRMaW5rRWxlbWVudCB8fCAvLyBGb3IgdG91Y2ggc2NyZWVuIGFsbG93IGRyYWdnaW5nIHRocmVzaG9sZCBlbHNlIHN0cmljdCBjaGVja1xuICAgICAgaXNUb3VjaFNjcmVlbiAmJiBkcmFnZ2VkRGlzdGFuY2UgPiBEUkFHR0lOR19USFJFU0hPTEQgfHwgIWlzVG91Y2hTY3JlZW4gJiYgZHJhZ2dlZERpc3RhbmNlICE9PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbGFzdFBvaW50ZXJEb3duQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHRoaXMubGFzdFBvaW50ZXJEb3duLCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGxhc3RQb2ludGVyRG93bkhpdHRpbmdMaW5rSWNvbiA9IGlzUG9pbnRIaXR0aW5nTGluayh0aGlzLmhpdExpbmtFbGVtZW50LCB0aGlzLnN0YXRlLCBbbGFzdFBvaW50ZXJEb3duQ29vcmRzLngsIGxhc3RQb2ludGVyRG93bkNvb3Jkcy55XSwgdGhpcy5kZXZpY2UuaXNNb2JpbGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJVcENvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh0aGlzLmxhc3RQb2ludGVyVXAsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJVcEhpdHRpbmdMaW5rSWNvbiA9IGlzUG9pbnRIaXR0aW5nTGluayh0aGlzLmhpdExpbmtFbGVtZW50LCB0aGlzLnN0YXRlLCBbbGFzdFBvaW50ZXJVcENvb3Jkcy54LCBsYXN0UG9pbnRlclVwQ29vcmRzLnldLCB0aGlzLmRldmljZS5pc01vYmlsZSk7XG5cbiAgICAgIGlmIChsYXN0UG9pbnRlckRvd25IaXR0aW5nTGlua0ljb24gJiYgbGFzdFBvaW50ZXJVcEhpdHRpbmdMaW5rSWNvbikge1xuICAgICAgICBsZXQgdXJsID0gdGhpcy5oaXRMaW5rRWxlbWVudC5saW5rO1xuXG4gICAgICAgIGlmICh1cmwpIHtcbiAgICAgICAgICB1cmwgPSBub3JtYWxpemVMaW5rKHVybCk7XG4gICAgICAgICAgbGV0IGN1c3RvbUV2ZW50O1xuXG4gICAgICAgICAgaWYgKHRoaXMucHJvcHMub25MaW5rT3Blbikge1xuICAgICAgICAgICAgY3VzdG9tRXZlbnQgPSB3cmFwRXZlbnQoRVZFTlQuRVhDQUxJRFJBV19MSU5LLCBldmVudC5uYXRpdmVFdmVudCk7XG4gICAgICAgICAgICB0aGlzLnByb3BzLm9uTGlua09wZW4oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmhpdExpbmtFbGVtZW50KSwge1xuICAgICAgICAgICAgICBsaW5rOiB1cmxcbiAgICAgICAgICAgIH0pLCBjdXN0b21FdmVudCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCEoY3VzdG9tRXZlbnQgPT09IG51bGwgfHwgY3VzdG9tRXZlbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGN1c3RvbUV2ZW50LmRlZmF1bHRQcmV2ZW50ZWQpKSB7XG4gICAgICAgICAgICBjb25zdCB0YXJnZXQgPSBpc0xvY2FsTGluayh1cmwpID8gXCJfc2VsZlwiIDogXCJfYmxhbmtcIjtcbiAgICAgICAgICAgIGNvbnN0IG5ld1dpbmRvdyA9IHdpbmRvdy5vcGVuKHVuZGVmaW5lZCwgdGFyZ2V0KTsgLy8gaHR0cHM6Ly9tYXRoaWFzYnluZW5zLmdpdGh1Yi5pby9yZWwtbm9vcGVuZXIvXG5cbiAgICAgICAgICAgIGlmIChuZXdXaW5kb3cpIHtcbiAgICAgICAgICAgICAgbmV3V2luZG93Lm9wZW5lciA9IG51bGw7XG4gICAgICAgICAgICAgIG5ld1dpbmRvdy5sb2NhdGlvbiA9IHVybDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3JkcyA9IHNjZW5lQ29vcmRzID0+IHtcbiAgICAgIGNvbnN0IGZyYW1lcyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLmZpbHRlcihmcmFtZSA9PiBpc0N1cnNvckluRnJhbWUoc2NlbmVDb29yZHMsIGZyYW1lKSk7XG4gICAgICByZXR1cm4gZnJhbWVzLmxlbmd0aCA/IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gOiBudWxsO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlID0gZXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCB0aGlzLnN0YXRlLmN1cnNvckJ1dHRvbik7XG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLmhhcyhldmVudC5wb2ludGVySWQpKSB7XG4gICAgICAgIGdlc3R1cmUucG9pbnRlcnMuc2V0KGV2ZW50LnBvaW50ZXJJZCwge1xuICAgICAgICAgIHg6IGV2ZW50LmNsaWVudFgsXG4gICAgICAgICAgeTogZXZlbnQuY2xpZW50WVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaW5pdGlhbFNjYWxlID0gZ2VzdHVyZS5pbml0aWFsU2NhbGU7XG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLnNpemUgPT09IDIgJiYgZ2VzdHVyZS5sYXN0Q2VudGVyICYmIGluaXRpYWxTY2FsZSAmJiBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSkge1xuICAgICAgICBjb25zdCBjZW50ZXIgPSBnZXRDZW50ZXIoZ2VzdHVyZS5wb2ludGVycyk7XG4gICAgICAgIGNvbnN0IGRlbHRhWCA9IGNlbnRlci54IC0gZ2VzdHVyZS5sYXN0Q2VudGVyLng7XG4gICAgICAgIGNvbnN0IGRlbHRhWSA9IGNlbnRlci55IC0gZ2VzdHVyZS5sYXN0Q2VudGVyLnk7XG4gICAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGNlbnRlcjtcbiAgICAgICAgY29uc3QgZGlzdGFuY2UgPSBnZXREaXN0YW5jZShBcnJheS5mcm9tKGdlc3R1cmUucG9pbnRlcnMudmFsdWVzKCkpKTtcbiAgICAgICAgY29uc3Qgc2NhbGVGYWN0b3IgPSB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmVlZHJhd1wiICYmIHRoaXMuc3RhdGUucGVuTW9kZSA/IDEgOiBkaXN0YW5jZSAvIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlO1xuICAgICAgICBjb25zdCBuZXh0Wm9vbSA9IHNjYWxlRmFjdG9yID8gZ2V0Tm9ybWFsaXplZFpvb20oaW5pdGlhbFNjYWxlICogc2NhbGVGYWN0b3IpIDogdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IHtcbiAgICAgICAgICBjb25zdCB6b29tU3RhdGUgPSBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICAgICAgdmlld3BvcnRYOiBjZW50ZXIueCxcbiAgICAgICAgICAgIHZpZXdwb3J0WTogY2VudGVyLnksXG4gICAgICAgICAgICBuZXh0Wm9vbVxuICAgICAgICAgIH0sIHN0YXRlKTtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyh7XG4gICAgICAgICAgICB6b29tOiB6b29tU3RhdGUuem9vbSxcbiAgICAgICAgICAgIHNjcm9sbFg6IHpvb21TdGF0ZS5zY3JvbGxYICsgZGVsdGFYIC8gbmV4dFpvb20sXG4gICAgICAgICAgICBzY3JvbGxZOiB6b29tU3RhdGUuc2Nyb2xsWSArIGRlbHRhWSAvIG5leHRab29tLFxuICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBnZXN0dXJlLmxhc3RDZW50ZXIgPSBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSA9IGdlc3R1cmUuaW5pdGlhbFNjYWxlID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzSG9sZGluZ1NwYWNlIHx8IGlzUGFubmluZyB8fCBpc0RyYWdnaW5nU2Nyb2xsQmFyIHx8IGlzSGFuZFRvb2xBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc1BvaW50ZXJPdmVyU2Nyb2xsQmFycyA9IGlzT3ZlclNjcm9sbEJhcnMoY3VycmVudFNjcm9sbEJhcnMsIGV2ZW50LmNsaWVudFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIGV2ZW50LmNsaWVudFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcCk7XG4gICAgICBjb25zdCBpc092ZXJTY3JvbGxCYXIgPSBpc1BvaW50ZXJPdmVyU2Nyb2xsQmFycy5pc092ZXJFaXRoZXI7XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIGlmIChpc092ZXJTY3JvbGxCYXIpIHtcbiAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3Qge1xuICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICB9ID0gc2NlbmVQb2ludGVyO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50ICYmIGlzQWN0aXZlVG9vbE5vbkxpbmVhclNuYXBwYWJsZSh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG9yaWdpbk9mZnNldCxcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSA9IGdldFNuYXBMaW5lc0F0UG9pbnRlcih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgeDogc2NlbmVQb2ludGVyWCxcbiAgICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICAgIH0sIGV2ZW50KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzLFxuICAgICAgICAgIG9yaWdpblNuYXBPZmZzZXQ6IG9yaWdpbk9mZnNldFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoIXRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNuYXBMaW5lczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgY29uc3QgZWRpdGluZ0xpbmVhckVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJNb3ZlKGV2ZW50LCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZWRpdGluZ0xpbmVhckVsZW1lbnQgIT09IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSBudWxsIHx8IGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlZGl0aW5nTGluZWFyRWxlbWVudC5sYXN0VW5jb21taXR0ZWRQb2ludCkgIT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0F0Q3Vyc29yKHNjZW5lUG9pbnRlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gY2F1c2VzIHN0YWNrIG92ZXJmbG93IGlmIG5vdCBzeW5jXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50VHlwZSh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgLy8gSG92ZXJpbmcgd2l0aCBhIHNlbGVjdGVkIHRvb2wgb3IgY3JlYXRpbmcgbmV3IGxpbmVhciBlbGVtZW50IHZpYSBjbGlja1xuICAgICAgICAvLyBhbmQgcG9pbnRcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBpZiAoaXNCaW5kaW5nRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ3NGb3JMaW5lYXJFbGVtZW50QXRDb29yZHMoZHJhZ2dpbmdFbGVtZW50LCBbc2NlbmVQb2ludGVyXSwgdGhpcy5zdGF0ZS5zdGFydEJvdW5kRWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3Ioc2NlbmVQb2ludGVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG11bHRpRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHJ4LFxuICAgICAgICAgIHk6IHJ5XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBwb2ludHMsXG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IGxhc3RQb2ludCA9IHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV07XG4gICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChsYXN0UG9pbnQgPT09IGxhc3RDb21taXR0ZWRQb2ludCkge1xuICAgICAgICAgIC8vIGlmIHdlIGhhdmVuJ3QgeWV0IGNyZWF0ZWQgYSB0ZW1wIHBvaW50IGFuZCB3ZSdyZSBiZXlvbmQgY29tbWl0LXpvbmVcbiAgICAgICAgICAvLyB0aHJlc2hvbGQsIGFkZCBhIHBvaW50XG4gICAgICAgICAgaWYgKGRpc3RhbmNlMmQoc2NlbmVQb2ludGVyWCAtIHJ4LCBzY2VuZVBvaW50ZXJZIC0gcnksIGxhc3RQb2ludFswXSwgbGFzdFBvaW50WzFdKSA+PSBMSU5FX0NPTkZJUk1fVEhSRVNIT0xEKSB7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeV1dXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpOyAvLyBpbiB0aGlzIGJyYW5jaCwgd2UncmUgaW5zaWRlIHRoZSBjb21taXQgem9uZSwgYW5kIG5vIHVuY29tbWl0dGVkXG4gICAgICAgICAgICAvLyBwb2ludCBleGlzdHMuIFRodXMgZG8gbm90aGluZyAoZG9uJ3QgYWRkL3JlbW92ZSBwb2ludHMpLlxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID4gMiAmJiBsYXN0Q29tbWl0dGVkUG9pbnQgJiYgZGlzdGFuY2UyZChzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeSwgbGFzdENvbW1pdHRlZFBvaW50WzBdLCBsYXN0Q29tbWl0dGVkUG9pbnRbMV0pIDwgTElORV9DT05GSVJNX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBwb2ludHMuc2xpY2UoMCwgLTEpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgICAgY29uc3QgW2xhc3RDb21taXR0ZWRYLCBsYXN0Q29tbWl0dGVkWV0gPSAoX2EgPSBtdWx0aUVsZW1lbnQgPT09IG51bGwgfHwgbXVsdGlFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBtdWx0aUVsZW1lbnQubGFzdENvbW1pdHRlZFBvaW50KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBbMCwgMF07XG4gICAgICAgICAgbGV0IGR4RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWCAtIHJ4IC0gbGFzdENvbW1pdHRlZFg7XG4gICAgICAgICAgbGV0IGR5RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWSAtIHJ5IC0gbGFzdENvbW1pdHRlZFk7XG5cbiAgICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpKSB7XG4gICAgICAgICAgICAoe1xuICAgICAgICAgICAgICB3aWR0aDogZHhGcm9tTGFzdENvbW1pdHRlZCxcbiAgICAgICAgICAgICAgaGVpZ2h0OiBkeUZyb21MYXN0Q29tbWl0dGVkXG4gICAgICAgICAgICB9ID0gZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplKCAvLyBhY3R1YWwgY29vcmRpbmF0ZSBvZiB0aGUgbGFzdCBjb21taXR0ZWQgcG9pbnRcbiAgICAgICAgICAgIGxhc3RDb21taXR0ZWRYICsgcngsIGxhc3RDb21taXR0ZWRZICsgcnksIC8vIGN1cnNvci1ncmlkIGNvb3JkaW5hdGVcbiAgICAgICAgICAgIGdyaWRYLCBncmlkWSkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChpc1BhdGhBTG9vcChwb2ludHMsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpIHtcbiAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICB9IC8vIHVwZGF0ZSBsYXN0IHVuY29tbWl0dGVkIHBvaW50XG5cblxuICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMuc2xpY2UoMCwgLTEpLCBbbGFzdENvbW1pdHRlZFggKyBkeEZyb21MYXN0Q29tbWl0dGVkLCBsYXN0Q29tbWl0dGVkWSArIGR5RnJvbUxhc3RDb21taXR0ZWRdXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNEZXNlbGVjdGVkQnV0dG9uID0gQm9vbGVhbihldmVudC5idXR0b25zKTtcblxuICAgICAgaWYgKGhhc0Rlc2VsZWN0ZWRCdXR0b24gfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwidGV4dFwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICFpc092ZXJTY3JvbGxCYXIgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlKGVsZW1lbnRzLCB0aGlzLnN0YXRlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICBpZiAoZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlICYmIGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS50cmFuc2Zvcm1IYW5kbGVUeXBlKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIGdldEN1cnNvckZvclJlc2l6aW5nRWxlbWVudChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiAxICYmICFpc092ZXJTY3JvbGxCYXIpIHtcbiAgICAgICAgY29uc3QgdHJhbnNmb3JtSGFuZGxlVHlwZSA9IGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzKGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG5cbiAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50KHtcbiAgICAgICAgICAgIHRyYW5zZm9ybUhhbmRsZVR5cGVcbiAgICAgICAgICB9KSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICB0aGlzLmhpdExpbmtFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KTtcblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGl0TGlua0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuaGl0TGlua0VsZW1lbnQuaWRdKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgc2hvd0h5cGVybGlua1Rvb2x0aXAodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoaWRlSHlwZXJsaW5rVG9vbGlwKCk7XG5cbiAgICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgKGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpKSAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSAmJiAhdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiAhdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXApIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogXCJpbmZvXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgaXNUZXh0RWxlbWVudChoaXRFbGVtZW50KSA/IENVUlNPUl9UWVBFLlRFWFQgOiBDVVJTT1JfVFlQRS5DUk9TU0hBSVIpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICB9IGVsc2UgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlSG92ZXJTZWxlY3RlZExpbmVhckVsZW1lbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpO1xuICAgICAgICB9IGVsc2UgaWYgKCAvLyBpZiB1c2luZyBjbWQvY3RybCwgd2UncmUgbm90IGRyYWdnaW5nXG4gICAgICAgICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICAgIGlmICgoaGl0RWxlbWVudCB8fCB0aGlzLmlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHNjZW5lUG9pbnRlciwgc2VsZWN0ZWRFbGVtZW50cykpICYmICEoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmxvY2tlZCkpIHtcbiAgICAgICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgZXZlbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICAgICAgZWxlbWVudDogaGl0RWxlbWVudCxcbiAgICAgICAgICAgICAgICAgIHN0YXRlOiBcImhvdmVyXCJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuXG4gICAgICAgICAgICAgIGlmICgoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImhvdmVyXCIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQVVUTyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVFcmFzZXIgPSAoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUsIHNjZW5lUG9pbnRlcikgPT4ge1xuICAgICAgY29uc3QgdXBkYXRlRWxlbWVudElkcyA9IGVsZW1lbnRzID0+IHtcbiAgICAgICAgZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoZWxlbWVudC5sb2NrZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZHNUb1VwZGF0ZS5wdXNoKGVsZW1lbnQuaWQpO1xuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSkge1xuICAgICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlbWVudC5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXS5lcmFzZSkge1xuICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdLmVyYXNlID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmICghcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSA9IHtcbiAgICAgICAgICAgICAgZXJhc2U6IHRydWUsXG4gICAgICAgICAgICAgIG9wYWNpdHk6IGVsZW1lbnQub3BhY2l0eVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfTtcblxuICAgICAgY29uc3QgaWRzVG9VcGRhdGUgPSBbXTtcbiAgICAgIGNvbnN0IGRpc3RhbmNlID0gZGlzdGFuY2UyZChwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnksIHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICBjb25zdCB0aHJlc2hvbGQgPSAxMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgIGNvbnN0IHBvaW50ID0gT2JqZWN0LmFzc2lnbih7fSwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzKTtcbiAgICAgIGxldCBzYW1wbGluZ0ludGVydmFsID0gMDtcblxuICAgICAgd2hpbGUgKHNhbXBsaW5nSW50ZXJ2YWwgPD0gZGlzdGFuY2UpIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbihwb2ludC54LCBwb2ludC55KTtcbiAgICAgICAgdXBkYXRlRWxlbWVudElkcyhoaXRFbGVtZW50cyk7IC8vIEV4aXQgc2luY2Ugd2UgcmVhY2hlZCBjdXJyZW50IHBvaW50XG5cbiAgICAgICAgaWYgKHNhbXBsaW5nSW50ZXJ2YWwgPT09IGRpc3RhbmNlKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gLy8gQ2FsY3VsYXRlIG5leHQgcG9pbnQgaW4gdGhlIGxpbmUgYXQgYSBkaXN0YW5jZSBvZiBzYW1wbGluZyBpbnRlcnZhbFxuXG5cbiAgICAgICAgc2FtcGxpbmdJbnRlcnZhbCA9IE1hdGgubWluKHNhbXBsaW5nSW50ZXJ2YWwgKyB0aHJlc2hvbGQsIGRpc3RhbmNlKTtcbiAgICAgICAgY29uc3QgZGlzdGFuY2VSYXRpbyA9IHNhbXBsaW5nSW50ZXJ2YWwgLyBkaXN0YW5jZTtcbiAgICAgICAgY29uc3QgbmV4dFggPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueCArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueDtcbiAgICAgICAgY29uc3QgbmV4dFkgPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueSArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueTtcbiAgICAgICAgcG9pbnQueCA9IG5leHRYO1xuICAgICAgICBwb2ludC55ID0gbmV4dFk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWxlID0+IHtcbiAgICAgICAgY29uc3QgaWQgPSBpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBpZHNUb1VwZGF0ZS5pbmNsdWRlcyhlbGUuY29udGFpbmVySWQpID8gZWxlLmNvbnRhaW5lcklkIDogZWxlLmlkO1xuXG4gICAgICAgIGlmIChpZHNUb1VwZGF0ZS5pbmNsdWRlcyhpZCkpIHtcbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0uZXJhc2UgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXS5vcGFjaXR5XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICAgIG9wYWNpdHk6IEVMRU1FTlRfUkVBRFlfVE9fRVJBU0VfT1BBQ0lUWVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBzY2VuZVBvaW50ZXIueDtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gc2NlbmVQb2ludGVyLnk7XG4gICAgfTsgLy8gc2V0IHRvdWNoIG1vdmluZyBmb3IgbW9iaWxlIGNvbnRleHQgbWVudVxuXG5cbiAgICB0aGlzLmhhbmRsZVRvdWNoTW92ZSA9IGV2ZW50ID0+IHtcbiAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IHRydWU7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24gPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBzaW5jZSBjb250ZXh0TWVudSBvcHRpb25zIGFyZSBwb3RlbnRpYWxseSBldmFsdWF0ZWQgb24gZWFjaCByZW5kZXIsXG4gICAgICAvLyBhbmQgYW4gY29udGV4dE1lbnUgYWN0aW9uIG1heSBkZXBlbmQgb24gc2VsZWN0aW9uIHN0YXRlLCB3ZSBtdXN0XG4gICAgICAvLyBjbG9zZSB0aGUgY29udGV4dE1lbnUgYmVmb3JlIHdlIHVwZGF0ZSB0aGUgc2VsZWN0aW9uIG9uIHBvaW50ZXJEb3duXG4gICAgICAvLyAoZS5nLiByZXNldHRpbmcgc2VsZWN0aW9uKVxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zbmFwTGluZXMpIHtcbiAgICAgICAgdGhpcy5zZXRBcHBTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy51cGRhdGVHZXN0dXJlT25Qb2ludGVyRG93bihldmVudCk7IC8vIGlmIGRyYWdnaW5nIGVsZW1lbnQgaXMgZnJlZWRyYXcgYW5kIGFub3RoZXIgcG9pbnRlcmRvd24gZXZlbnQgb2NjdXJzXG4gICAgICAvLyBhIHNlY29uZCBmaW5nZXIgaXMgb24gdGhlIHNjcmVlblxuICAgICAgLy8gZGlzY2FyZCB0aGUgZnJlZWRyYXcgZWxlbWVudCBpZiBpdCBpcyB2ZXJ5IHNob3J0IGJlY2F1c2UgaXQgaXMgbGlrZWx5XG4gICAgICAvLyBqdXN0IGEgc3Bpa2UsIG90aGVyd2lzZSBmaW5hbGl6ZSB0aGUgZnJlZWRyYXcgZWxlbWVudCB3aGVuIHRoZSBzZWNvbmRcbiAgICAgIC8vIGZpbmdlciBpcyBsaWZ0ZWRcblxuICAgICAgaWYgKGV2ZW50LnBvaW50ZXJUeXBlID09PSBcInRvdWNoXCIgJiYgdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudDtcbiAgICAgICAgdGhpcy51cGRhdGVTY2VuZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGVsZW1lbnQucG9pbnRzLmxlbmd0aCA8IDEwID8ge1xuICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbHRlcihlbCA9PiBlbC5pZCAhPT0gZWxlbWVudC5pZClcbiAgICAgICAgfSA6IHt9KSwge1xuICAgICAgICAgIGFwcFN0YXRlOiB7XG4gICAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgIHN0YXJ0Qm91bmRFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3Qua2V5cyh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcykuZmlsdGVyKGtleSA9PiBrZXkgIT09IGVsZW1lbnQuaWQpLnJlZHVjZSgob2JqLCBrZXkpID0+IHtcbiAgICAgICAgICAgICAgb2JqW2tleV0gPSB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1trZXldO1xuICAgICAgICAgICAgICByZXR1cm4gb2JqO1xuICAgICAgICAgICAgfSwge30pLCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSkpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHJlbW92ZSBhbnkgYWN0aXZlIHNlbGVjdGlvbiB3aGVuIHdlIHN0YXJ0IHRvIGludGVyYWN0IHdpdGggY2FudmFzXG4gICAgICAvLyAobWFpbmx5LCB3ZSBjYXJlIGFib3V0IHJlbW92aW5nIHNlbGVjdGlvbiBvdXRzaWRlIHRoZSBjb21wb25lbnQgd2hpY2hcbiAgICAgIC8vICB3b3VsZCBwcmV2ZW50IG91ciBjb3B5IGhhbmRsaW5nIG90aGVyd2lzZSlcblxuXG4gICAgICBjb25zdCBzZWxlY3Rpb24gPSBkb2N1bWVudC5nZXRTZWxlY3Rpb24oKTtcblxuICAgICAgaWYgKHNlbGVjdGlvbiA9PT0gbnVsbCB8fCBzZWxlY3Rpb24gPT09IHZvaWQgMCA/IHZvaWQgMCA6IHNlbGVjdGlvbi5hbmNob3JOb2RlKSB7XG4gICAgICAgIHNlbGVjdGlvbi5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tYXliZU9wZW5Db250ZXh0TWVudUFmdGVyUG9pbnRlckRvd25PblRvdWNoRGV2aWNlcyhldmVudCk7XG4gICAgICB0aGlzLm1heWJlQ2xlYW51cEFmdGVyTWlzc2luZ1BvaW50ZXJVcChldmVudCk7IC8vZmlyZXMgb25seSBvbmNlLCBpZiBwZW4gaXMgZGV0ZWN0ZWQsIHBlbk1vZGUgaXMgZW5hYmxlZFxuICAgICAgLy90aGUgdXNlciBjYW4gZGlzYWJsZSB0aGlzIGJ5IHRvZ2dsaW5nIHRoZSBwZW5Nb2RlIGJ1dHRvblxuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUucGVuRGV0ZWN0ZWQgJiYgZXZlbnQucG9pbnRlclR5cGUgPT09IFwicGVuXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBwZW5Nb2RlOiB0cnVlLFxuICAgICAgICAgICAgcGVuRGV0ZWN0ZWQ6IHRydWVcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuICYmIFtcInBlblwiLCBcInRvdWNoXCJdLmluY2x1ZGVzKGV2ZW50LnBvaW50ZXJUeXBlKSkge1xuICAgICAgICB0aGlzLmRldmljZSA9IHVwZGF0ZU9iamVjdCh0aGlzLmRldmljZSwge1xuICAgICAgICAgIGlzVG91Y2hTY3JlZW46IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc1Bhbm5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmxhc3RQb2ludGVyRG93biA9IGV2ZW50O1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGxhc3RQb2ludGVyRG93bldpdGg6IGV2ZW50LnBvaW50ZXJUeXBlLFxuICAgICAgICBjdXJzb3JCdXR0b246IFwiZG93blwiXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgXCJkb3duXCIpO1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVDYW52YXNQYW5Vc2luZ1doZWVsT3JTcGFjZURyYWcoZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gb25seSBoYW5kbGUgbGVmdCBtb3VzZSBidXR0b24gb3IgdG91Y2hcblxuXG4gICAgICBpZiAoZXZlbnQuYnV0dG9uICE9PSBQT0lOVEVSX0JVVFRPTi5NQUlOICYmIGV2ZW50LmJ1dHRvbiAhPT0gUE9JTlRFUl9CVVRUT04uVE9VQ0gpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBkb24ndCBzZWxlY3Qgd2hpbGUgcGFubmluZ1xuXG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLnNpemUgPiAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gU3RhdGUgZm9yIHRoZSBkdXJhdGlvbiBvZiBhIHBvaW50ZXIgaW50ZXJhY3Rpb24sIHdoaWNoIHN0YXJ0cyB3aXRoIGFcbiAgICAgIC8vIHBvaW50ZXJEb3duIGV2ZW50LCBlbmRzIHdpdGggYSBwb2ludGVyVXAgZXZlbnQgKG9yIGFub3RoZXIgcG9pbnRlckRvd24pXG5cblxuICAgICAgY29uc3QgcG9pbnRlckRvd25TdGF0ZSA9IHRoaXMuaW5pdGlhbFBvaW50ZXJEb3duU3RhdGUoZXZlbnQpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IGZhbHNlXG4gICAgICB9KTtcblxuICAgICAgaWYgKHRoaXMuaGFuZGxlRHJhZ2dpbmdTY3JvbGxCYXIoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5jbGVhclNlbGVjdGlvbklmTm90VXNpbmdTZWxlY3Rpb24oKTtcbiAgICAgIHRoaXMudXBkYXRlQmluZGluZ0VuYWJsZWRPblBvaW50ZXJNb3ZlKGV2ZW50KTtcblxuICAgICAgaWYgKHRoaXMuaGFuZGxlU2VsZWN0aW9uT25Qb2ludGVyRG93bihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBhbGxvd09uUG9pbnRlckRvd24gPSAhdGhpcy5zdGF0ZS5wZW5Nb2RlIHx8IGV2ZW50LnBvaW50ZXJUeXBlICE9PSBcInRvdWNoXCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwidGV4dFwiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImltYWdlXCI7XG5cbiAgICAgIGlmICghYWxsb3dPblBvaW50ZXJEb3duKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInRleHRcIikge1xuICAgICAgICB0aGlzLmhhbmRsZVRleHRPblBvaW50ZXJEb3duKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJhcnJvd1wiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxpbmVcIikge1xuICAgICAgICB0aGlzLmhhbmRsZUxpbmVhckVsZW1lbnRPblBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImltYWdlXCIpIHtcbiAgICAgICAgLy8gcmVzZXQgaW1hZ2UgcHJldmlldyBvbiBwb2ludGVyZG93blxuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQ1JPU1NIQUlSKTsgLy8gcmV0cmlldmUgdGhlIGxhdGVzdCBlbGVtZW50IGFzIHRoZSBzdGF0ZSBtYXkgYmUgc3RhbGVcblxuICAgICAgICBjb25zdCBwZW5kaW5nSW1hZ2VFbGVtZW50ID0gdGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQgJiYgdGhpcy5zY2VuZS5nZXRFbGVtZW50KHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkKTtcblxuICAgICAgICBpZiAoIXBlbmRpbmdJbWFnZUVsZW1lbnQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IHBlbmRpbmdJbWFnZUVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IHBlbmRpbmdJbWFnZUVsZW1lbnQsXG4gICAgICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiBudWxsLFxuICAgICAgICAgIG11bHRpRWxlbWVudDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgbXV0YXRlRWxlbWVudChwZW5kaW5nSW1hZ2VFbGVtZW50LCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlRnJlZURyYXdFbGVtZW50T25Qb2ludGVyRG93bihldmVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJjdXN0b21cIikge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLmN1c3RvbVR5cGUgPT09IFwiY29tbWVudFwiKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkFVVE8pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyYW1lXCIpIHtcbiAgICAgICAgdGhpcy5jcmVhdGVGcmFtZUVsZW1lbnRPblBvaW50ZXJEb3duKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJlcmFzZXJcIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJoYW5kXCIpIHtcbiAgICAgICAgdGhpcy5jcmVhdGVHZW5lcmljRWxlbWVudE9uUG9pbnRlckRvd24odGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eub25Qb2ludGVyRG93bikgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbCwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB0aGlzLm9uUG9pbnRlckRvd25FbWl0dGVyLnRyaWdnZXIodGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgICBjb25zdCBvblBvaW50ZXJNb3ZlID0gdGhpcy5vblBvaW50ZXJNb3ZlRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uUG9pbnRlclVwID0gdGhpcy5vblBvaW50ZXJVcEZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICBjb25zdCBvbktleURvd24gPSB0aGlzLm9uS2V5RG93bkZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICBjb25zdCBvbktleVVwID0gdGhpcy5vbktleVVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGxhc3RQb2ludGVyVXAgPSBvblBvaW50ZXJVcDtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBvblBvaW50ZXJVcCk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIG9uS2V5RG93bik7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULktFWVVQLCBvbktleVVwKTtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbk1vdmUgPSBvblBvaW50ZXJNb3ZlO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uVXAgPSBvblBvaW50ZXJVcDtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbktleVVwID0gb25LZXlVcDtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbktleURvd24gPSBvbktleURvd247XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlclVwID0gZXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgdGhpcy5yZW1vdmVQb2ludGVyKGV2ZW50KTtcbiAgICAgIHRoaXMubGFzdFBvaW50ZXJVcCA9IGV2ZW50O1xuICAgICAgY29uc3Qgc2NlbmVQb2ludGVyID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgY2xpZW50WDogZXZlbnQuY2xpZW50WCxcbiAgICAgICAgY2xpZW50WTogZXZlbnQuY2xpZW50WVxuICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBjbGlja2xlbmd0aCA9IGV2ZW50LnRpbWVTdGFtcCAtICgoX2IgPSAoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRpbWVTdGFtcCkgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogMCk7XG5cbiAgICAgIGlmICh0aGlzLmRldmljZS5pc01vYmlsZSAmJiBjbGlja2xlbmd0aCA8IDMwMCkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpO1xuXG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpICYmIHRoaXMuaXNFbWJlZGRhYmxlQ2VudGVyKGhpdEVsZW1lbnQsIGV2ZW50LCBzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpKSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2soaGl0RWxlbWVudCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICAgIHRoaXMuaGl0TGlua0VsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbihzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5oaXRMaW5rRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5oaXRMaW5rRWxlbWVudC5pZF0pIHtcbiAgICAgICAgaWYgKGNsaWNrbGVuZ3RoIDwgMzAwICYmIHRoaXMuaGl0TGlua0VsZW1lbnQudHlwZSA9PT0gXCJlbWJlZGRhYmxlXCIgJiYgIWlzUG9pbnRIaXR0aW5nTGlua0ljb24odGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSwgW3NjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueV0pKSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2sodGhpcy5oaXRMaW5rRWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5yZWRpcmVjdFRvTGluayhldmVudCwgdGhpcy5kZXZpY2UuaXNUb3VjaFNjcmVlbik7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbCxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHt9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLm1heWJlT3BlbkNvbnRleHRNZW51QWZ0ZXJQb2ludGVyRG93bk9uVG91Y2hEZXZpY2VzID0gZXZlbnQgPT4ge1xuICAgICAgLy8gZGVhbCB3aXRoIG9wZW5pbmcgY29udGV4dCBtZW51IG9uIHRvdWNoIGRldmljZXNcbiAgICAgIGlmIChldmVudC5wb2ludGVyVHlwZSA9PT0gXCJ0b3VjaFwiKSB7XG4gICAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IGZhbHNlO1xuXG4gICAgICAgIGlmICh0b3VjaFRpbWVvdXQpIHtcbiAgICAgICAgICAvLyBJZiB0aGVyZSdzIGFscmVhZHkgYSB0b3VjaFRpbWVvdXQsIHRoaXMgbWVhbnMgdGhhdCB0aGVyZSdzIGFub3RoZXJcbiAgICAgICAgICAvLyB0b3VjaCBkb3duIGFuZCB3ZSBhcmUgZG9pbmcgYW5vdGhlciB0b3VjaCwgc28gd2Ugc2hvdWxkbid0IG9wZW4gdGhlXG4gICAgICAgICAgLy8gY29udGV4dCBtZW51LlxuICAgICAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gb3BlbiB0aGUgY29udGV4dCBtZW51IHdpdGggdGhlIGZpcnN0IHRvdWNoJ3MgY2xpZW50WCBhbmQgY2xpZW50WVxuICAgICAgICAgIC8vIGlmIHRoZSB0b3VjaCBpcyBub3QgbW92aW5nXG4gICAgICAgICAgdG91Y2hUaW1lb3V0ID0gd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgdG91Y2hUaW1lb3V0ID0gMDtcblxuICAgICAgICAgICAgaWYgKCFpbnZhbGlkYXRlQ29udGV4dE1lbnUpIHtcbiAgICAgICAgICAgICAgdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudShldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSwgVE9VQ0hfQ1RYX01FTlVfVElNRU9VVCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIgPSAoKSA9PiB7XG4gICAgICBjbGVhclRpbWVvdXQodG91Y2hUaW1lb3V0KTtcbiAgICAgIHRvdWNoVGltZW91dCA9IDA7XG4gICAgICBpbnZhbGlkYXRlQ29udGV4dE1lbnUgPSBmYWxzZTtcbiAgICB9OyAvLyBSZXR1cm5zIHdoZXRoZXIgdGhlIGV2ZW50IGlzIGEgcGFubmluZ1xuXG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc1BhblVzaW5nV2hlZWxPclNwYWNlRHJhZyA9IGV2ZW50ID0+IHtcbiAgICAgIGlmICghKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA8PSAxICYmIChldmVudC5idXR0b24gPT09IFBPSU5URVJfQlVUVE9OLldIRUVMIHx8IGV2ZW50LmJ1dHRvbiA9PT0gUE9JTlRFUl9CVVRUT04uTUFJTiAmJiBpc0hvbGRpbmdTcGFjZSB8fCBpc0hhbmRUb29sQWN0aXZlKHRoaXMuc3RhdGUpIHx8IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSkgfHwgaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlzUGFubmluZyA9IHRydWU7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgbGV0IG5leHRQYXN0ZVByZXZlbnRlZCA9IGZhbHNlO1xuICAgICAgY29uc3QgaXNMaW51eCA9IC9MaW51eC8udGVzdCh3aW5kb3cubmF2aWdhdG9yLnBsYXRmb3JtKTtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCQklORyk7XG4gICAgICBsZXQge1xuICAgICAgICBjbGllbnRYOiBsYXN0WCxcbiAgICAgICAgY2xpZW50WTogbGFzdFlcbiAgICAgIH0gPSBldmVudDtcbiAgICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQoZXZlbnQgPT4ge1xuICAgICAgICBjb25zdCBkZWx0YVggPSBsYXN0WCAtIGV2ZW50LmNsaWVudFg7XG4gICAgICAgIGNvbnN0IGRlbHRhWSA9IGxhc3RZIC0gZXZlbnQuY2xpZW50WTtcbiAgICAgICAgbGFzdFggPSBldmVudC5jbGllbnRYO1xuICAgICAgICBsYXN0WSA9IGV2ZW50LmNsaWVudFk7XG4gICAgICAgIC8qXG4gICAgICAgICAqIFByZXZlbnQgcGFzdGUgZXZlbnQgaWYgd2UgbW92ZSB3aGlsZSBtaWRkbGUgY2xpY2tpbmcgb24gTGludXguXG4gICAgICAgICAqIFNlZSBpc3N1ZSAjMTM4My5cbiAgICAgICAgICovXG5cbiAgICAgICAgaWYgKGlzTGludXggJiYgIW5leHRQYXN0ZVByZXZlbnRlZCAmJiAoTWF0aC5hYnMoZGVsdGFYKSA+IDEgfHwgTWF0aC5hYnMoZGVsdGFZKSA+IDEpKSB7XG4gICAgICAgICAgbmV4dFBhc3RlUHJldmVudGVkID0gdHJ1ZTtcbiAgICAgICAgICAvKiBQcmV2ZW50IHRoZSBuZXh0IHBhc3RlIGV2ZW50ICovXG5cbiAgICAgICAgICBjb25zdCBwcmV2ZW50TmV4dFBhc3RlID0gZXZlbnQgPT4ge1xuICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCBwcmV2ZW50TmV4dFBhc3RlKTtcbiAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgIH07XG4gICAgICAgICAgLypcbiAgICAgICAgICAgKiBSZWVuYWJsZSBuZXh0IHBhc3RlIGluIGNhc2Ugb2YgZGlzYWJsZWQgbWlkZGxlIGNsaWNrIHBhc3RlIGZvclxuICAgICAgICAgICAqIGFueSByZWFzb246XG4gICAgICAgICAgICogLSByaWdodCBjbGljayBwYXN0ZVxuICAgICAgICAgICAqIC0gZW1wdHkgY2xpcGJvYXJkXG4gICAgICAgICAgICovXG5cblxuICAgICAgICAgIGNvbnN0IGVuYWJsZU5leHRQYXN0ZSA9ICgpID0+IHtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHByZXZlbnROZXh0UGFzdGUpO1xuICAgICAgICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBlbmFibGVOZXh0UGFzdGUpO1xuICAgICAgICAgICAgfSwgMTAwKTtcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCBwcmV2ZW50TmV4dFBhc3RlKTtcbiAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBlbmFibGVOZXh0UGFzdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoe1xuICAgICAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCAtIGRlbHRhWCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSxcbiAgICAgICAgICBzY3JvbGxZOiB0aGlzLnN0YXRlLnNjcm9sbFkgLSBkZWx0YVkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHRlYXJkb3duID0gd2l0aEJhdGNoZWRVcGRhdGVzKGxhc3RQb2ludGVyVXAgPSAoKSA9PiB7XG4gICAgICAgIGxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgICAgICBpc1Bhbm5pbmcgPSBmYWxzZTtcblxuICAgICAgICBpZiAoIWlzSG9sZGluZ1NwYWNlKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGN1cnNvckJ1dHRvbjogXCJ1cFwiXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRlYXJkb3duKTtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGVhcmRvd24pO1xuICAgICAgICBvblBvaW50ZXJNb3ZlLmZsdXNoKCk7XG4gICAgICB9KTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkJMVVIsIHRlYXJkb3duKTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSwge1xuICAgICAgICBwYXNzaXZlOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRlYXJkb3duKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH07XG5cbiAgICB0aGlzLmNsZWFyU2VsZWN0aW9uSWZOb3RVc2luZ1NlbGVjdGlvbiA9ICgpID0+IHtcbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybnMgd2hldGhlciB0aGUgcG9pbnRlciBldmVudCBoYXMgYmVlbiBjb21wbGV0ZWx5IGhhbmRsZWRcbiAgICAgKi9cblxuXG4gICAgdGhpcy5oYW5kbGVTZWxlY3Rpb25PblBvaW50ZXJEb3duID0gKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCk7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlKGVsZW1lbnRzLCB0aGlzLnN0YXRlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHJlc2l6aW5nRWxlbWVudDogZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLmVsZW1lbnRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSA9IGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS50cmFuc2Zvcm1IYW5kbGVUeXBlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlID0gZ2V0VHJhbnNmb3JtSGFuZGxlVHlwZUZyb21Db29yZHMoZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaXNSZXNpemluZyA9IHRydWU7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUub2Zmc2V0ID0gdHVwbGVUb0Nvb3JzKGdldFJlc2l6ZU9mZnNldFhZKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHMsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpKTtcblxuICAgICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkgJiYgc2VsZWN0ZWRFbGVtZW50c1swXS5wb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5hcnJvd0RpcmVjdGlvbiA9IGdldFJlc2l6ZUFycm93RGlyZWN0aW9uKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHNbMF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgIGNvbnN0IGxpbmVhckVsZW1lbnRFZGl0b3IgPSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50O1xuICAgICAgICAgICAgY29uc3QgcmV0ID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludGVyRG93bihldmVudCwgdGhpcy5zdGF0ZSwgdGhpcy5oaXN0b3J5LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbiwgbGluZWFyRWxlbWVudEVkaXRvcik7XG5cbiAgICAgICAgICAgIGlmIChyZXQuaGl0RWxlbWVudCkge1xuICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50ID0gcmV0LmhpdEVsZW1lbnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChyZXQubGluZWFyRWxlbWVudEVkaXRvcikge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IHJldC5saW5lYXJFbGVtZW50RWRpdG9yXG4gICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogcmV0LmxpbmVhckVsZW1lbnRFZGl0b3JcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAocmV0LmRpZEFkZFBvaW50KSB7XG4gICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gaGl0RWxlbWVudCBtYXkgYWxyZWFkeSBiZSBzZXQgYWJvdmUsIHNvIGNoZWNrIGZpcnN0XG5cblxuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQgPSAoX2EgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpO1xuXG4gICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpIHtcbiAgICAgICAgICAgIC8vIEVhcmx5IHJldHVybiBpZiBwb2ludGVyIGlzIGhpdHRpbmcgbGluayBpY29uXG4gICAgICAgICAgICBjb25zdCBoaXRMaW5rRWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudExpbmtBdFBvc2l0aW9uKHtcbiAgICAgICAgICAgICAgeDogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCxcbiAgICAgICAgICAgICAgeTogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueVxuICAgICAgICAgICAgfSwgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCk7XG5cbiAgICAgICAgICAgIGlmIChoaXRMaW5rRWxlbWVudCkge1xuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBGb3Igb3ZlcmxhcHBlZCBlbGVtZW50cyBvbmUgcG9zaXRpb24gbWF5IGhpdFxuICAgICAgICAgIC8vIG11bHRpcGxlIGVsZW1lbnRzXG5cblxuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzID0gdGhpcy5nZXRFbGVtZW50c0F0UG9zaXRpb24ocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSk7XG4gICAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQ7XG4gICAgICAgICAgY29uc3Qgc29tZUhpdEVsZW1lbnRJc1NlbGVjdGVkID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuYWxsSGl0RWxlbWVudHMuc29tZShlbGVtZW50ID0+IHRoaXMuaXNBU2VsZWN0ZWRFbGVtZW50KGVsZW1lbnQpKTtcblxuICAgICAgICAgIGlmICgoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCAhc29tZUhpdEVsZW1lbnRJc1NlbGVjdGVkKSAmJiAhZXZlbnQuc2hpZnRLZXkgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgICAgICAgICB0aGlzLmNsZWFyU2VsZWN0aW9uKGhpdEVsZW1lbnQpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICAgICAgW3RoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkXTogdHJ1ZVxuICAgICAgICAgICAgICB9LCB0aGlzLnN0YXRlKVxuICAgICAgICAgICAgfSk7IC8vIElmIHdlIGNsaWNrIG9uIHNvbWV0aGluZ1xuICAgICAgICAgIH0gZWxzZSBpZiAoaGl0RWxlbWVudCAhPSBudWxsKSB7XG4gICAgICAgICAgICAvLyBvbiBDTUQvQ1RSTCwgZHJpbGwgZG93biB0byBoaXQgZWxlbWVudCByZWdhcmRsZXNzIG9mIGdyb3VwcyBldGMuXG4gICAgICAgICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0Lndhc0FkZGVkVG9TZWxlY3Rpb24gPSB0cnVlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBlZGl0R3JvdXBGb3JTZWxlY3RlZEVsZW1lbnQocHJldlN0YXRlLCBoaXRFbGVtZW50KSksIHtcbiAgICAgICAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczogdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgfSkpOyAvLyBtYXJrIGFzIG5vdCBjb21wbGV0ZWx5IGhhbmRsZWQgc28gYXMgdG8gYWxsb3cgZHJhZ2dpbmcgZXRjLlxuXG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH0gLy8gZGVzZWxlY3QgaWYgaXRlbSBpcyBzZWxlY3RlZFxuICAgICAgICAgICAgLy8gaWYgc2hpZnQgaXMgbm90IGNsaWNrZWQsIHRoaXMgd2lsbCBhbHdheXMgcmV0dXJuIHRydWVcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSwgaXQgd2lsbCB0cmlnZ2VyIHNlbGVjdGlvbiBiYXNlZCBvbiBjdXJyZW50XG4gICAgICAgICAgICAvLyBzdGF0ZSBvZiB0aGUgYm94XG5cblxuICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgICAvLyBpZiB3ZSBhcmUgY3VycmVudGx5IGVkaXRpbmcgYSBncm91cCwgZXhpdGluZyBlZGl0aW5nIG1vZGUgYW5kIGRlc2VsZWN0IHRoZSBncm91cC5cbiAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQgJiYgIWlzRWxlbWVudEluR3JvdXAoaGl0RWxlbWVudCwgdGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSAvLyBBZGQgaGl0IGVsZW1lbnQgdG8gc2VsZWN0aW9uLiBBdCB0aGlzIHBvaW50IGlmIHdlJ3JlIG5vdCBob2xkaW5nXG4gICAgICAgICAgICAgIC8vIFNISUZUIHRoZSBwcmV2aW91c2x5IHNlbGVjdGVkIGVsZW1lbnQocykgd2VyZSBkZXNlbGVjdGVkIGFib3ZlXG4gICAgICAgICAgICAgIC8vIChtYWtlIHN1cmUgeW91IHVzZSBzZXRTdGF0ZSB1cGRhdGVyIHRvIHVzZSBsYXRlc3Qgc3RhdGUpXG4gICAgICAgICAgICAgIC8vIFdpdGggc2hpZnQtc2VsZWN0aW9uLCB3ZSB3YW50IHRvIG1ha2Ugc3VyZSB0aGF0IGZyYW1lcyBhbmQgdGhlaXIgY29udGFpbmluZ1xuICAgICAgICAgICAgICAvLyBlbGVtZW50cyBhcmUgbm90IHNlbGVjdGVkIGF0IHRoZSBzYW1lIHRpbWUuXG5cblxuICAgICAgICAgICAgICBpZiAoIXNvbWVIaXRFbGVtZW50SXNTZWxlY3RlZCAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgY29uc3QgcHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMgPSBbXTtcbiAgICAgICAgICAgICAgICAgIE9iamVjdC5rZXlzKHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLmZvckVhY2goaWQgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KGlkKTtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudCAmJiBwcmV2aW91c2x5U2VsZWN0ZWRFbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgICAgfSk7IC8vIGlmIGhpdEVsZW1lbnQgaXMgZnJhbWUsIGRlc2VsZWN0IGFsbCBvZiBpdHMgZWxlbWVudHMgaWYgdGhleSBhcmUgc2VsZWN0ZWRcblxuICAgICAgICAgICAgICAgICAgaWYgKGhpdEVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGdldEZyYW1lRWxlbWVudHMocHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMsIGhpdEVsZW1lbnQuaWQpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChoaXRFbGVtZW50LmZyYW1lSWQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gaWYgaGl0RWxlbWVudCBpcyBpbiBhIGZyYW1lIGFuZCBpdHMgZnJhbWUgaGFzIGJlZW4gc2VsZWN0ZWRcbiAgICAgICAgICAgICAgICAgICAgLy8gZGlzYWJsZSBzZWxlY3Rpb24gZm9yIHRoZSBnaXZlbiBlbGVtZW50XG4gICAgICAgICAgICAgICAgICAgIGlmIChuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuZnJhbWVJZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gaGl0RWxlbWVudCBpcyBuZWl0aGVyIGEgZnJhbWUgbm9yIGFuIGVsZW1lbnQgaW4gYSBmcmFtZVxuICAgICAgICAgICAgICAgICAgICAvLyBidXQgc2luY2UgaGl0RWxlbWVudCBjb3VsZCBiZSBpbiBhIGdyb3VwIHdpdGggc29tZSBmcmFtZXNcbiAgICAgICAgICAgICAgICAgICAgLy8gdGhpcyBtZWFucyBzZWxlY3RpbmcgaGl0RWxlbWVudCB3aWxsIGhhdmUgdGhlIGZyYW1lcyBzZWxlY3RlZCBhcyB3ZWxsXG4gICAgICAgICAgICAgICAgICAgIC8vIGJlY2F1c2Ugd2Ugd2FudCB0byBrZWVwIHRoZSBpbnZhcmlhbnQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIC0gZnJhbWVzIGFuZCB0aGVpciBlbGVtZW50cyBhcmUgbm90IHNlbGVjdGVkIGF0IHRoZSBzYW1lIHRpbWVcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgZGVzZWxlY3QgZWxlbWVudHMgaW4gdGhvc2UgZnJhbWVzIHRoYXQgd2VyZSBwcmV2aW91c2x5IHNlbGVjdGVkXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGdyb3VwSWRzID0gaGl0RWxlbWVudC5ncm91cElkcztcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZnJhbWVzSW5Hcm91cHMgPSBuZXcgU2V0KGdyb3VwSWRzLmZsYXRNYXAoZ2lkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBnaWQpKS5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIikubWFwKGZyYW1lID0+IGZyYW1lLmlkKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGZyYW1lc0luR3JvdXBzLnNpemUgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LmZyYW1lSWQgJiYgZnJhbWVzSW5Hcm91cHMuaGFzKGVsZW1lbnQuZnJhbWVJZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGVzZWxlY3QgZWxlbWVudCBhbmQgZ3JvdXBzIGNvbnRhaW5pbmcgdGhlIGVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZ3JvdXBJZHMuZmxhdE1hcChnaWQgPT4gZ2V0RWxlbWVudHNJbkdyb3VwKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGdpZCkpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogaGl0RWxlbWVudC5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZVRleHRPblBvaW50ZXJEb3duID0gKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICAvLyBpZiB3ZSdyZSBjdXJyZW50bHkgc3RpbGwgZWRpdGluZyB0ZXh0LCBjbGlja2luZyBvdXRzaWRlXG4gICAgICAvLyBzaG91bGQgb25seSBmaW5hbGl6ZSBpdCwgbm90IGNyZWF0ZSBhbm90aGVyIChpcnJlc3BlY3RpdmVcbiAgICAgIC8vIG9mIHN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKVxuICAgICAgaWYgKGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsZXQgc2NlbmVYID0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueDtcbiAgICAgIGxldCBzY2VuZVkgPSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55O1xuICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVYLCBzY2VuZVksIHtcbiAgICAgICAgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQ6IHRydWVcbiAgICAgIH0pOyAvLyBGSVhNRVxuXG4gICAgICBsZXQgY29udGFpbmVyID0gZ2V0VGV4dEJpbmRhYmxlQ29udGFpbmVyQXRQb3NpdGlvbih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCBzY2VuZVgsIHNjZW5lWSk7XG5cbiAgICAgIGlmIChoYXNCb3VuZFRleHRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgIGNvbnRhaW5lciA9IGVsZW1lbnQ7XG4gICAgICAgIHNjZW5lWCA9IGVsZW1lbnQueCArIGVsZW1lbnQud2lkdGggLyAyO1xuICAgICAgICBzY2VuZVkgPSBlbGVtZW50LnkgKyBlbGVtZW50LmhlaWdodCAvIDI7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc3RhcnRUZXh0RWRpdGluZyh7XG4gICAgICAgIHNjZW5lWCxcbiAgICAgICAgc2NlbmVZLFxuICAgICAgICBpbnNlcnRBdFBhcmVudENlbnRlcjogIWV2ZW50LmFsdEtleSxcbiAgICAgICAgY29udGFpbmVyXG4gICAgICB9KTtcbiAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlRnJlZURyYXdFbGVtZW50T25Qb2ludGVyRG93biA9IChldmVudCwgZWxlbWVudFR5cGUsIHBvaW50ZXJEb3duU3RhdGUpID0+IHtcbiAgICAgIC8vIEJlZ2luIGEgbWFyayBjYXB0dXJlLiBUaGlzIGRvZXMgbm90IGhhdmUgdG8gdXBkYXRlIHN0YXRlIHlldC5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIG51bGwpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0ZyZWVEcmF3RWxlbWVudCh7XG4gICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlLFxuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICByb3VuZG5lc3M6IG51bGwsXG4gICAgICAgIHNpbXVsYXRlUHJlc3N1cmU6IGV2ZW50LnByZXNzdXJlID09PSAwLjUsXG4gICAgICAgIGxvY2tlZDogZmFsc2UsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTtcbiAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRFbGVtZW50SWRzLCBwcmV2U3RhdGUpXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGVsZW1lbnQuc2ltdWxhdGVQcmVzc3VyZSA/IGVsZW1lbnQucHJlc3N1cmVzIDogWy4uLmVsZW1lbnQucHJlc3N1cmVzLCBldmVudC5wcmVzc3VyZV07XG4gICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgcG9pbnRzOiBbWzAsIDBdXSxcbiAgICAgICAgcHJlc3N1cmVzXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGJvdW5kRWxlbWVudCA9IGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZyhwb2ludGVyRG93blN0YXRlLm9yaWdpbiwgdGhpcy5zY2VuZSk7XG4gICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBlbGVtZW50LFxuICAgICAgICBlZGl0aW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IGJvdW5kRWxlbWVudCxcbiAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICB9KTtcbiAgICB9OyAvL2NyZWF0ZSByZWN0YW5nbGUgZWxlbWVudCB3aXRoIHlvdXR1YmUgdG9wIGxlZnQgb24gbmVhcmVzdCBncmlkIHBvaW50IHdpZHRoIC8gaGlnaHQgNjQwLzM2MFxuXG5cbiAgICB0aGlzLmluc2VydEVtYmVkZGFibGVFbGVtZW50ID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWSxcbiAgICAgIGxpbmtcbiAgICB9KSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHNjZW5lWCwgc2NlbmVZLCAoKF9hID0gdGhpcy5sYXN0UG9pbnRlckRvd24pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVtLRVlTLkNUUkxfT1JfQ01EXSkgPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBlbWJlZExpbmsgPSBnZXRFbWJlZExpbmsobGluayk7XG5cbiAgICAgIGlmICghZW1iZWRMaW5rKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGVtYmVkTGluay53YXJuaW5nKSB7XG4gICAgICAgIHRoaXMuc2V0VG9hc3Qoe1xuICAgICAgICAgIG1lc3NhZ2U6IGVtYmVkTGluay53YXJuaW5nLFxuICAgICAgICAgIGNsb3NhYmxlOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50ID0gbmV3RW1iZWRkYWJsZUVsZW1lbnQoe1xuICAgICAgICB0eXBlOiBcImVtYmVkZGFibGVcIixcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogXCJ0cmFuc3BhcmVudFwiLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IFwidHJhbnNwYXJlbnRcIixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIHJvdW5kbmVzczogdGhpcy5nZXRDdXJyZW50SXRlbVJvdW5kbmVzcyhcImVtYmVkZGFibGVcIiksXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICB3aWR0aDogZW1iZWRMaW5rLmFzcGVjdFJhdGlvLncsXG4gICAgICAgIGhlaWdodDogZW1iZWRMaW5rLmFzcGVjdFJhdGlvLmgsXG4gICAgICAgIGxpbmssXG4gICAgICAgIHZhbGlkYXRlZDogbnVsbFxuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZWxlbWVudF0pO1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50ID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWVxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVYLCBzY2VuZVksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hW0tFWVMuQ1RSTF9PUl9DTURdKSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdJbWFnZUVsZW1lbnQoe1xuICAgICAgICB0eXBlOiBcImltYWdlXCIsXG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgICAgbG9ja2VkOiBmYWxzZSxcbiAgICAgICAgZnJhbWVJZDogdG9wTGF5ZXJGcmFtZSA/IHRvcExheWVyRnJhbWUuaWQgOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiBlbGVtZW50O1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUxpbmVhckVsZW1lbnRPblBvaW50ZXJEb3duID0gKGV2ZW50LCBlbGVtZW50VHlwZSwgcG9pbnRlckRvd25TdGF0ZSkgPT4ge1xuICAgICAgaWYgKHRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBtdWx0aUVsZW1lbnRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7IC8vIGZpbmFsaXplIGlmIGNvbXBsZXRpbmcgYSBsb29wXG5cbiAgICAgICAgaWYgKG11bHRpRWxlbWVudC50eXBlID09PSBcImxpbmVcIiAmJiBpc1BhdGhBTG9vcChtdWx0aUVsZW1lbnQucG9pbnRzLCB0aGlzLnN0YXRlLnpvb20udmFsdWUpKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICAgIGxhc3RDb21taXR0ZWRQb2ludDogbXVsdGlFbGVtZW50LnBvaW50c1ttdWx0aUVsZW1lbnQucG9pbnRzLmxlbmd0aCAtIDFdXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiByeCxcbiAgICAgICAgICB5OiByeSxcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnRcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDsgLy8gY2xpY2tpbmcgaW5zaWRlIGNvbW1pdCB6b25lIOKGkiBmaW5hbGl6ZSBhcnJvd1xuXG4gICAgICAgIGlmIChtdWx0aUVsZW1lbnQucG9pbnRzLmxlbmd0aCA+IDEgJiYgbGFzdENvbW1pdHRlZFBvaW50ICYmIGRpc3RhbmNlMmQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCAtIHJ4LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55IC0gcnksIGxhc3RDb21taXR0ZWRQb2ludFswXSwgbGFzdENvbW1pdHRlZFBvaW50WzFdKSA8IExJTkVfQ09ORklSTV9USFJFU0hPTEQpIHtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgIFttdWx0aUVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgfSksIHByZXZTdGF0ZSlcbiAgICAgICAgfSkpOyAvLyBjbGlja2luZyBvdXRzaWRlIGNvbW1pdCB6b25lIOKGkiB1cGRhdGUgcmVmZXJlbmNlIGZvciBsYXN0IGNvbW1pdHRlZFxuICAgICAgICAvLyBwb2ludFxuXG4gICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50OiBtdWx0aUVsZW1lbnQucG9pbnRzW211bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoIC0gMV1cbiAgICAgICAgfSk7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgICAgeTogZ3JpZFlcbiAgICAgICAgfSk7XG4gICAgICAgIC8qIElmIGFycm93IGlzIHByZS1hcnJvd2hlYWRzLCBpdCB3aWxsIGhhdmUgdW5kZWZpbmVkIGZvciBib3RoIHN0YXJ0IGFuZCBlbmQgYXJyb3doZWFkcy5cbiAgICAgICAgSWYgc28sIHdlIHdhbnQgaXQgdG8gYmUgbnVsbCBmb3Igc3RhcnQgYW5kIFwiYXJyb3dcIiBmb3IgZW5kLiBJZiB0aGUgbGluZWFyIGl0ZW0gaXMgbm90XG4gICAgICAgIGFuIGFycm93LCB3ZSB3YW50IGl0IHRvIGJlIG51bGwgZm9yIGJvdGguIE90aGVyd2lzZSwgd2Ugd2FudCBpdCB0byB1c2UgdGhlXG4gICAgICAgIHZhbHVlcyBmcm9tIGFwcFN0YXRlLiAqL1xuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBjdXJyZW50SXRlbVN0YXJ0QXJyb3doZWFkLFxuICAgICAgICAgIGN1cnJlbnRJdGVtRW5kQXJyb3doZWFkXG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICBjb25zdCBbc3RhcnRBcnJvd2hlYWQsIGVuZEFycm93aGVhZF0gPSBlbGVtZW50VHlwZSA9PT0gXCJhcnJvd1wiID8gW2N1cnJlbnRJdGVtU3RhcnRBcnJvd2hlYWQsIGN1cnJlbnRJdGVtRW5kQXJyb3doZWFkXSA6IFtudWxsLCBudWxsXTtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0xpbmVhckVsZW1lbnQoe1xuICAgICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlLFxuICAgICAgICAgIHg6IGdyaWRYLFxuICAgICAgICAgIHk6IGdyaWRZLFxuICAgICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICAgIHJvdW5kbmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdW5kbmVzcyA9PT0gXCJyb3VuZFwiID8ge1xuICAgICAgICAgICAgdHlwZTogUk9VTkRORVNTLlBST1BPUlRJT05BTF9SQURJVVNcbiAgICAgICAgICB9IDogbnVsbCxcbiAgICAgICAgICBzdGFydEFycm93aGVhZCxcbiAgICAgICAgICBlbmRBcnJvd2hlYWQsXG4gICAgICAgICAgbG9ja2VkOiBmYWxzZSxcbiAgICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7XG4gICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMobmV4dFNlbGVjdGVkRWxlbWVudElkcywgcHJldlN0YXRlKVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICBwb2ludHM6IFsuLi5lbGVtZW50LnBvaW50cywgWzAsIDBdXVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgYm91bmRFbGVtZW50ID0gZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLCB0aGlzLnNjZW5lKTtcbiAgICAgICAgdGhpcy5zY2VuZS5hZGROZXdFbGVtZW50KGVsZW1lbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IGJvdW5kRWxlbWVudCxcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlR2VuZXJpY0VsZW1lbnRPblBvaW50ZXJEb3duID0gKGVsZW1lbnRUeXBlLCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hW0tFWVMuQ1RSTF9PUl9DTURdKSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGJhc2VFbGVtZW50QXR0cmlidXRlcyA9IHtcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZUNvbG9yLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgc3Ryb2tlV2lkdGg6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VXaWR0aCxcbiAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgICAgcm91bmRuZXNzOiB0aGlzLmdldEN1cnJlbnRJdGVtUm91bmRuZXNzKGVsZW1lbnRUeXBlKSxcbiAgICAgICAgbG9ja2VkOiBmYWxzZSxcbiAgICAgICAgZnJhbWVJZDogdG9wTGF5ZXJGcmFtZSA/IHRvcExheWVyRnJhbWUuaWQgOiBudWxsXG4gICAgICB9O1xuICAgICAgbGV0IGVsZW1lbnQ7XG5cbiAgICAgIGlmIChlbGVtZW50VHlwZSA9PT0gXCJlbWJlZGRhYmxlXCIpIHtcbiAgICAgICAgZWxlbWVudCA9IG5ld0VtYmVkZGFibGVFbGVtZW50KE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgIHR5cGU6IFwiZW1iZWRkYWJsZVwiLFxuICAgICAgICAgIHZhbGlkYXRlZDogbnVsbFxuICAgICAgICB9LCBiYXNlRWxlbWVudEF0dHJpYnV0ZXMpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVsZW1lbnQgPSBuZXdFbGVtZW50KE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlXG4gICAgICAgIH0sIGJhc2VFbGVtZW50QXR0cmlidXRlcykpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZWxlbWVudC50eXBlID09PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGlvbkVsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBlbGVtZW50XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zY2VuZS5hZGROZXdFbGVtZW50KGVsZW1lbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBtdWx0aUVsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBlbGVtZW50LFxuICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBlbGVtZW50XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmNyZWF0ZUZyYW1lRWxlbWVudE9uUG9pbnRlckRvd24gPSBwb2ludGVyRG93blN0YXRlID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgKChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgZnJhbWUgPSBuZXdGcmFtZUVsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIGxvY2tlZDogZmFsc2VcbiAgICAgIH0sIEZSQU1FX1NUWUxFKSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZnJhbWVdKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBtdWx0aUVsZW1lbnQ6IG51bGwsXG4gICAgICAgIGRyYWdnaW5nRWxlbWVudDogZnJhbWUsXG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBmcmFtZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzdG9yZVJlYWR5VG9FcmFzZUVsZW1lbnRzID0gcG9pbnRlckRvd25TdGF0ZSA9PiB7XG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsZSA9PiB7XG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgb3BhY2l0eTogcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5jb250YWluZXJJZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgb3BhY2l0eTogcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChlbGUuZnJhbWVJZCAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGU7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGVsZW1lbnRzKTtcbiAgICB9O1xuXG4gICAgdGhpcy5lcmFzZUVsZW1lbnRzID0gcG9pbnRlckRvd25TdGF0ZSA9PiB7XG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsZSA9PiB7XG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNCb3VuZFRvQ29udGFpbmVyKGVsZSkgJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGVsZS5mcmFtZUlkICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgfTtcblxuICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlID0gKHtcbiAgICAgIGltYWdlRmlsZSxcbiAgICAgIGltYWdlRWxlbWVudDogX2ltYWdlRWxlbWVudCxcbiAgICAgIHNob3dDdXJzb3JJbWFnZVByZXZpZXcgPSBmYWxzZVxuICAgIH0pID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfZiwgX2csIF9oLCBfajsgLy8gYXQgdGhpcyBwb2ludCB0aGlzIHNob3VsZCBiZSBndWFyYW50ZWVkIGltYWdlIGZpbGUsIGJ1dCB3ZSBkbyB0aGlzIGNoZWNrXG4gICAgICAvLyB0byBzYXRpc2Z5IFRTIGRvd24gdGhlIGxpbmVcblxuXG4gICAgICBpZiAoIWlzU3VwcG9ydGVkSW1hZ2VGaWxlKGltYWdlRmlsZSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMudW5zdXBwb3J0ZWRGaWxlVHlwZVwiKSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1pbWVUeXBlID0gaW1hZ2VGaWxlLnR5cGU7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgXCJ3YWl0XCIpO1xuXG4gICAgICBpZiAobWltZVR5cGUgPT09IE1JTUVfVFlQRVMuc3ZnKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaW1hZ2VGaWxlID0gU1ZHU3RyaW5nVG9GaWxlKHlpZWxkIG5vcm1hbGl6ZVNWRyh5aWVsZCBpbWFnZUZpbGUudGV4dCgpKSwgaW1hZ2VGaWxlLm5hbWUpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMuc3ZnSW1hZ2VJbnNlcnRFcnJvclwiKSk7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gZ2VuZXJhdGUgaW1hZ2UgaWQgKGJ5IGRlZmF1bHQgdGhlIGZpbGUgZGlnZXN0KSBiZWZvcmUgYW55XG4gICAgICAvLyByZXNpemluZy9jb21wcmVzc2lvbiB0YWtlcyBwbGFjZSB0byBrZWVwIGl0IG1vcmUgcG9ydGFibGVcblxuXG4gICAgICBjb25zdCBmaWxlSWQgPSB5aWVsZCAoKF9nID0gKF9mID0gdGhpcy5wcm9wcykuZ2VuZXJhdGVJZEZvckZpbGUpID09PSBudWxsIHx8IF9nID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZy5jYWxsKF9mLCBpbWFnZUZpbGUpKSB8fCBnZW5lcmF0ZUlkRnJvbUZpbGUoaW1hZ2VGaWxlKTtcblxuICAgICAgaWYgKCFmaWxlSWQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFwiQ291bGRuJ3QgZ2VuZXJhdGUgZmlsZSBpZCBvciB0aGUgc3VwcGxpZWQgYGdlbmVyYXRlSWRGb3JGaWxlYCBkaWRuJ3QgcmVzb2x2ZSB0byBvbmUuXCIpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IodChcImVycm9ycy5pbWFnZUluc2VydEVycm9yXCIpKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXhpc3RpbmdGaWxlRGF0YSA9IHRoaXMuZmlsZXNbZmlsZUlkXTtcblxuICAgICAgaWYgKCEoZXhpc3RpbmdGaWxlRGF0YSA9PT0gbnVsbCB8fCBleGlzdGluZ0ZpbGVEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBleGlzdGluZ0ZpbGVEYXRhLmRhdGFVUkwpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaW1hZ2VGaWxlID0geWllbGQgcmVzaXplSW1hZ2VGaWxlKGltYWdlRmlsZSwge1xuICAgICAgICAgICAgbWF4V2lkdGhPckhlaWdodDogREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hUXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcImVycm9yIHRyeWluZyB0byByZXNpbmcgaW1hZ2UgZmlsZSBvbiBpbnNlcnRpb25cIiwgZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGltYWdlRmlsZS5zaXplID4gTUFYX0FMTE9XRURfRklMRV9CWVRFUykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0KFwiZXJyb3JzLmZpbGVUb29CaWdcIiwge1xuICAgICAgICAgICAgbWF4U2l6ZTogYCR7TWF0aC50cnVuYyhNQVhfQUxMT1dFRF9GSUxFX0JZVEVTIC8gMTAyNCAvIDEwMjQpfU1CYFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoc2hvd0N1cnNvckltYWdlUHJldmlldykge1xuICAgICAgICBjb25zdCBkYXRhVVJMID0gKF9oID0gdGhpcy5maWxlc1tmaWxlSWRdKSA9PT0gbnVsbCB8fCBfaCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2guZGF0YVVSTDsgLy8gb3B0aW1pemF0aW9uIHNvIHRoYXQgd2UgZG9uJ3QgdW5uZWNlc3NhcmlseSByZXNpemUgdGhlIG9yaWdpbmFsXG4gICAgICAgIC8vIGZ1bGwtc2l6ZSBmaWxlIGZvciBjdXJzb3IgcHJldmlld1xuICAgICAgICAvLyAoaXQncyBtdWNoIGZhc3RlciB0byBjb252ZXJ0IHRoZSByZXNpemVkIGRhdGFVUkwgdG8gRmlsZSlcblxuICAgICAgICBjb25zdCByZXNpemVkRmlsZSA9IGRhdGFVUkwgJiYgZGF0YVVSTFRvRmlsZShkYXRhVVJMKTtcbiAgICAgICAgdGhpcy5zZXRJbWFnZVByZXZpZXdDdXJzb3IocmVzaXplZEZpbGUgfHwgaW1hZ2VGaWxlKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YVVSTCA9ICgoX2ogPSB0aGlzLmZpbGVzW2ZpbGVJZF0pID09PSBudWxsIHx8IF9qID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfai5kYXRhVVJMKSB8fCAoeWllbGQgZ2V0RGF0YVVSTChpbWFnZUZpbGUpKTtcbiAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IG11dGF0ZUVsZW1lbnQoX2ltYWdlRWxlbWVudCwge1xuICAgICAgICBmaWxlSWRcbiAgICAgIH0sIGZhbHNlKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgIHZhciBfaztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIHRoaXMuZmlsZXMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZmlsZXMpLCB7XG4gICAgICAgICAgICBbZmlsZUlkXToge1xuICAgICAgICAgICAgICBtaW1lVHlwZSxcbiAgICAgICAgICAgICAgaWQ6IGZpbGVJZCxcbiAgICAgICAgICAgICAgZGF0YVVSTCxcbiAgICAgICAgICAgICAgY3JlYXRlZDogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgbGFzdFJldHJpZXZlZDogRGF0ZS5ub3coKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGNvbnN0IGNhY2hlZEltYWdlRGF0YSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoZmlsZUlkKTtcblxuICAgICAgICAgIGlmICghY2FjaGVkSW1hZ2VEYXRhKSB7XG4gICAgICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgICAgICAgeWllbGQgdGhpcy51cGRhdGVJbWFnZUNhY2hlKFtpbWFnZUVsZW1lbnRdKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoKGNhY2hlZEltYWdlRGF0YSA9PT0gbnVsbCB8fCBjYWNoZWRJbWFnZURhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNhY2hlZEltYWdlRGF0YS5pbWFnZSkgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgICAgICB5aWVsZCBjYWNoZWRJbWFnZURhdGEuaW1hZ2U7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkICE9PSBpbWFnZUVsZW1lbnQuaWQgJiYgKChfayA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50KSA9PT0gbnVsbCB8fCBfayA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2suaWQpICE9PSBpbWFnZUVsZW1lbnQuaWQpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlRGltZW5zaW9ucyhpbWFnZUVsZW1lbnQsIHRydWUpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlc29sdmUoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKHQoXCJlcnJvcnMuaW1hZ2VJbnNlcnRFcnJvclwiKSkpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIGlmICghc2hvd0N1cnNvckltYWdlUHJldmlldykge1xuICAgICAgICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KSk7XG4gICAgfSk7XG4gICAgLyoqXG4gICAgICogaW5zZXJ0cyBpbWFnZSBpbnRvIGVsZW1lbnRzIGFycmF5IGFuZCByZXJlbmRlcnNcbiAgICAgKi9cblxuXG4gICAgdGhpcy5pbnNlcnRJbWFnZUVsZW1lbnQgPSAoaW1hZ2VFbGVtZW50LCBpbWFnZUZpbGUsIHNob3dDdXJzb3JJbWFnZVByZXZpZXcpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChpbWFnZUVsZW1lbnQpO1xuXG4gICAgICB0cnkge1xuICAgICAgICB5aWVsZCB0aGlzLmluaXRpYWxpemVJbWFnZSh7XG4gICAgICAgICAgaW1hZ2VGaWxlLFxuICAgICAgICAgIGltYWdlRWxlbWVudCxcbiAgICAgICAgICBzaG93Q3Vyc29ySW1hZ2VQcmV2aWV3XG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbXV0YXRlRWxlbWVudChpbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICBpc0RlbGV0ZWQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlIHx8IHQoXCJlcnJvcnMuaW1hZ2VJbnNlcnRFcnJvclwiKVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuc2V0SW1hZ2VQcmV2aWV3Q3Vyc29yID0gaW1hZ2VGaWxlID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIC8vIG11c3RuJ3QgYmUgbGFyZ2VyIHRoYW4gMTI4IHB4XG4gICAgICAvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9DU1MvQ1NTX0Jhc2ljX1VzZXJfSW50ZXJmYWNlL1VzaW5nX1VSTF92YWx1ZXNfZm9yX3RoZV9jdXJzb3JfcHJvcGVydHlcbiAgICAgIGNvbnN0IGN1cnNvckltYWdlU2l6ZVB4ID0gOTY7XG4gICAgICBjb25zdCBpbWFnZVByZXZpZXcgPSB5aWVsZCByZXNpemVJbWFnZUZpbGUoaW1hZ2VGaWxlLCB7XG4gICAgICAgIG1heFdpZHRoT3JIZWlnaHQ6IGN1cnNvckltYWdlU2l6ZVB4XG4gICAgICB9KTtcbiAgICAgIGxldCBwcmV2aWV3RGF0YVVSTCA9IHlpZWxkIGdldERhdGFVUkwoaW1hZ2VQcmV2aWV3KTsgLy8gU1ZHIGNhbm5vdCBiZSByZXNpemVkIHZpYSBgcmVzaXplSW1hZ2VGaWxlYCBzbyB3ZSByZXNpemUgYnkgcmVuZGVyaW5nIHRvXG4gICAgICAvLyBhIHNtYWxsIGNhbnZhc1xuXG4gICAgICBpZiAoaW1hZ2VGaWxlLnR5cGUgPT09IE1JTUVfVFlQRVMuc3ZnKSB7XG4gICAgICAgIGNvbnN0IGltZyA9IHlpZWxkIGxvYWRIVE1MSW1hZ2VFbGVtZW50KHByZXZpZXdEYXRhVVJMKTtcbiAgICAgICAgbGV0IGhlaWdodCA9IE1hdGgubWluKGltZy5oZWlnaHQsIGN1cnNvckltYWdlU2l6ZVB4KTtcbiAgICAgICAgbGV0IHdpZHRoID0gaGVpZ2h0ICogKGltZy53aWR0aCAvIGltZy5oZWlnaHQpO1xuXG4gICAgICAgIGlmICh3aWR0aCA+IGN1cnNvckltYWdlU2l6ZVB4KSB7XG4gICAgICAgICAgd2lkdGggPSBjdXJzb3JJbWFnZVNpemVQeDtcbiAgICAgICAgICBoZWlnaHQgPSB3aWR0aCAqIChpbWcuaGVpZ2h0IC8gaW1nLndpZHRoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgICAgIGNhbnZhcy5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgICAgIGNhbnZhcy53aWR0aCA9IHdpZHRoO1xuICAgICAgICBjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoXCIyZFwiKTtcbiAgICAgICAgY29udGV4dC5kcmF3SW1hZ2UoaW1nLCAwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICAgICAgcHJldmlld0RhdGFVUkwgPSBjYW52YXMudG9EYXRhVVJMKE1JTUVfVFlQRVMuc3ZnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBgdXJsKCR7cHJldmlld0RhdGFVUkx9KSA0IDQsIGF1dG9gKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub25JbWFnZUFjdGlvbiA9ICh7XG4gICAgICBpbnNlcnRPbkNhbnZhc0RpcmVjdGx5XG4gICAgfSA9IHtcbiAgICAgIGluc2VydE9uQ2FudmFzRGlyZWN0bHk6IGZhbHNlXG4gICAgfSkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY2xpZW50WCA9IHRoaXMuc3RhdGUud2lkdGggLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0O1xuICAgICAgICBjb25zdCBjbGllbnRZID0gdGhpcy5zdGF0ZS5oZWlnaHQgLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRUb3A7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgY2xpZW50WCxcbiAgICAgICAgICBjbGllbnRZXG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBpbWFnZUZpbGUgPSB5aWVsZCBmaWxlT3Blbih7XG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiSW1hZ2VcIixcbiAgICAgICAgICBleHRlbnNpb25zOiBPYmplY3Qua2V5cyhJTUFHRV9NSU1FX1RZUEVTKVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQoe1xuICAgICAgICAgIHNjZW5lWDogeCxcbiAgICAgICAgICBzY2VuZVk6IHlcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKGluc2VydE9uQ2FudmFzRGlyZWN0bHkpIHtcbiAgICAgICAgICB0aGlzLmluc2VydEltYWdlRWxlbWVudChpbWFnZUVsZW1lbnQsIGltYWdlRmlsZSk7XG4gICAgICAgICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zKGltYWdlRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgICAgW2ltYWdlRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiBpbWFnZUVsZW1lbnQuaWRcbiAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmluc2VydEltYWdlRWxlbWVudChpbWFnZUVsZW1lbnQsIGltYWdlRmlsZSxcbiAgICAgICAgICAgIC8qIHNob3dDdXJzb3JJbWFnZVByZXZpZXcgKi9cbiAgICAgICAgICAgIHRydWUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IubmFtZSAhPT0gXCJBYm9ydEVycm9yXCIpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiBudWxsLFxuICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0pXG4gICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zID0gKGltYWdlRWxlbWVudCwgZm9yY2VOYXR1cmFsU2l6ZSA9IGZhbHNlKSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IGltYWdlID0gaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChpbWFnZUVsZW1lbnQpICYmICgoX2EgPSB0aGlzLmltYWdlQ2FjaGUuZ2V0KGltYWdlRWxlbWVudC5maWxlSWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaW1hZ2UpO1xuXG4gICAgICBpZiAoIWltYWdlIHx8IGltYWdlIGluc3RhbmNlb2YgUHJvbWlzZSkge1xuICAgICAgICBpZiAoaW1hZ2VFbGVtZW50LndpZHRoIDwgRFJBR0dJTkdfVEhSRVNIT0xEIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlICYmIGltYWdlRWxlbWVudC5oZWlnaHQgPCBEUkFHR0lOR19USFJFU0hPTEQgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUpIHtcbiAgICAgICAgICBjb25zdCBwbGFjZWhvbGRlclNpemUgPSAxMDAgLyB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChpbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICAgIHg6IGltYWdlRWxlbWVudC54IC0gcGxhY2Vob2xkZXJTaXplIC8gMixcbiAgICAgICAgICAgIHk6IGltYWdlRWxlbWVudC55IC0gcGxhY2Vob2xkZXJTaXplIC8gMixcbiAgICAgICAgICAgIHdpZHRoOiBwbGFjZWhvbGRlclNpemUsXG4gICAgICAgICAgICBoZWlnaHQ6IHBsYWNlaG9sZGVyU2l6ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZm9yY2VOYXR1cmFsU2l6ZSB8fCAvLyBpZiB1c2VyLWNyZWF0ZWQgYm91bmRpbmcgYm94IGlzIGJlbG93IHRocmVzaG9sZCwgYXNzdW1lIHRoZVxuICAgICAgLy8gaW50ZW50aW9uIHdhcyB0byBjbGljayBpbnN0ZWFkIG9mIGRyYWcsIGFuZCB1c2UgdGhlIGltYWdlJ3NcbiAgICAgIC8vIGludHJpbnNpYyBzaXplXG4gICAgICBpbWFnZUVsZW1lbnQud2lkdGggPCBEUkFHR0lOR19USFJFU0hPTEQgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUgJiYgaW1hZ2VFbGVtZW50LmhlaWdodCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkge1xuICAgICAgICBjb25zdCBtaW5IZWlnaHQgPSBNYXRoLm1heCh0aGlzLnN0YXRlLmhlaWdodCAtIDEyMCwgMTYwKTsgLy8gbWF4IDY1JSBvZiBjYW52YXMgaGVpZ2h0LCBjbGFtcGVkIHRvIDwzMDBweCwgdmggLSAxMjBweD5cblxuICAgICAgICBjb25zdCBtYXhIZWlnaHQgPSBNYXRoLm1pbihtaW5IZWlnaHQsIE1hdGguZmxvb3IodGhpcy5zdGF0ZS5oZWlnaHQgKiAwLjUpIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlKTtcbiAgICAgICAgY29uc3QgaGVpZ2h0ID0gTWF0aC5taW4oaW1hZ2UubmF0dXJhbEhlaWdodCwgbWF4SGVpZ2h0KTtcbiAgICAgICAgY29uc3Qgd2lkdGggPSBoZWlnaHQgKiAoaW1hZ2UubmF0dXJhbFdpZHRoIC8gaW1hZ2UubmF0dXJhbEhlaWdodCk7IC8vIGFkZCBjdXJyZW50IGltYWdlRWxlbWVudCB3aWR0aC9oZWlnaHQgdG8gYWNjb3VudCBmb3IgcHJldmlvdXMgY2VudGVyaW5nXG4gICAgICAgIC8vIG9mIHRoZSBwbGFjZWhvbGRlciBpbWFnZVxuXG4gICAgICAgIGNvbnN0IHggPSBpbWFnZUVsZW1lbnQueCArIGltYWdlRWxlbWVudC53aWR0aCAvIDIgLSB3aWR0aCAvIDI7XG4gICAgICAgIGNvbnN0IHkgPSBpbWFnZUVsZW1lbnQueSArIGltYWdlRWxlbWVudC5oZWlnaHQgLyAyIC0gaGVpZ2h0IC8gMjtcbiAgICAgICAgbXV0YXRlRWxlbWVudChpbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHksXG4gICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgaGVpZ2h0XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG4gICAgLyoqIHVwZGF0ZXMgaW1hZ2UgY2FjaGUsIHJlZnJlc2hpbmcgdXBkYXRlZCBlbGVtZW50cyBhbmQvb3Igc2V0dGluZyBzdGF0dXNcbiAgICAgICAgdG8gZXJyb3IgZm9yIGltYWdlcyB0aGF0IGZhaWwgZHVyaW5nIDxpbWc+IGVsZW1lbnQgY3JlYXRpb24gKi9cblxuXG4gICAgdGhpcy51cGRhdGVJbWFnZUNhY2hlID0gKGVsZW1lbnRzLCBmaWxlcyA9IHRoaXMuZmlsZXMpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgdXBkYXRlZEZpbGVzLFxuICAgICAgICBlcnJvcmVkRmlsZXNcbiAgICAgIH0gPSB5aWVsZCBfdXBkYXRlSW1hZ2VDYWNoZSh7XG4gICAgICAgIGltYWdlQ2FjaGU6IHRoaXMuaW1hZ2VDYWNoZSxcbiAgICAgICAgZmlsZUlkczogZWxlbWVudHMubWFwKGVsZW1lbnQgPT4gZWxlbWVudC5maWxlSWQpLFxuICAgICAgICBmaWxlc1xuICAgICAgfSk7XG5cbiAgICAgIGlmICh1cGRhdGVkRmlsZXMuc2l6ZSB8fCBlcnJvcmVkRmlsZXMuc2l6ZSkge1xuICAgICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZWxlbWVudHMpIHtcbiAgICAgICAgICBpZiAodXBkYXRlZEZpbGVzLmhhcyhlbGVtZW50LmZpbGVJZCkpIHtcbiAgICAgICAgICAgIFNoYXBlQ2FjaGUuZGVsZXRlKGVsZW1lbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZXJyb3JlZEZpbGVzLnNpemUpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWxlbWVudCA9PiB7XG4gICAgICAgICAgaWYgKGlzSW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQoZWxlbWVudCkgJiYgZXJyb3JlZEZpbGVzLmhhcyhlbGVtZW50LmZpbGVJZCkpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGVtZW50LCB7XG4gICAgICAgICAgICAgIHN0YXR1czogXCJlcnJvclwiXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gZWxlbWVudDtcbiAgICAgICAgfSkpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICB1cGRhdGVkRmlsZXMsXG4gICAgICAgIGVycm9yZWRGaWxlc1xuICAgICAgfTtcbiAgICB9KTtcbiAgICAvKiogYWRkcyBuZXcgaW1hZ2VzIHRvIGltYWdlQ2FjaGUgYW5kIHJlLXJlbmRlcnMgaWYgbmVlZGVkICovXG5cblxuICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlID0gKGltYWdlRWxlbWVudHMgPSBnZXRJbml0aWFsaXplZEltYWdlRWxlbWVudHModGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSksIGZpbGVzID0gdGhpcy5maWxlcykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgY29uc3QgdW5jYWNoZWRJbWFnZUVsZW1lbnRzID0gaW1hZ2VFbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiAhZWxlbWVudC5pc0RlbGV0ZWQgJiYgIXRoaXMuaW1hZ2VDYWNoZS5oYXMoZWxlbWVudC5maWxlSWQpKTtcblxuICAgICAgaWYgKHVuY2FjaGVkSW1hZ2VFbGVtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHVwZGF0ZWRGaWxlc1xuICAgICAgICB9ID0geWllbGQgdGhpcy51cGRhdGVJbWFnZUNhY2hlKHVuY2FjaGVkSW1hZ2VFbGVtZW50cywgZmlsZXMpO1xuXG4gICAgICAgIGlmICh1cGRhdGVkRmlsZXMuc2l6ZSkge1xuICAgICAgICAgIHRoaXMuc2NlbmUuaW5mb3JtTXV0YXRpb24oKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICAgIC8qKiBnZW5lcmFsbHkgeW91IHNob3VsZCB1c2UgYGFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpYCBkaXJlY3RseSBpZiB5b3UgbmVlZFxuICAgICAqICB0byByZW5kZXIgbmV3IGltYWdlcy4gVGhpcyBpcyBqdXN0IGEgZmFpbHNhZmUgICovXG5cblxuICAgIHRoaXMuc2NoZWR1bGVJbWFnZVJlZnJlc2ggPSB0aHJvdHRsZSgoKSA9PiB7XG4gICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgIH0sIElNQUdFX1JFTkRFUl9USU1FT1VUKTtcblxuICAgIHRoaXMudXBkYXRlQmluZGluZ0VuYWJsZWRPblBvaW50ZXJNb3ZlID0gZXZlbnQgPT4ge1xuICAgICAgY29uc3Qgc2hvdWxkRW5hYmxlQmluZGluZyA9IHNob3VsZEVuYWJsZUJpbmRpbmdGb3JQb2ludGVyRXZlbnQoZXZlbnQpO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5pc0JpbmRpbmdFbmFibGVkICE9PSBzaG91bGRFbmFibGVCaW5kaW5nKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGlzQmluZGluZ0VuYWJsZWQ6IHNob3VsZEVuYWJsZUJpbmRpbmdcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0F0Q3Vyc29yID0gcG9pbnRlckNvb3JkcyA9PiB7XG4gICAgICBjb25zdCBob3ZlcmVkQmluZGFibGVFbGVtZW50ID0gZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nKHBvaW50ZXJDb29yZHMsIHRoaXMuc2NlbmUpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBob3ZlcmVkQmluZGFibGVFbGVtZW50ICE9IG51bGwgPyBbaG92ZXJlZEJpbmRhYmxlRWxlbWVudF0gOiBbXVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ3NGb3JMaW5lYXJFbGVtZW50QXRDb29yZHMgPSAobGluZWFyRWxlbWVudCxcbiAgICAvKiogc2NlbmUgY29vcmRzICovXG4gICAgcG9pbnRlckNvb3JkcywgLy8gRHVyaW5nIGxpbmUgY3JlYXRpb24gdGhlIHN0YXJ0IGJpbmRpbmcgaGFzbid0IGJlZW4gd3JpdHRlbiB5ZXRcbiAgICAvLyBpbnRvIGBsaW5lYXJFbGVtZW50YFxuICAgIG9wcG9zaXRlQmluZGluZ0JvdW5kRWxlbWVudCkgPT4ge1xuICAgICAgaWYgKCFwb2ludGVyQ29vcmRzLmxlbmd0aCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHN1Z2dlc3RlZEJpbmRpbmdzID0gcG9pbnRlckNvb3Jkcy5yZWR1Y2UoKGFjYywgY29vcmRzKSA9PiB7XG4gICAgICAgIGNvbnN0IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcoY29vcmRzLCB0aGlzLnNjZW5lKTtcblxuICAgICAgICBpZiAoaG92ZXJlZEJpbmRhYmxlRWxlbWVudCAhPSBudWxsICYmICFpc0xpbmVhckVsZW1lbnRTaW1wbGVBbmRBbHJlYWR5Qm91bmQobGluZWFyRWxlbWVudCwgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50ID09PSBudWxsIHx8IG9wcG9zaXRlQmluZGluZ0JvdW5kRWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50LmlkLCBob3ZlcmVkQmluZGFibGVFbGVtZW50KSkge1xuICAgICAgICAgIGFjYy5wdXNoKGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIFtdKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nc1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlSW50ZXJhY3RpdmVDYW52YXNSZWYgPSBjYW52YXMgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2M7IC8vIGNhbnZhcyBpcyBudWxsIHdoZW4gdW5tb3VudGluZ1xuXG5cbiAgICAgIGlmIChjYW52YXMgIT09IG51bGwpIHtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyA9IGNhbnZhczsgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgICAgLy8gTk9URSB3aGVlbCwgdG91Y2hzdGFydCwgdG91Y2hlbmQgZXZlbnRzIG11c3QgYmUgcmVnaXN0ZXJlZCBvdXRzaWRlXG4gICAgICAgIC8vIG9mIHJlYWN0IGJlY2F1c2UgcmVhY3QgYmluZHMgdGhlbSB0aGVtIHBhc3NpdmVseSAoc28gd2UgY2FuJ3QgcHJldmVudFxuICAgICAgICAvLyBkZWZhdWx0IG9uIHRoZW0pXG5cbiAgICAgICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLmhhbmRsZVdoZWVsKTtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlRPVUNIX1NUQVJULCB0aGlzLm9uVG91Y2hTdGFydCk7XG4gICAgICAgIHRoaXMuaW50ZXJhY3RpdmVDYW52YXMuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5UT1VDSF9FTkQsIHRoaXMub25Ub3VjaEVuZCk7IC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICB9IGVsc2Uge1xuICAgICAgICAoX2EgPSB0aGlzLmludGVyYWN0aXZlQ2FudmFzKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5XSEVFTCwgdGhpcy5oYW5kbGVXaGVlbCk7XG4gICAgICAgIChfYiA9IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlRPVUNIX1NUQVJULCB0aGlzLm9uVG91Y2hTdGFydCk7XG4gICAgICAgIChfYyA9IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlRPVUNIX0VORCwgdGhpcy5vblRvdWNoRW5kKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVBcHBPbkRyb3AgPSBldmVudCA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB2YXIgX2wsIF9tLCBfbywgX3A7IC8vIG11c3QgYmUgcmV0cmlldmVkIGZpcnN0LCBpbiB0aGUgc2FtZSBmcmFtZVxuXG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZmlsZSxcbiAgICAgICAgZmlsZUhhbmRsZVxuICAgICAgfSA9IHlpZWxkIGdldEZpbGVGcm9tRXZlbnQoZXZlbnQpO1xuICAgICAgY29uc3Qge1xuICAgICAgICB4OiBzY2VuZVgsXG4gICAgICAgIHk6IHNjZW5lWVxuICAgICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGlmIChpc1N1cHBvcnRlZEltYWdlRmlsZShmaWxlKSkge1xuICAgICAgICAgIC8vIGZpcnN0IGF0dGVtcHQgdG8gZGVjb2RlIHNjZW5lIGZyb20gdGhlIGltYWdlIGlmIGl0J3MgZW1iZWRkZWRcbiAgICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgICAgICBpZiAoKGZpbGUgPT09IG51bGwgfHwgZmlsZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogZmlsZS50eXBlKSA9PT0gTUlNRV9UWVBFUy5wbmcgfHwgKGZpbGUgPT09IG51bGwgfHwgZmlsZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogZmlsZS50eXBlKSA9PT0gTUlNRV9UWVBFUy5zdmcpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGNvbnN0IHNjZW5lID0geWllbGQgbG9hZEZyb21CbG9iKGZpbGUsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGZpbGVIYW5kbGUpO1xuICAgICAgICAgICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZSksIHtcbiAgICAgICAgICAgICAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSB8fCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAgICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZVxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIHJlcGxhY2VGaWxlczogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgICBpZiAoZXJyb3IubmFtZSAhPT0gXCJFbmNvZGluZ0Vycm9yXCIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gaWYgbm8gc2NlbmUgaXMgZW1iZWRkZWQgb3Igd2UgZmFpbCBmb3Igd2hhdGV2ZXIgcmVhc29uLCBmYWxsIGJhY2tcbiAgICAgICAgICAvLyB0byBpbXBvcnRpbmcgYXMgcmVndWxhciBpbWFnZVxuICAgICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbiAgICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSB0aGlzLmNyZWF0ZUltYWdlRWxlbWVudCh7XG4gICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICBzY2VuZVlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLmluc2VydEltYWdlRWxlbWVudChpbWFnZUVsZW1lbnQsIGZpbGUpO1xuICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlRGltZW5zaW9ucyhpbWFnZUVsZW1lbnQpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICAgIFtpbWFnZUVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICB9LCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGlzTG9hZGluZzogZmFsc2UsXG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBsaWJyYXJ5SlNPTiA9IGV2ZW50LmRhdGFUcmFuc2Zlci5nZXREYXRhKE1JTUVfVFlQRVMuZXhjYWxpZHJhd2xpYik7XG5cbiAgICAgIGlmIChsaWJyYXJ5SlNPTiAmJiB0eXBlb2YgbGlicmFyeUpTT04gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBsaWJyYXJ5SXRlbXMgPSBwYXJzZUxpYnJhcnlKU09OKGxpYnJhcnlKU09OKTtcbiAgICAgICAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5KHtcbiAgICAgICAgICAgIGVsZW1lbnRzOiBkaXN0cmlidXRlTGlicmFyeUl0ZW1zT25TcXVhcmVHcmlkKGxpYnJhcnlJdGVtcyksXG4gICAgICAgICAgICBwb3NpdGlvbjogZXZlbnQsXG4gICAgICAgICAgICBmaWxlczogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChmaWxlKSB7XG4gICAgICAgIC8vIGF0ZXRtcHQgdG8gcGFyc2UgYW4gZXhjYWxpZHJhdy9leGNhbGlkcmF3bGliIGZpbGVcbiAgICAgICAgeWllbGQgdGhpcy5sb2FkRmlsZVRvQ2FudmFzKGZpbGUsIGZpbGVIYW5kbGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoKF9tID0gKF9sID0gZXZlbnQuZGF0YVRyYW5zZmVyKSA9PT0gbnVsbCB8fCBfbCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2wudHlwZXMpID09PSBudWxsIHx8IF9tID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfbS5pbmNsdWRlcyhcInRleHQvcGxhaW5cIikpIHtcbiAgICAgICAgY29uc3QgdGV4dCA9IChfbyA9IGV2ZW50LmRhdGFUcmFuc2ZlcikgPT09IG51bGwgfHwgX28gPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9vLmdldERhdGEoXCJ0ZXh0XCIpO1xuXG4gICAgICAgIGlmICh0ZXh0ICYmIGVtYmVkZGFibGVVUkxWYWxpZGF0b3IodGV4dCwgdGhpcy5wcm9wcy52YWxpZGF0ZUVtYmVkZGFibGUpICYmICgvXihodHRwfGh0dHBzKTpcXC9cXC9bXlxccy8kLj8jXS5bXlxcc10qJC8udGVzdCh0ZXh0KSB8fCAoKF9wID0gZ2V0RW1iZWRMaW5rKHRleHQpKSA9PT0gbnVsbCB8fCBfcCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX3AudHlwZSkgPT09IFwidmlkZW9cIikpIHtcbiAgICAgICAgICBjb25zdCBlbWJlZGRhYmxlID0gdGhpcy5pbnNlcnRFbWJlZGRhYmxlRWxlbWVudCh7XG4gICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgICBsaW5rOiBub3JtYWxpemVMaW5rKHRleHQpXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBpZiAoZW1iZWRkYWJsZSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgIFtlbWJlZGRhYmxlLmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMubG9hZEZpbGVUb0NhbnZhcyA9IChmaWxlLCBmaWxlSGFuZGxlKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICBmaWxlID0geWllbGQgbm9ybWFsaXplRmlsZShmaWxlKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmV0ID0geWllbGQgbG9hZFNjZW5lT3JMaWJyYXJ5RnJvbUJsb2IoZmlsZSwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZmlsZUhhbmRsZSk7XG5cbiAgICAgICAgaWYgKHJldC50eXBlID09PSBNSU1FX1RZUEVTLmV4Y2FsaWRyYXcpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGlzTG9hZGluZzogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHJldC5kYXRhKSwge1xuICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcmV0LmRhdGEuYXBwU3RhdGUgfHwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZVxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICByZXBsYWNlRmlsZXM6IHRydWUsXG4gICAgICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH0gZWxzZSBpZiAocmV0LnR5cGUgPT09IE1JTUVfVFlQRVMuZXhjYWxpZHJhd2xpYikge1xuICAgICAgICAgIHlpZWxkIHRoaXMubGlicmFyeS51cGRhdGVMaWJyYXJ5KHtcbiAgICAgICAgICAgIGxpYnJhcnlJdGVtczogZmlsZSxcbiAgICAgICAgICAgIG1lcmdlOiB0cnVlLFxuICAgICAgICAgICAgb3BlbkxpYnJhcnlNZW51OiB0cnVlXG4gICAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiB0KFwiZXJyb3JzLmltcG9ydExpYnJhcnlFcnJvclwiKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGlzTG9hZGluZzogZmFsc2UsXG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudSA9IGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgIGlmICgoXCJwb2ludGVyVHlwZVwiIGluIGV2ZW50Lm5hdGl2ZUV2ZW50ICYmIGV2ZW50Lm5hdGl2ZUV2ZW50LnBvaW50ZXJUeXBlID09PSBcInRvdWNoXCIgfHwgXCJwb2ludGVyVHlwZVwiIGluIGV2ZW50Lm5hdGl2ZUV2ZW50ICYmIGV2ZW50Lm5hdGl2ZUV2ZW50LnBvaW50ZXJUeXBlID09PSBcInBlblwiICYmIC8vIGFsd2F5cyBhbGxvdyBpZiB1c2VyIHVzZXMgYSBwZW4gc2Vjb25kYXJ5IGJ1dHRvblxuICAgICAgZXZlbnQuYnV0dG9uICE9PSBQT0lOVEVSX0JVVFRPTi5TRUNPTkRBUlkpICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICB4LFxuICAgICAgICB5XG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHgsIHksIHtcbiAgICAgICAgcHJlZmVyU2VsZWN0ZWQ6IHRydWUsXG4gICAgICAgIGluY2x1ZGVMb2NrZWRFbGVtZW50czogdHJ1ZVxuICAgICAgfSk7XG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgaXNIaXR0aWduQ29tbW9uQm91bmRCb3ggPSB0aGlzLmlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfSwgc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICBjb25zdCB0eXBlID0gZWxlbWVudCB8fCBpc0hpdHRpZ25Db21tb25Cb3VuZEJveCA/IFwiZWxlbWVudFwiIDogXCJjYW52YXNcIjtcbiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgY29uc3Qge1xuICAgICAgICB0b3A6IG9mZnNldFRvcCxcbiAgICAgICAgbGVmdDogb2Zmc2V0TGVmdFxuICAgICAgfSA9IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGNvbnN0IGxlZnQgPSBldmVudC5jbGllbnRYIC0gb2Zmc2V0TGVmdDtcbiAgICAgIGNvbnN0IHRvcCA9IGV2ZW50LmNsaWVudFkgLSBvZmZzZXRUb3A7XG4gICAgICB0cmFja0V2ZW50KFwiY29udGV4dE1lbnVcIiwgXCJvcGVuQ29udGV4dE1lbnVcIiwgdHlwZSk7XG4gICAgICB0aGlzLnNldFN0YXRlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF0gPyBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICBlZGl0aW5nR3JvdXBJZDogdGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgW2VsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgIH1cbiAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHRoaXMpKSwge1xuICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IGlzTGluZWFyRWxlbWVudChlbGVtZW50KSA/IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKGVsZW1lbnQsIHRoaXMuc2NlbmUpIDogbnVsbFxuICAgICAgfSkgOiB0aGlzLnN0YXRlKSwge1xuICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGZhbHNlXG4gICAgICB9KSwgKCkgPT4ge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBjb250ZXh0TWVudToge1xuICAgICAgICAgICAgdG9wLFxuICAgICAgICAgICAgbGVmdCxcbiAgICAgICAgICAgIGl0ZW1zOiB0aGlzLmdldENvbnRleHRNZW51SXRlbXModHlwZSlcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVEcmFnTmV3R2VuZXJpY0VsZW1lbnQgPSAocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpID0+IHtcbiAgICAgIHZhciBfYSwgX2IsIF9jLCBfZCwgX2U7XG5cbiAgICAgIGNvbnN0IGRyYWdnaW5nRWxlbWVudCA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50O1xuICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3JkcztcblxuICAgICAgaWYgKCFkcmFnZ2luZ0VsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZHJhZ2dpbmdFbGVtZW50LnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwiZXJhc2VyXCIpIHtcbiAgICAgICAgZHJhZ05ld0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgcG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGRpc3RhbmNlKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJDb29yZHMueCksIGRpc3RhbmNlKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIHBvaW50ZXJDb29yZHMueSksIHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyKGV2ZW50KSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCBpbWFnZSA9IGlzSW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSAmJiAoKF9hID0gdGhpcy5pbWFnZUNhY2hlLmdldChkcmFnZ2luZ0VsZW1lbnQuZmlsZUlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmltYWdlKTtcbiAgICAgICAgY29uc3QgYXNwZWN0UmF0aW8gPSBpbWFnZSAmJiAhKGltYWdlIGluc3RhbmNlb2YgUHJvbWlzZSkgPyBpbWFnZS53aWR0aCAvIGltYWdlLmhlaWdodCA6IG51bGw7XG4gICAgICAgIHRoaXMubWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIFtkcmFnZ2luZ0VsZW1lbnRdKTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHNuYXBPZmZzZXQsXG4gICAgICAgICAgc25hcExpbmVzXG4gICAgICAgIH0gPSBzbmFwTmV3RWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUsIGV2ZW50LCB7XG4gICAgICAgICAgeDogcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCArICgoX2MgPSAoX2IgPSB0aGlzLnN0YXRlLm9yaWdpblNuYXBPZmZzZXQpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi54KSAhPT0gbnVsbCAmJiBfYyAhPT0gdm9pZCAwID8gX2MgOiAwKSxcbiAgICAgICAgICB5OiBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55ICsgKChfZSA9IChfZCA9IHRoaXMuc3RhdGUub3JpZ2luU25hcE9mZnNldCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnkpICE9PSBudWxsICYmIF9lICE9PSB2b2lkIDAgPyBfZSA6IDApXG4gICAgICAgIH0sIHtcbiAgICAgICAgICB4OiBncmlkWCAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLngsXG4gICAgICAgICAgeTogZ3JpZFkgLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55XG4gICAgICAgIH0pO1xuICAgICAgICBncmlkWCArPSBzbmFwT2Zmc2V0Lng7XG4gICAgICAgIGdyaWRZICs9IHNuYXBPZmZzZXQueTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzXG4gICAgICAgIH0pO1xuICAgICAgICBkcmFnTmV3RWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55LCBncmlkWCwgZ3JpZFksIGRpc3RhbmNlKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLngsIGdyaWRYKSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueSwgZ3JpZFkpLCBpc0ltYWdlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpID8gIXNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpIDogc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCksIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIoZXZlbnQpLCBhc3BlY3RSYXRpbywgdGhpcy5zdGF0ZS5vcmlnaW5TbmFwT2Zmc2V0KTtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKFtkcmFnZ2luZ0VsZW1lbnRdKTsgLy8gaGlnaGxpZ2h0IGVsZW1lbnRzIHRoYXQgYXJlIHRvIGJlIGFkZGVkIHRvIGZyYW1lcyBvbiBmcmFtZXMgY3JlYXRpb25cblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWxlbWVudHNUb0hpZ2hsaWdodDogZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVIYW5kbGVSZXNpemUgPSAocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpID0+IHtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBzZWxlY3RlZEZyYW1lcyA9IHNlbGVjdGVkRWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuICAgICAgY29uc3QgdHJhbnNmb3JtSGFuZGxlVHlwZSA9IHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGU7XG5cbiAgICAgIGlmIChzZWxlY3RlZEZyYW1lcy5sZW5ndGggPiAwICYmIHRyYW5zZm9ybUhhbmRsZVR5cGUgPT09IFwicm90YXRpb25cIikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAvLyBUT0RPOiByZW5hbWUgdGhpcyBzdGF0ZSBmaWVsZCB0byBcImlzU2NhbGluZ1wiIHRvIGRpc3Rpbmd1aXNoXG4gICAgICAgIC8vIGl0IGZyb20gdGhlIGdlbmVyaWMgXCJpc1Jlc2l6aW5nXCIgd2hpY2ggaW5jbHVkZXMgc2NhbGluZyBhbmRcbiAgICAgICAgLy8gcm90YXRpbmdcbiAgICAgICAgaXNSZXNpemluZzogdHJhbnNmb3JtSGFuZGxlVHlwZSAmJiB0cmFuc2Zvcm1IYW5kbGVUeXBlICE9PSBcInJvdGF0aW9uXCIsXG4gICAgICAgIGlzUm90YXRpbmc6IHRyYW5zZm9ybUhhbmRsZVR5cGUgPT09IFwicm90YXRpb25cIixcbiAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzO1xuICAgICAgbGV0IFtyZXNpemVYLCByZXNpemVZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLnggLSBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5vZmZzZXQueCwgcG9pbnRlckNvb3Jkcy55IC0gcG9pbnRlckRvd25TdGF0ZS5yZXNpemUub2Zmc2V0LnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgZnJhbWVFbGVtZW50c09mZnNldHNNYXAgPSBuZXcgTWFwKCk7XG4gICAgICBzZWxlY3RlZEZyYW1lcy5mb3JFYWNoKGZyYW1lID0+IHtcbiAgICAgICAgY29uc3QgZWxlbWVudHNJbkZyYW1lID0gZ2V0RnJhbWVFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBmcmFtZS5pZCk7XG4gICAgICAgIGVsZW1lbnRzSW5GcmFtZS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLnNldChmcmFtZS5pZCArIGVsZW1lbnQuaWQsIHtcbiAgICAgICAgICAgIHg6IGVsZW1lbnQueCAtIGZyYW1lLngsXG4gICAgICAgICAgICB5OiBlbGVtZW50LnkgLSBmcmFtZS55XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7IC8vIGNoZWNrIG5lZWRlZCBmb3IgYXZvaWRpbmcgZmxpY2tlcmluZyB3aGVuIGEga2V5IGdldHMgcHJlc3NlZFxuICAgICAgLy8gZHVyaW5nIGRyYWdnaW5nXG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkKSB7XG4gICAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgICAgY29uc3QgZHJhZ09mZnNldCA9IHtcbiAgICAgICAgICB4OiBncmlkWCAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLngsXG4gICAgICAgICAgeTogZ3JpZFkgLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IG9yaWdpbmFsRWxlbWVudHMgPSBbLi4ucG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLnZhbHVlcygpXTtcbiAgICAgICAgdGhpcy5tYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBzbmFwT2Zmc2V0LFxuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9ID0gc25hcFJlc2l6aW5nRWxlbWVudHMoc2VsZWN0ZWRFbGVtZW50cywgZ2V0U2VsZWN0ZWRFbGVtZW50cyhvcmlnaW5hbEVsZW1lbnRzLCB0aGlzLnN0YXRlKSwgdGhpcy5zdGF0ZSwgZXZlbnQsIGRyYWdPZmZzZXQsIHRyYW5zZm9ybUhhbmRsZVR5cGUpO1xuICAgICAgICByZXNpemVYICs9IHNuYXBPZmZzZXQueDtcbiAgICAgICAgcmVzaXplWSArPSBzbmFwT2Zmc2V0Lnk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRyYW5zZm9ybUVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUsIHRyYW5zZm9ybUhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHMsIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmFycm93RGlyZWN0aW9uLCBzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZShldmVudCksIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIoZXZlbnQpLCBzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0ltYWdlRWxlbWVudChzZWxlY3RlZEVsZW1lbnRzWzBdKSA/ICFzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSA6IHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpLCByZXNpemVYLCByZXNpemVZLCBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5jZW50ZXIueCwgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuY2VudGVyLnksIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgY29uc3QgZWxlbWVudHNUb0hpZ2hsaWdodCA9IG5ldyBTZXQoKTtcbiAgICAgICAgc2VsZWN0ZWRGcmFtZXMuZm9yRWFjaChmcmFtZSA9PiB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudHNJbkZyYW1lID0gZ2V0RnJhbWVFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBmcmFtZS5pZCk7IC8vIGtlZXAgZWxlbWVudHMnIHBvc2l0aW9ucyByZWxhdGl2ZSB0byB0aGVpciBmcmFtZXMgb24gZnJhbWVzIHJlc2l6aW5nXG5cbiAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZSkge1xuICAgICAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUuaW5jbHVkZXMoXCJ3XCIpKSB7XG4gICAgICAgICAgICAgIGVsZW1lbnRzSW5GcmFtZS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgIHg6IGZyYW1lLnggKyAoKChfYSA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EueCkgfHwgMCksXG4gICAgICAgICAgICAgICAgICB5OiBmcmFtZS55ICsgKCgoX2IgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnkpIHx8IDApXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZS5pbmNsdWRlcyhcIm5cIikpIHtcbiAgICAgICAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgeDogZnJhbWUueCArICgoKF9hID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS54KSB8fCAwKSxcbiAgICAgICAgICAgICAgICAgIHk6IGZyYW1lLnkgKyAoKChfYiA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IueSkgfHwgMClcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZnJhbWUsIHRoaXMuc3RhdGUpLmZvckVhY2goZWxlbWVudCA9PiBlbGVtZW50c1RvSGlnaGxpZ2h0LmFkZChlbGVtZW50KSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBbLi4uZWxlbWVudHNUb0hpZ2hsaWdodF1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0Q29udGV4dE1lbnVJdGVtcyA9IHR5cGUgPT4ge1xuICAgICAgY29uc3Qgb3B0aW9ucyA9IFtdO1xuICAgICAgb3B0aW9ucy5wdXNoKGFjdGlvbkNvcHlBc1BuZywgYWN0aW9uQ29weUFzU3ZnKTsgLy8gY2FudmFzIGNvbnRleHRNZW51XG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICAgIGlmICh0eXBlID09PSBcImNhbnZhc1wiKSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICAgIHJldHVybiBbLi4ub3B0aW9ucywgYWN0aW9uVG9nZ2xlR3JpZE1vZGUsIGFjdGlvblRvZ2dsZVplbk1vZGUsIGFjdGlvblRvZ2dsZVZpZXdNb2RlLCBhY3Rpb25Ub2dnbGVTdGF0c107XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gW2FjdGlvblBhc3RlLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Db3B5QXNQbmcsIGFjdGlvbkNvcHlBc1N2ZywgY29weVRleHQsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvblNlbGVjdEFsbCwgYWN0aW9uVW5sb2NrQWxsRWxlbWVudHMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvblRvZ2dsZUdyaWRNb2RlLCBhY3Rpb25Ub2dnbGVPYmplY3RzU25hcE1vZGUsIGFjdGlvblRvZ2dsZVplbk1vZGUsIGFjdGlvblRvZ2dsZVZpZXdNb2RlLCBhY3Rpb25Ub2dnbGVTdGF0c107XG4gICAgICB9IC8vIGVsZW1lbnQgY29udGV4dE1lbnVcbiAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gICAgICBvcHRpb25zLnB1c2goY29weVRleHQpO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgcmV0dXJuIFthY3Rpb25Db3B5LCAuLi5vcHRpb25zXTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIFthY3Rpb25DdXQsIGFjdGlvbkNvcHksIGFjdGlvblBhc3RlLCBhY3Rpb25TZWxlY3RBbGxFbGVtZW50c0luRnJhbWUsIGFjdGlvblJlbW92ZUFsbEVsZW1lbnRzRnJvbUZyYW1lLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCAuLi5vcHRpb25zLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Db3B5U3R5bGVzLCBhY3Rpb25QYXN0ZVN0eWxlcywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uR3JvdXAsIGFjdGlvblVuYmluZFRleHQsIGFjdGlvbkJpbmRUZXh0LCBhY3Rpb25XcmFwVGV4dEluQ29udGFpbmVyLCBhY3Rpb25Vbmdyb3VwLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25BZGRUb0xpYnJhcnksIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvblNlbmRCYWNrd2FyZCwgYWN0aW9uQnJpbmdGb3J3YXJkLCBhY3Rpb25TZW5kVG9CYWNrLCBhY3Rpb25CcmluZ1RvRnJvbnQsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkZsaXBIb3Jpem9udGFsLCBhY3Rpb25GbGlwVmVydGljYWwsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvblRvZ2dsZUxpbmVhckVkaXRvciwgYWN0aW9uTGluaywgYWN0aW9uRHVwbGljYXRlU2VsZWN0aW9uLCBhY3Rpb25Ub2dnbGVFbGVtZW50TG9jaywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uRGVsZXRlU2VsZWN0ZWRdO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZVdoZWVsID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgIGlmIChpc1Bhbm5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIGRlbHRhWCxcbiAgICAgICAgZGVsdGFZXG4gICAgICB9ID0gZXZlbnQ7IC8vIG5vdGUgdGhhdCBldmVudC5jdHJsS2V5IGlzIG5lY2Vzc2FyeSB0byBoYW5kbGUgcGluY2ggem9vbWluZ1xuXG4gICAgICBpZiAoZXZlbnQubWV0YUtleSB8fCBldmVudC5jdHJsS2V5KSB7XG4gICAgICAgIGNvbnN0IHNpZ24gPSBNYXRoLnNpZ24oZGVsdGFZKTtcbiAgICAgICAgY29uc3QgTUFYX1NURVAgPSBaT09NX1NURVAgKiAxMDA7XG4gICAgICAgIGNvbnN0IGFic0RlbHRhID0gTWF0aC5hYnMoZGVsdGFZKTtcbiAgICAgICAgbGV0IGRlbHRhID0gZGVsdGFZO1xuXG4gICAgICAgIGlmIChhYnNEZWx0YSA+IE1BWF9TVEVQKSB7XG4gICAgICAgICAgZGVsdGEgPSBNQVhfU1RFUCAqIHNpZ247XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbmV3Wm9vbSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZSAtIGRlbHRhIC8gMTAwOyAvLyBpbmNyZWFzZSB6b29tIHN0ZXBzIHRoZSBtb3JlIHpvb21lZC1pbiB3ZSBhcmUgKGFwcGxpZXMgdG8gPjEwMCUgb25seSlcblxuICAgICAgICBuZXdab29tICs9IE1hdGgubG9nMTAoTWF0aC5tYXgoMSwgdGhpcy5zdGF0ZS56b29tLnZhbHVlKSkgKiAtc2lnbiAqIC8vIHJlZHVjZWQgYW1wbGlmaWNhdGlvbiBmb3Igc21hbGwgZGVsdGFzIChzbWFsbCBtb3ZlbWVudHMgb24gYSB0cmFja3BhZClcbiAgICAgICAgTWF0aC5taW4oMSwgYWJzRGVsdGEgLyAyMCk7XG4gICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgICB2aWV3cG9ydFg6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCxcbiAgICAgICAgICB2aWV3cG9ydFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSxcbiAgICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20obmV3Wm9vbSlcbiAgICAgICAgfSwgc3RhdGUpKSwge1xuICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogdHJ1ZVxuICAgICAgICB9KSk7XG4gICAgICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBzY3JvbGwgaG9yaXpvbnRhbGx5IHdoZW4gc2hpZnQgcHJlc3NlZFxuXG5cbiAgICAgIGlmIChldmVudC5zaGlmdEtleSkge1xuICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcygoe1xuICAgICAgICAgIHpvb20sXG4gICAgICAgICAgc2Nyb2xsWFxuICAgICAgICB9KSA9PiAoe1xuICAgICAgICAgIC8vIG9uIE1hYywgc2hpZnQrd2hlZWwgdGVuZHMgdG8gcmVzdWx0IGluIGRlbHRhWFxuICAgICAgICAgIHNjcm9sbFg6IHNjcm9sbFggLSAoZGVsdGFZIHx8IGRlbHRhWCkgLyB6b29tLnZhbHVlXG4gICAgICAgIH0pKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcygoe1xuICAgICAgICB6b29tLFxuICAgICAgICBzY3JvbGxYLFxuICAgICAgICBzY3JvbGxZXG4gICAgICB9KSA9PiAoe1xuICAgICAgICBzY3JvbGxYOiBzY3JvbGxYIC0gZGVsdGFYIC8gem9vbS52YWx1ZSxcbiAgICAgICAgc2Nyb2xsWTogc2Nyb2xsWSAtIGRlbHRhWSAvIHpvb20udmFsdWVcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRoaXMuc2F2ZVBvaW50ZXIgPSAoeCwgeSwgYnV0dG9uKSA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICBpZiAoIXggfHwgIXkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBwb2ludGVyID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgY2xpZW50WDogeCxcbiAgICAgICAgY2xpZW50WTogeVxuICAgICAgfSwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChpc05hTihwb2ludGVyLngpIHx8IGlzTmFOKHBvaW50ZXIueSkpIHsvLyBzb21ldGltZXMgdGhlIHBvaW50ZXIgZ29lcyBvZmYgc2NyZWVuXG4gICAgICB9XG5cbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpLm9uUG9pbnRlclVwZGF0ZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHtcbiAgICAgICAgcG9pbnRlcixcbiAgICAgICAgYnV0dG9uLFxuICAgICAgICBwb2ludGVyc01hcDogZ2VzdHVyZS5wb2ludGVyc1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQgPSBkZWJvdW5jZSgoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMudW5tb3VudGVkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSwgMzAwKTtcblxuICAgIHRoaXMudXBkYXRlRE9NUmVjdCA9IGNiID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgaWYgKChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmN1cnJlbnQpIHtcbiAgICAgICAgY29uc3QgZXhjYWxpZHJhd0NvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgIGxlZnQ6IG9mZnNldExlZnQsXG4gICAgICAgICAgdG9wOiBvZmZzZXRUb3BcbiAgICAgICAgfSA9IGV4Y2FsaWRyYXdDb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB3aWR0aDogY3VycmVudFdpZHRoLFxuICAgICAgICAgIGhlaWdodDogY3VycmVudEhlaWdodCxcbiAgICAgICAgICBvZmZzZXRUb3A6IGN1cnJlbnRPZmZzZXRUb3AsXG4gICAgICAgICAgb2Zmc2V0TGVmdDogY3VycmVudE9mZnNldExlZnRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7XG5cbiAgICAgICAgaWYgKHdpZHRoID09PSBjdXJyZW50V2lkdGggJiYgaGVpZ2h0ID09PSBjdXJyZW50SGVpZ2h0ICYmIG9mZnNldExlZnQgPT09IGN1cnJlbnRPZmZzZXRMZWZ0ICYmIG9mZnNldFRvcCA9PT0gY3VycmVudE9mZnNldFRvcCkge1xuICAgICAgICAgIGlmIChjYikge1xuICAgICAgICAgICAgY2IoKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgb2Zmc2V0TGVmdCxcbiAgICAgICAgICBvZmZzZXRUb3BcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIGNiICYmIGNiKCk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLnJlZnJlc2ggPSAoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZ2V0Q2FudmFzT2Zmc2V0cygpKSk7XG4gICAgfTtcblxuICAgIGNvbnN0IGRlZmF1bHRBcHBTdGF0ZSA9IGdldERlZmF1bHRBcHBTdGF0ZSgpO1xuICAgIGNvbnN0IHtcbiAgICAgIGV4Y2FsaWRyYXdSZWYsXG4gICAgICB2aWV3TW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIHplbk1vZGVFbmFibGVkID0gZmFsc2UsXG4gICAgICBncmlkTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIG9iamVjdHNTbmFwTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIHRoZW1lID0gZGVmYXVsdEFwcFN0YXRlLnRoZW1lLFxuICAgICAgbmFtZSA9IGRlZmF1bHRBcHBTdGF0ZS5uYW1lXG4gICAgfSA9IHByb3BzO1xuICAgIHRoaXMuc3RhdGUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBkZWZhdWx0QXBwU3RhdGUpLCB7XG4gICAgICB0aGVtZSxcbiAgICAgIGlzTG9hZGluZzogdHJ1ZVxuICAgIH0pLCB0aGlzLmdldENhbnZhc09mZnNldHMoKSksIHtcbiAgICAgIHZpZXdNb2RlRW5hYmxlZCxcbiAgICAgIHplbk1vZGVFbmFibGVkLFxuICAgICAgb2JqZWN0c1NuYXBNb2RlRW5hYmxlZCxcbiAgICAgIGdyaWRTaXplOiBncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsLFxuICAgICAgbmFtZSxcbiAgICAgIHdpZHRoOiB3aW5kb3cuaW5uZXJXaWR0aCxcbiAgICAgIGhlaWdodDogd2luZG93LmlubmVySGVpZ2h0XG4gICAgfSk7XG4gICAgdGhpcy5pZCA9IG5hbm9pZCgpO1xuICAgIHRoaXMubGlicmFyeSA9IG5ldyBMaWJyYXJ5KHRoaXMpO1xuICAgIHRoaXMuc2NlbmUgPSBuZXcgU2NlbmUoKTtcbiAgICB0aGlzLmNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgdGhpcy5yYyA9IHJvdWdoLmNhbnZhcyh0aGlzLmNhbnZhcyk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcblxuICAgIGlmIChleGNhbGlkcmF3UmVmKSB7XG4gICAgICBjb25zdCByZWFkeVByb21pc2UgPSBcImN1cnJlbnRcIiBpbiBleGNhbGlkcmF3UmVmICYmICgoX2EgPSBleGNhbGlkcmF3UmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZWFkeVByb21pc2UpIHx8IHJlc29sdmFibGVQcm9taXNlKCk7XG4gICAgICBjb25zdCBhcGkgPSB7XG4gICAgICAgIHJlYWR5OiB0cnVlLFxuICAgICAgICByZWFkeVByb21pc2UsXG4gICAgICAgIHVwZGF0ZVNjZW5lOiB0aGlzLnVwZGF0ZVNjZW5lLFxuICAgICAgICB1cGRhdGVMaWJyYXJ5OiB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSxcbiAgICAgICAgYWRkRmlsZXM6IHRoaXMuYWRkRmlsZXMsXG4gICAgICAgIHJlc2V0U2NlbmU6IHRoaXMucmVzZXRTY2VuZSxcbiAgICAgICAgZ2V0U2NlbmVFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQ6IHRoaXMuZ2V0U2NlbmVFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQsXG4gICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICBjbGVhcjogdGhpcy5yZXNldEhpc3RvcnlcbiAgICAgICAgfSxcbiAgICAgICAgc2Nyb2xsVG9Db250ZW50OiB0aGlzLnNjcm9sbFRvQ29udGVudCxcbiAgICAgICAgZ2V0U2NlbmVFbGVtZW50czogdGhpcy5nZXRTY2VuZUVsZW1lbnRzLFxuICAgICAgICBnZXRBcHBTdGF0ZTogKCkgPT4gdGhpcy5zdGF0ZSxcbiAgICAgICAgZ2V0RmlsZXM6ICgpID0+IHRoaXMuZmlsZXMsXG4gICAgICAgIHJlZnJlc2g6IHRoaXMucmVmcmVzaCxcbiAgICAgICAgc2V0VG9hc3Q6IHRoaXMuc2V0VG9hc3QsXG4gICAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgICBzZXRBY3RpdmVUb29sOiB0aGlzLnNldEFjdGl2ZVRvb2wsXG4gICAgICAgIHNldEN1cnNvcjogdGhpcy5zZXRDdXJzb3IsXG4gICAgICAgIHJlc2V0Q3Vyc29yOiB0aGlzLnJlc2V0Q3Vyc29yLFxuICAgICAgICB1cGRhdGVGcmFtZVJlbmRlcmluZzogdGhpcy51cGRhdGVGcmFtZVJlbmRlcmluZyxcbiAgICAgICAgdG9nZ2xlU2lkZWJhcjogdGhpcy50b2dnbGVTaWRlYmFyLFxuICAgICAgICBhcHA6IHRoaXMsXG4gICAgICAgIG9uQ2hhbmdlOiBjYiA9PiB0aGlzLm9uQ2hhbmdlRW1pdHRlci5vbihjYiksXG4gICAgICAgIG9uUG9pbnRlckRvd246IGNiID0+IHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIub24oY2IpLFxuICAgICAgICBvblBvaW50ZXJVcDogY2IgPT4gdGhpcy5vblBvaW50ZXJVcEVtaXR0ZXIub24oY2IpXG4gICAgICB9O1xuXG4gICAgICBpZiAodHlwZW9mIGV4Y2FsaWRyYXdSZWYgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBleGNhbGlkcmF3UmVmKGFwaSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBleGNhbGlkcmF3UmVmLmN1cnJlbnQgPSBhcGk7XG4gICAgICB9XG5cbiAgICAgIHJlYWR5UHJvbWlzZS5yZXNvbHZlKGFwaSk7XG4gICAgfVxuXG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWUgPSB7XG4gICAgICBjb250YWluZXI6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LFxuICAgICAgaWQ6IHRoaXMuaWRcbiAgICB9O1xuICAgIHRoaXMuZm9udHMgPSBuZXcgRm9udHMoe1xuICAgICAgc2NlbmU6IHRoaXMuc2NlbmUsXG4gICAgICBvblNjZW5lVXBkYXRlZDogdGhpcy5vblNjZW5lVXBkYXRlZFxuICAgIH0pO1xuICAgIHRoaXMuaGlzdG9yeSA9IG5ldyBIaXN0b3J5KCk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyID0gbmV3IEFjdGlvbk1hbmFnZXIodGhpcy5zeW5jQWN0aW9uUmVzdWx0LCAoKSA9PiB0aGlzLnN0YXRlLCAoKSA9PiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBbGwoYWN0aW9ucyk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVVuZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVJlZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gIH1cblxuICBvbldpbmRvd01lc3NhZ2UoZXZlbnQpIHtcbiAgICBpZiAoZXZlbnQub3JpZ2luICE9PSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiICYmIGV2ZW50Lm9yaWdpbiAhPT0gXCJodHRwczovL3d3dy55b3V0dWJlLmNvbVwiKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IGRhdGEgPSBudWxsO1xuXG4gICAgdHJ5IHtcbiAgICAgIGRhdGEgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG5cbiAgICBpZiAoIWRhdGEpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKGV2ZW50Lm9yaWdpbikge1xuICAgICAgY2FzZSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiOlxuICAgICAgICAvL0FsbG93aW5nIGZvciBtdWx0aXBsZSBpbnN0YW5jZXMgb2YgRXhjYWxpZHJhdyBydW5uaW5nIGluIHRoZSB3aW5kb3dcbiAgICAgICAgaWYgKGRhdGEubWV0aG9kID09PSBcInBhdXNlZFwiKSB7XG4gICAgICAgICAgbGV0IHNvdXJjZSA9IG51bGw7XG4gICAgICAgICAgY29uc3QgaWZyYW1lcyA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvckFsbChcImlmcmFtZS5leGNhbGlkcmF3X19lbWJlZGRhYmxlXCIpO1xuXG4gICAgICAgICAgaWYgKCFpZnJhbWVzKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBmb3IgKGNvbnN0IGlmcmFtZSBvZiBpZnJhbWVzKSB7XG4gICAgICAgICAgICBpZiAoaWZyYW1lLmNvbnRlbnRXaW5kb3cgPT09IGV2ZW50LnNvdXJjZSkge1xuICAgICAgICAgICAgICBzb3VyY2UgPSBpZnJhbWUuY29udGVudFdpbmRvdztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzb3VyY2UgPT09IG51bGwgfHwgc291cmNlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBzb3VyY2UucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgbWV0aG9kOiBkYXRhLnZhbHVlID8gXCJwbGF5XCIgOiBcInBhdXNlXCIsXG4gICAgICAgICAgICB2YWx1ZTogdHJ1ZVxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBcImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tXCI6XG4gICAgICAgIGlmIChkYXRhLmV2ZW50ID09PSBcImluZm9EZWxpdmVyeVwiICYmIGRhdGEuaW5mbyAmJiBkYXRhLmlkICYmIHR5cGVvZiBkYXRhLmluZm8ucGxheWVyU3RhdGUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICBjb25zdCBpZCA9IGRhdGEuaWQ7XG4gICAgICAgICAgY29uc3QgcGxheWVyU3RhdGUgPSBkYXRhLmluZm8ucGxheWVyU3RhdGU7XG5cbiAgICAgICAgICBpZiAoT2JqZWN0LnZhbHVlcyhZT1VUVUJFX1NUQVRFUykuaW5jbHVkZXMocGxheWVyU3RhdGUpKSB7XG4gICAgICAgICAgICBZT1VUVUJFX1ZJREVPX1NUQVRFUy5zZXQoaWQsIHBsYXllclN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICB1cGRhdGVFbWJlZGRhYmxlUmVmKGlkLCByZWYpIHtcbiAgICBpZiAocmVmKSB7XG4gICAgICB0aGlzLmlGcmFtZVJlZnMuc2V0KGlkLCByZWYpO1xuICAgIH1cbiAgfVxuXG4gIGdldEhUTUxJRnJhbWVFbGVtZW50KGlkKSB7XG4gICAgcmV0dXJuIHRoaXMuaUZyYW1lUmVmcy5nZXQoaWQpO1xuICB9XG5cbiAgaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKGVsZW1lbnQpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG5cbiAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpID09PSBlbGVtZW50ICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiYWN0aXZlXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9IC8vIFRoZSBkZWxheSBzZXJ2ZXMgdHdvIHB1cnBvc2VzXG4gICAgLy8gMS4gVG8gcHJldmVudCBmaXJzdCBjbGljayBwcm9wYWdhdGluZyB0byBpZnJhbWUgb24gbW9iaWxlLFxuICAgIC8vICAgIGVsc2UgdGhlIGNsaWNrIHdpbGwgaW1tZWRpYXRlbHkgc3RhcnQgYW5kIHN0b3AgdGhlIHZpZGVvXG4gICAgLy8gMi4gSWYgdGhlIHVzZXIgZG91YmxlIGNsaWNrcyB0aGUgZnJhbWUgY2VudGVyIHRvIGFjdGl2YXRlIGl0XG4gICAgLy8gICAgd2l0aG91dCB0aGUgZGVsYXkgeW91dHViZSB3aWxsIGltbWVkaWF0ZWx5IG9wZW4gdGhlIHZpZGVvXG4gICAgLy8gICAgaW4gZnVsbHNjcmVlbiBtb2RlXG5cblxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IHtcbiAgICAgICAgICBlbGVtZW50LFxuICAgICAgICAgIHN0YXRlOiBcImFjdGl2ZVwiXG4gICAgICAgIH0sXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgIFtlbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGlvbkVsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH0sIDEwMCk7XG4gICAgY29uc3QgaWZyYW1lID0gdGhpcy5nZXRIVE1MSUZyYW1lRWxlbWVudChlbGVtZW50LmlkKTtcblxuICAgIGlmICghKGlmcmFtZSA9PT0gbnVsbCB8fCBpZnJhbWUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGlmcmFtZS5jb250ZW50V2luZG93KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpZnJhbWUuc3JjLmluY2x1ZGVzKFwieW91dHViZVwiKSkge1xuICAgICAgY29uc3Qgc3RhdGUgPSBZT1VUVUJFX1ZJREVPX1NUQVRFUy5nZXQoZWxlbWVudC5pZCk7XG5cbiAgICAgIGlmICghc3RhdGUpIHtcbiAgICAgICAgWU9VVFVCRV9WSURFT19TVEFURVMuc2V0KGVsZW1lbnQuaWQsIFlPVVRVQkVfU1RBVEVTLlVOU1RBUlRFRCk7XG4gICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBldmVudDogXCJsaXN0ZW5pbmdcIixcbiAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgfVxuXG4gICAgICBzd2l0Y2ggKHN0YXRlKSB7XG4gICAgICAgIGNhc2UgWU9VVFVCRV9TVEFURVMuUExBWUlORzpcbiAgICAgICAgY2FzZSBZT1VUVUJFX1NUQVRFUy5CVUZGRVJJTkc6XG4gICAgICAgICAgKF9jID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBhdXNlVmlkZW9cIixcbiAgICAgICAgICAgIGFyZ3M6IFwiXCJcbiAgICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgKF9kID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBsYXlWaWRlb1wiLFxuICAgICAgICAgICAgYXJnczogXCJcIlxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGlmcmFtZS5zcmMuaW5jbHVkZXMoXCJwbGF5ZXIudmltZW8uY29tXCIpKSB7XG4gICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIG1ldGhvZDogXCJwYXVzZWRcIiAvL3ZpZGVvIHBsYXkvcGF1c2UgaW4gb25XaW5kb3dNZXNzYWdlIGhhbmRsZXJcblxuICAgICAgfSksIFwiKlwiKTtcbiAgICB9XG4gIH1cblxuICBpc0VtYmVkZGFibGVDZW50ZXIoZWwsIGV2ZW50LCBzY2VuZVgsIHNjZW5lWSkge1xuICAgIHZhciBfYSwgX2I7XG5cbiAgICByZXR1cm4gZWwgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQuc2hpZnRLZXkgJiYgIWV2ZW50Lm1ldGFLZXkgJiYgIWV2ZW50LmN0cmxLZXkgJiYgKCgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSAhPT0gZWwgfHwgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJob3ZlclwiIHx8ICF0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpICYmIHNjZW5lWCA+PSBlbC54ICsgZWwud2lkdGggLyAzICYmIHNjZW5lWCA8PSBlbC54ICsgMiAqIGVsLndpZHRoIC8gMyAmJiBzY2VuZVkgPj0gZWwueSArIGVsLmhlaWdodCAvIDMgJiYgc2NlbmVZIDw9IGVsLnkgKyAyICogZWwuaGVpZ2h0IC8gMztcbiAgfVxuXG4gIHJlbmRlckVtYmVkZGFibGVzKCkge1xuICAgIGNvbnN0IHNjYWxlID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRXaWR0aCA9IHRoaXMuc3RhdGUud2lkdGg7XG4gICAgY29uc3Qgbm9ybWFsaXplZEhlaWdodCA9IHRoaXMuc3RhdGUuaGVpZ2h0O1xuICAgIGNvbnN0IGVtYmVkZGFibGVFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsID0+IGlzRW1iZWRkYWJsZUVsZW1lbnQoZWwpICYmICEhZWwudmFsaWRhdGVkKTtcbiAgICByZXR1cm4gX2pzeChfRnJhZ21lbnQsIHtcbiAgICAgIGNoaWxkcmVuOiBlbWJlZGRhYmxlRWxlbWVudHMubWFwKGVsID0+IHtcbiAgICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaDtcblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogZWwueCxcbiAgICAgICAgICBzY2VuZVk6IGVsLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGVtYmVkTGluayA9IGdldEVtYmVkTGluayh0b1ZhbGlkVVJMKGVsLmxpbmsgfHwgXCJcIikpO1xuICAgICAgICBjb25zdCBpc1Zpc2libGUgPSBpc0VsZW1lbnRJblZpZXdwb3J0KGVsLCBub3JtYWxpemVkV2lkdGgsIG5vcm1hbGl6ZWRIZWlnaHQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBpc0FjdGl2ZSA9ICgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSA9PT0gZWwgJiYgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJhY3RpdmVcIjtcbiAgICAgICAgY29uc3QgaXNIb3ZlcmVkID0gKChfYyA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmVsZW1lbnQpID09PSBlbCAmJiAoKF9kID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Quc3RhdGUpID09PSBcImhvdmVyXCI7XG4gICAgICAgIHJldHVybiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgIGNsYXNzTmFtZTogY2xzeChcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtY29udGFpbmVyXCIsIHtcbiAgICAgICAgICAgIFwiaXMtaG92ZXJlZFwiOiBpc0hvdmVyZWRcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgdHJhbnNmb3JtOiBpc1Zpc2libGUgPyBgdHJhbnNsYXRlKCR7eCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdH1weCwgJHt5IC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3B9cHgpIHNjYWxlKCR7c2NhbGV9KWAgOiBcIm5vbmVcIixcbiAgICAgICAgICAgIGRpc3BsYXk6IGlzVmlzaWJsZSA/IFwiYmxvY2tcIiA6IFwibm9uZVwiLFxuICAgICAgICAgICAgb3BhY2l0eTogZWwub3BhY2l0eSAvIDEwMCxcbiAgICAgICAgICAgIFtcIi0tZW1iZWRkYWJsZS1yYWRpdXNcIl06IGAke2dldENvcm5lclJhZGl1cyhNYXRoLm1pbihlbC53aWR0aCwgZWwuaGVpZ2h0KSwgZWwpfXB4YFxuICAgICAgICAgIH1cbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBfanN4cyhcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgIC8vdGhpcyBpcyBhIGhhY2sgdGhhdCBhZGRyZXNzZXMgaXNzZSB3aXRoIGVtYmVkZGVkIGV4Y2FsaWRyYXcuY29tIGVtYmVkZGFibGVcbiAgICAgICAgICAgIC8vaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzY2OTEjaXNzdWVjb21tZW50LTE2MDczODM5MzhcblxuICAgICAgICAgICAgLypyZWY9eyhyZWYpID0+IHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgICAgICAgICAgY29uc3Qgc2ggPSBjb250YWluZXIuc2Nyb2xsSGVpZ2h0O1xuICAgICAgICAgICAgICBjb25zdCBjaCA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQ7XG4gICAgICAgICAgICAgIGlmIChzaCAhPT0gY2gpIHtcbiAgICAgICAgICAgICAgICBjb250YWluZXIuc3R5bGUuaGVpZ2h0ID0gYCR7c2h9cHhgO1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgY29udGFpbmVyLnN0eWxlLmhlaWdodCA9IGAxMDAlYDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfX0qL1xuICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtY29udGFpbmVyX19pbm5lclwiLFxuICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgd2lkdGg6IGlzVmlzaWJsZSA/IGAke2VsLndpZHRofXB4YCA6IDAsXG4gICAgICAgICAgICAgIGhlaWdodDogaXNWaXNpYmxlID8gYCR7ZWwuaGVpZ2h0fXB4YCA6IDAsXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogaXNWaXNpYmxlID8gYHJvdGF0ZSgke2VsLmFuZ2xlfXJhZClgIDogXCJub25lXCIsXG4gICAgICAgICAgICAgIHBvaW50ZXJFdmVudHM6IGlzQWN0aXZlID8gUE9JTlRFUl9FVkVOVFMuZW5hYmxlZCA6IFBPSU5URVJfRVZFTlRTLmRpc2FibGVkXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgY2hpbGRyZW46IFtpc0hvdmVyZWQgJiYgX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtaGludFwiXG4gICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgIGNoaWxkcmVuOiB0KFwiYnV0dG9ucy5lbWJlZGRhYmxlSW50ZXJhY3Rpb25CdXR0b25cIilcbiAgICAgICAgICAgIH0pKSwgX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGVfX291dGVyXCIsXG4gICAgICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgcGFkZGluZzogYCR7ZWwuc3Ryb2tlV2lkdGh9cHhgXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IChfZyA9IChfZiA9IChfZSA9IHRoaXMucHJvcHMpLnJlbmRlckVtYmVkZGFibGUpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5jYWxsKF9lLCBlbCwgdGhpcy5zdGF0ZSkpICE9PSBudWxsICYmIF9nICE9PSB2b2lkIDAgPyBfZyA6IF9qc3goXCJpZnJhbWVcIiwge1xuICAgICAgICAgICAgICAgIHJlZjogcmVmID0+IHRoaXMudXBkYXRlRW1iZWRkYWJsZVJlZihlbC5pZCwgcmVmKSxcbiAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZVwiLFxuICAgICAgICAgICAgICAgIHNyY0RvYzogKGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay50eXBlKSA9PT0gXCJkb2N1bWVudFwiID8gZW1iZWRMaW5rLnNyY2RvYyh0aGlzLnN0YXRlLnRoZW1lKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBzcmM6IChlbWJlZExpbmsgPT09IG51bGwgfHwgZW1iZWRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbWJlZExpbmsudHlwZSkgIT09IFwiZG9jdW1lbnRcIiA/IChfaCA9IGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay5saW5rKSAhPT0gbnVsbCAmJiBfaCAhPT0gdm9pZCAwID8gX2ggOiBcIlwiIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcS8xODQ3MDAxNVxuICAgICAgICAgICAgICAgIHNjcm9sbGluZzogXCJub1wiLFxuICAgICAgICAgICAgICAgIHJlZmVycmVyUG9saWN5OiBcIm5vLXJlZmVycmVyLXdoZW4tZG93bmdyYWRlXCIsXG4gICAgICAgICAgICAgICAgdGl0bGU6IFwiRXhjYWxpZHJhdyBFbWJlZGRlZCBDb250ZW50XCIsXG4gICAgICAgICAgICAgICAgYWxsb3c6IFwiYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZVwiLFxuICAgICAgICAgICAgICAgIGFsbG93RnVsbFNjcmVlbjogdHJ1ZSxcbiAgICAgICAgICAgICAgICBzYW5kYm94OiBcImFsbG93LXNhbWUtb3JpZ2luIGFsbG93LXNjcmlwdHMgYWxsb3ctZm9ybXMgYWxsb3ctcG9wdXBzIGFsbG93LXBvcHVwcy10by1lc2NhcGUtc2FuZGJveCBhbGxvdy1wcmVzZW50YXRpb24gYWxsb3ctZG93bmxvYWRzXCJcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pKV1cbiAgICAgICAgICB9KSlcbiAgICAgICAgfSksIGVsLmlkKTtcbiAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICByZW5kZXIoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2M7XG5cbiAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHtcbiAgICAgIHJlbmRlclRvcFJpZ2h0VUksXG4gICAgICByZW5kZXJDdXN0b21TdGF0c1xuICAgIH0gPSB0aGlzLnByb3BzO1xuICAgIGNvbnN0IHZlcnNpb25Ob25jZSA9IHRoaXMuc2NlbmUuZ2V0VmVyc2lvbk5vbmNlKCk7XG4gICAgY29uc3Qge1xuICAgICAgY2FudmFzRWxlbWVudHMsXG4gICAgICB2aXNpYmxlRWxlbWVudHNcbiAgICB9ID0gdGhpcy5yZW5kZXJlci5nZXRSZW5kZXJhYmxlRWxlbWVudHMoe1xuICAgICAgdmVyc2lvbk5vbmNlLFxuICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLFxuICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgb2Zmc2V0VG9wOiB0aGlzLnN0YXRlLm9mZnNldFRvcCxcbiAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCxcbiAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgIGhlaWdodDogdGhpcy5zdGF0ZS5oZWlnaHQsXG4gICAgICB3aWR0aDogdGhpcy5zdGF0ZS53aWR0aCxcbiAgICAgIGVkaXRpbmdFbGVtZW50OiB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50LFxuICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiB0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZFxuICAgIH0pO1xuICAgIHJldHVybiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgY2xhc3NOYW1lOiBjbHN4KFwiZXhjYWxpZHJhdyBleGNhbGlkcmF3LWNvbnRhaW5lclwiLCB7XG4gICAgICAgIFwiZXhjYWxpZHJhdy0tdmlldy1tb2RlXCI6IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkLFxuICAgICAgICBcImV4Y2FsaWRyYXctLXplbi1tb2RlXCI6IHRoaXMuc3RhdGUuemVuTW9kZUVuYWJsZWQsXG4gICAgICAgIFwiZXhjYWxpZHJhdy0tbW9iaWxlXCI6IHRoaXMuZGV2aWNlLmlzTW9iaWxlXG4gICAgICB9KSxcbiAgICAgIHN0eWxlOiB7XG4gICAgICAgIFtcIi0tdWktcG9pbnRlckV2ZW50c1wiXTogdGhpcy5zdGF0ZS5zZWxlY3Rpb25FbGVtZW50IHx8IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50IHx8IHRoaXMuc3RhdGUucmVzaXppbmdFbGVtZW50IHx8IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQgJiYgIWlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPyBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZCA6IFBPSU5URVJfRVZFTlRTLmVuYWJsZWRcbiAgICAgIH0sXG4gICAgICByZWY6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZixcbiAgICAgIG9uRHJvcDogdGhpcy5oYW5kbGVBcHBPbkRyb3AsXG4gICAgICB0YWJJbmRleDogMCxcbiAgICAgIG9uS2V5RG93bjogdGhpcy5wcm9wcy5oYW5kbGVLZXlib2FyZEdsb2JhbGx5ID8gdW5kZWZpbmVkIDogdGhpcy5vbktleURvd25cbiAgICB9LCB7XG4gICAgICBjaGlsZHJlbjogX2pzeChBcHBDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgdmFsdWU6IHRoaXNcbiAgICAgIH0sIHtcbiAgICAgICAgY2hpbGRyZW46IF9qc3goQXBwUHJvcHNDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICB2YWx1ZTogdGhpcy5wcm9wc1xuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgdmFsdWU6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlXG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRGV2aWNlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmRldmljZVxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICBjaGlsZHJlbjogX2pzeChFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5zZXRBcHBTdGF0ZVxuICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5zdGF0ZVxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4cyhFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKClcbiAgICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IFtfanN4cyhFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmFjdGlvbk1hbmFnZXJcbiAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbX2pzeChMYXllclVJLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uSG9tZUJ1dHRvbkNsaWNrOiB0aGlzLnByb3BzLm9uSG9tZUJ1dHRvbkNsaWNrIHx8ICgoKSA9PiB7fSksXG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmVDYW52YXM6IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVzOiB0aGlzLmZpbGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0QXBwU3RhdGU6IHRoaXMuc2V0QXBwU3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25NYW5hZ2VyOiB0aGlzLmFjdGlvbk1hbmFnZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uTG9ja1RvZ2dsZTogdGhpcy50b2dnbGVMb2NrLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25QZW5Nb2RlVG9nZ2xlOiB0aGlzLnRvZ2dsZVBlbk1vZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkhhbmRUb29sVG9nZ2xlOiB0aGlzLm9uSGFuZFRvb2xUb2dnbGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBsYW5nQ29kZTogZ2V0TGFuZ3VhZ2UoKS5jb2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyQ3VzdG9tU3RhdHM6IHJlbmRlckN1c3RvbVN0YXRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2hvd0V4aXRaZW5Nb2RlQnRuOiB0eXBlb2YgKChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS56ZW5Nb2RlRW5hYmxlZCkgPT09IFwidW5kZWZpbmVkXCIgJiYgdGhpcy5zdGF0ZS56ZW5Nb2RlRW5hYmxlZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIFVJT3B0aW9uczogdGhpcy5wcm9wcy5VSU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkV4cG9ydEltYWdlOiB0aGlzLm9uRXhwb3J0SW1hZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkltYWdlQWN0aW9uOiB0aGlzLm9uSW1hZ2VBY3Rpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJXZWxjb21lU2NyZWVuOiAhdGhpcy5zdGF0ZS5pc0xvYWRpbmcgJiYgdGhpcy5zdGF0ZS5zaG93V2VsY29tZVNjcmVlbiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiAhdGhpcy5zdGF0ZS56ZW5Nb2RlRW5hYmxlZCAmJiAhdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICBhcHA6IHRoaXMsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJUb3BSaWdodFVJOiByZW5kZXJUb3BSaWdodFVJXG4gICAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IHRoaXMucHJvcHMuY2hpbGRyZW5cbiAgICAgICAgICAgICAgICAgICAgICB9KSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctdGV4dEVkaXRvckNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctY29udGV4dE1lbnVDb250YWluZXJcIlxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KFwiZGl2XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3LWV5ZS1kcm9wcGVyLWNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICF0aGlzLnN0YXRlLmNvbnRleHRNZW51ICYmIHRoaXMuc3RhdGUuc2hvd0h5cGVybGlua1BvcHVwICYmIF9qc3goSHlwZXJsaW5rLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50OiBzZWxlY3RlZEVsZW1lbnRzWzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0QXBwU3RhdGU6IHRoaXMuc2V0QXBwU3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkxpbmtPcGVuOiB0aGlzLnByb3BzLm9uTGlua09wZW4sXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRUb2FzdDogdGhpcy5zZXRUb2FzdFxuICAgICAgICAgICAgICAgICAgICAgIH0sIHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpLCB0aGlzLnN0YXRlLnRvYXN0ICE9PSBudWxsICYmIF9qc3goVG9hc3QsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IHRoaXMuc3RhdGUudG9hc3QubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xvc2U6ICgpID0+IHRoaXMuc2V0VG9hc3QobnVsbCksXG4gICAgICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogdGhpcy5zdGF0ZS50b2FzdC5kdXJhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsb3NhYmxlOiB0aGlzLnN0YXRlLnRvYXN0LmNsb3NhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHRoaXMuc3RhdGUuY29udGV4dE1lbnUgJiYgX2pzeChDb250ZXh0TWVudSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbXM6IHRoaXMuc3RhdGUuY29udGV4dE1lbnUuaXRlbXMsXG4gICAgICAgICAgICAgICAgICAgICAgICB0b3A6IHRoaXMuc3RhdGUuY29udGV4dE1lbnUudG9wLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGVmdDogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS5sZWZ0LFxuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uTWFuYWdlcjogdGhpcy5hY3Rpb25NYW5hZ2VyXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goU3RhdGljQ2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmM6IHRoaXMucmMsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogY2FudmFzRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB2aXNpYmxlRWxlbWVudHM6IHZpc2libGVFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb25Ob25jZTogdmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uTm9uY2U6IChfYiA9IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyQ29uZmlnOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlQ2FjaGU6IHRoaXMuaW1hZ2VDYWNoZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaXNFeHBvcnRpbmc6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJHcmlkOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBjYW52YXNCYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUudmlld0JhY2tncm91bmRDb2xvclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KEludGVyYWN0aXZlQ2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250YWluZXJSZWY6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbnZhczogdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzOiBjYW52YXNFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpc2libGVFbGVtZW50czogdmlzaWJsZUVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50czogc2VsZWN0ZWRFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb25Ob25jZTogdmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uTm9uY2U6IChfYyA9IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrOiB0aGlzLnJlbmRlckludGVyYWN0aXZlU2NlbmVDYWxsYmFjayxcbiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZUNhbnZhc1JlZjogdGhpcy5oYW5kbGVJbnRlcmFjdGl2ZUNhbnZhc1JlZixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ29udGV4dE1lbnU6IHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJNb3ZlOiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Qb2ludGVyVXA6IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlclVwLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Qb2ludGVyQ2FuY2VsOiB0aGlzLnJlbW92ZVBvaW50ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblRvdWNoTW92ZTogdGhpcy5oYW5kbGVUb3VjaE1vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJEb3duOiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJEb3duLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Eb3VibGVDbGljazogdGhpcy5oYW5kbGVDYW52YXNEb3VibGVDbGlja1xuICAgICAgICAgICAgICAgICAgICAgIH0pLCB0aGlzLnJlbmRlckZyYW1lTmFtZXMoKV1cbiAgICAgICAgICAgICAgICAgICAgfSkpLCB0aGlzLnJlbmRlckVtYmVkZGFibGVzKCldXG4gICAgICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgICAgfSkpXG4gICAgICAgICAgICB9KSlcbiAgICAgICAgICB9KSlcbiAgICAgICAgfSkpXG4gICAgICB9KSlcbiAgICB9KSk7XG4gIH1cblxuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICB2YXIgX2EsIF9iO1xuXG4gICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRoaXMudW5tb3VudGVkID0gZmFsc2U7XG4gICAgICB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJWYWx1ZS5jb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcblxuICAgICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBFTlYuVEVTVCB8fCBwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gXCJwcm9kdWN0aW9uXCIpIHtcbiAgICAgICAgY29uc3Qgc2V0U3RhdGUgPSB0aGlzLnNldFN0YXRlLmJpbmQodGhpcyk7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHdpbmRvdy5oLCB7XG4gICAgICAgICAgc3RhdGU6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIGdldDogKCkgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIHNldFN0YXRlOiB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogKC4uLmFyZ3MpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2V0U3RhdGUoLi4uYXJncyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBhcHA6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzXG4gICAgICAgICAgfSxcbiAgICAgICAgICBoaXN0b3J5OiB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogdGhpcy5oaXN0b3J5XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zY2VuZS5hZGRDYWxsYmFjayh0aGlzLm9uU2NlbmVVcGRhdGVkKTtcbiAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcnMoKTtcblxuICAgICAgaWYgKHRoaXMucHJvcHMuYXV0b0ZvY3VzICYmIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSB7XG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50ICYmIC8vIGJvdW5kaW5nIHJlY3RzIGRvbid0IHdvcmsgaW4gdGVzdHMgc28gdXBkYXRpbmdcbiAgICAgIC8vIHRoZSBzdGF0ZSBvbiBpbml0IHdvdWxkIHJlc3VsdCBpbiBtYWtpbmcgdGhlIHRlc3QgZW52aXJvIHJ1blxuICAgICAgLy8gaW4gbW9iaWxlIGJyZWFrcG9pbnQgKDAgd2lkdGgvaGVpZ2h0KSwgbWFraW5nIGV2ZXJ5dGhpbmcgZmFpbFxuICAgICAgIWlzVGVzdEVudigpKSB7XG4gICAgICAgIHRoaXMucmVmcmVzaERldmljZVN0YXRlKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKFwiUmVzaXplT2JzZXJ2ZXJcIiBpbiB3aW5kb3cgJiYgKChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmN1cnJlbnQpKSB7XG4gICAgICAgIHRoaXMucmVzaXplT2JzZXJ2ZXIgPSBuZXcgUmVzaXplT2JzZXJ2ZXIoKCkgPT4ge1xuICAgICAgICAgIC8vIHJlY29tcHV0ZSBkZXZpY2UgZGltZW5zaW9ucyBzdGF0ZVxuICAgICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAgIHRoaXMucmVmcmVzaERldmljZVN0YXRlKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KTsgLy8gcmVmcmVzaCBvZmZzZXRzXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICAgICAgICB0aGlzLnVwZGF0ZURPTVJlY3QoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIChfYiA9IHRoaXMucmVzaXplT2JzZXJ2ZXIpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5vYnNlcnZlKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KTtcbiAgICAgIH0gZWxzZSBpZiAod2luZG93Lm1hdGNoTWVkaWEpIHtcbiAgICAgICAgY29uc3QgbWRTY3JlZW5RdWVyeSA9IHdpbmRvdy5tYXRjaE1lZGlhKGAobWF4LXdpZHRoOiAke01RX01BWF9XSURUSF9QT1JUUkFJVH1weCksIChtYXgtaGVpZ2h0OiAke01RX01BWF9IRUlHSFRfTEFORFNDQVBFfXB4KSBhbmQgKG1heC13aWR0aDogJHtNUV9NQVhfV0lEVEhfTEFORFNDQVBFfXB4KWApO1xuICAgICAgICBjb25zdCBzbVNjcmVlblF1ZXJ5ID0gd2luZG93Lm1hdGNoTWVkaWEoYChtYXgtd2lkdGg6ICR7TVFfU01fTUFYX1dJRFRIfXB4KWApO1xuICAgICAgICBjb25zdCBjYW5EZXZpY2VGaXRTaWRlYmFyTWVkaWFRdWVyeSA9IHdpbmRvdy5tYXRjaE1lZGlhKGAobWluLXdpZHRoOiAkey8vIE5PVEUgdGhpcyB3b24ndCB1cGRhdGUgaWYgYSBkaWZmZXJlbnQgYnJlYWtwb2ludCBpcyBzdXBwbGllZFxuICAgICAgICAvLyBhZnRlciBtb3VudFxuICAgICAgICB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCAhPSBudWxsID8gdGhpcy5wcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgOiBNUV9SSUdIVF9TSURFQkFSX01JTl9XSURUSH1weClgKTtcblxuICAgICAgICBjb25zdCBoYW5kbGVyID0gKCkgPT4ge1xuICAgICAgICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICAgIHRoaXMuZGV2aWNlID0gdXBkYXRlT2JqZWN0KHRoaXMuZGV2aWNlLCB7XG4gICAgICAgICAgICBpc1NtU2NyZWVuOiBzbVNjcmVlblF1ZXJ5Lm1hdGNoZXMsXG4gICAgICAgICAgICBpc01vYmlsZTogbWRTY3JlZW5RdWVyeS5tYXRjaGVzLFxuICAgICAgICAgICAgY2FuRGV2aWNlRml0U2lkZWJhcjogY2FuRGV2aWNlRml0U2lkZWJhck1lZGlhUXVlcnkubWF0Y2hlc1xuICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIG1kU2NyZWVuUXVlcnkuYWRkTGlzdGVuZXIoaGFuZGxlcik7XG5cbiAgICAgICAgdGhpcy5kZXRhY2hJc01vYmlsZU1xSGFuZGxlciA9ICgpID0+IG1kU2NyZWVuUXVlcnkucmVtb3ZlTGlzdGVuZXIoaGFuZGxlcik7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNlYXJjaFBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaC5zbGljZSgxKSk7XG5cbiAgICAgIGlmIChzZWFyY2hQYXJhbXMuaGFzKFwid2ViLXNoYXJlLXRhcmdldFwiKSkge1xuICAgICAgICAvLyBPYnRhaW4gYSBmaWxlIHRoYXQgd2FzIHNoYXJlZCB2aWEgdGhlIFdlYiBTaGFyZSBUYXJnZXQgQVBJLlxuICAgICAgICB0aGlzLnJlc3RvcmVGaWxlRnJvbVNoYXJlKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnVwZGF0ZURPTVJlY3QodGhpcy5pbml0aWFsaXplU2NlbmUpO1xuICAgICAgfSAvLyBub3RlIHRoYXQgdGhpcyBjaGVjayBzZWVtcyB0byBhbHdheXMgcGFzcyBpbiBsb2NhbGhvc3RcblxuXG4gICAgICBpZiAoaXNCcmF2ZSgpICYmICFpc01lYXN1cmVUZXh0U3VwcG9ydGVkKCkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBfanN4KEJyYXZlTWVhc3VyZVRleHRFcnJvciwge30pXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgdmFyIF9hO1xuXG4gICAgdGhpcy5yZW5kZXJlci5kZXN0cm95KCk7XG4gICAgdGhpcy5zY2VuZSA9IG5ldyBTY2VuZSgpO1xuICAgIHRoaXMucmVuZGVyZXIgPSBuZXcgUmVuZGVyZXIodGhpcy5zY2VuZSk7XG4gICAgdGhpcy5maWxlcyA9IHt9O1xuICAgIHRoaXMuaW1hZ2VDYWNoZS5jbGVhcigpO1xuICAgIChfYSA9IHRoaXMucmVzaXplT2JzZXJ2ZXIpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5kaXNjb25uZWN0KCk7XG4gICAgdGhpcy51bm1vdW50ZWQgPSB0cnVlO1xuICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICB0aGlzLnNjZW5lLmRlc3Ryb3koKTtcbiAgICB0aGlzLmxpYnJhcnkuZGVzdHJveSgpO1xuICAgIFNoYXBlQ2FjaGUuZGVzdHJveSgpO1xuICAgIFNuYXBDYWNoZS5kZXN0cm95KCk7XG4gICAgY2xlYXJSZW5kZXJDYWNoZSgpO1xuICAgIHRoaXMub25DaGFuZ2VFbWl0dGVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLnNjZW5lID0gbmV3IFNjZW5lKCk7XG4gICAgdGhpcy5oaXN0b3J5ID0gbmV3IEhpc3RvcnkoKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIgPSBuZXcgQWN0aW9uTWFuYWdlcih0aGlzLnN5bmNBY3Rpb25SZXN1bHQsICgpID0+IHRoaXMuc3RhdGUsICgpID0+IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMpO1xuICAgIHRoaXMubGlicmFyeSA9IG5ldyBMaWJyYXJ5KHRoaXMpOyAvLyBAdHMtaWdub3JlXG5cbiAgICB0aGlzLmNhbnZhcyA9IG51bGw7XG4gICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyA9IG51bGw7IC8vIEB0cy1pZ25vcmVcblxuICAgIHRoaXMucmMgPSBudWxsOyAvLyBAdHMtaWdub3JlXG5cbiAgICB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlID0ge1xuICAgICAgY29udGFpbmVyOiBudWxsLFxuICAgICAgaWQ6IFwidW5tb3VudGVkXCJcbiAgICB9O1xuICAgIGlzU29tZUVsZW1lbnRTZWxlY3RlZC5jbGVhckNhY2hlKCk7XG4gICAgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cy5jbGVhckNhY2hlKCk7XG4gICAgdG91Y2hUaW1lb3V0ID0gMDtcbiAgfVxuXG4gIHJlbW92ZUV2ZW50TGlzdGVuZXJzKCkge1xuICAgIHZhciBfYSwgX2IsIF9jLCBfZCwgX2UsIF9mLCBfZztcblxuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGhpcy5yZW1vdmVQb2ludGVyKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkNPUFksIHRoaXMub25Db3B5KTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5DVVQsIHRoaXMub25DdXQpO1xuICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5XSEVFTCwgdGhpcy5vbldoZWVsKTtcbiAgICAoX2IgPSB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5TQ1JPTEwsIHRoaXMub25TY3JvbGwpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgdGhpcy5vbktleURvd24sIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1PVVNFX01PVkUsIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfYyA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9kID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9mID0gKF9lID0gZG9jdW1lbnQuZm9udHMpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5yZW1vdmVFdmVudExpc3RlbmVyKSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuY2FsbChfZSwgXCJsb2FkaW5nZG9uZVwiLCB0aGlzLm9uRm9udHNMb2FkaW5nRG9uZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX1NUQVJULCB0aGlzLm9uR2VzdHVyZVN0YXJ0LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0NIQU5HRSwgdGhpcy5vbkdlc3R1cmVDaGFuZ2UsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfRU5ELCB0aGlzLm9uR2VzdHVyZUVuZCwgZmFsc2UpO1xuICAgIChfZyA9IHRoaXMuZGV0YWNoSXNNb2JpbGVNcUhhbmRsZXIpID09PSBudWxsIHx8IF9nID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZy5jYWxsKHRoaXMpO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gIH1cblxuICBhZGRFdmVudExpc3RlbmVycygpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lO1xuXG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0aGlzLnJlbW92ZVBvaW50ZXIpOyAvLyAjMzU1M1xuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5DT1BZLCB0aGlzLm9uQ29weSk7XG4gICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLm9uV2hlZWwsIHtcbiAgICAgIHBhc3NpdmU6IGZhbHNlXG4gICAgfSk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5oYW5kbGVLZXlib2FyZEdsb2JhbGx5KSB7XG4gICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHRoaXMub25LZXlEb3duLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwLCB7XG4gICAgICBwYXNzaXZlOiB0cnVlXG4gICAgfSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5NT1VTRV9NT1ZFLCB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbik7IC8vIHJlcmVuZGVyIHRleHQgZWxlbWVudHMgb24gZm9udCBsb2FkIHRvIGZpeCAjNjM3ICYmICMxNTUzXG5cbiAgICAoX2MgPSAoX2IgPSBkb2N1bWVudC5mb250cykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmFkZEV2ZW50TGlzdGVuZXIpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5jYWxsKF9iLCBcImxvYWRpbmdkb25lXCIsIHRoaXMub25Gb250c0xvYWRpbmdEb25lKTsgLy8gU2FmYXJpLW9ubHkgZGVza3RvcCBwaW5jaCB6b29tXG5cbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfU1RBUlQsIHRoaXMub25HZXN0dXJlU3RhcnQsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfQ0hBTkdFLCB0aGlzLm9uR2VzdHVyZUNoYW5nZSwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9FTkQsIHRoaXMub25HZXN0dXJlRW5kLCBmYWxzZSk7XG5cbiAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5DVVQsIHRoaXMub25DdXQpO1xuXG4gICAgaWYgKHRoaXMucHJvcHMuZGV0ZWN0U2Nyb2xsKSB7XG4gICAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyID0gZ2V0TmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgdGhpcy5uZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lci5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlNDUk9MTCwgdGhpcy5vblNjcm9sbCk7XG4gICAgfVxuXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUkVTSVpFLCB0aGlzLm9uUmVzaXplLCBmYWxzZSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuVU5MT0FELCB0aGlzLm9uVW5sb2FkLCBmYWxzZSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGhpcy5vbkJsdXIsIGZhbHNlKTtcbiAgICAoX2QgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuRFJBR19PVkVSLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICAgIChfZSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2UuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5EUk9QLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICB9XG5cbiAgY29tcG9uZW50RGlkVXBkYXRlKHByZXZQcm9wcywgcHJldlN0YXRlKSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2Y7XG5cbiAgICB0aGlzLnVwZGF0ZUVtYmVkZGFibGVzKCk7XG5cbiAgICBpZiAoIXRoaXMuc3RhdGUuc2hvd1dlbGNvbWVTY3JlZW4gJiYgIXRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubGVuZ3RoKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2hvd1dlbGNvbWVTY3JlZW46IHRydWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCAmJiBwcmV2UHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50ICE9PSB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCkge1xuICAgICAgdGhpcy5yZWZyZXNoRGV2aWNlU3RhdGUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgIH1cblxuICAgIGlmIChwcmV2U3RhdGUuc2Nyb2xsWCAhPT0gdGhpcy5zdGF0ZS5zY3JvbGxYIHx8IHByZXZTdGF0ZS5zY3JvbGxZICE9PSB0aGlzLnN0YXRlLnNjcm9sbFkpIHtcbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vblNjcm9sbENoYW5nZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHRoaXMuc3RhdGUuc2Nyb2xsWCwgdGhpcy5zdGF0ZS5zY3JvbGxZKTtcbiAgICB9XG5cbiAgICBpZiAoT2JqZWN0LmtleXModGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLmxlbmd0aCAmJiBpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgfSlcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJlcmFzZXJcIiAmJiBwcmV2U3RhdGUudGhlbWUgIT09IHRoaXMuc3RhdGUudGhlbWUpIHtcbiAgICAgIHNldEVyYXNlckN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlLnRoZW1lKTtcbiAgICB9IC8vIEhpZGUgaHlwZXJsaW5rIHBvcHVwIGlmIHNob3duIHdoZW4gZWxlbWVudCB0eXBlIGlzIG5vdCBzZWxlY3Rpb25cblxuXG4gICAgaWYgKHByZXZTdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXApIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGZhbHNlXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLmxhbmdDb2RlICE9PSB0aGlzLnByb3BzLmxhbmdDb2RlKSB7XG4gICAgICB0aGlzLnVwZGF0ZUxhbmd1YWdlKCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy52aWV3TW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMudmlld01vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgdmlld01vZGVFbmFibGVkOiAhIXRoaXMucHJvcHMudmlld01vZGVFbmFibGVkXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlN0YXRlLnZpZXdNb2RlRW5hYmxlZCAhPT0gdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICAgIHRoaXMuZGVzZWxlY3RFbGVtZW50cygpO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMuemVuTW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB6ZW5Nb2RlRW5hYmxlZDogISF0aGlzLnByb3BzLnplbk1vZGVFbmFibGVkXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLnRoZW1lICE9PSB0aGlzLnByb3BzLnRoZW1lICYmIHRoaXMucHJvcHMudGhlbWUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy5ncmlkTW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZ3JpZFNpemU6IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkID8gR1JJRF9TSVpFIDogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnByb3BzLlVJT3B0aW9ucy5jYW52YXNBY3Rpb25zICYmIHRoaXMuc3RhdGUub3Blbk1lbnUgPT09IFwiY2FudmFzXCIpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBvcGVuTWVudTogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucHJvcHMubmFtZSAmJiBwcmV2UHJvcHMubmFtZSAhPT0gdGhpcy5wcm9wcy5uYW1lKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgbmFtZTogdGhpcy5wcm9wcy5uYW1lXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAoX2MgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmNsYXNzTGlzdC50b2dnbGUoXCJ0aGVtZS0tZGFya1wiLCB0aGlzLnN0YXRlLnRoZW1lID09PSBcImRhcmtcIik7XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWRdKSB7XG4gICAgICAvLyBkZWZlciBzbyB0aGF0IHRoZSBjb21taXRUb0hpc3RvcnkgZmxhZyBpc24ndCByZXNldCB2aWEgY3VycmVudCB1cGRhdGVcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAvLyBleGVjdXRlIG9ubHkgaWYgdGhlIGNvbmRpdGlvbiBzdGlsbCBob2xkcyB3aGVuIHRoZSBkZWZlcnJlZCBjYWxsYmFja1xuICAgICAgICAvLyBleGVjdXRlcyAoaXQgY2FuIGJlIHNjaGVkdWxlZCBtdWx0aXBsZSB0aW1lcyBkZXBlbmRpbmcgb24gaG93XG4gICAgICAgIC8vIG1hbnkgdGltZXMgdGhlIGNvbXBvbmVudCByZW5kZXJzKVxuICAgICAgICB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgIH0pO1xuICAgIH0gLy8gZmFpbHNhZmUgaW4gY2FzZSB0aGUgc3RhdGUgaXMgYmVpbmcgdXBkYXRlZCBpbiBpbmNvcnJlY3Qgb3JkZXIgcmVzdWx0aW5nXG4gICAgLy8gaW4gdGhlIGVkaXRpbmdFbGVtZW50IGJlaW5nIG5vdyBhIGRlbGV0ZWQgZWxlbWVudFxuXG5cbiAgICBpZiAoKF9kID0gdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmlzRGVsZXRlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmVsZW1lbnRJZF0pIHtcbiAgICAgIC8vIFRvIG1ha2Ugc3VyZSBgc2VsZWN0ZWRMaW5lYXJFbGVtZW50YCBpcyBpbiBzeW5jIHdpdGggYHNlbGVjdGVkRWxlbWVudElkc2AsIGhvd2V2ZXIgdGhpcyBzaG91bGRuJ3QgYmUgbmVlZGVkIG9uY2VcbiAgICAgIC8vIHdlIGhhdmUgYSBzaW5nbGUgQVBJIHRvIHVwZGF0ZSBgc2VsZWN0ZWRFbGVtZW50SWRzYFxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3Qge1xuICAgICAgbXVsdGlFbGVtZW50XG4gICAgfSA9IHByZXZTdGF0ZTtcblxuICAgIGlmIChwcmV2U3RhdGUuYWN0aXZlVG9vbCAhPT0gdGhpcy5zdGF0ZS5hY3RpdmVUb29sICYmIG11bHRpRWxlbWVudCAhPSBudWxsICYmIGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgJiYgaXNCaW5kaW5nRWxlbWVudChtdWx0aUVsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgbWF5YmVCaW5kTGluZWFyRWxlbWVudChtdWx0aUVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUsIHR1cGxlVG9Db29ycyhMaW5lYXJFbGVtZW50RWRpdG9yLmdldFBvaW50QXRJbmRleEdsb2JhbENvb3JkaW5hdGVzKG11bHRpRWxlbWVudCwgLTEpKSk7XG4gICAgfVxuXG4gICAgdGhpcy5oaXN0b3J5LnJlY29yZCh0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpKTsgLy8gRG8gbm90IG5vdGlmeSBjb25zdW1lcnMgaWYgd2UncmUgc3RpbGwgbG9hZGluZyB0aGUgc2NlbmUuIEFtb25nIG90aGVyXG4gICAgLy8gcG90ZW50aWFsIGlzc3VlcywgdGhpcyBmaXhlcyBhIGNhc2Ugd2hlcmUgdGhlIHRhYiBpc24ndCBmb2N1c2VkIGR1cmluZ1xuICAgIC8vIGluaXQsIHdoaWNoIHdvdWxkIHRyaWdnZXIgb25DaGFuZ2Ugd2l0aCBlbXB0eSBlbGVtZW50cywgd2hpY2ggd291bGQgdGhlblxuICAgIC8vIG92ZXJyaWRlIHdoYXRldmVyIGlzIGluIGxvY2FsU3RvcmFnZSBjdXJyZW50bHkuXG5cbiAgICBpZiAoIXRoaXMuc3RhdGUuaXNMb2FkaW5nKSB7XG4gICAgICAoX2YgPSAoX2UgPSB0aGlzLnByb3BzKS5vbkNoYW5nZSkgPT09IG51bGwgfHwgX2YgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9mLmNhbGwoX2UsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMuc3RhdGUsIHRoaXMuZmlsZXMsIHRoaXMucHJvcHMuaWQpO1xuICAgICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIudHJpZ2dlcih0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzLnN0YXRlLCB0aGlzLmZpbGVzKTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgcmVzZXRUYXBUd2ljZSgpIHtcbiAgICBkaWRUYXBUd2ljZSA9IGZhbHNlO1xuICB9XG5cbiAgYWRkVGV4dEZyb21QYXN0ZSh0ZXh0LCBpc1BsYWluUGFzdGUgPSBmYWxzZSkge1xuICAgIGNvbnN0IHtcbiAgICAgIHgsXG4gICAgICB5XG4gICAgfSA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICBjbGllbnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICBjbGllbnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnlcbiAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICBjb25zdCB0ZXh0RWxlbWVudFByb3BzID0ge1xuICAgICAgeCxcbiAgICAgIHksXG4gICAgICBzdHJva2VDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZUNvbG9yLFxuICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgc3Ryb2tlV2lkdGg6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VXaWR0aCxcbiAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICByb3VuZG5lc3M6IG51bGwsXG4gICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgIHRleHQsXG4gICAgICBmb250U2l6ZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRTaXplLFxuICAgICAgZm9udEZhbWlseTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRGYW1pbHksXG4gICAgICB0ZXh0QWxpZ246IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1UZXh0QWxpZ24sXG4gICAgICB2ZXJ0aWNhbEFsaWduOiBERUZBVUxUX1ZFUlRJQ0FMX0FMSUdOLFxuICAgICAgbG9ja2VkOiBmYWxzZVxuICAgIH07XG4gICAgY29uc3QgTElORV9HQVAgPSAxMDtcbiAgICBsZXQgY3VycmVudFkgPSB5O1xuICAgIGNvbnN0IGxpbmVzID0gaXNQbGFpblBhc3RlID8gW3RleHRdIDogdGV4dC5zcGxpdChcIlxcblwiKTtcbiAgICBjb25zdCB0ZXh0RWxlbWVudHMgPSBsaW5lcy5yZWR1Y2UoKGFjYywgbGluZSwgaWR4KSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IHRleHQgPSBsaW5lLnRyaW0oKTtcbiAgICAgIGNvbnN0IGxpbmVIZWlnaHQgPSBnZXREZWZhdWx0TGluZUhlaWdodCh0ZXh0RWxlbWVudFByb3BzLmZvbnRGYW1pbHkpO1xuXG4gICAgICBpZiAodGV4dC5sZW5ndGgpIHtcbiAgICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeTogY3VycmVudFlcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdUZXh0RWxlbWVudChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRleHRFbGVtZW50UHJvcHMpLCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5OiBjdXJyZW50WSxcbiAgICAgICAgICB0ZXh0LFxuICAgICAgICAgIGxpbmVIZWlnaHQsXG4gICAgICAgICAgZnJhbWVJZDogdG9wTGF5ZXJGcmFtZSA/IHRvcExheWVyRnJhbWUuaWQgOiBudWxsXG4gICAgICAgIH0pKTtcbiAgICAgICAgYWNjLnB1c2goZWxlbWVudCk7XG4gICAgICAgIGN1cnJlbnRZICs9IGVsZW1lbnQuaGVpZ2h0ICsgTElORV9HQVA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBwcmV2TGluZSA9IChfYSA9IGxpbmVzW2lkeCAtIDFdKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudHJpbSgpOyAvLyBhZGQgcGFyYWdyYXBoIG9ubHkgaWYgcHJldmlvdXMgbGluZSB3YXMgbm90IGVtcHR5LCBJT1cgZG9uJ3QgYWRkXG4gICAgICAgIC8vIG1vcmUgdGhhbiBvbmUgZW1wdHkgbGluZVxuXG4gICAgICAgIGlmIChwcmV2TGluZSkge1xuICAgICAgICAgIGN1cnJlbnRZICs9IGdldExpbmVIZWlnaHRJblB4KHRleHRFbGVtZW50UHJvcHMuZm9udFNpemUsIGxpbmVIZWlnaHQpICsgTElORV9HQVA7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCBbXSk7XG5cbiAgICBpZiAodGV4dEVsZW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGZyYW1lSWQgPSB0ZXh0RWxlbWVudHNbMF0uZnJhbWVJZDtcblxuICAgIGlmIChmcmFtZUlkKSB7XG4gICAgICB0aGlzLnNjZW5lLmluc2VydEVsZW1lbnRzQXRJbmRleCh0ZXh0RWxlbWVudHMsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudEluZGV4KGZyYW1lSWQpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoWy4uLnRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIC4uLnRleHRFbGVtZW50c10pO1xuICAgIH1cblxuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuZnJvbUVudHJpZXModGV4dEVsZW1lbnRzLm1hcChlbCA9PiBbZWwuaWQsIHRydWVdKSksIHRoaXMuc3RhdGUpXG4gICAgfSk7XG5cbiAgICBpZiAoIWlzUGxhaW5QYXN0ZSAmJiB0ZXh0RWxlbWVudHMubGVuZ3RoID4gMSAmJiBQTEFJTl9QQVNURV9UT0FTVF9TSE9XTiA9PT0gZmFsc2UgJiYgIXRoaXMuZGV2aWNlLmlzTW9iaWxlKSB7XG4gICAgICB0aGlzLnNldFRvYXN0KHtcbiAgICAgICAgbWVzc2FnZTogdChcInRvYXN0LnBhc3RlQXNTaW5nbGVFbGVtZW50XCIsIHtcbiAgICAgICAgICBzaG9ydGN1dDogZ2V0U2hvcnRjdXRLZXkoXCJDdHJsT3JDbWQrU2hpZnQrVlwiKVxuICAgICAgICB9KSxcbiAgICAgICAgZHVyYXRpb246IDUwMDBcbiAgICAgIH0pO1xuICAgICAgUExBSU5fUEFTVEVfVE9BU1RfU0hPV04gPSB0cnVlO1xuICAgIH1cblxuICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgfVxuXG4gIGhhbmRsZVRleHRXeXNpd3lnKGVsZW1lbnQsIHtcbiAgICBpc0V4aXN0aW5nRWxlbWVudCA9IGZhbHNlXG4gIH0pIHtcbiAgICBjb25zdCB1cGRhdGVFbGVtZW50ID0gKHRleHQsIG9yaWdpbmFsVGV4dCwgaXNEZWxldGVkKSA9PiB7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoX2VsZW1lbnQgPT4ge1xuICAgICAgICBpZiAoX2VsZW1lbnQuaWQgPT09IGVsZW1lbnQuaWQgJiYgaXNUZXh0RWxlbWVudChfZWxlbWVudCkpIHtcbiAgICAgICAgICByZXR1cm4gdXBkYXRlVGV4dEVsZW1lbnQoX2VsZW1lbnQsIHtcbiAgICAgICAgICAgIHRleHQsXG4gICAgICAgICAgICBpc0RlbGV0ZWQsXG4gICAgICAgICAgICBvcmlnaW5hbFRleHRcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBfZWxlbWVudDtcbiAgICAgIH0pXSk7XG4gICAgfTtcblxuICAgIHRleHRXeXNpd3lnKHtcbiAgICAgIGlkOiBlbGVtZW50LmlkLFxuICAgICAgY2FudmFzOiB0aGlzLmNhbnZhcyxcbiAgICAgIGdldFZpZXdwb3J0Q29vcmRzOiAoeCwgeSkgPT4ge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogdmlld3BvcnRYLFxuICAgICAgICAgIHk6IHZpZXdwb3J0WVxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IHgsXG4gICAgICAgICAgc2NlbmVZOiB5XG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICByZXR1cm4gW3ZpZXdwb3J0WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgdmlld3BvcnRZIC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3BdO1xuICAgICAgfSxcbiAgICAgIG9uQ2hhbmdlOiB3aXRoQmF0Y2hlZFVwZGF0ZXModGV4dCA9PiB7XG4gICAgICAgIHVwZGF0ZUVsZW1lbnQodGV4dCwgdGV4dCwgZmFsc2UpO1xuXG4gICAgICAgIGlmIChpc05vbkRlbGV0ZWRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgdXBkYXRlQm91bmRFbGVtZW50cyhlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSksXG4gICAgICBvblN1Ym1pdDogd2l0aEJhdGNoZWRVcGRhdGVzKCh7XG4gICAgICAgIHRleHQsXG4gICAgICAgIHZpYUtleWJvYXJkLFxuICAgICAgICBvcmlnaW5hbFRleHRcbiAgICAgIH0pID0+IHtcbiAgICAgICAgY29uc3QgaXNEZWxldGVkID0gIXRleHQudHJpbSgpO1xuICAgICAgICB1cGRhdGVFbGVtZW50KHRleHQsIG9yaWdpbmFsVGV4dCwgaXNEZWxldGVkKTsgLy8gc2VsZWN0IHRoZSBjcmVhdGVkIHRleHQgZWxlbWVudCBvbmx5IGlmIHN1Ym1pdHRpbmcgdmlhIGtleWJvYXJkXG4gICAgICAgIC8vICh3aGVuIHN1Ym1pdHRpbmcgdmlhIGNsaWNrIGl0IHNob3VsZCBhY3QgYXMgc2lnbmFsIHRvIGRlc2VsZWN0KVxuXG4gICAgICAgIGlmICghaXNEZWxldGVkICYmIHZpYUtleWJvYXJkKSB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudElkVG9TZWxlY3QgPSBlbGVtZW50LmNvbnRhaW5lcklkID8gZWxlbWVudC5jb250YWluZXJJZCA6IGVsZW1lbnQuaWQ7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICBbZWxlbWVudElkVG9TZWxlY3RdOiB0cnVlXG4gICAgICAgICAgICB9KSwgcHJldlN0YXRlKVxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpc0RlbGV0ZWQpIHtcbiAgICAgICAgICBmaXhCaW5kaW5nc0FmdGVyRGVsZXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgW2VsZW1lbnRdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaXNEZWxldGVkIHx8IGlzRXhpc3RpbmdFbGVtZW50KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmZvY3VzQ29udGFpbmVyKCk7XG4gICAgICB9KSxcbiAgICAgIGVsZW1lbnQsXG4gICAgICBleGNhbGlkcmF3Q29udGFpbmVyOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCxcbiAgICAgIGFwcDogdGhpc1xuICAgIH0pOyAvLyBkZXNlbGVjdCBhbGwgb3RoZXIgZWxlbWVudHMgd2hlbiBpbnNlcnRpbmcgdGV4dFxuXG4gICAgdGhpcy5kZXNlbGVjdEVsZW1lbnRzKCk7IC8vIGRvIGFuIGluaXRpYWwgdXBkYXRlIHRvIHJlLWluaXRpYWxpemUgZWxlbWVudCBwb3NpdGlvbiBzaW5jZSB3ZSB3ZXJlXG4gICAgLy8gbW9kaWZ5aW5nIGVsZW1lbnQncyB4L3kgZm9yIHNha2Ugb2YgZWRpdG9yIChjYXNlOiBzeW5jaW5nIHRvIHJlbW90ZSlcblxuICAgIHVwZGF0ZUVsZW1lbnQoZWxlbWVudC50ZXh0LCBlbGVtZW50Lm9yaWdpbmFsVGV4dCwgZmFsc2UpO1xuICB9XG5cbiAgZGVzZWxlY3RFbGVtZW50cygpIHtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICB9KTtcbiAgfVxuXG4gIGdldFRleHRFbGVtZW50QXRQb3NpdGlvbih4LCB5KSB7XG4gICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oeCwgeSwge1xuICAgICAgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQ6IHRydWVcbiAgICB9KTtcblxuICAgIGlmIChlbGVtZW50ICYmIGlzVGV4dEVsZW1lbnQoZWxlbWVudCkgJiYgIWVsZW1lbnQuaXNEZWxldGVkKSB7XG4gICAgICByZXR1cm4gZWxlbWVudDtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGdldEVsZW1lbnRBdFBvc2l0aW9uKHgsIHksIG9wdHMpIHtcbiAgICBjb25zdCBhbGxIaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHgsIHksIG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5pbmNsdWRlQm91bmRUZXh0RWxlbWVudCwgb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmluY2x1ZGVMb2NrZWRFbGVtZW50cyk7XG5cbiAgICBpZiAoYWxsSGl0RWxlbWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgaWYgKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5wcmVmZXJTZWxlY3RlZCkge1xuICAgICAgICBmb3IgKGxldCBpbmRleCA9IGFsbEhpdEVsZW1lbnRzLmxlbmd0aCAtIDE7IGluZGV4ID4gLTE7IGluZGV4LS0pIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbYWxsSGl0RWxlbWVudHNbaW5kZXhdLmlkXSkge1xuICAgICAgICAgICAgcmV0dXJuIGFsbEhpdEVsZW1lbnRzW2luZGV4XTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudFdpdGhIaWdoZXN0WkluZGV4ID0gYWxsSGl0RWxlbWVudHNbYWxsSGl0RWxlbWVudHMubGVuZ3RoIC0gMV07IC8vIElmIHdlJ3JlIGhpdHRpbmcgZWxlbWVudCB3aXRoIGhpZ2hlc3Qgei1pbmRleCBvbmx5IG9uIGl0cyBib3VuZGluZyBib3hcbiAgICAgIC8vIHdoaWxlIGFsc28gaGl0dGluZyBvdGhlciBlbGVtZW50IGZpZ3VyZSwgdGhlIGxhdHRlciBzaG91bGQgYmUgY29uc2lkZXJlZC5cblxuICAgICAgcmV0dXJuIGlzSGl0dGluZ0VsZW1lbnRCb3VuZGluZ0JveFdpdGhvdXRIaXR0aW5nRWxlbWVudChlbGVtZW50V2l0aEhpZ2hlc3RaSW5kZXgsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHgsIHkpID8gYWxsSGl0RWxlbWVudHNbYWxsSGl0RWxlbWVudHMubGVuZ3RoIC0gMl0gOiBlbGVtZW50V2l0aEhpZ2hlc3RaSW5kZXg7XG4gICAgfVxuXG4gICAgaWYgKGFsbEhpdEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcmV0dXJuIGFsbEhpdEVsZW1lbnRzWzBdO1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHgsIHksIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50ID0gZmFsc2UsIGluY2x1ZGVMb2NrZWRFbGVtZW50cyA9IGZhbHNlKSB7XG4gICAgY29uc3QgZWxlbWVudHMgPSBpbmNsdWRlQm91bmRUZXh0RWxlbWVudCAmJiBpbmNsdWRlTG9ja2VkRWxlbWVudHMgPyB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpIDogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiAoaW5jbHVkZUxvY2tlZEVsZW1lbnRzIHx8ICFlbGVtZW50LmxvY2tlZCkgJiYgKGluY2x1ZGVCb3VuZFRleHRFbGVtZW50IHx8ICEoaXNUZXh0RWxlbWVudChlbGVtZW50KSAmJiBlbGVtZW50LmNvbnRhaW5lcklkKSkpO1xuICAgIHJldHVybiBnZXRFbGVtZW50c0F0UG9zaXRpb24oZWxlbWVudHMsIGVsZW1lbnQgPT4gaGl0VGVzdChlbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCB4LCB5KSkuZmlsdGVyKGVsZW1lbnQgPT4ge1xuICAgICAgLy8gaGl0dGluZyBhIGZyYW1lJ3MgZWxlbWVudCBmcm9tIG91dHNpZGUgdGhlIGZyYW1lIGlzIG5vdCBjb25zaWRlcmVkIGEgaGl0XG4gICAgICBjb25zdCBjb250YWluaW5nRnJhbWUgPSBnZXRDb250YWluaW5nRnJhbWUoZWxlbWVudCk7XG4gICAgICByZXR1cm4gY29udGFpbmluZ0ZyYW1lICYmIHRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCAmJiB0aGlzLnN0YXRlLmZyYW1lUmVuZGVyaW5nLmNsaXAgPyBpc0N1cnNvckluRnJhbWUoe1xuICAgICAgICB4LFxuICAgICAgICB5XG4gICAgICB9LCBjb250YWluaW5nRnJhbWUpIDogdHJ1ZTtcbiAgICB9KTtcbiAgfVxuXG4gIGhhbmRsZUhvdmVyU2VsZWN0ZWRMaW5lYXJFbGVtZW50KGxpbmVhckVsZW1lbnRFZGl0b3IsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpIHtcbiAgICBjb25zdCBlbGVtZW50ID0gTGluZWFyRWxlbWVudEVkaXRvci5nZXRFbGVtZW50KGxpbmVhckVsZW1lbnRFZGl0b3IuZWxlbWVudElkKTtcbiAgICBjb25zdCBib3VuZFRleHRFbGVtZW50ID0gZ2V0Qm91bmRUZXh0RWxlbWVudChlbGVtZW50KTtcblxuICAgIGlmICghZWxlbWVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgbGV0IGhvdmVyUG9pbnRJbmRleCA9IC0xO1xuICAgICAgbGV0IHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMgPSBudWxsO1xuXG4gICAgICBpZiAoaXNIaXR0aW5nRWxlbWVudE5vdENvbnNpZGVyaW5nQm91bmRpbmdCb3goZWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgW3NjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclldKSkge1xuICAgICAgICBob3ZlclBvaW50SW5kZXggPSBMaW5lYXJFbGVtZW50RWRpdG9yLmdldFBvaW50SW5kZXhVbmRlckN1cnNvcihlbGVtZW50LCB0aGlzLnN0YXRlLnpvb20sIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpO1xuICAgICAgICBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzID0gTGluZWFyRWxlbWVudEVkaXRvci5nZXRTZWdtZW50TWlkcG9pbnRIaXRDb29yZHMobGluZWFyRWxlbWVudEVkaXRvciwge1xuICAgICAgICAgIHg6IHNjZW5lUG9pbnRlclgsXG4gICAgICAgICAgeTogc2NlbmVQb2ludGVyWVxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoaG92ZXJQb2ludEluZGV4ID49IDAgfHwgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3Jkcykge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc2hvdWxkU2hvd0JvdW5kaW5nQm94KFtlbGVtZW50XSwgdGhpcy5zdGF0ZSkgJiYgaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50KGVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5NT1ZFKTtcbiAgICAgIH0gZWxzZSBpZiAoYm91bmRUZXh0RWxlbWVudCAmJiBoaXRUZXN0KGJvdW5kVGV4dEVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5NT1ZFKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmhvdmVyUG9pbnRJbmRleCAhPT0gaG92ZXJQb2ludEluZGV4KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgIGhvdmVyUG9pbnRJbmRleFxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoIUxpbmVhckVsZW1lbnRFZGl0b3IuYXJlUG9pbnRzRXF1YWwodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3Jkcywgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3JkcykpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3Jkc1xuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQVVUTyk7XG4gICAgfVxuICB9XG5cbiAgbWF5YmVDbGVhbnVwQWZ0ZXJNaXNzaW5nUG9pbnRlclVwKGV2ZW50KSB7XG4gICAgaWYgKGxhc3RQb2ludGVyVXAgIT09IG51bGwpIHtcbiAgICAgIC8vIFVuZm9ydHVuYXRlbHksIHNvbWV0aW1lcyB3ZSBkb24ndCBnZXQgYSBwb2ludGVydXAgYWZ0ZXIgYSBwb2ludGVyZG93bixcbiAgICAgIC8vIHRoaXMgY2FuIGhhcHBlbiB3aGVuIGEgY29udGV4dHVhbCBtZW51IG9yIGFsZXJ0IGlzIHRyaWdnZXJlZC4gSW4gb3JkZXIgdG8gYXZvaWRcbiAgICAgIC8vIGJlaW5nIGluIGEgd2VpcmQgc3RhdGUsIHdlIGNsZWFuIHVwIG9uIHRoZSBuZXh0IHBvaW50ZXJkb3duXG4gICAgICBsYXN0UG9pbnRlclVwKGV2ZW50KTtcbiAgICB9XG4gIH1cblxuICB1cGRhdGVHZXN0dXJlT25Qb2ludGVyRG93bihldmVudCkge1xuICAgIGdlc3R1cmUucG9pbnRlcnMuc2V0KGV2ZW50LnBvaW50ZXJJZCwge1xuICAgICAgeDogZXZlbnQuY2xpZW50WCxcbiAgICAgIHk6IGV2ZW50LmNsaWVudFlcbiAgICB9KTtcblxuICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLnNpemUgPT09IDIpIHtcbiAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGdldENlbnRlcihnZXN0dXJlLnBvaW50ZXJzKTtcbiAgICAgIGdlc3R1cmUuaW5pdGlhbFNjYWxlID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgZ2VzdHVyZS5pbml0aWFsRGlzdGFuY2UgPSBnZXREaXN0YW5jZShBcnJheS5mcm9tKGdlc3R1cmUucG9pbnRlcnMudmFsdWVzKCkpKTtcbiAgICB9XG4gIH1cblxuICBpbml0aWFsUG9pbnRlckRvd25TdGF0ZShldmVudCkge1xuICAgIGNvbnN0IG9yaWdpbiA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICBjb25zdCBbbWluWCwgbWluWSwgbWF4WCwgbWF4WV0gPSBnZXRDb21tb25Cb3VuZHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgcmV0dXJuIHtcbiAgICAgIG9yaWdpbixcbiAgICAgIHdpdGhDbWRPckN0cmw6IGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdLFxuICAgICAgb3JpZ2luSW5HcmlkOiB0dXBsZVRvQ29vcnMoZ2V0R3JpZFBvaW50KG9yaWdpbi54LCBvcmlnaW4ueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSkpLFxuICAgICAgc2Nyb2xsYmFyczogaXNPdmVyU2Nyb2xsQmFycyhjdXJyZW50U2Nyb2xsQmFycywgZXZlbnQuY2xpZW50WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgZXZlbnQuY2xpZW50WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wKSxcbiAgICAgIC8vIHdlIG5lZWQgdG8gZHVwbGljYXRlIGJlY2F1c2Ugd2UnbGwgYmUgdXBkYXRpbmcgdGhpcyBzdGF0ZVxuICAgICAgbGFzdENvb3JkczogT2JqZWN0LmFzc2lnbih7fSwgb3JpZ2luKSxcbiAgICAgIG9yaWdpbmFsRWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkucmVkdWNlKChhY2MsIGVsZW1lbnQpID0+IHtcbiAgICAgICAgYWNjLnNldChlbGVtZW50LmlkLCBkZWVwQ29weUVsZW1lbnQoZWxlbWVudCkpO1xuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwgbmV3IE1hcCgpKSxcbiAgICAgIHJlc2l6ZToge1xuICAgICAgICBoYW5kbGVUeXBlOiBmYWxzZSxcbiAgICAgICAgaXNSZXNpemluZzogZmFsc2UsXG4gICAgICAgIG9mZnNldDoge1xuICAgICAgICAgIHg6IDAsXG4gICAgICAgICAgeTogMFxuICAgICAgICB9LFxuICAgICAgICBhcnJvd0RpcmVjdGlvbjogXCJvcmlnaW5cIixcbiAgICAgICAgY2VudGVyOiB7XG4gICAgICAgICAgeDogKG1heFggKyBtaW5YKSAvIDIsXG4gICAgICAgICAgeTogKG1heFkgKyBtaW5ZKSAvIDJcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGhpdDoge1xuICAgICAgICBlbGVtZW50OiBudWxsLFxuICAgICAgICBhbGxIaXRFbGVtZW50czogW10sXG4gICAgICAgIHdhc0FkZGVkVG9TZWxlY3Rpb246IGZhbHNlLFxuICAgICAgICBoYXNCZWVuRHVwbGljYXRlZDogZmFsc2UsXG4gICAgICAgIGhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzOiB0aGlzLmlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKG9yaWdpbiwgc2VsZWN0ZWRFbGVtZW50cylcbiAgICAgIH0sXG4gICAgICBkcmFnOiB7XG4gICAgICAgIGhhc09jY3VycmVkOiBmYWxzZSxcbiAgICAgICAgb2Zmc2V0OiBudWxsXG4gICAgICB9LFxuICAgICAgZXZlbnRMaXN0ZW5lcnM6IHtcbiAgICAgICAgb25Nb3ZlOiBudWxsLFxuICAgICAgICBvblVwOiBudWxsLFxuICAgICAgICBvbktleVVwOiBudWxsLFxuICAgICAgICBvbktleURvd246IG51bGxcbiAgICAgIH0sXG4gICAgICBib3hTZWxlY3Rpb246IHtcbiAgICAgICAgaGFzT2NjdXJyZWQ6IGZhbHNlXG4gICAgICB9LFxuICAgICAgZWxlbWVudElkc1RvRXJhc2U6IHt9XG4gICAgfTtcbiAgfSAvLyBSZXR1cm5zIHdoZXRoZXIgdGhlIGV2ZW50IGlzIGEgZHJhZ2dpbmcgYSBzY3JvbGxiYXJcblxuXG4gIGhhbmRsZURyYWdnaW5nU2Nyb2xsQmFyKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSB7XG4gICAgaWYgKCEocG9pbnRlckRvd25TdGF0ZS5zY3JvbGxiYXJzLmlzT3ZlckVpdGhlciAmJiAhdGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaXNEcmFnZ2luZ1Njcm9sbEJhciA9IHRydWU7XG4gICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBldmVudC5jbGllbnRYO1xuICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gZXZlbnQuY2xpZW50WTtcbiAgICBjb25zdCBvblBvaW50ZXJNb3ZlID0gd2l0aEJhdGNoZWRVcGRhdGVzVGhyb3R0bGVkKGV2ZW50ID0+IHtcbiAgICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldDtcblxuICAgICAgaWYgKCEodGFyZ2V0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5oYW5kbGVQb2ludGVyTW92ZU92ZXJTY3JvbGxiYXJzKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKTtcbiAgICB9KTtcbiAgICBjb25zdCBvblBvaW50ZXJVcCA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gZmFsc2U7XG4gICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgIGxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGN1cnNvckJ1dHRvbjogXCJ1cFwiXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgXCJ1cFwiKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBvblBvaW50ZXJVcCk7XG4gICAgICBvblBvaW50ZXJNb3ZlLmZsdXNoKCk7XG4gICAgfSk7XG4gICAgbGFzdFBvaW50ZXJVcCA9IG9uUG9pbnRlclVwO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgb25Qb2ludGVyVXApO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgaXNBU2VsZWN0ZWRFbGVtZW50KGhpdEVsZW1lbnQpIHtcbiAgICByZXR1cm4gaGl0RWxlbWVudCAhPSBudWxsICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdO1xuICB9XG5cbiAgaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMocG9pbnQsIHNlbGVjdGVkRWxlbWVudHMpIHtcbiAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPCAyKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSAvLyBIb3cgbWFueSBwaXhlbHMgb2ZmIHRoZSBzaGFwZSBib3VuZGFyeSB3ZSBzdGlsbCBjb25zaWRlciBhIGhpdFxuXG5cbiAgICBjb25zdCB0aHJlc2hvbGQgPSAxMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICBjb25zdCBbeDEsIHkxLCB4MiwgeTJdID0gZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgIHJldHVybiBwb2ludC54ID4geDEgLSB0aHJlc2hvbGQgJiYgcG9pbnQueCA8IHgyICsgdGhyZXNob2xkICYmIHBvaW50LnkgPiB5MSAtIHRocmVzaG9sZCAmJiBwb2ludC55IDwgeTIgKyB0aHJlc2hvbGQ7XG4gIH1cblxuICBnZXRDdXJyZW50SXRlbVJvdW5kbmVzcyhlbGVtZW50VHlwZSkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91bmRuZXNzID09PSBcInJvdW5kXCIgPyB7XG4gICAgICB0eXBlOiBpc1VzaW5nQWRhcHRpdmVSYWRpdXMoZWxlbWVudFR5cGUpID8gUk9VTkRORVNTLkFEQVBUSVZFX1JBRElVUyA6IFJPVU5ETkVTUy5QUk9QT1JUSU9OQUxfUkFESVVTXG4gICAgfSA6IG51bGw7XG4gIH1cblxuICBtYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgcmVjb21wdXRlQW55d2F5cyA9IGZhbHNlKSB7XG4gICAgaWYgKGlzU25hcHBpbmdFbmFibGVkKHtcbiAgICAgIGV2ZW50LFxuICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICBzZWxlY3RlZEVsZW1lbnRzXG4gICAgfSkgJiYgKHJlY29tcHV0ZUFueXdheXMgfHwgIVNuYXBDYWNoZS5nZXRSZWZlcmVuY2VTbmFwUG9pbnRzKCkpKSB7XG4gICAgICBTbmFwQ2FjaGUuc2V0UmVmZXJlbmNlU25hcFBvaW50cyhnZXRSZWZlcmVuY2VTbmFwUG9pbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHNlbGVjdGVkRWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcbiAgICB9XG4gIH1cblxuICBtYXliZUNhY2hlVmlzaWJsZUdhcHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMsIHJlY29tcHV0ZUFueXdheXMgPSBmYWxzZSkge1xuICAgIGlmIChpc1NuYXBwaW5nRW5hYmxlZCh7XG4gICAgICBldmVudCxcbiAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgc2VsZWN0ZWRFbGVtZW50c1xuICAgIH0pICYmIChyZWNvbXB1dGVBbnl3YXlzIHx8ICFTbmFwQ2FjaGUuZ2V0VmlzaWJsZUdhcHMoKSkpIHtcbiAgICAgIFNuYXBDYWNoZS5zZXRWaXNpYmxlR2FwcyhnZXRWaXNpYmxlR2Fwcyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBzZWxlY3RlZEVsZW1lbnRzLCB0aGlzLnN0YXRlKSk7XG4gICAgfVxuICB9XG5cbiAgb25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIFByZXZlbnRzIGZvY3VzIGZyb20gZXNjYXBpbmcgZXhjYWxpZHJhdyB0YWJcbiAgICAgIGV2ZW50LmtleSA9PT0gS0VZUy5BTFQgJiYgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKHRoaXMubWF5YmVIYW5kbGVSZXNpemUocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudChwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgfSk7XG4gIH1cblxuICBvblBvaW50ZXJNb3ZlRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZChldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBXZSBuZWVkIHRvIGluaXRpYWxpemUgZHJhZ09mZnNldFhZIG9ubHkgYWZ0ZXIgd2UndmUgdXBkYXRlZFxuICAgICAgLy8gYHN0YXRlLnNlbGVjdGVkRWxlbWVudElkc2Agb24gcG9pbnRlckRvd24uIERvaW5nIGl0IGhlcmUgaW4gcG9pbnRlck1vdmVcbiAgICAgIC8vIGV2ZW50IGhhbmRsZXIgc2hvdWxkIGhvcGVmdWxseSBlbnN1cmUgd2UncmUgYWxyZWFkeSB3b3JraW5nIHdpdGhcbiAgICAgIC8vIHRoZSB1cGRhdGVkIHN0YXRlLlxuXG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0ID09PSBudWxsKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5vZmZzZXQgPSB0dXBsZVRvQ29vcnMoZ2V0RHJhZ09mZnNldFhZKHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQ7XG5cbiAgICAgIGlmICghKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICB0aGlzLmhhbmRsZUVyYXNlcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSwgcG9pbnRlckNvb3Jkcyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpOyAvLyBmb3IgYXJyb3dzL2xpbmVzLCBkb24ndCBzdGFydCBkcmFnZ2luZyB1bnRpbCBhIGdpdmVuIHRocmVzaG9sZFxuICAgICAgLy8gdG8gZW5zdXJlIHdlIGRvbid0IGNyZWF0ZSBhIDItcG9pbnQgYXJyb3cgYnkgbWlzdGFrZSB3aGVuXG4gICAgICAvLyB1c2VyIGNsaWNrcyBtb3VzZSBpbiBhIHdheSB0aGF0IGl0IG1vdmVzIGEgdGlueSBiaXQgKHRodXNcbiAgICAgIC8vIHRyaWdnZXJpbmcgcG9pbnRlcm1vdmUpXG5cbiAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJhcnJvd1wiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxpbmVcIikpIHtcbiAgICAgICAgaWYgKGRpc3RhbmNlMmQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpIDwgRFJBR0dJTkdfVEhSRVNIT0xEKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5pc1Jlc2l6aW5nKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gcG9pbnRlckNvb3Jkcy54O1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcblxuICAgICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudEVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQ7XG5cbiAgICAgICAgaWYgKExpbmVhckVsZW1lbnRFZGl0b3Iuc2hvdWxkQWRkTWlkcG9pbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHBvaW50ZXJDb29yZHMsIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgICAgY29uc3QgcmV0ID0gTGluZWFyRWxlbWVudEVkaXRvci5hZGRNaWRwb2ludCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgcG9pbnRlckNvb3JkcywgdGhpcy5zdGF0ZSwgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKTtcblxuICAgICAgICAgIGlmICghcmV0KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG5cblxuICAgICAgICAgIGZsdXNoU3luYygoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZTogcmV0LnBvaW50ZXJEb3duU3RhdGUsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IHJldC5zZWxlY3RlZFBvaW50c0luZGljZXNcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGU6IHJldC5wb2ludGVyRG93blN0YXRlLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRQb2ludHNJbmRpY2VzOiByZXQuc2VsZWN0ZWRQb2ludHNJbmRpY2VzXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2UgaWYgKGxpbmVhckVsZW1lbnRFZGl0b3IucG9pbnRlckRvd25TdGF0ZS5zZWdtZW50TWlkcG9pbnQudmFsdWUgIT09IG51bGwgJiYgIWxpbmVhckVsZW1lbnRFZGl0b3IucG9pbnRlckRvd25TdGF0ZS5zZWdtZW50TWlkcG9pbnQuYWRkZWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBkaWREcmFnID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludERyYWdnaW5nKGV2ZW50LCB0aGlzLnN0YXRlLCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgKGVsZW1lbnQsIHBvaW50c1NjZW5lQ29vcmRzKSA9PiB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhlbGVtZW50LCBwb2ludHNTY2VuZUNvb3Jkcyk7XG4gICAgICAgIH0sIGxpbmVhckVsZW1lbnRFZGl0b3IpO1xuXG4gICAgICAgIGlmIChkaWREcmFnKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBwb2ludGVyQ29vcmRzLnk7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgIGlzRHJhZ2dpbmc6IHRydWVcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICBpc0RyYWdnaW5nOiB0cnVlXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgaGFzSGl0QVNlbGVjdGVkRWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiB0aGlzLmlzQVNlbGVjdGVkRWxlbWVudChlbGVtZW50KSk7XG4gICAgICBjb25zdCBpc1NlbGVjdGluZ1BvaW50c0luTGluZUVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZXZlbnQuc2hpZnRLZXkgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgPT09ICgoX2EgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaWQpO1xuXG4gICAgICBpZiAoKGhhc0hpdEFTZWxlY3RlZEVsZW1lbnQgfHwgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpICYmICFpc1NlbGVjdGluZ1BvaW50c0luTGluZUVkaXRvcikge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmV2ZXJ5KGVsZW1lbnQgPT4gZWxlbWVudC5sb2NrZWQpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50c0hhc0FGcmFtZSA9IHNlbGVjdGVkRWxlbWVudHMuZmluZChlID0+IGlzRnJhbWVFbGVtZW50KGUpKTtcbiAgICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMocG9pbnRlckNvb3Jkcyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGZyYW1lVG9IaWdobGlnaHQ6IHRvcExheWVyRnJhbWUgJiYgIXNlbGVjdGVkRWxlbWVudHNIYXNBRnJhbWUgPyB0b3BMYXllckZyYW1lIDogbnVsbFxuICAgICAgICB9KTsgLy8gTWFya2luZyB0aGF0IGNsaWNrIHdhcyB1c2VkIGZvciBkcmFnZ2luZyB0byBjaGVja1xuICAgICAgICAvLyBpZiBlbGVtZW50cyBzaG91bGQgYmUgZGVzZWxlY3RlZCBvbiBwb2ludGVydXBcblxuICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkOiB0cnVlXG4gICAgICAgIH0pOyAvLyBwcmV2ZW50IGRyYWdnaW5nIGV2ZW4gaWYgd2UncmUgbm8gbG9uZ2VyIGhvbGRpbmcgY21kL2N0cmwgb3RoZXJ3aXNlXG4gICAgICAgIC8vIGl0IHdvdWxkIGhhdmUgd2VpcmQgcmVzdWx0cyAoc3R1ZmYganVtcGluZyBhbGwgb3ZlciB0aGUgc2NyZWVuKVxuICAgICAgICAvLyBDaGVja2luZyBmb3IgZWRpdGluZ0VsZW1lbnQgdG8gYXZvaWQganVtcCB3aGlsZSBlZGl0aW5nIG9uIG1vYmlsZSAjNjUwM1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDAgJiYgIXBvaW50ZXJEb3duU3RhdGUud2l0aENtZE9yQ3RybCAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAmJiAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpICE9PSBcImFjdGl2ZVwiKSB7XG4gICAgICAgICAgY29uc3QgZHJhZ09mZnNldCA9IHtcbiAgICAgICAgICAgIHg6IHBvaW50ZXJDb29yZHMueCAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsXG4gICAgICAgICAgICB5OiBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55XG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zdCBvcmlnaW5hbEVsZW1lbnRzID0gWy4uLnBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50cy52YWx1ZXMoKV07IC8vIFdlIG9ubHkgZHJhZyBpbiBvbmUgZGlyZWN0aW9uIGlmIHNoaWZ0IGlzIHByZXNzZWRcblxuICAgICAgICAgIGNvbnN0IGxvY2tEaXJlY3Rpb24gPSBldmVudC5zaGlmdEtleTtcblxuICAgICAgICAgIGlmIChsb2NrRGlyZWN0aW9uKSB7XG4gICAgICAgICAgICBjb25zdCBkaXN0YW5jZVggPSBNYXRoLmFicyhkcmFnT2Zmc2V0LngpO1xuICAgICAgICAgICAgY29uc3QgZGlzdGFuY2VZID0gTWF0aC5hYnMoZHJhZ09mZnNldC55KTtcbiAgICAgICAgICAgIGNvbnN0IGxvY2tYID0gbG9ja0RpcmVjdGlvbiAmJiBkaXN0YW5jZVggPCBkaXN0YW5jZVk7XG4gICAgICAgICAgICBjb25zdCBsb2NrWSA9IGxvY2tEaXJlY3Rpb24gJiYgZGlzdGFuY2VYID4gZGlzdGFuY2VZO1xuXG4gICAgICAgICAgICBpZiAobG9ja1gpIHtcbiAgICAgICAgICAgICAgZHJhZ09mZnNldC54ID0gMDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGxvY2tZKSB7XG4gICAgICAgICAgICAgIGRyYWdPZmZzZXQueSA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBTbmFwIGNhY2hlICptdXN0KiBiZSBzeW5jaHJvbm91c2x5IHBvcHVwbGF0ZWQgYmVmb3JlIGluaXRpYWwgZHJhZyxcbiAgICAgICAgICAvLyBvdGhlcndpc2UgdGhlIGZpcnN0IGRyYWcgZXZlbiB3aWxsIG5vdCBzbmFwLCBjYXVzaW5nIGEganVtcCBiZWZvcmVcbiAgICAgICAgICAvLyBpdCBzbmFwcyB0byBpdHMgcG9zaXRpb24gaWYgcHJldmlvdXNseSBzbmFwcGVkIGFscmVhZHkuXG5cblxuICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVZpc2libGVHYXBzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgICB0aGlzLm1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgICBjb25zdCB7XG4gICAgICAgICAgICBzbmFwT2Zmc2V0LFxuICAgICAgICAgICAgc25hcExpbmVzXG4gICAgICAgICAgfSA9IHNuYXBEcmFnZ2VkRWxlbWVudHMoZ2V0U2VsZWN0ZWRFbGVtZW50cyhvcmlnaW5hbEVsZW1lbnRzLCB0aGlzLnN0YXRlKSwgZHJhZ09mZnNldCwgdGhpcy5zdGF0ZSwgZXZlbnQpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc25hcExpbmVzXG4gICAgICAgICAgfSk7IC8vIHdoZW4gd2UncmUgZWRpdGluZyB0aGUgbmFtZSBvZiBhIGZyYW1lLCB3ZSB3YW50IHRoZSB1c2VyIHRvIGJlXG4gICAgICAgICAgLy8gYWJsZSB0byBzZWxlY3QgYW5kIGludGVyYWN0IHdpdGggdGhlIHRleHQgaW5wdXRcblxuICAgICAgICAgICF0aGlzLnN0YXRlLmVkaXRpbmdGcmFtZSAmJiBkcmFnU2VsZWN0ZWRFbGVtZW50cyhwb2ludGVyRG93blN0YXRlLCBzZWxlY3RlZEVsZW1lbnRzLCBkcmFnT2Zmc2V0LCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLCBzbmFwT2Zmc2V0LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cyk7IC8vIFdlIGR1cGxpY2F0ZSB0aGUgc2VsZWN0ZWQgZWxlbWVudCBpZiBhbHQgaXMgcHJlc3NlZCBvbiBwb2ludGVyIG1vdmVcblxuICAgICAgICAgIGlmIChldmVudC5hbHRLZXkgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0JlZW5EdXBsaWNhdGVkKSB7XG4gICAgICAgICAgICAvLyBNb3ZlIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgZWxlbWVudHMgdG8gdGhlIHRvcCBvZiB0aGUgeiBpbmRleCBzdGFjaywgYW5kXG4gICAgICAgICAgICAvLyBwdXQgdGhlIGR1cGxpY2F0ZXMgd2hlcmUgdGhlIHNlbGVjdGVkIGVsZW1lbnRzIHVzZWQgdG8gYmUuXG4gICAgICAgICAgICAvLyAodGhlIG9yaWdpbiBwb2ludCB3aGVyZSB0aGUgZHJhZ2dpbmcgc3RhcnRlZClcbiAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0JlZW5EdXBsaWNhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IG5leHRFbGVtZW50cyA9IFtdO1xuICAgICAgICAgICAgY29uc3QgZWxlbWVudHNUb0FwcGVuZCA9IFtdO1xuICAgICAgICAgICAgY29uc3QgZ3JvdXBJZE1hcCA9IG5ldyBNYXAoKTtcbiAgICAgICAgICAgIGNvbnN0IG9sZElkVG9EdXBsaWNhdGVkSWQgPSBuZXcgTWFwKCk7XG4gICAgICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudDtcbiAgICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudElkcyA9IG5ldyBTZXQodGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyxcbiAgICAgICAgICAgICAgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQ6IHRydWUsXG4gICAgICAgICAgICAgIGluY2x1ZGVFbGVtZW50c0luRnJhbWVzOiB0cnVlXG4gICAgICAgICAgICB9KS5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmlkKSk7XG4gICAgICAgICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG5cbiAgICAgICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50SWRzLmhhcyhlbGVtZW50LmlkKSB8fCAvLyBjYXNlOiB0aGUgc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzIG1pZ2h0IG5vdCBoYXZlIGJlZW5cbiAgICAgICAgICAgICAgLy8gdXBkYXRlZCB5ZXQgYnkgdGhlIHRpbWUgdGhpcyBtb3VzZW1vdmUgZXZlbnQgaXMgZmlyZWRcbiAgICAgICAgICAgICAgZWxlbWVudC5pZCA9PT0gKGhpdEVsZW1lbnQgPT09IG51bGwgfHwgaGl0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogaGl0RWxlbWVudC5pZCkgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQud2FzQWRkZWRUb1NlbGVjdGlvbikge1xuICAgICAgICAgICAgICAgIGNvbnN0IGR1cGxpY2F0ZWRFbGVtZW50ID0gZHVwbGljYXRlRWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkLCBncm91cElkTWFwLCBlbGVtZW50KTtcbiAgICAgICAgICAgICAgICBjb25zdCBvcmlnRWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50cy5nZXQoZWxlbWVudC5pZCk7XG4gICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChkdXBsaWNhdGVkRWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgeDogb3JpZ0VsZW1lbnQueCxcbiAgICAgICAgICAgICAgICAgIHk6IG9yaWdFbGVtZW50LnlcbiAgICAgICAgICAgICAgICB9KTsgLy8gcHV0IGR1cGxpY2F0ZWQgZWxlbWVudCB0byBwb2ludGVyRG93blN0YXRlLm9yaWdpbmFsRWxlbWVudHNcbiAgICAgICAgICAgICAgICAvLyBzbyB0aGF0IHdlIGNhbiBzbmFwIHRvIHRoZSBkdXBsaWNhdGVkIGVsZW1lbnQgd2l0aG91dCByZWxlYXNpbmdcblxuICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50cy5zZXQoZHVwbGljYXRlZEVsZW1lbnQuaWQsIGR1cGxpY2F0ZWRFbGVtZW50KTtcbiAgICAgICAgICAgICAgICBuZXh0RWxlbWVudHMucHVzaChkdXBsaWNhdGVkRWxlbWVudCk7XG4gICAgICAgICAgICAgICAgZWxlbWVudHNUb0FwcGVuZC5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIG9sZElkVG9EdXBsaWNhdGVkSWQuc2V0KGVsZW1lbnQuaWQsIGR1cGxpY2F0ZWRFbGVtZW50LmlkKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZXh0RWxlbWVudHMucHVzaChlbGVtZW50KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBuZXh0U2NlbmVFbGVtZW50cyA9IFsuLi5uZXh0RWxlbWVudHMsIC4uLmVsZW1lbnRzVG9BcHBlbmRdO1xuICAgICAgICAgICAgYmluZFRleHRUb1NoYXBlQWZ0ZXJEdXBsaWNhdGlvbihuZXh0RWxlbWVudHMsIGVsZW1lbnRzVG9BcHBlbmQsIG9sZElkVG9EdXBsaWNhdGVkSWQpO1xuICAgICAgICAgICAgZml4QmluZGluZ3NBZnRlckR1cGxpY2F0aW9uKG5leHRTY2VuZUVsZW1lbnRzLCBlbGVtZW50c1RvQXBwZW5kLCBvbGRJZFRvRHVwbGljYXRlZElkLCBcImR1cGxpY2F0ZXNTZXJ2ZUFzT2xkXCIpO1xuICAgICAgICAgICAgYmluZEVsZW1lbnRzVG9GcmFtZXNBZnRlckR1cGxpY2F0aW9uKG5leHRTY2VuZUVsZW1lbnRzLCBlbGVtZW50c1RvQXBwZW5kLCBvbGRJZFRvRHVwbGljYXRlZElkKTtcbiAgICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKG5leHRTY2VuZUVsZW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVZpc2libGVHYXBzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzLCB0cnVlKTtcbiAgICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMsIHRydWUpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfSAvLyBJdCBpcyB2ZXJ5IGltcG9ydGFudCB0byByZWFkIHRoaXMuc3RhdGUgd2l0aGluIGVhY2ggbW92ZSBldmVudCxcbiAgICAgIC8vIG90aGVyd2lzZSB3ZSB3b3VsZCByZWFkIGEgc3RhbGUgb25lIVxuXG5cbiAgICAgIGNvbnN0IGRyYWdnaW5nRWxlbWVudCA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50O1xuXG4gICAgICBpZiAoIWRyYWdnaW5nRWxlbWVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIGNvbnN0IHBvaW50cyA9IGRyYWdnaW5nRWxlbWVudC5wb2ludHM7XG4gICAgICAgIGNvbnN0IGR4ID0gcG9pbnRlckNvb3Jkcy54IC0gZHJhZ2dpbmdFbGVtZW50Lng7XG4gICAgICAgIGNvbnN0IGR5ID0gcG9pbnRlckNvb3Jkcy55IC0gZHJhZ2dpbmdFbGVtZW50Lnk7XG4gICAgICAgIGNvbnN0IGxhc3RQb2ludCA9IHBvaW50cy5sZW5ndGggPiAwICYmIHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV07XG4gICAgICAgIGNvbnN0IGRpc2NhcmRQb2ludCA9IGxhc3RQb2ludCAmJiBsYXN0UG9pbnRbMF0gPT09IGR4ICYmIGxhc3RQb2ludFsxXSA9PT0gZHk7XG5cbiAgICAgICAgaWYgKCFkaXNjYXJkUG9pbnQpIHtcbiAgICAgICAgICBjb25zdCBwcmVzc3VyZXMgPSBkcmFnZ2luZ0VsZW1lbnQuc2ltdWxhdGVQcmVzc3VyZSA/IGRyYWdnaW5nRWxlbWVudC5wcmVzc3VyZXMgOiBbLi4uZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcywgZXZlbnQucHJlc3N1cmVdO1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtkeCwgZHldXSxcbiAgICAgICAgICAgIHByZXNzdXJlc1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGlzTGluZWFyRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCA9IHRydWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHBvaW50cyA9IGRyYWdnaW5nRWxlbWVudC5wb2ludHM7XG4gICAgICAgIGxldCBkeCA9IGdyaWRYIC0gZHJhZ2dpbmdFbGVtZW50Lng7XG4gICAgICAgIGxldCBkeSA9IGdyaWRZIC0gZHJhZ2dpbmdFbGVtZW50Lnk7XG5cbiAgICAgICAgaWYgKHNob3VsZFJvdGF0ZVdpdGhEaXNjcmV0ZUFuZ2xlKGV2ZW50KSAmJiBwb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgKHtcbiAgICAgICAgICAgIHdpZHRoOiBkeCxcbiAgICAgICAgICAgIGhlaWdodDogZHlcbiAgICAgICAgICB9ID0gZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplKGRyYWdnaW5nRWxlbWVudC54LCBkcmFnZ2luZ0VsZW1lbnQueSwgcG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnkpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwb2ludHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAocG9pbnRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMuc2xpY2UoMCwgLTEpLCBbZHgsIGR5XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICAgICAgLy8gV2hlbiBjcmVhdGluZyBhIGxpbmVhciBlbGVtZW50IGJ5IGRyYWdnaW5nXG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhkcmFnZ2luZ0VsZW1lbnQsIFtwb2ludGVyQ29vcmRzXSwgdGhpcy5zdGF0ZS5zdGFydEJvdW5kRWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gcG9pbnRlckNvb3Jkcy54O1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcbiAgICAgICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudChwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmJveFNlbGVjdGlvbi5oYXNPY2N1cnJlZCA9IHRydWU7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKTsgLy8gYm94LXNlbGVjdCBsaW5lIGVkaXRvciBwb2ludHNcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlQm94U2VsZWN0aW9uKGV2ZW50LCB0aGlzLnN0YXRlLCB0aGlzLnNldFN0YXRlLmJpbmQodGhpcykpOyAvLyByZWd1bGFyIGJveC1zZWxlY3RcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsZXQgc2hvdWxkUmV1c2VTZWxlY3Rpb24gPSB0cnVlO1xuXG4gICAgICAgICAgaWYgKCFldmVudC5zaGlmdEtleSAmJiBpc1NvbWVFbGVtZW50U2VsZWN0ZWQoZWxlbWVudHMsIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS53aXRoQ21kT3JDdHJsICYmIHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICAgICAgICAgIFtwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSksIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc2hvdWxkUmV1c2VTZWxlY3Rpb24gPSBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBlbGVtZW50c1dpdGhpblNlbGVjdGlvbiA9IGdldEVsZW1lbnRzV2l0aGluU2VsZWN0aW9uKGVsZW1lbnRzLCBkcmFnZ2luZ0VsZW1lbnQpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNob3VsZFJldXNlU2VsZWN0aW9uICYmIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCBlbGVtZW50c1dpdGhpblNlbGVjdGlvbi5yZWR1Y2UoKGFjYywgZWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICBhY2NbZWxlbWVudC5pZF0gPSB0cnVlO1xuICAgICAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICAgICAgfSwge30pKTtcblxuICAgICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgLy8gaWYgdXNpbmcgY3RybC9jbWQsIHNlbGVjdCB0aGUgaGl0RWxlbWVudCBvbmx5IGlmIHdlXG4gICAgICAgICAgICAgIC8vIGhhdmVuJ3QgYm94LXNlbGVjdGVkIGFueXRoaW5nIGVsc2VcbiAgICAgICAgICAgICAgaWYgKCFlbGVtZW50c1dpdGhpblNlbGVjdGlvbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1twb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBwcmV2U3RhdGUgPSAhc2hvdWxkUmV1c2VTZWxlY3Rpb24gPyBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsXG4gICAgICAgICAgICB9KSA6IHByZXZTdGF0ZTtcbiAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgIC8vIHNlbGVjdCBsaW5lYXIgZWxlbWVudCBvbmx5IHdoZW4gd2UgaGF2ZW4ndCBib3gtc2VsZWN0ZWQgYW55dGhpbmcgZWxzZVxuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0pID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0sIHRoaXMuc2NlbmUpIDogbnVsbCxcbiAgICAgICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBlbGVtZW50c1dpdGhpblNlbGVjdGlvbi5sZW5ndGggPT09IDEgJiYgKGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdLmxpbmsgfHwgaXNFbWJlZGRhYmxlRWxlbWVudChlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSkpID8gXCJpbmZvXCIgOiBmYWxzZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfSAvLyBSZXR1cm5zIHdoZXRoZXIgdGhlIHBvaW50ZXIgbW92ZSBoYXBwZW5lZCBvdmVyIGVpdGhlciBzY3JvbGxiYXJcblxuXG4gIGhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5zY3JvbGxiYXJzLmlzT3Zlckhvcml6b250YWwpIHtcbiAgICAgIGNvbnN0IHggPSBldmVudC5jbGllbnRYO1xuICAgICAgY29uc3QgZHggPSB4IC0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLng7XG4gICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyh7XG4gICAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCAtIGR4IC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlXG4gICAgICB9KTtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0geDtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGlmIChwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVyVmVydGljYWwpIHtcbiAgICAgIGNvbnN0IHkgPSBldmVudC5jbGllbnRZO1xuICAgICAgY29uc3QgZHkgPSB5IC0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnk7XG4gICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyh7XG4gICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSAtIGR5IC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlXG4gICAgICB9KTtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0geTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIG9uUG9pbnRlclVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlcyhjaGlsZEV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2IsIF9jLCBfZCwgX2UsIF9mO1xuXG4gICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbk1vdmUpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbk1vdmUuZmx1c2goKTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQsXG4gICAgICAgIHJlc2l6aW5nRWxlbWVudCxcbiAgICAgICAgbXVsdGlFbGVtZW50LFxuICAgICAgICBhY3RpdmVUb29sLFxuICAgICAgICBpc1Jlc2l6aW5nLFxuICAgICAgICBpc1JvdGF0aW5nXG4gICAgICB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBpc1Jlc2l6aW5nOiBmYWxzZSxcbiAgICAgICAgaXNSb3RhdGluZzogZmFsc2UsXG4gICAgICAgIHJlc2l6aW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgc2VsZWN0aW9uRWxlbWVudDogbnVsbCxcbiAgICAgICAgZnJhbWVUb0hpZ2hsaWdodDogbnVsbCxcbiAgICAgICAgZWxlbWVudHNUb0hpZ2hsaWdodDogbnVsbCxcbiAgICAgICAgY3Vyc29yQnV0dG9uOiBcInVwXCIsXG4gICAgICAgIC8vIHRleHQgZWxlbWVudHMgYXJlIHJlc2V0IG9uIGZpbmFsaXplLCBhbmQgcmVzZXR0aW5nIG9uIHBvaW50ZXJ1cFxuICAgICAgICAvLyBtYXkgY2F1c2UgaXNzdWVzIHdpdGggZG91YmxlIHRhcHNcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG11bHRpRWxlbWVudCB8fCBpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID8gdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCA6IG51bGwsXG4gICAgICAgIHNuYXBMaW5lczogW10sXG4gICAgICAgIG9yaWdpblNuYXBPZmZzZXQ6IG51bGxcbiAgICAgIH0pO1xuICAgICAgU25hcENhY2hlLnNldFJlZmVyZW5jZVNuYXBQb2ludHMobnVsbCk7XG4gICAgICBTbmFwQ2FjaGUuc2V0VmlzaWJsZUdhcHMobnVsbCk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGNoaWxkRXZlbnQuY2xpZW50WCwgY2hpbGRFdmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IGZhbHNlXG4gICAgICB9KTtcbiAgICAgIHRoaXMub25Qb2ludGVyVXBFbWl0dGVyLnRyaWdnZXIodGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlLCBjaGlsZEV2ZW50KTsgLy8gSGFuZGxlIGVuZCBvZiBkcmFnZ2luZyBhIHBvaW50IG9mIGEgbGluZWFyIGVsZW1lbnQsIG1pZ2h0IGNsb3NlIGEgbG9vcFxuICAgICAgLy8gYW5kIHNldHMgYmluZGluZyBlbGVtZW50XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5ib3hTZWxlY3Rpb24uaGFzT2NjdXJyZWQgJiYgKChfYiA9IChfYSA9IHBvaW50ZXJEb3duU3RhdGUuaGl0KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmlkKSAhPT0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQpIHtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgZWRpdGluZ0xpbmVhckVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJVcChjaGlsZEV2ZW50LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgICAgIGlmIChlZGl0aW5nTGluZWFyRWxlbWVudCAhPT0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50LFxuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICBpZiAoKChfZCA9IChfYyA9IHBvaW50ZXJEb3duU3RhdGUuaGl0KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZWxlbWVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmlkKSAhPT0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuZWxlbWVudElkKSB7XG4gICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFTGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTsgLy8gc2V0IHNlbGVjdGVkTGluZWFyRWxlbWVudCB0byBudWxsIGlmIHRoZXJlIGlzIG1vcmUgdGhhbiBvbmUgZWxlbWVudCBzZWxlY3RlZCBzaW5jZSB3ZSBkb24ndCB3YW50IHRvIHNob3cgbGluZWFyIGVsZW1lbnQgaGFuZGxlc1xuXG4gICAgICAgICAgaWYgKHNlbGVjdGVkRUxlbWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbnVsbFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnN0IGxpbmVhckVsZW1lbnRFZGl0b3IgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJVcChjaGlsZEV2ZW50LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgY29uc3Qge1xuICAgICAgICAgICAgc3RhcnRCaW5kaW5nRWxlbWVudCxcbiAgICAgICAgICAgIGVuZEJpbmRpbmdFbGVtZW50XG4gICAgICAgICAgfSA9IGxpbmVhckVsZW1lbnRFZGl0b3I7XG4gICAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudChsaW5lYXJFbGVtZW50RWRpdG9yLmVsZW1lbnRJZCk7XG5cbiAgICAgICAgICBpZiAoaXNCaW5kaW5nRWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICAgICAgYmluZE9yVW5iaW5kTGluZWFyRWxlbWVudChlbGVtZW50LCBzdGFydEJpbmRpbmdFbGVtZW50LCBlbmRCaW5kaW5nRWxlbWVudCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGxpbmVhckVsZW1lbnRFZGl0b3IgIT09IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGxpbmVhckVsZW1lbnRFZGl0b3IpLCB7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRQb2ludHNJbmRpY2VzOiBudWxsXG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBsYXN0UG9pbnRlclVwID0gbnVsbDtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbk1vdmUpO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vblVwKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlEb3duKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULktFWVVQLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5VXApO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoKGRyYWdnaW5nRWxlbWVudCA9PT0gbnVsbCB8fCBkcmFnZ2luZ0VsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGRyYWdnaW5nRWxlbWVudC50eXBlKSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoY2hpbGRFdmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IHBvaW50cyA9IGRyYWdnaW5nRWxlbWVudC5wb2ludHM7XG4gICAgICAgIGxldCBkeCA9IHBvaW50ZXJDb29yZHMueCAtIGRyYWdnaW5nRWxlbWVudC54O1xuICAgICAgICBsZXQgZHkgPSBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueTsgLy8gQWxsb3dzIGRvdHMgdG8gYXZvaWQgYmVpbmcgZmxhZ2dlZCBhcyBpbmZpbml0ZWx5IHNtYWxsXG5cbiAgICAgICAgaWYgKGR4ID09PSBwb2ludHNbMF1bMF0gJiYgZHkgPT09IHBvaW50c1swXVsxXSkge1xuICAgICAgICAgIGR5ICs9IDAuMDAwMTtcbiAgICAgICAgICBkeCArPSAwLjAwMDE7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwcmVzc3VyZXMgPSBkcmFnZ2luZ0VsZW1lbnQuc2ltdWxhdGVQcmVzc3VyZSA/IFtdIDogWy4uLmRyYWdnaW5nRWxlbWVudC5wcmVzc3VyZXMsIGNoaWxkRXZlbnQucHJlc3N1cmVdO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dLFxuICAgICAgICAgIHByZXNzdXJlcyxcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnQ6IFtkeCwgZHldXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gZHJhZ2dpbmdFbGVtZW50O1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zKGltYWdlRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgICAgW2ltYWdlRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSBpbWFnZUVsZW1lbnQuaWQpKTtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0xpbmVhckVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSkge1xuICAgICAgICBpZiAoZHJhZ2dpbmdFbGVtZW50LnBvaW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhjaGlsZEV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoIXBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiBkcmFnZ2luZ0VsZW1lbnQgJiYgIW11bHRpRWxlbWVudCkge1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucG9pbnRzLCBbcG9pbnRlckNvb3Jkcy54IC0gZHJhZ2dpbmdFbGVtZW50LngsIHBvaW50ZXJDb29yZHMueSAtIGRyYWdnaW5nRWxlbWVudC55XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIG11bHRpRWxlbWVudDogZHJhZ2dpbmdFbGVtZW50LFxuICAgICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAocG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICFtdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgICBpZiAoaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSAmJiBpc0JpbmRpbmdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICAgICAgICBtYXliZUJpbmRMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZSwgcG9pbnRlckNvb3Jkcyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgICBzdGFydEJvdW5kRWxlbWVudDogbnVsbFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKCFhY3RpdmVUb29sLmxvY2tlZCkge1xuICAgICAgICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgIFtkcmFnZ2luZ0VsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH0pLCBwcmV2U3RhdGUpLFxuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zY2VuZSlcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiICYmIGRyYWdnaW5nRWxlbWVudCAmJiBpc0ludmlzaWJseVNtYWxsRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpKSB7XG4gICAgICAgIC8vIHJlbW92ZSBpbnZpc2libGUgZWxlbWVudCB3aGljaCB3YXMgYWRkZWQgaW4gb25Qb2ludGVyRG93blxuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLnNsaWNlKDAsIC0xKSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQpIHtcbiAgICAgICAgICBjb25zdCBzY2VuZUNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhjaGlsZEV2ZW50LCB0aGlzLnN0YXRlKTsgLy8gd2hlbiBlZGl0aW5nIHRoZSBwb2ludHMgb2YgYSBsaW5lYXIgZWxlbWVudCwgd2UgY2hlY2sgaWYgdGhlXG4gICAgICAgICAgLy8gbGluZWFyIGVsZW1lbnQgc3RpbGwgaXMgaW4gdGhlIGZyYW1lIGFmdGVyd2FyZHNcbiAgICAgICAgICAvLyBpZiBub3QsIHRoZSBsaW5lYXIgZWxlbWVudCB3aWxsIGJlIHJlbW92ZWQgZnJvbSBpdHMgZnJhbWUgKGlmIGFueSlcblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICBjb25zdCBsaW5lYXJFbGVtZW50ID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCk7XG5cbiAgICAgICAgICAgIGlmIChsaW5lYXJFbGVtZW50ID09PSBudWxsIHx8IGxpbmVhckVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGxpbmVhckVsZW1lbnQuZnJhbWVJZCkge1xuICAgICAgICAgICAgICBjb25zdCBmcmFtZSA9IGdldENvbnRhaW5pbmdGcmFtZShsaW5lYXJFbGVtZW50KTtcblxuICAgICAgICAgICAgICBpZiAoZnJhbWUgJiYgbGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICAgIGlmICghZWxlbWVudE92ZXJsYXBzV2l0aEZyYW1lKGxpbmVhckVsZW1lbnQsIGZyYW1lKSkge1xuICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlIHRoZSBsaW5lYXIgZWxlbWVudCBmcm9tIGFsbCBncm91cHNcbiAgICAgICAgICAgICAgICAgIC8vIGJlZm9yZSByZW1vdmluZyBpdCBmcm9tIHRoZSBmcmFtZSBhcyB3ZWxsXG4gICAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGxpbmVhckVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZHM6IFtdXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHJlbW92ZUVsZW1lbnRzRnJvbUZyYW1lKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIFtsaW5lYXJFbGVtZW50XSwgdGhpcy5zdGF0ZSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyB1cGRhdGUgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBzZWxlY3RlZCBlbGVtZW50cyBhbmQgZnJhbWVzXG4gICAgICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3JkcyhzY2VuZUNvb3Jkcyk7XG4gICAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgbGV0IG5leHRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG5cbiAgICAgICAgICAgIGNvbnN0IHVwZGF0ZUdyb3VwSWRzQWZ0ZXJFZGl0aW5nR3JvdXAgPSBlbGVtZW50cyA9PiB7XG4gICAgICAgICAgICAgIGlmIChlbGVtZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBpbmRleCA9IGVsZW1lbnQuZ3JvdXBJZHMuaW5kZXhPZih0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkKTtcbiAgICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgICBncm91cElkczogZWxlbWVudC5ncm91cElkcy5zbGljZSgwLCBpbmRleClcbiAgICAgICAgICAgICAgICAgIH0sIGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBuZXh0RWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50Lmdyb3VwSWRzLmxlbmd0aCAmJiBnZXRFbGVtZW50c0luR3JvdXAobmV4dEVsZW1lbnRzLCBlbGVtZW50Lmdyb3VwSWRzW2VsZW1lbnQuZ3JvdXBJZHMubGVuZ3RoIC0gMV0pLmxlbmd0aCA8IDIpIHtcbiAgICAgICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZHM6IFtdXG4gICAgICAgICAgICAgICAgICAgIH0sIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICh0b3BMYXllckZyYW1lICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0b3BMYXllckZyYW1lLmlkXSkge1xuICAgICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvQWRkID0gc2VsZWN0ZWRFbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LmZyYW1lSWQgIT09IHRvcExheWVyRnJhbWUuaWQgJiYgaXNFbGVtZW50SW5GcmFtZShlbGVtZW50LCBuZXh0RWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcblxuICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHVwZGF0ZUdyb3VwSWRzQWZ0ZXJFZGl0aW5nR3JvdXAoZWxlbWVudHNUb0FkZCk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBuZXh0RWxlbWVudHMgPSBhZGRFbGVtZW50c1RvRnJhbWUobmV4dEVsZW1lbnRzLCBlbGVtZW50c1RvQWRkLCB0b3BMYXllckZyYW1lKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIXRvcExheWVyRnJhbWUpIHtcbiAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvUmVtb3ZlID0gc2VsZWN0ZWRFbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LmZyYW1lSWQgJiYgIWlzRWxlbWVudEluRnJhbWUoZWxlbWVudCwgbmV4dEVsZW1lbnRzLCB0aGlzLnN0YXRlKSk7XG4gICAgICAgICAgICAgICAgdXBkYXRlR3JvdXBJZHNBZnRlckVkaXRpbmdHcm91cChlbGVtZW50c1RvUmVtb3ZlKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBuZXh0RWxlbWVudHMgPSB1cGRhdGVGcmFtZU1lbWJlcnNoaXBPZlNlbGVjdGVkRWxlbWVudHMobmV4dEVsZW1lbnRzLCB0aGlzLnN0YXRlLCB0aGlzKTtcbiAgICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKG5leHRFbGVtZW50cyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpIHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50c0luc2lkZUZyYW1lID0gZ2V0RWxlbWVudHNJbk5ld0ZyYW1lKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGRyYWdnaW5nRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoYWRkRWxlbWVudHNUb0ZyYW1lKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGVsZW1lbnRzSW5zaWRlRnJhbWUsIGRyYWdnaW5nRWxlbWVudCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGdldE5vcm1hbGl6ZWREaW1lbnNpb25zKGRyYWdnaW5nRWxlbWVudCkpO1xuICAgICAgfVxuXG4gICAgICBpZiAocmVzaXppbmdFbGVtZW50KSB7XG4gICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHJlc2l6aW5nRWxlbWVudCAmJiBpc0ludmlzaWJseVNtYWxsRWxlbWVudChyZXNpemluZ0VsZW1lbnQpKSB7XG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSByZXNpemluZ0VsZW1lbnQuaWQpKTtcbiAgICAgIH0gLy8gaGFuZGxlIGZyYW1lIG1lbWJlcnNoaXAgZm9yIHJlc2l6aW5nIGZyYW1lcyBhbmQvb3Igc2VsZWN0ZWQgZWxlbWVudHNcblxuXG4gICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaXNSZXNpemluZykge1xuICAgICAgICBsZXQgbmV4dEVsZW1lbnRzID0gdXBkYXRlRnJhbWVNZW1iZXJzaGlwT2ZTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMuc3RhdGUsIHRoaXMpO1xuICAgICAgICBjb25zdCBzZWxlY3RlZEZyYW1lcyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKS5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG5cbiAgICAgICAgZm9yIChjb25zdCBmcmFtZSBvZiBzZWxlY3RlZEZyYW1lcykge1xuICAgICAgICAgIG5leHRFbGVtZW50cyA9IHJlcGxhY2VBbGxFbGVtZW50c0luRnJhbWUobmV4dEVsZW1lbnRzLCBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBmcmFtZSwgdGhpcy5zdGF0ZSksIGZyYW1lLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKG5leHRFbGVtZW50cyk7XG4gICAgICB9IC8vIENvZGUgYmVsb3cgaGFuZGxlcyBzZWxlY3Rpb24gd2hlbiBlbGVtZW50KHMpIHdlcmVuJ3RcbiAgICAgIC8vIGRyYWcgb3IgYWRkZWQgdG8gc2VsZWN0aW9uIG9uIHBvaW50ZXIgZG93biBwaGFzZS5cblxuXG4gICAgICBjb25zdCBoaXRFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudDtcblxuICAgICAgaWYgKCgoX2UgPSB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLmVsZW1lbnRJZCkgIT09IChoaXRFbGVtZW50ID09PSBudWxsIHx8IGhpdEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGhpdEVsZW1lbnQuaWQpICYmIGlzTGluZWFyRWxlbWVudChoaXRFbGVtZW50KSkge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVMZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpOyAvLyBzZXQgc2VsZWN0ZWRMaW5lYXJFbGVtZW50IHdoZW4gbm8gb3RoZXIgZWxlbWVudCBzZWxlY3RlZCBleGNlcHRcbiAgICAgICAgLy8gdGhlIG9uZSB3ZSd2ZSBoaXRcblxuICAgICAgICBpZiAoc2VsZWN0ZWRFTGVtZW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoaGl0RWxlbWVudCwgdGhpcy5zY2VuZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoaXNFcmFzZXJBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgY29uc3QgZHJhZ2dlZERpc3RhbmNlID0gZGlzdGFuY2UyZCh0aGlzLmxhc3RQb2ludGVyRG93bi5jbGllbnRYLCB0aGlzLmxhc3RQb2ludGVyRG93bi5jbGllbnRZLCB0aGlzLmxhc3RQb2ludGVyVXAuY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlclVwLmNsaWVudFkpO1xuXG4gICAgICAgIGlmIChkcmFnZ2VkRGlzdGFuY2UgPT09IDApIHtcbiAgICAgICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgY2xpZW50WDogdGhpcy5sYXN0UG9pbnRlclVwLmNsaWVudFgsXG4gICAgICAgICAgICBjbGllbnRZOiB0aGlzLmxhc3RQb2ludGVyVXAuY2xpZW50WVxuICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnRzID0gdGhpcy5nZXRFbGVtZW50c0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgICAgICBoaXRFbGVtZW50cy5mb3JFYWNoKGhpdEVsZW1lbnQgPT4gcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtoaXRFbGVtZW50LmlkXSA9IHtcbiAgICAgICAgICAgIGVyYXNlOiB0cnVlLFxuICAgICAgICAgICAgb3BhY2l0eTogaGl0RWxlbWVudC5vcGFjaXR5XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmVyYXNlRWxlbWVudHMocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAoT2JqZWN0LmtleXMocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZSkubGVuZ3RoKSB7XG4gICAgICAgIHRoaXMucmVzdG9yZVJlYWR5VG9FcmFzZUVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoaGl0RWxlbWVudCAmJiAhcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICFwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uICYmICggLy8gaWYgd2UncmUgZWRpdGluZyBhIGxpbmUsIHBvaW50ZXJ1cCBzaG91bGRuJ3Qgc3dpdGNoIHNlbGVjdGlvbiBpZlxuICAgICAgLy8gYm94IHNlbGVjdGVkXG4gICAgICAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCAhcG9pbnRlckRvd25TdGF0ZS5ib3hTZWxlY3Rpb24uaGFzT2NjdXJyZWQpKSB7XG4gICAgICAgIC8vIHdoZW4gaW5zaWRlIGxpbmUgZWRpdG9yLCBzaGlmdCBzZWxlY3RzIHBvaW50cyBpbnN0ZWFkXG4gICAgICAgIGlmIChjaGlsZEV2ZW50LnNoaWZ0S2V5ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdKSB7XG4gICAgICAgICAgICBpZiAoaXNTZWxlY3RlZFZpYUdyb3VwKHRoaXMuc3RhdGUsIGhpdEVsZW1lbnQpKSB7XG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoX3ByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oe30sIF9wcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTsgLy8gV2Ugd2FudCB0byB1bnNlbGVjdCBhbGwgZ3JvdXBzIGhpdEVsZW1lbnQgaXMgcGFydCBvZlxuICAgICAgICAgICAgICAgIC8vIGFzIHdlbGwgYXMgYWxsIGVsZW1lbnRzIHRoYXQgYXJlIHBhcnQgb2YgdGhlIGdyb3Vwc1xuICAgICAgICAgICAgICAgIC8vIGhpdEVsZW1lbnQgaXMgcGFydCBvZlxuXG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBncm91cGVkRWxlbWVudCBvZiBoaXRFbGVtZW50Lmdyb3VwSWRzLmZsYXRNYXAoZ3JvdXBJZCA9PiBnZXRFbGVtZW50c0luR3JvdXAodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZ3JvdXBJZCkpKSB7XG4gICAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tncm91cGVkRWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgX3ByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCBoaXRFbGVtZW50Lmdyb3VwSWRzLm1hcChnSWQgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgW2dJZF06IGZhbHNlXG4gICAgICAgICAgICAgICAgICB9KSkucmVkdWNlKChwcmV2LCBhY2MpID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldiksIGFjYyksIHt9KSksXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKG5leHRTZWxlY3RlZEVsZW1lbnRJZHMsIF9wcmV2U3RhdGUpXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgfSk7IC8vIGlmIG5vdCBncmFnZ2luZyBhIGxpbmVhciBlbGVtZW50IHBvaW50IChvdXRzaWRlIGVkaXRvcilcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoISgoX2YgPSB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkgPT09IG51bGwgfHwgX2YgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9mLmlzRHJhZ2dpbmcpKSB7XG4gICAgICAgICAgICAgIC8vIHJlbW92ZSBlbGVtZW50IGZyb20gc2VsZWN0aW9uIHdoaWxlXG4gICAgICAgICAgICAgIC8vIGtlZXBpbmcgcHJldiBlbGVtZW50cyBzZWxlY3RlZFxuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgbmV3U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7XG4gICAgICAgICAgICAgICAgZGVsZXRlIG5ld1NlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXdTZWxlY3RlZEVsZW1lbnRzID0gZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB7XG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5ld1NlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV3U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgICAgIC8vIHNldCBzZWxlY3RlZExpbmVhckVsZW1lbnQgb25seSBpZiB0aGF0cyB0aGUgb25seSBlbGVtZW50IHNlbGVjdGVkXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG5ld1NlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmIGlzTGluZWFyRWxlbWVudChuZXdTZWxlY3RlZEVsZW1lbnRzWzBdKSA/IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKG5ld1NlbGVjdGVkRWxlbWVudHNbMF0sIHRoaXMuc2NlbmUpIDogcHJldlN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKGhpdEVsZW1lbnQuZnJhbWVJZCAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmZyYW1lSWRdKSB7XG4gICAgICAgICAgICAvLyB3aGVuIGhpdEVsZW1lbnQgaXMgcGFydCBvZiBhIHNlbGVjdGVkIGZyYW1lLCBkZXNlbGVjdCB0aGUgZnJhbWVcbiAgICAgICAgICAgIC8vIHRvIGF2b2lkIGZyYW1lIGFuZCBjb250YWluaW5nIGVsZW1lbnRzIHNlbGVjdGVkIHNpbXVsdGFuZW91c2x5XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgfSk7IC8vIGRlc2VsZWN0IHRoZSBmcmFtZVxuXG4gICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuZnJhbWVJZF07IC8vIGRlc2VsZWN0IGdyb3VwcyBjb250YWluaW5nIHRoZSBmcmFtZVxuXG4gICAgICAgICAgICAgICgoX2IgPSAoX2EgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnQoaGl0RWxlbWVudC5mcmFtZUlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmdyb3VwSWRzKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiBbXSkuZmxhdE1hcChnaWQgPT4gZ2V0RWxlbWVudHNJbkdyb3VwKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGdpZCkpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZWxlbWVudC5pZF07XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dFNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogaGl0RWxlbWVudC5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGFkZCBlbGVtZW50IHRvIHNlbGVjdGlvbiB3aGlsZSBrZWVwaW5nIHByZXYgZWxlbWVudHMgc2VsZWN0ZWRcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoX3ByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgX3ByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgICAgW2hpdEVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH0pLCBfcHJldlN0YXRlKVxuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBpc0xpbmVhckVsZW1lbnQoaGl0RWxlbWVudCkgJiYgLy8gRG9uJ3Qgc2V0IGBzZWxlY3RlZExpbmVhckVsZW1lbnRgIGlmIGl0cyBzYW1lIGFzIHRoZSBoaXRFbGVtZW50LCB0aGlzIGlzIG1haW5seSB0byBwcmV2ZW50IHJlc2V0dGluZyB0aGUgYGhvdmVyUG9pbnRJbmRleGAgdG8gLTEuXG4gICAgICAgICAgICAgIC8vIEZ1dHVyZSB3ZSBzaG91bGQgdXBkYXRlIHRoZSBBUEkgdG8gdGFrZSBjYXJlIG9mIHNldHRpbmcgdGhlIGNvcnJlY3QgYGhvdmVyUG9pbnRJbmRleGAgd2hlbiBpbml0aWFsaXplZFxuICAgICAgICAgICAgICAoKF9hID0gcHJldlN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnRJZCkgIT09IGhpdEVsZW1lbnQuaWQgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihoaXRFbGVtZW50LCB0aGlzLnNjZW5lKSA6IHByZXZTdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICF0aGlzLnN0YXRlLmlzUmVzaXppbmcgJiYgKGhpdEVsZW1lbnQgJiYgaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50KGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpIHx8ICFoaXRFbGVtZW50ICYmIHBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBEZXNlbGVjdCBzZWxlY3RlZCBlbGVtZW50c1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWFjdGl2ZVRvb2wubG9ja2VkICYmIGFjdGl2ZVRvb2wudHlwZSAhPT0gXCJmcmVlZHJhd1wiICYmIGRyYWdnaW5nRWxlbWVudCAmJiBkcmFnZ2luZ0VsZW1lbnQudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgW2RyYWdnaW5nRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICB9KSwgcHJldlN0YXRlKSxcbiAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGlzRW1iZWRkYWJsZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSAmJiAhZHJhZ2dpbmdFbGVtZW50LmxpbmsgPyBcImVkaXRvclwiIDogcHJldlN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cFxuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgfHwgaXNTb21lRWxlbWVudFNlbGVjdGVkKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCB8fCBpc1Jlc2l6aW5nIHx8IGlzUm90YXRpbmcpIHtcbiAgICAgICAgKGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgPyBiaW5kT3JVbmJpbmRTZWxlY3RlZEVsZW1lbnRzIDogdW5iaW5kTGluZWFyRWxlbWVudHMpKHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghYWN0aXZlVG9vbC5sb2NrZWQgJiYgYWN0aXZlVG9vbC50eXBlICE9PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoaGl0RWxlbWVudCAmJiB0aGlzLmxhc3RQb2ludGVyVXAgJiYgdGhpcy5sYXN0UG9pbnRlckRvd24gJiYgdGhpcy5sYXN0UG9pbnRlclVwLnRpbWVTdGFtcCAtIHRoaXMubGFzdFBvaW50ZXJEb3duLnRpbWVTdGFtcCA8IDMwMCAmJiBnZXN0dXJlLnBvaW50ZXJzLnNpemUgPD0gMSAmJiBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpICYmIHRoaXMuaXNFbWJlZGRhYmxlQ2VudGVyKGhpdEVsZW1lbnQsIHRoaXMubGFzdFBvaW50ZXJVcCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2soaGl0RWxlbWVudCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBtYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpIHtcbiAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiA1MCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHN1Z2dlc3RlZEJpbmRpbmdzID0gZ2V0RWxpZ2libGVFbGVtZW50c0ZvckJpbmRpbmcoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzdWdnZXN0ZWRCaW5kaW5nc1xuICAgIH0pO1xuICB9XG5cbiAgY2xlYXJTZWxlY3Rpb24oaGl0RWxlbWVudCkge1xuICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCBwcmV2U3RhdGUpLFxuICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbCxcbiAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgLy8gQ29udGludWUgZWRpdGluZyB0aGUgc2FtZSBncm91cCBpZiB0aGUgdXNlciBzZWxlY3RlZCBhIGRpZmZlcmVudFxuICAgICAgLy8gZWxlbWVudCBmcm9tIGl0XG4gICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkICYmIGhpdEVsZW1lbnQgIT0gbnVsbCAmJiBpc0VsZW1lbnRJbkdyb3VwKGhpdEVsZW1lbnQsIHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCkgPyBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQgOiBudWxsXG4gICAgfSkpO1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsLFxuICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgfSk7XG4gIH1cblxuICBnZXRUZXh0V3lzaXd5Z1NuYXBwZWRUb0NlbnRlclBvc2l0aW9uKHgsIHksIGFwcFN0YXRlLCBjb250YWluZXIpIHtcbiAgICBpZiAoY29udGFpbmVyKSB7XG4gICAgICBsZXQgZWxlbWVudENlbnRlclggPSBjb250YWluZXIueCArIGNvbnRhaW5lci53aWR0aCAvIDI7XG4gICAgICBsZXQgZWxlbWVudENlbnRlclkgPSBjb250YWluZXIueSArIGNvbnRhaW5lci5oZWlnaHQgLyAyO1xuICAgICAgY29uc3QgZWxlbWVudENlbnRlciA9IGdldENvbnRhaW5lckNlbnRlcihjb250YWluZXIsIGFwcFN0YXRlKTtcblxuICAgICAgaWYgKGVsZW1lbnRDZW50ZXIpIHtcbiAgICAgICAgZWxlbWVudENlbnRlclggPSBlbGVtZW50Q2VudGVyLng7XG4gICAgICAgIGVsZW1lbnRDZW50ZXJZID0gZWxlbWVudENlbnRlci55O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBkaXN0YW5jZVRvQ2VudGVyID0gTWF0aC5oeXBvdCh4IC0gZWxlbWVudENlbnRlclgsIHkgLSBlbGVtZW50Q2VudGVyWSk7XG4gICAgICBjb25zdCBpc1NuYXBwZWRUb0NlbnRlciA9IGRpc3RhbmNlVG9DZW50ZXIgPCBURVhUX1RPX0NFTlRFUl9TTkFQX1RIUkVTSE9MRDtcblxuICAgICAgaWYgKGlzU25hcHBlZFRvQ2VudGVyKSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB2aWV3cG9ydFgsXG4gICAgICAgICAgeTogdmlld3BvcnRZXG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogZWxlbWVudENlbnRlclgsXG4gICAgICAgICAgc2NlbmVZOiBlbGVtZW50Q2VudGVyWVxuICAgICAgICB9LCBhcHBTdGF0ZSk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdmlld3BvcnRYLFxuICAgICAgICAgIHZpZXdwb3J0WSxcbiAgICAgICAgICBlbGVtZW50Q2VudGVyWCxcbiAgICAgICAgICBlbGVtZW50Q2VudGVyWVxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGdldENhbnZhc09mZnNldHMoKSB7XG4gICAgdmFyIF9hO1xuXG4gICAgaWYgKChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmN1cnJlbnQpIHtcbiAgICAgIGNvbnN0IGV4Y2FsaWRyYXdDb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgbGVmdCxcbiAgICAgICAgdG9wXG4gICAgICB9ID0gZXhjYWxpZHJhd0NvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG9mZnNldExlZnQ6IGxlZnQsXG4gICAgICAgIG9mZnNldFRvcDogdG9wXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBvZmZzZXRMZWZ0OiAwLFxuICAgICAgb2Zmc2V0VG9wOiAwXG4gICAgfTtcbiAgfVxuXG4gIHVwZGF0ZUxhbmd1YWdlKCkge1xuICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCBjdXJyZW50TGFuZyA9IGxhbmd1YWdlcy5maW5kKGxhbmcgPT4gbGFuZy5jb2RlID09PSB0aGlzLnByb3BzLmxhbmdDb2RlKSB8fCBkZWZhdWx0TGFuZztcbiAgICAgIHlpZWxkIHNldExhbmd1YWdlKGN1cnJlbnRMYW5nKTtcbiAgICAgIHRoaXMuc2V0QXBwU3RhdGUoe30pO1xuICAgIH0pO1xuICB9XG5cbn1cblxuQXBwLmRlZmF1bHRQcm9wcyA9IHtcbiAgLy8gbmVlZGVkIGZvciB0ZXN0cyB0byBwYXNzIHNpbmNlIHdlIGRpcmVjdGx5IHJlbmRlciBBcHAgaW4gbWFueSB0ZXN0c1xuICBVSU9wdGlvbnM6IERFRkFVTFRfVUlfT1BUSU9OU1xufTtcblxuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBFTlYuVEVTVCB8fCBwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gXCJwcm9kdWN0aW9uXCIpIHtcbiAgd2luZG93LmggPSB3aW5kb3cuaCB8fCB7fTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMod2luZG93LmgsIHtcbiAgICBlbGVtZW50czoge1xuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuXG4gICAgICBnZXQoKSB7XG4gICAgICAgIHZhciBfYTtcblxuICAgICAgICByZXR1cm4gKF9hID0gdGhpcy5hcHApID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcbiAgICAgIH0sXG5cbiAgICAgIHNldChlbGVtZW50cykge1xuICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgcmV0dXJuIChfYSA9IHRoaXMuYXBwKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Euc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGVsZW1lbnRzKTtcbiAgICAgIH1cblxuICAgIH1cbiAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IEFwcDsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../components/App.tsx\n");
2242
+ 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 */ \"../../../node_modules/react/jsx-runtime.js\");\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_68__ = __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 _renderer_renderElement__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ../renderer/renderElement */ \"../../renderer/renderElement.ts\");\n/* harmony import */ var _scene__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ../scene */ \"../../scene/index.ts\");\n/* harmony import */ var _scene_Scene__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ../scene/Scene */ \"../../scene/Scene.ts\");\n/* harmony import */ var _scene_zoom__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ../scene/zoom */ \"../../scene/zoom.ts\");\n/* harmony import */ var _shapes__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ../shapes */ \"../../shapes.tsx\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _element_embeddable__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ../element/embeddable */ \"../../element/embeddable.ts\");\n/* harmony import */ var _ContextMenu__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./ContextMenu */ \"../../components/ContextMenu.tsx\");\n/* harmony import */ var _LayerUI__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./LayerUI */ \"../../components/LayerUI.tsx\");\n/* harmony import */ var _Toast__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ./Toast */ \"../../components/Toast.tsx\");\n/* harmony import */ var _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ../actions/actionToggleViewMode */ \"../../actions/actionToggleViewMode.tsx\");\n/* harmony import */ var _data_blob__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ../data/blob */ \"../../data/blob.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! ../element/image */ \"../../element/image.ts\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! lodash.throttle */ \"../../../node_modules/lodash.throttle/index.js\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_42___default = /*#__PURE__*/__webpack_require__.n(lodash_throttle__WEBPACK_IMPORTED_MODULE_42__);\n/* harmony import */ var _data_filesystem__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ../data/filesystem */ \"../../data/filesystem.ts\");\n/* harmony import */ var _element_textElement__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ../element/textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _element_collision__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! ../element/collision */ \"../../element/collision.ts\");\n/* harmony import */ var _element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! ../element/Hyperlink */ \"../../element/Hyperlink.tsx\");\n/* harmony import */ var _data_url__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! ../data/url */ \"../../data/url.ts\");\n/* harmony import */ var _element_transformHandles__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! ../element/transformHandles */ \"../../element/transformHandles.ts\");\n/* harmony import */ var _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! ../actions/actionElementLock */ \"../../actions/actionElementLock.ts\");\n/* harmony import */ var _scene_Fonts__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! ../scene/Fonts */ \"../../scene/Fonts.ts\");\n/* harmony import */ var _frame__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! ../frame */ \"../../frame.ts\");\n/* harmony import */ var _scene_selection__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! ../scene/selection */ \"../../scene/selection.ts\");\n/* harmony import */ var _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! ../actions/actionClipboard */ \"../../actions/actionClipboard.tsx\");\n/* harmony import */ var _actions_actionFrame__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ../actions/actionFrame */ \"../../actions/actionFrame.ts\");\n/* harmony import */ var _actions_actionCanvas__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ../actions/actionCanvas */ \"../../actions/actionCanvas.tsx\");\n/* harmony import */ var _jotai__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! ../jotai */ \"../../jotai.ts\");\n/* harmony import */ var _ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ./ActiveConfirmDialog */ \"../../components/ActiveConfirmDialog.tsx\");\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 _emitter__WEBPACK_IMPORTED_MODULE_67__ = __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\nconst AppContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst AppPropsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst deviceContextInitialValue = {\n isSmScreen: false,\n isMobile: false,\n isTouchScreen: false,\n canDeviceFitSidebar: false,\n isLandscape: 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);\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 var _a;\n\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.lastPointerDown = null;\n this.lastPointerUp = null;\n this.lastViewportPosition = {\n x: 0,\n y: 0\n };\n this.onChangeEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_67__.Emitter();\n this.onPointerDownEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_67__.Emitter();\n this.onPointerUpEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_67__.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_35__.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_34__.viewportCoordsToSceneCoords)({\n clientX: box.x,\n clientY: box.y\n }, this.state);\n const boxSceneBottomRight = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.sceneCoordsToViewportCoords)({\n sceneX: f.x,\n sceneY: f.y\n }, this.state);\n const {\n x: x2\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.sceneCoordsToViewportCoords)({\n sceneX: f.x + f.width,\n sceneY: f.y + f.height\n }, this.state);\n const FRAME_NAME_GAP = 20;\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: `translateY(-${FRAME_NAME_EDIT_PADDING}px)`,\n color: \"var(--color-gray-80)\",\n overflow: \"hidden\",\n maxWidth: `${Math.min(x2 - x1 - FRAME_NAME_EDIT_PADDING, 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 top: `${y1 - FRAME_NAME_GAP - this.state.offsetTop}px`,\n left: `${x1 - this.state.offsetLeft - (this.state.editingFrame === f.id ? FRAME_NAME_EDIT_PADDING : 0)}px`,\n zIndex: 2,\n fontSize: \"14px\",\n color: isDarkTheme ? \"var(--color-gray-60)\" : \"var(--color-gray-50)\",\n width: \"max-content\",\n maxWidth: `${x2 - x1 + FRAME_NAME_EDIT_PADDING * 2}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) => __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__.exportAsImage)(type, elements, this.state, this.files, {\n exportBackground: this.state.exportBackground,\n name: this.state.name,\n viewBackgroundColor: this.state.viewBackgroundColor\n }).catch(_utils__WEBPACK_IMPORTED_MODULE_34__.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_40__.isImageFileHandle)(fileHandle)) {\n this.setState({\n fileHandle\n });\n }\n });\n\n this.openEyeDropper = ({\n type\n }) => {\n _jotai__WEBPACK_IMPORTED_MODULE_56__.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_34__.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_34__.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_34__.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 _b;\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: ((_b = scene.appState) === null || _b === void 0 ? void 0 : _b.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_30__.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\n if ((initialData === null || initialData === void 0 ? void 0 : initialData.scrollX) != null) {\n scene.appState.scrollX = initialData.scrollX;\n }\n\n if ((initialData === null || initialData === void 0 ? void 0 : initialData.scrollY) != null) {\n scene.appState.scrollY = initialData.scrollY;\n }\n\n this.resetHistory();\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n commitToHistory: true\n }));\n });\n\n this.refreshDeviceState = container => {\n const {\n width,\n height\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 this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.updateObject)(this.device, {\n isLandscape: width > height,\n isSmScreen: width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_SM_MAX_WIDTH,\n isMobile: 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 canDeviceFitSidebar: width > sidebarBreakpoint\n });\n };\n\n this.onResize = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.withBatchedUpdates)(() => {\n this.scene.getElementsIncludingDeleted().forEach(element => _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache[\"delete\"](element));\n this.setState({});\n });\n\n this.onFontsLoadingDone = event => {\n const loadedFontFaces = event.fontfaces;\n this.fonts.onFontsLoaded(loadedFontFaces);\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_34__.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_34__.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_34__.isWritableElement)(event.target)) {\n return;\n }\n\n this.cutAll();\n event.preventDefault();\n event.stopPropagation();\n });\n this.onCopy = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.isWritableElement)(event.target)) {\n return;\n }\n\n this.copyAll();\n event.preventDefault();\n event.stopPropagation();\n });\n\n this.cutAll = () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, \"keyboard\");\n };\n\n this.copyAll = () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, \"keyboard\");\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_52__.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_52__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n } else {\n gesture.pointers.clear();\n }\n };\n\n this.pasteFromClipboard = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.withBatchedUpdates)(event => __awaiter(this, void 0, void 0, function* () {\n var _c, _d, _e;\n\n const isPlainPaste = !!(IS_PLAIN_PASTE && event); // #686\n\n const target = document.activeElement;\n const isExcalidrawActive = (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.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_34__.isWritableElement)(target))) {\n return;\n } // 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\n let file = (_d = event === null || event === void 0 ? void 0 : event.clipboardData) === null || _d === void 0 ? void 0 : _d.files[0];\n const data = yield (0,_clipboard__WEBPACK_IMPORTED_MODULE_11__.parseClipboard)(event, isPlainPaste);\n\n if (!file && data.text && !isPlainPaste) {\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_40__.SVGStringToFile)(string);\n }\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state); // prefer spreadsheet data over image file (MS Office/Libre Office)\n\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.isSupportedImageFile)(file) && !data.spreadsheet) {\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_52__.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_35__.extractSrc)(data.text);\n\n if (!isPlainPaste && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.embeddableURLValidator)(maybeUrl, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(maybeUrl) || ((_e = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.getEmbedLink)(maybeUrl)) === null || _e === void 0 ? void 0 : _e.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_47__.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_34__.distance)(minX, maxX) / 2;\n const elementsCenterY = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_44__.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_52__.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.canDeviceFitSidebar && _jotai__WEBPACK_IMPORTED_MODULE_56__.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\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.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_34__.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 = () => {\n this.setState(prevState => {\n return {\n penMode: !prevState.penMode\n };\n });\n };\n\n this.onHandToolToggle = () => {\n this.actionManager.executeAction(_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_55__.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_32__.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_30__.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_55__.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_30__.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_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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_44__.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_44__.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_33__.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.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_30__.hasBackground)(this.state.activeTool.type) || selectedElements.some(element => (0,_scene__WEBPACK_IMPORTED_MODULE_30__.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[_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_56__.jotaiStore.set(_ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_57__.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_34__.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_34__.withBatchedUpdates)(event => {\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE) {\n if (this.state.viewModeEnabled) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (this.state.activeTool.type === \"selection\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursorForShape)(this.interactiveCanvas, this.state);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_52__.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 });\n\n this.setActiveTool = tool => {\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.updateActiveTool)(this.state, tool);\n\n if (nextActiveTool.type === \"hand\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (!isHoldingSpace) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_34__.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 }\n\n if (nextActiveTool.type !== \"selection\") {\n this.setState(prevState => ({\n activeTool: nextActiveTool,\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_52__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n snapLines: [],\n originSnapOffset: null\n }));\n } else {\n this.setState({\n activeTool: nextActiveTool,\n snapLines: [],\n originSnapOffset: null,\n activeEmbeddable: null\n });\n }\n };\n\n this.setCursor = cursor => {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, cursor);\n };\n\n this.resetCursor = () => {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_52__.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_34__.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_32__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_30__.getNormalizedZoom)(initialScale * event.scale)\n }, state)));\n }\n }); // fires only on Safari\n\n this.onGestureEnd = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_44__.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_44__.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_44__.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_44__.getApproxMinLineWidth)((0,_utils__WEBPACK_IMPORTED_MODULE_34__.getFontString)(fontString), lineHeight);\n const minHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_44__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n let {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_44__.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_34__.isTransparent)(container.backgroundColor) || (0,_element_collision__WEBPACK_IMPORTED_MODULE_45__.isHittingElementNotConsideringBoundingBox)(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY])) {\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_44__.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_46__.isPointHittingLink)(element, this.state, [scenePointer.x, scenePointer.y], this.device.isMobile);\n });\n };\n\n this.redirectToLink = (event, isTouchScreen) => {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDown.clientX, this.lastPointerDown.clientY, this.lastPointerUp.clientX, this.lastPointerUp.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_34__.viewportCoordsToSceneCoords)(this.lastPointerDown, this.state);\n const lastPointerDownHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerDownCoords.x, lastPointerDownCoords.y], this.device.isMobile);\n const lastPointerUpCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)(this.lastPointerUp, this.state);\n const lastPointerUpHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerUpCoords.x, lastPointerUpCoords.y], this.device.isMobile);\n\n if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {\n let url = this.hitLinkElement.link;\n\n if (url) {\n url = (0,_data_url__WEBPACK_IMPORTED_MODULE_47__.normalizeLink)(url);\n let customEvent;\n\n if (this.props.onLinkOpen) {\n customEvent = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_47__.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_51__.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_30__.getNormalizedZoom)(initialScale * scaleFactor) : this.state.zoom.value;\n this.setState(state => {\n const zoomState = (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_32__.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_30__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.showHyperlinkTooltip)(this.hitLinkElement, this.state);\n } else {\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (isOverScrollBar) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_34__.updateObject)(this.device, {\n isTouchScreen: true\n });\n }\n\n if (isPanning) {\n return;\n }\n\n this.lastPointerDown = event;\n this.setState({\n lastPointerDownWith: event.pointerType,\n cursorButton: \"down\"\n });\n this.savePointer(event.clientX, event.clientY, \"down\");\n\n if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) {\n return;\n } // only handle left mouse button or touch\n\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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.viewportCoordsToSceneCoords)(event, this.state);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(pendingImageElement, {\n x,\n y\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 if (this.state.activeTool.customType === \"comment\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursorForShape)(this.interactiveCanvas, this.state);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n } else if (this.state.activeTool.type === \"frame\") {\n this.createFrameElementOnPointerDown(pointerDownState);\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) {\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.lastPointerUp = event;\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)({\n clientX: event.clientX,\n clientY: event.clientY\n }, this.state);\n const clicklength = event.timeStamp - ((_b = (_a = this.lastPointerDown) === null || _a === void 0 ? void 0 : _a.timeStamp) !== null && _b !== void 0 ? _b : 0);\n\n if (this.device.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_46__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_34__.withBatchedUpdates)(lastPointerUp = () => {\n lastPointerUp = null;\n isPanning = false;\n\n if (!isHoldingSpace) {\n if (this.state.viewModeEnabled) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_34__.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_52__.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_52__.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_51__.getFrameElements)(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_44__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n\n if (!this.state.activeTool.locked) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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.lastPointerDown) === 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_35__.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 }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDown) === 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 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_52__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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.lastPointerDown) === 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.lastPointerDown) === 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 _f, _g, _h, _j; // 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_40__.isSupportedImageFile)(imageFile)) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.unsupportedFileType\"));\n }\n\n const mimeType = imageFile.type;\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_40__.SVGStringToFile)(yield (0,_element_image__WEBPACK_IMPORTED_MODULE_41__.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 ((_g = (_f = this.props).generateIdForFile) === null || _g === void 0 ? void 0 : _g.call(_f, imageFile)) || (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.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_40__.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 = (_h = this.files[fileId]) === null || _h === void 0 ? void 0 : _h.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_40__.dataURLToFile)(dataURL);\n this.setImagePreviewCursor(resizedFile || imageFile);\n }\n\n const dataURL = ((_j = this.files[fileId]) === null || _j === void 0 ? void 0 : _j.dataURL) || (yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.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 _k;\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 && ((_k = this.state.draggingElement) === null || _k === void 0 ? void 0 : _k.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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 this.scene.addNewElement(imageElement);\n\n try {\n 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 }\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_40__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: cursorImageSizePx\n });\n let previewDataURL = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.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_41__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, `url(${previewDataURL}) 4 4, auto`);\n }\n });\n\n this.onImageAction = ({\n insertOnCanvasDirectly\n } = {\n insertOnCanvasDirectly: false\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_34__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const imageFile = yield (0,_data_filesystem__WEBPACK_IMPORTED_MODULE_43__.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 });\n\n if (insertOnCanvasDirectly) {\n this.insertImageElement(imageElement, imageFile);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_52__.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_34__.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_41__.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_41__.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_42___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 _l, _m, _o, _p; // must be retrieved first, in the same frame\n\n\n const {\n file,\n fileHandle\n } = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.getFileFromEvent)(event);\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)(event, this.state);\n\n try {\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.isSupportedImageFile)(file)) {\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_52__.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_40__.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 ((_m = (_l = event.dataTransfer) === null || _l === void 0 ? void 0 : _l.types) === null || _m === void 0 ? void 0 : _m.includes(\"text/plain\")) {\n const text = (_o = event.dataTransfer) === null || _o === void 0 ? void 0 : _o.getData(\"text\");\n\n if (text && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.embeddableURLValidator)(text, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(text) || ((_p = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.getEmbedLink)(text)) === null || _p === void 0 ? void 0 : _p.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_47__.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_40__.normalizeFile)(file);\n\n try {\n const ret = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_40__.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 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_34__.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_34__.distance)(pointerDownState.origin.x, pointerCoords.x), (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.distance)(pointerDownState.originInGrid.x, gridX), (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_51__.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_51__.getFrameElements)(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_30__.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_51__.getFrameElements)(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_51__.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_39__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n }\n\n return [_actions_actionClipboard__WEBPACK_IMPORTED_MODULE_53__.actionPaste, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSelectAll, _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_49__.actionUnlockAllElements, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_39__.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_53__.actionPaste, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_54__.actionSelectAllElementsInFrame, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_54__.actionRemoveAllElementsFromFrame, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.CONTEXT_MENU_SEPARATOR, ...options, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyStyles, _actions__WEBPACK_IMPORTED_MODULE_5__.actionPasteStyles, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionAddToLibrary, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipHorizontal, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipVertical, _ContextMenu__WEBPACK_IMPORTED_MODULE_36__.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_36__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDeleteSelected];\n };\n\n this.handleWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_32__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_30__.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 pointer = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)({\n clientX: x,\n clientY: y\n }, this.state);\n\n if (isNaN(pointer.x) || isNaN(pointer.y)) {// sometimes the pointer goes off screen\n }\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_34__.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 excalidrawRef,\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_68__.nanoid)();\n this.library = new _data_library__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this);\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_31__[\"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 (excalidrawRef) {\n const readyPromise = \"current\" in excalidrawRef && ((_a = excalidrawRef.current) === null || _a === void 0 ? void 0 : _a.readyPromise) || (0,_utils__WEBPACK_IMPORTED_MODULE_34__.resolvablePromise)();\n const api = {\n ready: true,\n readyPromise,\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 app: this,\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 excalidrawRef === \"function\") {\n excalidrawRef(api);\n } else {\n excalidrawRef.current = api;\n }\n\n readyPromise.resolve(api);\n }\n\n this.excalidrawContainerValue = {\n container: this.excalidrawContainerRef.current,\n id: this.id\n };\n this.fonts = new _scene_Fonts__WEBPACK_IMPORTED_MODULE_50__.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_34__.sceneCoordsToViewportCoords)({\n sceneX: el.x,\n sceneY: el.y\n }, this.state);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_35__.getEmbedLink)((0,_data_url__WEBPACK_IMPORTED_MODULE_47__.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 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--zen-mode\": this.state.zenModeEnabled,\n \"excalidraw--mobile\": this.device.isMobile\n }),\n style: {\n [\"--ui-pointerEvents\"]: this.state.selectionElement || this.state.draggingElement || this.state.resizingElement || this.state.editingElement && !(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? _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__.jsx)(_LayerUI__WEBPACK_IMPORTED_MODULE_37__[\"default\"], Object.assign({\n onHomeButtonClick: this.props.onHomeButtonClick || (() => {}),\n canvas: this.canvas,\n interactiveCanvas: this.interactiveCanvas,\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 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 onImageAction: this.onImageAction,\n renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === \"selection\" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,\n app: this,\n renderTopRightUI: renderTopRightUI\n }, {\n children: this.props.children\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 }), selectedElements.length === 1 && !this.state.contextMenu && this.state.showHyperlinkPopup && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_element_Hyperlink__WEBPACK_IMPORTED_MODULE_46__.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_38__.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_36__.ContextMenu, {\n items: this.state.contextMenu.items,\n top: this.state.contextMenu.top,\n left: this.state.contextMenu.left,\n actionManager: this.actionManager\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 canvasBackgroundColor: this.state.viewBackgroundColor\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, _b;\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 (this.excalidrawContainerRef.current && // 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_34__.isTestEnv)()) {\n this.refreshDeviceState(this.excalidrawContainerRef.current);\n }\n\n if (\"ResizeObserver\" in window && ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current)) {\n this.resizeObserver = new ResizeObserver(() => {\n // recompute device dimensions state\n // ---------------------------------------------------------------------\n this.refreshDeviceState(this.excalidrawContainerRef.current); // refresh offsets\n // ---------------------------------------------------------------------\n\n this.updateDOMRect();\n });\n (_b = this.resizeObserver) === null || _b === void 0 ? void 0 : _b.observe(this.excalidrawContainerRef.current);\n } else if (window.matchMedia) {\n const mdScreenQuery = window.matchMedia(`(max-width: ${_constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_PORTRAIT}px), (max-height: ${_constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_HEIGHT_LANDSCAPE}px) and (max-width: ${_constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_LANDSCAPE}px)`);\n const smScreenQuery = window.matchMedia(`(max-width: ${_constants__WEBPACK_IMPORTED_MODULE_12__.MQ_SM_MAX_WIDTH}px)`);\n const canDeviceFitSidebarMediaQuery = window.matchMedia(`(min-width: ${// NOTE this won't update if a different breakpoint is supplied\n // after mount\n this.props.UIOptions.dockedSidebarBreakpoint != null ? this.props.UIOptions.dockedSidebarBreakpoint : _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_RIGHT_SIDEBAR_MIN_WIDTH}px)`);\n\n const handler = () => {\n this.excalidrawContainerRef.current.getBoundingClientRect();\n this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.updateObject)(this.device, {\n isSmScreen: smScreenQuery.matches,\n isMobile: mdScreenQuery.matches,\n canDeviceFitSidebar: canDeviceFitSidebarMediaQuery.matches\n });\n };\n\n mdScreenQuery.addListener(handler);\n\n this.detachIsMobileMqHandler = () => mdScreenQuery.removeListener(handler);\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_44__.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_31__[\"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 _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_66__.ShapeCache.destroy();\n _snapping__WEBPACK_IMPORTED_MODULE_58__.SnapCache.destroy();\n (0,_renderer_renderElement__WEBPACK_IMPORTED_MODULE_29__.clearRenderCache)();\n this.onChangeEmitter.destroy();\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_31__[\"default\"]();\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.library = new _data_library__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this); // @ts-ignore\n\n this.canvas = null;\n this.interactiveCanvas = null; // @ts-ignore\n\n this.rc = null; // @ts-ignore\n\n this.excalidrawContainerRef.current = undefined;\n this.nearestScrollableContainer = undefined;\n this.excalidrawContainerValue = {\n container: null,\n id: \"unmounted\"\n };\n clearTimeout(touchTimeout);\n _scene__WEBPACK_IMPORTED_MODULE_30__.isSomeElementSelected.clearCache();\n _groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements.clearCache();\n touchTimeout = 0;\n }\n\n removeEventListeners() {\n var _a, _b, _c, _d, _e, _f, _g;\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 (_f = (_e = document.fonts) === null || _e === void 0 ? void 0 : _e.removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_e, \"loadingdone\", this.onFontsLoadingDone);\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 (_g = this.detachIsMobileMqHandler) === null || _g === void 0 ? void 0 : _g.call(this);\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\", this.onFontsLoadingDone); // 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_34__.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 (this.excalidrawContainerRef.current && prevProps.UIOptions.dockedSidebarBreakpoint !== this.props.UIOptions.dockedSidebarBreakpoint) {\n this.refreshDeviceState(this.excalidrawContainerRef.current);\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_34__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n\n if (this.state.activeTool.type === \"eraser\" && prevState.theme !== this.state.theme) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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.UIOptions.canvasActions && this.state.openMenu === \"canvas\") {\n this.setState({\n openMenu: 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_34__.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, this.props.id);\n this.onChangeEmitter.trigger(this.scene.getElementsIncludingDeleted(), this.state, this.files);\n }\n }\n\n static resetTapTwice() {\n didTapTwice = false;\n }\n\n addTextFromPaste(text, isPlainPaste = false) {\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_44__.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_44__.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_52__.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.isMobile) {\n this.setToast({\n message: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"toast.pasteAsSingleElement\", {\n shortcut: (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_34__.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_34__.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_52__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_30__.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_51__.getContainingFrame)(element);\n return containingFrame && this.state.frameRendering.enabled && this.state.frameRendering.clip ? (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_44__.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_45__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n } else if ((0,_element_transformHandles__WEBPACK_IMPORTED_MODULE_48__.shouldShowBoundingBox)([element], this.state) && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_34__.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_30__.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_34__.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_34__.withBatchedUpdates)(() => {\n isDraggingScrollBar = false;\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_34__.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_34__.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_34__.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_34__.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_34__.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 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_30__.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_44__.bindTextToShapeAfterDuplication)(nextElements, elementsToAppend, oldIdToDuplicatedId);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, \"duplicatesServeAsOld\");\n (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_30__.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_30__.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_34__.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 });\n this.onPointerUpEmitter.trigger(this.state.activeTool, pointerDownState, childEvent); // 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 if ((draggingElement === null || draggingElement === void 0 ? void 0 : draggingElement.type) === \"freedraw\") {\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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_52__.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_34__.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,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n this.setState(prevState => ({\n draggingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_34__.updateActiveTool)(this.state, {\n type: \"selection\"\n }),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_52__.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().slice(0, -1));\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_34__.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_51__.getContainingFrame)(linearElement);\n\n if (frame && linearElement) {\n if (!(0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_51__.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_51__.isElementInFrame)(element, nextElements, this.state));\n\n if (this.state.editingGroupId) {\n updateGroupIdsAfterEditingGroup(elementsToAdd);\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_51__.isElementInFrame)(element, nextElements, this.state));\n updateGroupIdsAfterEditingGroup(elementsToRemove);\n }\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_51__.getElementsInNewFrame)(this.scene.getElementsIncludingDeleted(), draggingElement);\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_51__.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_51__.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_51__.replaceAllElementsInFrame)(nextElements, (0,_frame__WEBPACK_IMPORTED_MODULE_51__.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.lastPointerDown.clientX, this.lastPointerDown.clientY, this.lastPointerUp.clientX, this.lastPointerUp.clientY);\n\n if (draggedDistance === 0) {\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_34__.viewportCoordsToSceneCoords)({\n clientX: this.lastPointerUp.clientX,\n clientY: this.lastPointerUp.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_52__.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_30__.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_52__.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_52__.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_52__.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_30__.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.locked && activeTool.type !== \"freedraw\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_34__.resetCursor)(this.interactiveCanvas);\n this.setState({\n draggingElement: null,\n suggestedBindings: [],\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_34__.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.lastPointerUp && this.lastPointerDown && this.lastPointerUp.timeStamp - this.lastPointerDown.timeStamp < 300 && gesture.pointers.size <= 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, this.lastPointerUp, 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_52__.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_52__.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_44__.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_34__.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vY29tcG9uZW50cy9BcHAudHN4LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxnQkFBZ0IsU0FBSSxJQUFJLFNBQUk7QUFDNUI7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDs7QUFFc0Y7QUFDNUM7QUFDSjtBQUNBO0FBQ2Q7QUFDUTtBQUN5aEI7QUFDM2U7QUFDM0I7QUFDTDtBQUNKO0FBQ3lDO0FBQ3JDO0FBQzBwQjtBQUNscEI7QUFDd0I7QUFDbkI7QUFDbWdCO0FBQy9NO0FBQzFTO0FBQ0k7QUFDNkQ7QUFDK0k7QUFDak87QUFDa0o7QUFDcks7QUFDNkM7QUFDc0Q7QUFDdkU7QUFDb0I7QUFDcEI7QUFDdUk7QUFDaks7QUFDYTtBQUNMO0FBQ3NhO0FBQ3hYO0FBQ3JCO0FBQ3BDO0FBQ0E7QUFDdUM7QUFDZ0s7QUFDN0Y7QUFDbkc7QUFDTztBQUNtUTtBQUNoTztBQUN1RDtBQUNuRTtBQUNEO0FBQ0c7QUFDaEM7QUFDZ1M7QUFDak87QUFDN0M7QUFDaUQ7QUFDaEM7QUFDcEM7QUFDMEI7QUFDcUo7QUFDOUk7QUFDWDtBQUNSO0FBQ1k7QUFDUjtBQUNLO0FBQ2hCO0FBQ0k7QUFDWjtBQUNyQyxtQkFBbUIsMERBQW1CO0FBQ3RDLHdCQUF3QiwwREFBbUI7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsMERBQW1CO0FBQ3pDO0FBQ08sbUNBQW1DLDBEQUFtQjtBQUM3RDtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0Esa0NBQWtDLDBEQUFtQjtBQUNyRDtBQUNBLGtDQUFrQywwREFBbUIsK0JBQStCLEVBQUUsOERBQWtCO0FBQ3hHO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0EscUNBQXFDLDBEQUFtQjtBQUN4RDtBQUNBLENBQUM7QUFDRDtBQUNBLHVDQUF1QywwREFBbUI7QUFDMUQ7QUFDTyxxQkFBcUIsaURBQVU7QUFDL0IsMEJBQTBCLGlEQUFVO0FBQ3BDLHdCQUF3QixpREFBVTtBQUNsQyxxQ0FBcUMsaURBQVU7QUFDL0Msb0NBQW9DLGlEQUFVO0FBQzlDLG9DQUFvQyxpREFBVTtBQUM5Qyx1Q0FBdUMsaURBQVU7QUFDakQseUNBQXlDLGlEQUFVO0FBQzFEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxrQkFBa0Isd0RBQWU7QUFDakM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxzREFBZTtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0IsOENBQU87QUFDdEMsb0NBQW9DLDhDQUFPO0FBQzNDLGtDQUFrQyw4Q0FBTzs7QUFFekM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLHlFQUFtQjtBQUMvQjs7QUFFQTtBQUNBO0FBQ0EsOEJBQThCLDRFQUFzQjtBQUNwRCxZQUFZLHNFQUFhO0FBQ3pCO0FBQ0EsYUFBYTtBQUNiLFlBQVksb0VBQWlCO0FBQzdCO0FBQ0E7O0FBRUE7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQSxRQUFROzs7QUFHUjtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBLGdCQUFnQixRQUFRLGNBQWMsZ0JBQWdCO0FBQ3REOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxvQ0FBb0Msb0VBQTJCO0FBQy9EO0FBQ0E7QUFDQSxhQUFhO0FBQ2Isd0NBQXdDLG9FQUEyQjtBQUNuRTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGFBQWEsMEVBQW1CO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsRUFBRSxvRUFBMkI7QUFDdkM7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsVUFBVSxFQUFFLG9FQUEyQjtBQUN2QztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLFlBQVksc0VBQWE7QUFDekI7QUFDQSxhQUFhO0FBQ2I7O0FBRUE7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTs7QUFFQTtBQUNBLDREQUE0RCxVQUFVO0FBQ3RFLHlCQUF5QixzREFBSTtBQUM3QjtBQUNBO0FBQ0E7QUFDQSxjQUFjLHNFQUFhO0FBQzNCO0FBQ0EsZUFBZTtBQUNmLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLCtDQUFXLGtCQUFrQiw4Q0FBVTtBQUN2RTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQSxvQ0FBb0MscURBQVk7QUFDaEQ7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLHdCQUF3QjtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdDQUF3Qyx3QkFBd0I7QUFDaEU7QUFDQTtBQUNBLDJCQUEyQixzR0FBc0c7QUFDakksYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsVUFBVTtBQUNWLDJFQUEyRSxVQUFVO0FBQ3JGOztBQUVBLGVBQWUsc0RBQUk7QUFDbkI7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLDJDQUEyQztBQUMvRCxxQkFBcUIsOEZBQThGO0FBQ25IO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHNDQUFzQztBQUMvRDtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IseURBQWdCO0FBQ3BDLHdEQUF3RCxnRUFBdUIsR0FBRywrREFBc0I7QUFDeEcsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBLFNBQVM7QUFDVDtBQUNBLFNBQVM7QUFDVCxPQUFPO0FBQ1A7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBLE1BQU0sc0RBQVU7QUFDaEIsK0JBQStCLHFEQUFhO0FBQzVDO0FBQ0E7QUFDQTtBQUNBLE9BQU8sUUFBUSxxREFBZ0I7QUFDL0I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULE9BQU87O0FBRVAsdURBQXVELDhEQUFpQjtBQUN4RTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSztBQUNMLE1BQU0sbURBQWMsQ0FBQyw4REFBb0I7QUFDekM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSx3REFBd0Q7QUFDeEQ7QUFDQSxpQkFBaUI7QUFDakI7QUFDQSxlQUFlO0FBQ2YsY0FBYztBQUNkO0FBQ0Esd0RBQXdEO0FBQ3hEO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0EsZUFBZTtBQUNmO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBLHlCQUF5Qix1RUFBYztBQUN2QztBQUNBLG1CQUFtQjtBQUNuQjs7QUFFQTtBQUNBLGVBQWU7QUFDZixhQUFhO0FBQ2I7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxPQUFPO0FBQ1A7O0FBRUEsNEJBQTRCLDJEQUFrQjtBQUM5Qzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLHVKQUF1Siw4REFBbUI7QUFDMUs7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG9HQUFvRztBQUNwRztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHNMQUFzTCxvREFBVztBQUNqTTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxrREFBa0Qsa0RBQVM7QUFDM0Q7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBEQUEwRDtBQUMxRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLLEdBQUc7O0FBRVIsa0JBQWtCLDJEQUFrQjtBQUNwQztBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQSxzQkFBc0IsMkRBQWtCO0FBQ3hDO0FBQ0EsMkRBQTJELEVBQUUsOERBQWtCO0FBQy9FO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0EsV0FBVztBQUNYO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9CQUFvQix1REFBTztBQUMzQjtBQUNBLE9BQU87QUFDUCxxREFBcUQ7QUFDckQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0ZBQStGO0FBQy9GO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0EsdURBQXVELG1CQUFtQiw4REFBcUIsK0NBQStDO0FBQzlJO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULFFBQVE7QUFDUjtBQUNBO0FBQ0E7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSwwREFBMEQ7QUFDMUQ7QUFDQSxPQUFPO0FBQ1AsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUixzSUFBc0ksbUVBQTBCO0FBQ2hLLG9CQUFvQixxREFBWTtBQUNoQztBQUNBLDRCQUE0Qix3REFBZTtBQUMzQywwQkFBMEIsOERBQXFCLGFBQWEsZ0VBQXVCLFlBQVksK0RBQXNCO0FBQ3JIO0FBQ0EsT0FBTztBQUNQOztBQUVBLG9CQUFvQiwyREFBa0I7QUFDdEMsa0VBQWtFLG9FQUFpQjtBQUNuRixzQkFBc0I7QUFDdEIsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxNQUFNLHdEQUFhOztBQUVuQjtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsaURBQVE7QUFDNUI7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLEtBQUssRUFBRSx1REFBYyxHQUFHOztBQUV4QixpQkFBaUIsMkRBQWtCO0FBQ25DOztBQUVBOztBQUVBLGlDQUFpQywwREFBaUI7QUFDbEQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsa0JBQWtCLDJEQUFrQjtBQUNwQzs7QUFFQTs7QUFFQSxpQ0FBaUMsMERBQWlCO0FBQ2xEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLHVDQUF1QywrQ0FBUztBQUNoRDs7QUFFQTtBQUNBLHVDQUF1QyxnREFBVTtBQUNqRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGtEQUFTO0FBQ3BCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0VBQWdFLDBEQUFpQjtBQUNqRjtBQUNBLFFBQVE7QUFDUjs7O0FBR0E7QUFDQSx3Q0FBd0M7O0FBRXhDO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUEsVUFBVSxrREFBUztBQUNuQjtBQUNBOztBQUVBO0FBQ0E7QUFDQSw4QkFBOEIsNkVBQTBCLEdBQUc7QUFDM0Q7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSx3Q0FBd0M7QUFDeEMsOEJBQThCLDZFQUEwQjtBQUN4RCxTQUFTO0FBQ1QsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQSw4QkFBOEIsMkRBQWtCO0FBQ2hEOztBQUVBLHdEQUF3RDs7QUFFeEQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsMEVBQTBFLDBEQUFpQjtBQUMzRjtBQUNBLFFBQVE7QUFDUjtBQUNBOzs7QUFHQTtBQUNBLHlCQUF5QiwyREFBYzs7QUFFdkM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsNERBQWU7QUFDaEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLEVBQUUsb0VBQTJCO0FBQ3JDO0FBQ0E7QUFDQSxPQUFPLGVBQWU7O0FBRXRCLFVBQVUsaUVBQW9CO0FBQzlCO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSw4QkFBOEIsNkVBQTBCO0FBQ3hEO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1IsZ0RBQWdELDZFQUEyQixpQ0FBaUM7O0FBRTVHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTtBQUNSLHlCQUF5QixnRUFBVTs7QUFFbkMsNkJBQTZCLDRFQUFzQiw4R0FBOEcsa0VBQVk7QUFDN0s7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLHlEQUFhO0FBQy9CLFdBQVc7O0FBRVg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLEtBQUs7O0FBRUw7QUFDQSx1QkFBdUIsK0RBQWU7QUFDdEMsdUNBQXVDLDBEQUFlO0FBQ3RELDhCQUE4QixpREFBUTtBQUN0Qyw4QkFBOEIsaURBQVE7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVEsRUFBRSxvRUFBMkI7QUFDckM7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsNkJBQTZCLG9EQUFZO0FBQ3pDLDBCQUEwQix1RUFBaUI7QUFDM0MsZUFBZSx1RUFBYztBQUM3QjtBQUNBO0FBQ0EsU0FBUztBQUNULE9BQU87QUFDUDtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxZQUFZLHdEQUFhLGdCQUFnQix3RUFBa0I7QUFDM0QsNEJBQTRCLDBFQUFtQjtBQUMvQyxVQUFVLGdFQUFxQjtBQUMvQjtBQUNBLE9BQU87O0FBRVA7QUFDQSxtREFBbUQ7QUFDbkQ7O0FBRUE7QUFDQSxtQ0FBbUMsdUZBQW9DO0FBQ3ZFLGdFQUFnRTtBQUNoRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0ZBQWtGLG1EQUFjLENBQUMsa0VBQW1CO0FBQ3BILE9BQU8sR0FBRyx5RUFBK0I7QUFDekM7QUFDQTtBQUNBLGVBQWUsd0VBQWtCO0FBQ2pDO0FBQ0E7O0FBRUE7QUFDQSxTQUFTLElBQUk7QUFDYixPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVEsc0RBQVUsNkJBQTZCLFFBQVEsR0FBRyw0Q0FBNEM7QUFDdEc7O0FBRUE7QUFDQTtBQUNBLGtFQUFrRSx5QkFBeUIseURBQWdCO0FBQzNHO0FBQ0EsWUFBWTtBQUNaO0FBQ0EsV0FBVztBQUNYO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBLHVDQUF1Qyx3RUFBb0I7QUFDM0Q7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQyxFQUFFLDZEQUFlO0FBQ3JEO0FBQ0E7QUFDQSxrQkFBa0IsMERBQWlCO0FBQ25DLE9BQU87QUFDUDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLCtGQUErRjs7QUFFL0Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLGlFQUFTO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBLHVCQUF1Qiw4REFBcUI7QUFDNUM7QUFDQTtBQUNBLFFBQVE7QUFDUjs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUIsd0RBQWU7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0EsZ0RBQWdELGdEQUFPO0FBQ3ZELGNBQWM7OztBQUdkO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQSw0Q0FBNEMsaURBQVE7QUFDcEQ7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7QUFDTDs7O0FBR0Esb0JBQW9CLDJEQUFrQjtBQUN0QztBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsaURBQWlEO0FBQ2pEO0FBQ0EsWUFBWSwrRUFBeUI7QUFDckM7QUFDQSxVQUFVLG9FQUFpQjtBQUMzQjtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsS0FBSztBQUNMLHVCQUF1QiwyREFBa0I7QUFDekM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLHNCQUFzQjtBQUN0QjtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWLE9BQU87QUFDUDtBQUNBOztBQUVBLHVDQUF1QywyREFBa0I7QUFDekQ7QUFDQTtBQUNBLEtBQUssR0FBRzs7QUFFUixxQkFBcUIsMkRBQWtCO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsU0FBUztBQUNUOztBQUVBLGdCQUFnQixvREFBZ0IsaUNBQWlDLDBDQUFNO0FBQ3ZFO0FBQ0EsNENBQTRDO0FBQzVDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFROzs7QUFHUixnQkFBZ0Isb0RBQWdCLEtBQUssMERBQWlCO0FBQ3RELDJCQUEyQiwrQ0FBVyxtQkFBbUIsK0NBQVc7QUFDcEU7QUFDQTtBQUNBO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQSxNQUFNLDBEQUFpQjtBQUN2QixvQkFBb0IsK0NBQVc7QUFDL0IsTUFBTSxrREFBVSxlQUFlLG9EQUFXO0FBQzFDO0FBQ0E7O0FBRUEsd0JBQXdCLHNEQUFrQjtBQUMxQztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsUUFBUSxxQ0FBcUMsMENBQU0sNEJBQTRCLG9EQUFnQjtBQUMvRjtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQSx3QkFBd0IsZ0RBQVksa0JBQWtCLGtEQUFjO0FBQ3BFOztBQUVBLDBCQUEwQixrREFBYztBQUN4QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1Y7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsZ0JBQWdCLG9EQUFnQjtBQUNoQztBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBLFVBQVUsa0RBQVU7QUFDcEIsOERBQThELGlFQUF3Qiw2Q0FBNkMsdUVBQThCLEdBQUcsaUVBQXdCO0FBQzVMO0FBQ0E7O0FBRUEsMEJBQTBCLG1EQUFlO0FBQ3pDO0FBQ0EsVUFBVSx1QkFBdUIsb0RBQWdCO0FBQ2pEO0FBQ0EsVUFBVSx1QkFBdUIsaURBQWE7QUFDOUM7QUFDQSxVQUFVLHVCQUF1QixtREFBZTtBQUNoRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsVUFBVSxzRUFBYTtBQUN2QjtBQUNBO0FBQ0EsV0FBVztBQUNYLFVBQVUsc0VBQW1CO0FBQzdCO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBO0FBQ0EsUUFBUSx1QkFBdUIsOENBQVU7QUFDekM7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0Isb0RBQWdCO0FBQ3BDLGdCQUFnQixxRUFBZTtBQUMvQjtBQUNBO0FBQ0E7QUFDQSw0Q0FBNEMsOEVBQW1CO0FBQy9ELGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0EsWUFBWSxTQUFTLHdEQUFhLHFCQUFxQiwyRUFBb0I7QUFDM0U7O0FBRUEsaUJBQWlCLHdEQUFhO0FBQzlCO0FBQ0E7O0FBRUEsNkJBQTZCLHlFQUFrQjtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBLFlBQVksU0FBUyxvRUFBYztBQUNuQztBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQSxRQUFRO0FBQ1Isc0JBQXNCLHdEQUFjOztBQUVwQztBQUNBO0FBQ0EsWUFBWSxzREFBVSxnQ0FBZ0MsNENBQTRDO0FBQ2xHOztBQUVBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQSxVQUFVLHVCQUF1QiwwQ0FBTTtBQUN2QztBQUNBO0FBQ0E7QUFDQTs7QUFFQSx3QkFBd0IsOENBQVU7QUFDbEM7QUFDQSxRQUFRLGtEQUFTLHlCQUF5Qix5REFBZ0I7QUFDMUQ7QUFDQTs7QUFFQSx5QkFBeUIsMENBQU0sa0JBQWtCLDBDQUFNLDZCQUE2QixvREFBZ0I7QUFDcEc7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDBCQUEwQiwwQ0FBTSxLQUFLLHNEQUFhLGlFQUFpRSxzREFBYTtBQUNoSTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUEsMEJBQTBCLDBDQUFNO0FBQ2hDO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBOztBQUVBLGdCQUFnQixvREFBZ0Isb0JBQW9CLGtEQUFjLGtCQUFrQiwrQ0FBVztBQUMvRixRQUFRLG1EQUFjLENBQUMsMEVBQXVCO0FBQzlDLFFBQVE7QUFDUjs7O0FBR0E7QUFDQSw2Q0FBNkMsMENBQU07QUFDbkQsZ0RBQWdELDBDQUFNLG1CQUFtQiwwQ0FBTTs7QUFFL0U7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULFFBQVE7O0FBRVIsS0FBSztBQUNMLG1CQUFtQiwyREFBa0I7QUFDckM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsbUJBQW1CLDJEQUFrQjtBQUNyQyx3QkFBd0IsOENBQVU7QUFDbEM7QUFDQSxVQUFVLGtEQUFTLHlCQUF5Qix5REFBZ0I7QUFDNUQsVUFBVTtBQUNWLFVBQVUsb0RBQVc7QUFDckIsVUFBVTtBQUNWLFVBQVUsMERBQWlCO0FBQzNCO0FBQ0EsZ0NBQWdDLDZFQUEwQixHQUFHO0FBQzdELGdDQUFnQztBQUNoQztBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0E7O0FBRUEsaUJBQWlCLG9EQUFnQjtBQUNqQztBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBLFVBQVUsa0RBQVU7QUFDcEI7QUFDQSxRQUFRLG1FQUFnQixlQUFlLCtFQUE0QixxQkFBcUIsdUVBQW9CO0FBQzVHO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLOztBQUVMO0FBQ0EsNkJBQTZCLHlEQUFnQjs7QUFFN0M7QUFDQSxRQUFRLGtEQUFTLHlCQUF5Qix5REFBZ0I7QUFDMUQsUUFBUTtBQUNSLFFBQVEsMERBQWlCO0FBQ3pCOztBQUVBLFVBQVUsbURBQVU7QUFDcEI7QUFDQTs7QUFFQSxXQUFXLHlFQUFtQjtBQUM5QjtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEIsNkVBQTBCLEdBQUc7QUFDM0QsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0EsTUFBTSxrREFBUztBQUNmOztBQUVBO0FBQ0EsTUFBTSxvREFBVztBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87OztBQUdQLDBCQUEwQiwyREFBa0I7QUFDNUMsOEJBQThCO0FBQzlCOztBQUVBO0FBQ0E7QUFDQSw4QkFBOEIsNkVBQTBCLEdBQUc7QUFDM0Q7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQSxLQUFLLEdBQUc7O0FBRVIsMkJBQTJCLDJEQUFrQjtBQUM3Qyw4QkFBOEI7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSwrQ0FBK0MsRUFBRSw2REFBZTtBQUNoRTtBQUNBO0FBQ0Esb0JBQW9CLDBEQUFpQjtBQUNyQyxTQUFTO0FBQ1Q7QUFDQSxLQUFLLEdBQUc7O0FBRVIsd0JBQXdCLDJEQUFrQjtBQUMxQyw4QkFBOEI7O0FBRTlCO0FBQ0E7QUFDQSx3Q0FBd0M7QUFDeEMsOEJBQThCLDZFQUEwQjtBQUN4RCxTQUFTO0FBQ1Q7O0FBRUE7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDRDQUE0QywwRUFBbUI7O0FBRS9EO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLHdEQUFhO0FBQ3pCO0FBQ0EsVUFBVTtBQUNWLGdDQUFnQywwRUFBbUI7QUFDbkQsVUFBVTtBQUNWO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBLHVJQUF1SSwyRUFBb0I7QUFDM0o7O0FBRUEseUVBQXlFLG9FQUFjO0FBQ3ZGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLDRFQUFxQixDQUFDLHNEQUFhO0FBQzVELDBCQUEwQiw2RUFBc0I7QUFDaEQ7QUFDQTtBQUNBLFFBQVEsc0VBQWE7QUFDckI7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCxrRUFBa0UseURBQWM7QUFDaEY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsOERBQXFCLEdBQUcsK0RBQXNCO0FBQzVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0EsUUFBUSxzRUFBYTtBQUNyQjtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSwyQ0FBMkMscUVBQWU7QUFDMUQsa0JBQWtCLG9EQUFnQjtBQUNsQztBQUNBO0FBQ0Esc0NBQXNDLDhFQUFtQjtBQUN6RCxXQUFXO0FBQ1g7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBOztBQUVBLE1BQU0sb0RBQVc7QUFDakI7QUFDQTtBQUNBO0FBQ0EsUUFBUSxFQUFFLG9FQUEyQjtBQUNyQywrQkFBK0IsNkRBQW1COztBQUVsRDtBQUNBO0FBQ0EsOENBQThDLHNFQUE0Qjs7QUFFMUU7QUFDQSxtRUFBbUUsY0FBYyx5RUFBK0I7QUFDaEg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBOztBQUVBLE1BQU0sb0RBQVc7O0FBRWpCLGlCQUFpQixvREFBZ0I7QUFDakM7O0FBRUEsWUFBWSx5RUFBbUI7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBOztBQUVBLDBCQUEwQix5RkFBa0M7O0FBRTVEO0FBQ0EsY0FBYyx5RUFBbUIsZ0JBQWdCLHNEQUFhLCtCQUErQiw4RkFBeUM7QUFDdEksNkJBQTZCLHlFQUFrQjtBQUMvQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDJEQUEyRCx1RUFBa0I7QUFDN0UsT0FBTztBQUNQOztBQUVBO0FBQ0EsOEJBQThCLGtEQUFVOztBQUV4QztBQUNBLHlDQUF5QywyREFBa0I7QUFDM0Q7QUFDQTs7QUFFQSxvQ0FBb0Msb0VBQTJCO0FBQy9ELDZDQUE2Qyx1RUFBa0I7QUFDL0Qsa0NBQWtDLG9FQUEyQjtBQUM3RCwyQ0FBMkMsdUVBQWtCOztBQUU3RDtBQUNBOztBQUVBO0FBQ0EsZ0JBQWdCLHlEQUFhO0FBQzdCOztBQUVBO0FBQ0EsMEJBQTBCLGtEQUFTLENBQUMsOERBQXFCO0FBQ3pELGdFQUFnRTtBQUNoRTtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBLDJCQUEyQix1REFBVztBQUN0Qyw4REFBOEQ7O0FBRTlEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzRUFBc0Usd0RBQWU7QUFDckY7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBOztBQUVBO0FBQ0EsdUJBQXVCLG9EQUFTO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QixzREFBVztBQUNwQztBQUNBLHVDQUF1QywwREFBaUI7QUFDeEQ7QUFDQSw0QkFBNEIsNkRBQWU7QUFDM0M7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUEsZ0VBQWdFLDREQUFnQjtBQUNoRjtBQUNBOztBQUVBLHNDQUFzQyx5REFBZ0I7QUFDdEQ7O0FBRUE7QUFDQTtBQUNBLFVBQVUsb0RBQVc7QUFDckIsVUFBVTtBQUNWLFVBQVUsMERBQWlCO0FBQzNCO0FBQ0E7O0FBRUEsMkJBQTJCLG9FQUEyQjtBQUN0RDtBQUNBO0FBQ0E7QUFDQSxRQUFROztBQUVSLHlDQUF5QywwRUFBOEI7QUFDdkU7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLGlFQUFxQjtBQUNqQztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBLHFDQUFxQyxnR0FBcUM7O0FBRTFFO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxvREFBUztBQUNuQjtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDs7QUFFQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0EsVUFBVSxvREFBUztBQUNuQjtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBOztBQUVBLFVBQVUsMEVBQW9CO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTs7QUFFVixZQUFZLHNFQUFnQjtBQUM1QjtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxRQUFRLDBEQUFpQjs7QUFFekI7QUFDQTtBQUNBO0FBQ0EsY0FBYyxrREFBVSx3RUFBd0UsK0RBQXNCO0FBQ3RILFlBQVksc0VBQWE7QUFDekI7QUFDQSxhQUFhO0FBQ2IsWUFBWTtBQUNaLFlBQVksa0RBQVMseUJBQXlCLDREQUFtQixHQUFHO0FBQ3BFO0FBQ0E7QUFDQSxVQUFVLG9EQUFvRCxrREFBVSx5RkFBeUYsK0RBQXNCO0FBQ3ZMLFVBQVUsa0RBQVMseUJBQXlCLDREQUFtQjtBQUMvRCxVQUFVLHNFQUFhO0FBQ3ZCO0FBQ0EsV0FBVztBQUNYLFVBQVU7QUFDVixpQ0FBaUMsb0RBQVkscUNBQXFDLG9EQUFnQjtBQUNsRztBQUNBO0FBQ0E7O0FBRUEsY0FBYyxxRUFBNkI7QUFDM0M7QUFDQTtBQUNBO0FBQ0EsY0FBYyxFQUFFLHlFQUE4QjtBQUM5QztBQUNBO0FBQ0E7O0FBRUEsY0FBYyxtREFBVztBQUN6QixZQUFZLGtEQUFTLHlCQUF5Qiw0REFBbUI7QUFDakUsWUFBWTs7O0FBR1osVUFBVSxzRUFBYTtBQUN2QjtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsK0NBQStDLDRFQUFpQzs7QUFFaEY7QUFDQSxVQUFVLGtEQUFTLHlCQUF5QixzRUFBMkI7QUFDdkU7QUFDQTtBQUNBLFFBQVE7QUFDUixvQ0FBb0MsMkVBQWdDLENBQUMsMERBQWU7O0FBRXBGO0FBQ0EsVUFBVSxrREFBUyx5QkFBeUIsc0VBQTJCO0FBQ3ZFO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLFVBQVUsMERBQWM7QUFDeEI7QUFDQTs7QUFFQTtBQUNBLFFBQVEsa0RBQVMseUJBQXlCLDREQUFtQjtBQUM3RCxRQUFRLHlFQUFvQjtBQUM1QixRQUFRO0FBQ1IsUUFBUSx3RUFBbUI7O0FBRTNCLDhDQUE4Qyx5RUFBbUI7QUFDakU7QUFDQTtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1YsVUFBVSxrREFBUyx5QkFBeUIsd0RBQWEsZUFBZSx5REFBZ0IsR0FBRyw4REFBcUI7QUFDaEgsVUFBVTtBQUNWLFVBQVUsa0RBQVMseUJBQXlCLHlEQUFnQjtBQUM1RCxVQUFVO0FBQ1YsVUFBVSxrREFBUyx5QkFBeUIseURBQWdCO0FBQzVELFVBQVU7QUFDVjtBQUNBLFVBQVU7QUFDVixlQUFlLG9EQUFnQjtBQUMvQjtBQUNBLDhCQUE4Qix5RUFBbUI7QUFDakQsY0FBYyxrREFBUyx5QkFBeUIsNERBQW1CO0FBQ25FO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlO0FBQ2YsY0FBYztBQUNkLGNBQWMsa0RBQVMseUJBQXlCLHlEQUFnQjs7QUFFaEU7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVixVQUFVLGtEQUFTLHlCQUF5Qix5REFBZ0I7QUFDNUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0EsdUJBQXVCLGtEQUFVO0FBQ2pDO0FBQ0Esb0NBQW9DO0FBQ3BDOztBQUVBO0FBQ0E7QUFDQSx1Q0FBdUM7O0FBRXZDO0FBQ0E7QUFDQSxVQUFVOzs7QUFHVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQix3RUFBa0I7O0FBRXJDO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQix1RUFBYztBQUNuQztBQUNBLGVBQWU7QUFDZjtBQUNBLFlBQVk7QUFDWixtQkFBbUIsdUVBQWM7QUFDakMsdUJBQXVCLHVFQUE4QjtBQUNyRCxhQUFhO0FBQ2I7QUFDQTs7QUFFQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPOzs7QUFHUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxrQkFBa0I7QUFDbEI7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBLDhDQUE4QztBQUM5QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsdURBQXVEO0FBQ3ZEO0FBQ0EsVUFBVSxJQUFJO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQyw2RUFBMEI7QUFDMUQ7QUFDQTtBQUNBLGFBQWEsSUFBSTtBQUNqQjtBQUNBLFNBQVM7QUFDVDtBQUNBLFFBQVE7QUFDUjtBQUNBOzs7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxxREFBcUQ7QUFDckQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0Esc0JBQXNCLHFEQUFZO0FBQ2xDO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0EsUUFBUTs7O0FBR1IsMkJBQTJCLDREQUFtQixxQkFBcUIsNkRBQW9CO0FBQ3ZGO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQTtBQUNBLFFBQVE7QUFDUjs7O0FBR0E7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBLFFBQVE7QUFDUjtBQUNBLFFBQVEsa0RBQVMseUJBQXlCLDhEQUFxQixHQUFHOztBQUVsRTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUUsb0VBQTJCO0FBQ3ZDLFFBQVEsc0VBQWE7QUFDckI7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQSxRQUFRO0FBQ1I7QUFDQSxVQUFVLDBEQUFpQjtBQUMzQixVQUFVO0FBQ1YsVUFBVSxrREFBUyx5QkFBeUIseURBQWdCO0FBQzVEO0FBQ0EsUUFBUTtBQUNSO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxnQ0FBZ0MsMkRBQWtCO0FBQ2xELGdDQUFnQyx5REFBZ0I7QUFDaEQsZ0NBQWdDLHNEQUFhO0FBQzdDLGdDQUFnQyxvREFBVztBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsMkJBQTJCLG9FQUEyQjtBQUN0RDtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7O0FBRUEsWUFBWSx5RUFBbUI7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSwrRUFBK0UsMkVBQXNCO0FBQ3JHO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUUsK0RBQXNCO0FBQ25DO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87OztBQUdQO0FBQ0EsNERBQTRELDZEQUFvQixxQkFBcUIsNERBQW1CLHNCQUFzQiw0REFBZ0IsZ0RBQWdELHdEQUFhO0FBQzNOO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLGtEQUFTLHlCQUF5Qiw2REFBb0I7QUFDNUQ7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSLDRCQUE0QixvRUFBMkI7QUFDdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw4Q0FBOEMsb0RBQVc7QUFDekQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBLGdEQUFnRCxvREFBVztBQUMzRCx5Q0FBeUMseURBQWdCO0FBQ3pELGFBQWE7QUFDYjs7QUFFQSx5Q0FBeUMsb0RBQVc7QUFDcEQsa0NBQWtDLHlEQUFnQjtBQUNsRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTztBQUNQLHVCQUF1QiwyREFBa0I7QUFDekM7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxrREFBUyx5QkFBeUIseURBQWdCO0FBQzlELFlBQVk7QUFDWixZQUFZLDBEQUFpQjtBQUM3QjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxtQ0FBbUMsMkRBQWtCO0FBQ3JELG1DQUFtQyx5REFBZ0I7QUFDbkQsbUNBQW1DLG1EQUFVO0FBQzdDO0FBQ0EsT0FBTztBQUNQLDhCQUE4QixtREFBVTtBQUN4Qyw4QkFBOEIsMkRBQWtCO0FBQ2hEO0FBQ0EsT0FBTztBQUNQLDhCQUE4Qix5REFBZ0I7QUFDOUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEIsNkVBQTBCLEdBQUc7QUFDM0QsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxpREFBaUQsNEVBQWlDOztBQUVsRjtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBLFVBQVU7QUFDViwrQ0FBK0MsMkVBQWdDLENBQUMsMERBQWU7QUFDL0Y7O0FBRUE7QUFDQTtBQUNBLDJDQUEyQyxxREFBWSxDQUFDLDREQUFpQjs7QUFFekUsK0NBQStDLHFFQUFlO0FBQzlELHFEQUFxRCxrRUFBdUI7QUFDNUU7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBLHdCQUF3QixnR0FBcUM7O0FBRTdEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxlQUFlOztBQUVmO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7OztBQUdaOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhOztBQUViO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjs7O0FBR0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esa0NBQWtDLDZFQUEwQjtBQUM1RDtBQUNBLGVBQWU7QUFDZixhQUFhLEdBQUc7QUFDaEIsWUFBWTtBQUNaO0FBQ0Esc0JBQXNCLG9EQUFnQjtBQUN0QztBQUNBO0FBQ0E7O0FBRUEsdUVBQXVFLEVBQUUscUVBQTJCO0FBQ3BHO0FBQ0EsZUFBZSxJQUFJOztBQUVuQjtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQSxnREFBZ0QsMERBQWdCO0FBQ2hFO0FBQ0Esc0NBQXNDLDZFQUEwQixHQUFHO0FBQ25FLHNDQUFzQztBQUN0QztBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBLCtFQUErRTtBQUMvRTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixHQUFHOztBQUV0QjtBQUNBLG9CQUFvQix5REFBZ0I7QUFDcEM7QUFDQSxxQkFBcUI7QUFDckIsb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0I7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyRUFBMkUsNERBQWtCOztBQUU3RjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMERBQTBELDREQUFrQjtBQUM1RTtBQUNBLDJCQUEyQjtBQUMzQjtBQUNBLHVCQUF1QjtBQUN2QjtBQUNBOztBQUVBLHVEQUF1RCxFQUFFLHlFQUErQjtBQUN4RjtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CLDJEQUEyRCx5RUFBbUI7QUFDOUUsbUJBQW1CO0FBQ25CLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsd0RBQWE7QUFDdkI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sR0FBRzs7QUFFVixzQkFBc0IseUZBQWtDOztBQUV4RCxVQUFVLHlFQUFtQjtBQUM3QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLE1BQU0sb0RBQVc7O0FBRWpCO0FBQ0E7QUFDQSxzQkFBc0IseURBQWdCO0FBQ3RDO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQSw2QkFBNkIsb0RBQVk7QUFDekM7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLHNCQUFzQix3RUFBa0I7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLHVEQUF1RDtBQUN2RDtBQUNBO0FBQ0EsOEJBQThCLDZFQUEwQjtBQUN4RDtBQUNBLE9BQU87QUFDUDtBQUNBLE1BQU0sc0VBQWE7QUFDbkI7QUFDQTtBQUNBLE9BQU87QUFDUCwyQkFBMkIsOEVBQTJCO0FBQ3REO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCxPQUFPOzs7QUFHUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQSw2QkFBNkIsb0RBQVksc0ZBQXNGLG9EQUFnQjtBQUMvSSx3QkFBd0Isa0VBQVk7O0FBRXBDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQSxzQkFBc0IsMEVBQW9CO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUEsNkJBQTZCLG9EQUFZLHNGQUFzRixvREFBZ0I7QUFDL0k7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLHNCQUFzQiwwREFBZTtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxjQUFjOztBQUV4Qiw0Q0FBNEMsbURBQVc7QUFDdkQsVUFBVSxzRUFBYTtBQUN2QjtBQUNBLFdBQVc7QUFDWCwyQ0FBMkMsb0RBQWM7QUFDekQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsZ0JBQWdCOztBQUUxQixvRUFBb0Usa0RBQVUsaUhBQWlILCtEQUFzQjtBQUNyTiwyQ0FBMkMsb0RBQWM7QUFDekQ7QUFDQTs7QUFFQTtBQUNBLDhCQUE4Qiw2RUFBMEIsK0JBQStCO0FBQ3ZGO0FBQ0EsV0FBVztBQUNYLFNBQVMsSUFBSTtBQUNiOztBQUVBLFFBQVEsc0VBQWE7QUFDckI7QUFDQSxTQUFTO0FBQ1QsUUFBUSxrREFBUyx5QkFBeUIsNERBQW1CO0FBQzdELFFBQVE7QUFDUiwrQkFBK0Isb0RBQVksNkRBQTZELG9EQUFnQjtBQUN4SDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0Esd0JBQXdCLDJEQUFnQjtBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLHNFQUE2QjtBQUMvQyxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSx5REFBeUQ7QUFDekQ7QUFDQTtBQUNBLGdDQUFnQyw2RUFBMEI7QUFDMUQ7QUFDQSxTQUFTO0FBQ1QsUUFBUSxzRUFBYTtBQUNyQjtBQUNBLFNBQVM7QUFDVCw2QkFBNkIsOEVBQTJCO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsNkJBQTZCLG9EQUFZLDRIQUE0SCxvREFBZ0I7QUFDckw7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGtCQUFrQiwwRUFBb0I7QUFDdEM7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1Isa0JBQWtCLHFEQUFVO0FBQzVCO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSw2QkFBNkIsb0RBQVksNEhBQTRILG9EQUFnQjtBQUNyTCxvQkFBb0IscUVBQWU7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPLEVBQUUsb0RBQVc7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsdUVBQWM7QUFDL0I7QUFDQSxXQUFXO0FBQ1gsVUFBVSxTQUFTLHdFQUFrQjtBQUNyQyxpQkFBaUIsdUVBQWM7QUFDL0I7QUFDQSxXQUFXO0FBQ1gsVUFBVTtBQUNWLGlCQUFpQix1RUFBYztBQUMvQjtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQix1RUFBYztBQUMvQjtBQUNBLFdBQVc7QUFDWCxVQUFVLFNBQVMsd0VBQWtCO0FBQ3JDLGlCQUFpQix1RUFBYztBQUMvQjtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1YsaUJBQWlCLHVFQUFjO0FBQy9CO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCwwQkFBMEI7QUFDMUI7OztBQUdBLFdBQVcsaUVBQW9CO0FBQy9CLHdCQUF3Qix5Q0FBQztBQUN6Qjs7QUFFQTtBQUNBLE1BQU0sa0RBQVM7O0FBRWYsdUJBQXVCLHVEQUFjO0FBQ3JDO0FBQ0Esc0JBQXNCLDREQUFlLE9BQU8sNkRBQVk7QUFDeEQsVUFBVTtBQUNWO0FBQ0EsMEJBQTBCLHlDQUFDO0FBQzNCO0FBQ0EsUUFBUTtBQUNSOzs7QUFHQSx1SUFBdUksK0RBQWtCOztBQUV6SjtBQUNBO0FBQ0Esd0JBQXdCLHlDQUFDO0FBQ3pCOztBQUVBOztBQUVBO0FBQ0E7QUFDQSw0QkFBNEIsNERBQWU7QUFDM0MsOEJBQThCLDBFQUFpQztBQUMvRCxXQUFXO0FBQ1gsVUFBVTtBQUNWO0FBQ0E7O0FBRUEsNkJBQTZCLCtEQUFzQjtBQUNuRCwwQkFBMEIseUNBQUM7QUFDM0Isd0JBQXdCLFdBQVcsK0RBQXNCLGdCQUFnQjtBQUN6RSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBLG1HQUFtRztBQUNuRztBQUNBOztBQUVBLHVDQUF1QywwREFBYTtBQUNwRDtBQUNBOztBQUVBLDRHQUE0Ryx1REFBVTtBQUN0SCwyQkFBMkIsc0VBQWE7QUFDeEM7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBLHFEQUFxRDtBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsVUFBVTtBQUNWO0FBQ0EsMkJBQTJCLHlDQUFDO0FBQzVCLFVBQVU7QUFDVjtBQUNBLFlBQVksb0RBQVc7QUFDdkI7QUFDQTtBQUNBLE9BQU87QUFDUCxLQUFLO0FBQ0w7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTtBQUNSLFFBQVEsc0VBQWE7QUFDckI7QUFDQSxTQUFTO0FBQ1QseUNBQXlDLG9EQUFjO0FBQ3ZEO0FBQ0EseUNBQXlDLHlDQUFDO0FBQzFDLFNBQVM7QUFDVDtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsNERBQWU7QUFDaEQ7QUFDQSxPQUFPO0FBQ1AsaUNBQWlDLHVEQUFVLGdCQUFnQjtBQUMzRDs7QUFFQSw2QkFBNkIsdURBQWM7QUFDM0MsMEJBQTBCLHFFQUFvQjtBQUM5QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsdURBQWM7QUFDeEQ7O0FBRUE7QUFDQSxRQUFRLGtEQUFTLGdDQUFnQyxlQUFlO0FBQ2hFO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsRUFBRSxvRUFBMkI7QUFDdkM7QUFDQTtBQUNBLFNBQVM7QUFDVCxnQ0FBZ0MsMkRBQVE7QUFDeEM7QUFDQSxrQ0FBa0MseURBQWdCO0FBQ2xELFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLDZFQUEwQjtBQUMxRDtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1gsNkNBQTZDLG9EQUFjO0FBQzNELFdBQVc7QUFDWCxVQUFVO0FBQ1Y7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQix5REFBZ0I7QUFDdEM7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNULDJDQUEyQyxvREFBYztBQUN6RCxTQUFTO0FBQ1Q7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUEsb0JBQW9CLCtFQUF5Qjs7QUFFN0M7QUFDQSxpQ0FBaUMsMkRBQWtCLGtEQUFrRCwyREFBa0I7QUFDdkg7QUFDQSxVQUFVLHNFQUFhO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCLDJEQUFrQixrREFBa0QsMkRBQWtCO0FBQ2pILGtFQUFrRTs7QUFFbEU7QUFDQTtBQUNBLDJFQUEyRTtBQUMzRTs7QUFFQTtBQUNBO0FBQ0EsUUFBUSxzRUFBYTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLFFBQVEsaUVBQWlCO0FBQ2pDO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0EsWUFBWSxvRUFBaUI7QUFDN0I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxjQUFjLCtFQUF5QjtBQUN2QyxtQkFBbUIsdUVBQWM7QUFDakM7QUFDQSxhQUFhO0FBQ2I7O0FBRUE7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7OztBQUdBLHFEQUFxRCw0RUFBMkI7QUFDaEY7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVTs7QUFFVjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOzs7QUFHQSxnQ0FBZ0MsdURBQVE7QUFDeEM7QUFDQSxLQUFLLEVBQUUsNkRBQW9COztBQUUzQjtBQUNBLGtDQUFrQyxxRkFBa0M7O0FBRXBFO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0EscUNBQXFDLDhFQUEyQjtBQUNoRTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx1Q0FBdUMsOEVBQTJCOztBQUVsRSwrQ0FBK0MsdUZBQW9DO0FBQ25GO0FBQ0E7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBLHNCQUFzQjs7O0FBR3RCO0FBQ0EseUNBQXlDO0FBQ3pDO0FBQ0E7QUFDQTs7QUFFQSxnREFBZ0Qsb0RBQVc7QUFDM0QsZ0RBQWdELDBEQUFpQjtBQUNqRSxnREFBZ0Qsd0RBQWUsb0JBQW9CO0FBQ25GLFFBQVE7QUFDUixrR0FBa0csb0RBQVc7QUFDN0csa0dBQWtHLDBEQUFpQjtBQUNuSCxrR0FBa0csd0RBQWU7QUFDakg7QUFDQTs7QUFFQTtBQUNBLDBCQUEwQjs7O0FBRzFCO0FBQ0E7QUFDQTtBQUNBLFFBQVEsUUFBUSw2REFBZ0I7QUFDaEM7QUFDQTtBQUNBO0FBQ0EsUUFBUSxFQUFFLG9FQUEyQjs7QUFFckM7QUFDQSxZQUFZLGlFQUFvQjtBQUNoQztBQUNBO0FBQ0EsMEVBQTBFLHVEQUFjLGdFQUFnRSx1REFBYztBQUN0SztBQUNBLGtDQUFrQyxvREFBWTtBQUM5QyxrRUFBa0U7QUFDbEUsd0RBQXdEO0FBQ3hEO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQyw2RUFBMEI7QUFDMUQ7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBLHFEQUFxRCxpRUFBd0I7O0FBRTdFO0FBQ0E7QUFDQSwrQkFBK0IsNkRBQWdCO0FBQy9DO0FBQ0Esc0JBQXNCLGtGQUFrQztBQUN4RDtBQUNBO0FBQ0EsV0FBVztBQUNYLFVBQVU7QUFDVjtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsNEVBQXNCLHNHQUFzRyxrRUFBWTtBQUM1SjtBQUNBO0FBQ0E7QUFDQSxrQkFBa0IseURBQWE7QUFDL0IsV0FBVzs7QUFFWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQSxtQkFBbUIsMERBQWE7O0FBRWhDO0FBQ0EsMEJBQTBCLHVFQUEwQjs7QUFFcEQseUJBQXlCLDhEQUFxQjtBQUM5QztBQUNBO0FBQ0EsV0FBVztBQUNYLDhEQUE4RDtBQUM5RCxvREFBb0Q7QUFDcEQ7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBLFdBQVc7QUFDWCxVQUFVLHNCQUFzQixpRUFBd0I7QUFDeEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBLDRCQUE0Qix5Q0FBQztBQUM3QixhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBLHVCQUF1QixpRUFBd0I7QUFDL0M7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLEVBQUUsb0VBQTJCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxNQUFNLHNEQUFVO0FBQ2hCLGtEQUFrRCxzR0FBc0csZUFBZSx5RUFBK0I7QUFDdE07QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsK0JBQStCLHFFQUFlLGdCQUFnQiw4RUFBbUI7QUFDakYsT0FBTztBQUNQO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxPQUFPO0FBQ1A7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFFBQVEseURBQWMsc0lBQXNJLGlEQUFRLDhDQUE4QyxpREFBUSw4Q0FBOEMsaUVBQXlCLFNBQVMsOERBQXNCO0FBQ2hVLFFBQVE7QUFDUiw2QkFBNkIsb0RBQVkseUNBQXlDLG9EQUFnQjtBQUNsRyxzQkFBc0IsK0VBQXlCO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUUsMERBQWM7QUFDMUI7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULFFBQVEseURBQWMsOEhBQThILGlEQUFRLDBDQUEwQyxpREFBUSwwQ0FBMEMsb0VBQWMscUJBQXFCLGlFQUF5QixVQUFVLGlFQUF5QixTQUFTLDhEQUFzQjtBQUN0WCwyREFBMkQ7O0FBRTNEO0FBQ0E7QUFDQSxpQ0FBaUMsbUVBQTBCO0FBQzNELFdBQVc7QUFDWDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0EsK0JBQStCLG9EQUFZLCtHQUErRyxvREFBZ0I7QUFDMUs7QUFDQTtBQUNBLGdDQUFnQyx5REFBZ0I7QUFDaEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNULE9BQU8sR0FBRztBQUNWOztBQUVBO0FBQ0EsK0JBQStCLG9EQUFZLHlDQUF5QyxvREFBZ0I7QUFDcEc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLGdFQUFvQixtQkFBbUIsNERBQW1CO0FBQ3RFO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBLFVBQVUsNERBQWlCLGtHQUFrRyxxRUFBNkIsU0FBUyw4REFBc0IsMENBQTBDLG9FQUFjLHlCQUF5QixpRUFBeUIsVUFBVSxpRUFBeUI7QUFDdFU7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLHlEQUFnQixnREFBZ0Q7O0FBRWxHO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdCQUFnQixzRUFBYTtBQUM3QjtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCLGVBQWU7QUFDZjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsZ0JBQWdCLHNFQUFhO0FBQzdCO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakIsZUFBZTtBQUNmO0FBQ0E7O0FBRUEsVUFBVSxtRUFBMEI7QUFDcEMsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxtQkFBbUIscURBQWUsRUFBRSxxREFBZSxHQUFHO0FBQ3REOztBQUVBO0FBQ0E7QUFDQSw4QkFBOEIsMERBQW9CLEVBQUUseURBQW1CLEVBQUUsZ0ZBQW9CLEVBQUUsdURBQWlCO0FBQ2hIOztBQUVBLGdCQUFnQixrRUFBVyxFQUFFLGlFQUFzQixFQUFFLHFEQUFlLEVBQUUscURBQWUsRUFBRSw4Q0FBUSxFQUFFLGlFQUFzQixFQUFFLHFEQUFlLEVBQUUsZ0ZBQXVCLEVBQUUsaUVBQXNCLEVBQUUsMERBQW9CLEVBQUUsaUVBQTJCLEVBQUUseURBQW1CLEVBQUUsZ0ZBQW9CLEVBQUUsdURBQWlCO0FBQzFTLFFBQVE7QUFDUjs7O0FBR0EsbUJBQW1CLDhDQUFROztBQUUzQjtBQUNBLGdCQUFnQixnREFBVTtBQUMxQjs7QUFFQSxjQUFjLCtDQUFTLEVBQUUsZ0RBQVUsRUFBRSxrRUFBVyxFQUFFLGlGQUE4QixFQUFFLG1GQUFnQyxFQUFFLGlFQUFzQixjQUFjLGlFQUFzQixFQUFFLHNEQUFnQixFQUFFLHVEQUFpQixFQUFFLGlFQUFzQixFQUFFLGlEQUFXLEVBQUUsc0RBQWdCLEVBQUUsb0RBQWMsRUFBRSxnRkFBeUIsRUFBRSxtREFBYSxFQUFFLGlFQUFzQixFQUFFLHdEQUFrQixFQUFFLGlFQUFzQixFQUFFLHdEQUFrQixFQUFFLHdEQUFrQixFQUFFLHNEQUFnQixFQUFFLHdEQUFrQixFQUFFLGlFQUFzQixFQUFFLDBEQUFvQixFQUFFLHdEQUFrQixFQUFFLGlFQUFzQixFQUFFLDhEQUF3QixFQUFFLGdEQUFVLEVBQUUsOERBQXdCLEVBQUUsNkRBQXVCLEVBQUUsaUVBQXNCLEVBQUUsMERBQW9CO0FBQ3ZyQjs7QUFFQSx1QkFBdUIsMkRBQWtCO0FBQ3pDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLFNBQVM7O0FBRWpCO0FBQ0E7QUFDQSx5QkFBeUIsa0RBQVM7QUFDbEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsMkRBQTJEOztBQUUzRDtBQUNBO0FBQ0Esb0VBQW9FLEVBQUUsNkRBQWU7QUFDckY7QUFDQTtBQUNBLG9CQUFvQiwwREFBaUI7QUFDckMsU0FBUztBQUNUO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxRQUFROzs7QUFHUjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUCxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLHNCQUFzQixvRUFBMkI7QUFDakQ7QUFDQTtBQUNBLE9BQU87O0FBRVAsaURBQWlEO0FBQ2pEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBLCtDQUErQyxpREFBUTtBQUN2RDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7O0FBRVY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQSxvQ0FBb0M7QUFDcEM7O0FBRUEsNEJBQTRCLDhEQUFrQjtBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOLDJFQUEyRTtBQUMzRTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxrREFBUztBQUMzQztBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsY0FBYywrQ0FBTTtBQUNwQix1QkFBdUIsc0RBQU87QUFDOUIscUJBQXFCLHFEQUFLO0FBQzFCO0FBQ0EsY0FBYyxnRUFBWTtBQUMxQix3QkFBd0Isc0RBQVE7O0FBRWhDO0FBQ0EsZ0pBQWdKLDBEQUFpQjtBQUNqSztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLGdEQUFLO0FBQzFCO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsdUJBQXVCLGlEQUFPO0FBQzlCLDZCQUE2QiwyREFBYTtBQUMxQyxtQ0FBbUMsc0RBQU87QUFDMUMsc0NBQXNDLHdFQUFnQjtBQUN0RCxzQ0FBc0Msd0VBQWdCO0FBQ3REOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDRCQUE0Qix1REFBYztBQUMxQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLE9BQU87QUFDUCxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSw2Q0FBNkMsaUVBQXdCO0FBQ3JFO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBLGFBQWEsK0RBQXNCO0FBQ25DLGFBQWEsaUVBQXdCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0VBQStFLHlFQUFtQjtBQUNsRyxXQUFXLHNEQUFJLENBQUMsdURBQVM7QUFDekI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUUsb0VBQTJCO0FBQ3ZDO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsMEJBQTBCLGtFQUFZLENBQUMsc0RBQVU7QUFDakQsMEJBQTBCLDBFQUFtQjtBQUM3QztBQUNBO0FBQ0EsZUFBZSxzREFBSTtBQUNuQixxQkFBcUIsZ0RBQUk7QUFDekI7QUFDQSxXQUFXO0FBQ1g7QUFDQSxnREFBZ0QsMEJBQTBCLE1BQU0seUJBQXlCLFlBQVksTUFBTTtBQUMzSDtBQUNBO0FBQ0Esd0NBQXdDLHVEQUFlLG9DQUFvQztBQUMzRjtBQUNBLFNBQVM7QUFDVCxvQkFBb0IsdURBQUs7QUFDekI7QUFDQTs7QUFFQSxtQkFBbUI7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0Q0FBNEMsR0FBRztBQUMvQztBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQSxvQ0FBb0MsU0FBUztBQUM3QyxxQ0FBcUMsVUFBVTtBQUMvQywrQ0FBK0MsU0FBUztBQUN4RCx3Q0FBd0MsK0RBQXNCLEdBQUcsZ0VBQXVCO0FBQ3hGO0FBQ0EsV0FBVztBQUNYLG9DQUFvQyxzREFBSTtBQUN4QztBQUNBLGFBQWE7QUFDYix3QkFBd0IseUNBQUM7QUFDekIsYUFBYSxJQUFJLHNEQUFJO0FBQ3JCO0FBQ0E7QUFDQSw0QkFBNEIsZUFBZTtBQUMzQztBQUNBLGFBQWE7QUFDYiwyS0FBMkssc0RBQUk7QUFDL0s7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxVQUFVLGlCQUFpQixpQkFBaUIsV0FBVztBQUM5RjtBQUNBO0FBQ0EsZUFBZTtBQUNmLGFBQWE7QUFDYixXQUFXO0FBQ1gsU0FBUztBQUNULE9BQU87QUFDUCxLQUFLO0FBQ0w7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxXQUFXLHNEQUFJO0FBQ2YsaUJBQWlCLGdEQUFJO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLHlKQUF5Six3REFBYSw4QkFBOEIsZ0VBQXVCLEdBQUcsK0RBQXNCO0FBQ3BQLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxnQkFBZ0Isc0RBQUk7QUFDcEI7QUFDQSxPQUFPO0FBQ1Asa0JBQWtCLHNEQUFJO0FBQ3RCO0FBQ0EsU0FBUztBQUNULG9CQUFvQixzREFBSTtBQUN4QjtBQUNBLFdBQVc7QUFDWCxzQkFBc0Isc0RBQUk7QUFDMUI7QUFDQSxhQUFhO0FBQ2Isd0JBQXdCLHNEQUFJO0FBQzVCO0FBQ0EsZUFBZTtBQUNmLDBCQUEwQixzREFBSTtBQUM5QjtBQUNBLGlCQUFpQjtBQUNqQiw0QkFBNEIsdURBQUs7QUFDakM7QUFDQSxtQkFBbUI7QUFDbkIsK0JBQStCLHVEQUFLO0FBQ3BDO0FBQ0EscUJBQXFCO0FBQ3JCLGlDQUFpQyxzREFBSSxDQUFDLGlEQUFPO0FBQzdDLG9GQUFvRjtBQUNwRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxtREFBVztBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCO0FBQ3ZCO0FBQ0EsdUJBQXVCLElBQUksc0RBQUk7QUFDL0I7QUFDQSx1QkFBdUIsR0FBRyxzREFBSTtBQUM5QjtBQUNBLHVCQUF1QixHQUFHLHNEQUFJO0FBQzlCO0FBQ0EsdUJBQXVCLGdHQUFnRyxzREFBSSxDQUFDLDBEQUFTO0FBQ3JJO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLHdEQUF3RCxzREFBSSxDQUFDLDBDQUFLO0FBQ3pGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLDZCQUE2QixzREFBSSxDQUFDLHNEQUFXO0FBQ3BFO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLEdBQUcsc0RBQUksQ0FBQyxvREFBWTtBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLEdBQUcsc0RBQUksQ0FBQyx5REFBaUI7QUFDaEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCO0FBQ3ZCLHFCQUFxQjtBQUNyQixtQkFBbUI7QUFDbkIsaUJBQWlCO0FBQ2pCLGVBQWU7QUFDZixhQUFhO0FBQ2IsV0FBVztBQUNYLFNBQVM7QUFDVCxPQUFPO0FBQ1AsS0FBSztBQUNMOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLFVBQVUsYUFBb0IsS0FBSyxpREFBUSxJQUFJLGFBQW9CO0FBQ25FO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sa0RBQVM7QUFDaEI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdFQUF3RTtBQUN4RTs7QUFFQTtBQUNBLFNBQVM7QUFDVDtBQUNBLFFBQVE7QUFDUiwrREFBK0QsOERBQXFCLENBQUMsb0JBQW9CLGdFQUF1QixDQUFDLHNCQUFzQiwrREFBc0IsQ0FBQztBQUM5SywrREFBK0Qsd0RBQWUsQ0FBQztBQUMvRSwrRUFBK0U7QUFDL0U7QUFDQSw4R0FBOEcsbUVBQTBCLENBQUM7O0FBRXpJO0FBQ0E7QUFDQSx3QkFBd0IscURBQVk7QUFDcEM7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0EsUUFBUTs7O0FBR1IsVUFBVSxvREFBTyxPQUFPLDZFQUFzQjtBQUM5QztBQUNBLHdCQUF3QixzREFBSSxDQUFDLCtEQUFxQixJQUFJO0FBQ3RELFNBQVM7QUFDVDtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBOztBQUVBO0FBQ0EscUJBQXFCLHFEQUFLO0FBQzFCLHdCQUF3QixzREFBUTtBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUksa0VBQWtCO0FBQ3RCLElBQUkseURBQWlCO0FBQ3JCLElBQUksMEVBQWdCO0FBQ3BCO0FBQ0EscUJBQXFCLHFEQUFLO0FBQzFCLHVCQUF1QixpREFBTztBQUM5Qiw2QkFBNkIsMkRBQWE7QUFDMUMsdUJBQXVCLHNEQUFPLFFBQVE7O0FBRXRDO0FBQ0EsbUNBQW1DOztBQUVuQyxvQkFBb0I7O0FBRXBCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSSxxRUFBZ0M7QUFDcEMsSUFBSSxnRkFBMEM7QUFDOUM7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGlDQUFpQyx5REFBZ0I7QUFDakQsaUNBQWlDLG1EQUFVO0FBQzNDLGlDQUFpQyxvREFBVztBQUM1QyxpQ0FBaUMsa0RBQVM7QUFDMUMsMkdBQTJHLG9EQUFXO0FBQ3RILHVHQUF1RyxxREFBWTtBQUNuSCxpQ0FBaUMsc0RBQWE7QUFDOUMsaUNBQWlDLHlEQUFnQjtBQUNqRCxpQ0FBaUMsb0RBQVc7QUFDNUMsK0JBQStCLHFEQUFZO0FBQzNDLCtCQUErQixxREFBWTtBQUMzQywrQkFBK0IsbURBQVU7QUFDekMsMkdBQTJHLHdEQUFlO0FBQzFILDJHQUEyRyxtREFBVTtBQUNySDtBQUNBLGlDQUFpQyw0REFBbUI7QUFDcEQsaUNBQWlDLDZEQUFvQjtBQUNyRCxpQ0FBaUMsMERBQWlCO0FBQ2xEO0FBQ0EsK0JBQStCLHNEQUFhO0FBQzVDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSw0QkFBNEIsc0RBQWE7QUFDekMsOEJBQThCLHlEQUFnQix1QkFBdUI7O0FBRXJFLDhCQUE4QixtREFBVTtBQUN4Qyx3R0FBd0csb0RBQVc7QUFDbkg7QUFDQSxLQUFLOztBQUVMO0FBQ0EsZ0NBQWdDLHNEQUFhO0FBQzdDOztBQUVBLDhCQUE4QixvREFBVztBQUN6QztBQUNBLEtBQUs7QUFDTCw4QkFBOEIseURBQWdCLHFDQUFxQzs7QUFFbkYsb0xBQW9MOztBQUVwTCw4QkFBOEIsNERBQW1CO0FBQ2pELDhCQUE4Qiw2REFBb0I7QUFDbEQsOEJBQThCLDBEQUFpQjs7QUFFL0M7QUFDQTtBQUNBOztBQUVBLDhCQUE4QixvREFBVztBQUN6Qyw4QkFBOEIsa0RBQVM7O0FBRXZDO0FBQ0Esd0NBQXdDLHNFQUE2QjtBQUNyRSx1REFBdUQscURBQVk7QUFDbkU7O0FBRUEsNEJBQTRCLHFEQUFZO0FBQ3hDLDRCQUE0QixxREFBWTtBQUN4Qyw0QkFBNEIsbURBQVU7QUFDdEMsd0dBQXdHLHdEQUFlO0FBQ3ZILHdHQUF3RyxtREFBVTtBQUNsSDs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDZEQUE2RCwwREFBYztBQUMzRTtBQUNBLG9CQUFvQix5REFBZ0I7QUFDcEM7QUFDQSxTQUFTO0FBQ1QsT0FBTztBQUNQOztBQUVBO0FBQ0EsTUFBTSx3REFBZTtBQUNyQixNQUFNOzs7QUFHTjtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQSwrQ0FBK0Msa0RBQVM7QUFDeEQsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEVBQTRFLG9EQUFjO0FBQzFGLE9BQU87QUFDUCxNQUFNO0FBQ047OztBQUdBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQSxNQUFNOztBQUVOLGtGQUFrRixtRUFBZ0IsZ0JBQWdCLHNFQUFnQjtBQUNsSSxNQUFNLHlFQUFzQix1Q0FBdUMscURBQVksQ0FBQywrR0FBb0Q7QUFDcEk7O0FBRUEsK0VBQStFO0FBQy9FO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU0sRUFBRSxvRUFBMkI7QUFDbkM7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsK0RBQXNCO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EseUJBQXlCLDJFQUFvQjs7QUFFN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Qsd0JBQXdCLHlEQUFjLCtCQUErQjtBQUNyRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxRQUFRO0FBQ1IsK0ZBQStGO0FBQy9GOztBQUVBO0FBQ0Esc0JBQXNCLHdFQUFpQjtBQUN2QztBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0EsMEJBQTBCLDZFQUEwQjtBQUNwRCxLQUFLOztBQUVMO0FBQ0E7QUFDQSxpQkFBaUIseUNBQUM7QUFDbEIsb0JBQW9CLHVEQUFjO0FBQ2xDLFNBQVM7QUFDVDtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsMENBQTBDLHdEQUFhO0FBQ3ZELGlCQUFpQiw0REFBaUI7QUFDbEM7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0EsT0FBTztBQUNQOztBQUVBLElBQUksc0RBQVc7QUFDZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUUsb0VBQTJCO0FBQ3ZDO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxPQUFPO0FBQ1AsZ0JBQWdCLDJEQUFrQjtBQUNsQzs7QUFFQSxZQUFZLDhEQUFtQjtBQUMvQixVQUFVLHNFQUFtQjtBQUM3QjtBQUNBLE9BQU87QUFDUCxnQkFBZ0IsMkRBQWtCO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLHNEQUFzRDtBQUN0RDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsNkVBQTBCLCtCQUErQjtBQUN6RjtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7O0FBRUE7QUFDQSxVQUFVLDJFQUF3QjtBQUNsQzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBLFVBQVUsMERBQWlCO0FBQzNCOztBQUVBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLEtBQUssR0FBRzs7QUFFUiw2QkFBNkI7QUFDN0I7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsMEJBQTBCLDZFQUEwQixHQUFHO0FBQ3ZELDBCQUEwQjtBQUMxQjtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUwsbUJBQW1CLHdEQUFhO0FBQ2hDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxvREFBb0QsWUFBWTtBQUNoRTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtGQUFrRjtBQUNsRjs7QUFFQSxhQUFhLDJGQUFnRDtBQUM3RDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDhPQUE4Tyx3REFBYTtBQUMzUCxXQUFXLDhEQUFxQixzQkFBc0Isa0RBQU87QUFDN0Q7QUFDQSw4QkFBOEIsMkRBQWtCO0FBQ2hELHNHQUFzRyx3REFBZTtBQUNySDtBQUNBO0FBQ0EsT0FBTztBQUNQLEtBQUs7QUFDTDs7QUFFQTtBQUNBLG9CQUFvQix5RkFBOEI7QUFDbEQsNkJBQTZCLDBFQUFtQjs7QUFFaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxVQUFVLDhGQUF5QztBQUNuRCwwQkFBMEIsdUdBQTRDO0FBQ3RFLHVDQUF1QywwR0FBK0M7QUFDdEY7QUFDQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQSxVQUFVLGtEQUFTLHlCQUF5Qiw0REFBbUI7QUFDL0QsVUFBVTtBQUNWLFVBQVUsa0RBQVMseUJBQXlCLHlEQUFnQjtBQUM1RDtBQUNBLFFBQVEsU0FBUyxpRkFBcUIsMkJBQTJCLDJGQUFnRDtBQUNqSCxRQUFRLGtEQUFTLHlCQUF5Qix5REFBZ0I7QUFDMUQsUUFBUSw2QkFBNkIsa0RBQU87QUFDNUMsUUFBUSxrREFBUyx5QkFBeUIseURBQWdCO0FBQzFEOztBQUVBO0FBQ0E7QUFDQSwrREFBK0Q7QUFDL0Q7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUOztBQUVBLFdBQVcsNkZBQWtDO0FBQzdDO0FBQ0EsK0RBQStEO0FBQy9EO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBLE1BQU07QUFDTixNQUFNLGtEQUFTLHlCQUF5Qix5REFBZ0I7QUFDeEQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLDJCQUEyQixvREFBUztBQUNwQztBQUNBLGdDQUFnQyxzREFBVztBQUMzQztBQUNBOztBQUVBO0FBQ0EsbUJBQW1CLG9FQUEyQjtBQUM5QztBQUNBLHFDQUFxQywwREFBZTtBQUNwRDtBQUNBO0FBQ0EsMkJBQTJCLG9EQUFnQjtBQUMzQyxvQkFBb0IscURBQVksQ0FBQyxvREFBWSwyQkFBMkIsb0RBQWdCO0FBQ3hGLGtCQUFrQix5REFBZ0I7QUFDbEM7QUFDQSxrQ0FBa0M7QUFDbEM7QUFDQSw0QkFBNEIscUVBQWU7QUFDM0M7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLElBQUk7OztBQUdKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixvRUFBMkI7QUFDckQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMLHdCQUF3QiwyREFBa0I7QUFDMUM7QUFDQSxNQUFNLDBEQUFpQjtBQUN2QjtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxpQ0FBaUMsMkRBQWtCO0FBQ25ELGlDQUFpQyx5REFBZ0I7QUFDakQ7QUFDQSxLQUFLO0FBQ0w7QUFDQSw0QkFBNEIsMkRBQWtCO0FBQzlDLDRCQUE0Qix5REFBZ0I7QUFDNUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7O0FBR047QUFDQSw2QkFBNkIsMERBQWU7QUFDNUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSwyRUFBcUIsZ0JBQWdCLGtFQUF5QixHQUFHLHNFQUE2QjtBQUMxRyxNQUFNO0FBQ047O0FBRUE7QUFDQSxRQUFRLDZEQUFpQjtBQUN6QjtBQUNBO0FBQ0E7QUFDQSxLQUFLLDJCQUEyQix3RUFBZ0M7QUFDaEUsTUFBTSx3RUFBZ0MsQ0FBQyxrRUFBc0I7QUFDN0Q7QUFDQTs7QUFFQTtBQUNBLFFBQVEsNkRBQWlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBLEtBQUssMkJBQTJCLGdFQUF3QjtBQUN4RCxNQUFNLGdFQUF3QixDQUFDLDBEQUFjO0FBQzdDO0FBQ0E7O0FBRUE7QUFDQSxXQUFXLDJEQUFrQjtBQUM3QjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQSxXQUFXLDJEQUFrQjtBQUM3QjtBQUNBLG9CQUFvQiw0Q0FBUTs7QUFFNUI7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0EsV0FBVyxvRUFBMkI7QUFDdEMsa0JBQWtCO0FBQ2xCO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQSx1Q0FBdUMscURBQVksQ0FBQywwREFBZTtBQUNuRTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDRCQUE0QixvRUFBMkI7O0FBRXZELFVBQVUsMERBQWM7QUFDeEI7QUFDQTtBQUNBOztBQUVBLDZCQUE2QixvREFBWSx5Q0FBeUMsb0RBQWdCLGlDQUFpQztBQUNuSTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLGtEQUFVLDJGQUEyRiwyREFBa0I7QUFDbkk7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLFlBQVksZ0dBQXFDO0FBQ2pELHNCQUFzQiwwRkFBK0IscUVBQXFFLG9EQUFnQjs7QUFFMUk7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOzs7QUFHQSxVQUFVLG9EQUFTO0FBQ25CO0FBQ0E7QUFDQSxxRUFBcUU7QUFDckU7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixlQUFlO0FBQ2Y7O0FBRUE7QUFDQTtBQUNBLG9FQUFvRTtBQUNwRTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCLGVBQWU7QUFDZjtBQUNBLFdBQVc7QUFDWDtBQUNBLFVBQVU7QUFDVjtBQUNBOztBQUVBLHdCQUF3QixrR0FBdUM7QUFDL0Q7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxrRUFBa0U7QUFDbEU7QUFDQSxlQUFlO0FBQ2YsYUFBYTtBQUNiOztBQUVBO0FBQ0E7QUFDQSxtRUFBbUU7QUFDbkU7QUFDQSxlQUFlO0FBQ2YsYUFBYTtBQUNiOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLHFFQUFxRSxvRUFBYztBQUNuRjtBQUNBO0FBQ0E7QUFDQSxTQUFTLEdBQUc7QUFDWjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLEdBQUc7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvRkFBb0Y7O0FBRXBGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxFQUFFLCtEQUFtQixDQUFDLDREQUFtQjtBQUNyRDtBQUNBO0FBQ0EsV0FBVyxHQUFHO0FBQ2Q7O0FBRUEsc0NBQXNDLCtEQUFvQiwyRkFBMkYsb0RBQWdCO0FBQ3JLLDREQUE0RDs7QUFFNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQywyREFBZ0I7QUFDMUQ7QUFDQSxnQkFBZ0Isc0VBQWE7QUFDN0I7QUFDQTtBQUNBLGlCQUFpQixHQUFHO0FBQ3BCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFlBQVksc0ZBQStCO0FBQzNDLFlBQVksOEVBQTJCO0FBQ3ZDLFlBQVksNkVBQW9DO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFVBQVUsc0VBQWE7QUFDdkI7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBLFFBQVEsU0FBUyxxRUFBZTtBQUNoQztBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBOztBQUVBLFlBQVkscUVBQTZCO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBLFlBQVksRUFBRSx5RUFBOEI7QUFDNUM7O0FBRUE7QUFDQSxVQUFVLHNFQUFhO0FBQ3ZCO0FBQ0EsV0FBVztBQUNYLFVBQVU7QUFDVixVQUFVLHNFQUFhO0FBQ3ZCO0FBQ0EsV0FBVztBQUNYOztBQUVBLFlBQVksc0VBQWdCO0FBQzVCO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNkRBQTZEOztBQUU3RDtBQUNBLFVBQVUsaUdBQXNDLCtDQUErQztBQUMvRixVQUFVO0FBQ1Y7O0FBRUEsaUNBQWlDLDhEQUFxQjtBQUN0RDtBQUNBLHlDQUF5Qyx5RUFBK0IsK0JBQStCO0FBQ3ZHO0FBQ0E7QUFDQTtBQUNBLGVBQWU7QUFDZixjQUFjO0FBQ2Q7QUFDQTtBQUNBOztBQUVBLDBDQUEwQyxtRUFBMEI7QUFDcEU7QUFDQSx5RUFBeUU7QUFDekU7QUFDQTtBQUNBLGFBQWEsSUFBSTs7QUFFakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7O0FBRUEsOEVBQThFO0FBQzlFLGtDQUFrQztBQUNsQztBQUNBLGFBQWE7QUFDYixpREFBaUQsRUFBRSx5RUFBK0I7QUFDbEY7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBLDZFQUE2RSxxRUFBZSxtQ0FBbUMsOEVBQW1CO0FBQ2xKLDhHQUE4Ryx5RUFBbUI7QUFDakksYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0EsS0FBSztBQUNMLElBQUk7OztBQUdKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLFdBQVcsMkRBQWtCO0FBQzdCOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdDQUF3Qyx3REFBYTtBQUNyRDtBQUNBO0FBQ0EsT0FBTztBQUNQLE1BQU0sd0VBQWdDO0FBQ3RDLE1BQU0sZ0VBQXdCO0FBQzlCO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCw0RkFBNEY7QUFDNUY7O0FBRUE7QUFDQTtBQUNBLDJDQUEyQyxvREFBYztBQUN6RCxVQUFVO0FBQ1YsdUNBQXVDLDhGQUFtQzs7QUFFMUU7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBLCtFQUErRTs7QUFFL0U7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0EsVUFBVTtBQUNWLHNDQUFzQyw4RkFBbUM7QUFDekU7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaOztBQUVBLGNBQWMsc0VBQWdCO0FBQzlCLFlBQVksNEVBQXlCO0FBQ3JDOztBQUVBO0FBQ0E7QUFDQSxtRUFBbUU7QUFDbkU7QUFDQSxlQUFlO0FBQ2Y7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBOztBQUVBO0FBQ0EsaUNBQWlDLDJEQUFrQjtBQUNuRCxpQ0FBaUMseURBQWdCO0FBQ2pELGlDQUFpQyxzREFBYTtBQUM5QyxpQ0FBaUMsb0RBQVc7O0FBRTVDO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBLDhCQUE4QixvRUFBMkI7QUFDekQ7QUFDQTtBQUNBLHNEQUFzRDs7QUFFdEQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxRQUFRLHNFQUFhO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCx5Q0FBeUMsb0RBQWM7QUFDdkQ7QUFDQTs7QUFFQSxVQUFVLG9FQUFjO0FBQ3hCOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQyw2RUFBMEI7QUFDMUQ7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYLDZDQUE2QyxvREFBYztBQUMzRCxXQUFXO0FBQ1gsVUFBVTtBQUNWO0FBQ0E7QUFDQSwyQ0FBMkMsb0RBQWM7QUFDekQ7O0FBRUE7QUFDQTs7QUFFQSxVQUFVLHFFQUFlO0FBQ3pCO0FBQ0E7QUFDQTs7QUFFQSw4QkFBOEIsb0VBQTJCOztBQUV6RDtBQUNBLFVBQVUsc0VBQWE7QUFDdkI7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFVBQVU7QUFDVixjQUFjLG1FQUFnQixnQkFBZ0Isc0VBQWdCO0FBQzlELFlBQVkseUVBQXNCO0FBQ2xDOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7O0FBRVg7QUFDQSxZQUFZLG9EQUFXO0FBQ3ZCO0FBQ0E7QUFDQSwwQkFBMEIseURBQWdCO0FBQzFDO0FBQ0EsZUFBZTtBQUNmLGtDQUFrQyw2RUFBMEIsK0JBQStCO0FBQzNGO0FBQ0EsZUFBZTtBQUNmLHlDQUF5Qyw4RUFBbUI7QUFDNUQsYUFBYTtBQUNiLFlBQVk7QUFDWjtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxnRUFBZ0Usa0VBQXVCO0FBQ3ZGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDhCQUE4QixvRUFBMkIsMEJBQTBCO0FBQ25GO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDRCQUE0QiwyREFBa0I7O0FBRTlDO0FBQ0EscUJBQXFCLGlFQUF3QjtBQUM3QztBQUNBO0FBQ0Esa0JBQWtCLHNFQUFhO0FBQy9CO0FBQ0EsbUJBQW1CO0FBQ25CLGdEQUFnRCxnRUFBdUI7QUFDdkU7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLHNFQUFhO0FBQy9CO0FBQ0EsbUJBQW1CO0FBQ25COztBQUVBO0FBQ0EsaURBQWlELDREQUFrQjtBQUNuRSxvQkFBb0Isc0VBQWE7QUFDakM7QUFDQSxxQkFBcUI7QUFDckI7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBOztBQUVBO0FBQ0EsK0dBQStHLHlEQUFnQjs7QUFFL0g7QUFDQTtBQUNBOztBQUVBLDZCQUE2QiwyREFBa0I7QUFDL0MsY0FBYztBQUNkO0FBQ0EsZ0dBQWdHLHlEQUFnQjtBQUNoSDtBQUNBO0FBQ0E7O0FBRUEsMkJBQTJCLGdGQUF1QztBQUNsRTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzQ0FBc0MsOERBQXFCO0FBQzNELHdDQUF3QywyREFBa0I7QUFDMUQ7O0FBRUEsUUFBUSxzRUFBYSxrQkFBa0Isa0VBQXVCO0FBQzlEOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSw2QkFBNkIsa0VBQXVCO0FBQ3BEO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQSwyQkFBMkIsZ0ZBQXVDO0FBQ2xFOztBQUVBO0FBQ0EseUJBQXlCLGtFQUF5QixlQUFlLG1FQUEwQjtBQUMzRjs7QUFFQTtBQUNBLFFBQVE7QUFDUjs7O0FBR0E7O0FBRUEscUxBQXFMLHFFQUFlO0FBQ3BNLDZFQUE2RTtBQUM3RTs7QUFFQTtBQUNBO0FBQ0EsdUNBQXVDLDhFQUFtQjtBQUMxRCxXQUFXO0FBQ1g7QUFDQTs7QUFFQSxVQUFVLDBEQUFjO0FBQ3hCLGdDQUFnQyxrREFBVTs7QUFFMUM7QUFDQSwrQkFBK0Isb0VBQTJCO0FBQzFEO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQiw0REFBa0I7QUFDbEM7QUFDQSwrREFBK0Qsa0NBQWtDO0FBQ2pHO0FBQ0E7O0FBRUEsb0ZBQW9GLDREQUFrQjtBQUN0RztBQUNBOztBQUVBO0FBQ0Esa0VBQWtFO0FBQ2xFO0FBQ0EsbUJBQW1CLHVEQUF1RCxpQkFBaUI7QUFDM0Ysc0NBQXNDLDZFQUEwQjtBQUNoRTtBQUNBLGVBQWUsR0FBRztBQUNsQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0EsOERBQThEO0FBQzlEO0FBQ0EsNENBQTRDLDREQUFtQjtBQUMvRDtBQUNBLGlCQUFpQjtBQUNqQixxREFBcUQsRUFBRSx5RUFBK0I7QUFDdEY7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBLDZFQUE2RSxxRUFBZSwrQkFBK0IsOEVBQW1CO0FBQzlJLGlCQUFpQjtBQUNqQixlQUFlO0FBQ2Y7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsMkVBQTJFO0FBQzNFO0FBQ0EsZUFBZSxHQUFHOztBQUVsQixpRUFBaUU7O0FBRWpFLDRLQUE0Syw0REFBa0I7QUFDOUw7QUFDQSxlQUFlO0FBQ2YsbURBQW1ELEVBQUUseUVBQStCO0FBQ3BGO0FBQ0E7QUFDQSxlQUFlO0FBQ2YsdURBQXVELHlFQUFtQjtBQUMxRSxlQUFlO0FBQ2YsYUFBYTtBQUNiLFlBQVk7QUFDWjtBQUNBO0FBQ0Esa0NBQWtDLDZFQUEwQiwrQkFBK0I7QUFDM0Y7QUFDQSxlQUFlO0FBQ2YsYUFBYTtBQUNiO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7O0FBRUEsaURBQWlELEVBQUUseUVBQStCO0FBQ2xGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLHFDQUFxQyxxRUFBZTtBQUNwRDtBQUNBLGlJQUFpSSw4RUFBbUI7QUFDcEosYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBOztBQUVBLHlGQUF5RiwyRkFBZ0Q7QUFDekk7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFVBQVU7QUFDVjtBQUNBO0FBQ0EsZ0NBQWdDLDZFQUEwQixHQUFHO0FBQzdELGdDQUFnQztBQUNoQztBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDhCQUE4Qiw2RUFBMEIsK0JBQStCO0FBQ3ZGO0FBQ0EsV0FBVztBQUNYLDhCQUE4Qix5RUFBbUI7QUFDakQsU0FBUztBQUNUOztBQUVBLDZDQUE2Qyw4REFBcUI7QUFDbEU7QUFDQTs7QUFFQTtBQUNBLFNBQVMsbUVBQWdCLGVBQWUsMkVBQTRCLEdBQUcsbUVBQW9CO0FBQzNGOztBQUVBO0FBQ0EsUUFBUSxvREFBVztBQUNuQjtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IseURBQWdCO0FBQ3RDO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBLDJLQUEySyx5RUFBbUI7QUFDOUw7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSw4QkFBOEIsZ0ZBQTZCO0FBQzNEO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBLDBCQUEwQiw2RUFBMEIsR0FBRztBQUN2RDtBQUNBLDBCQUEwQjtBQUMxQjtBQUNBO0FBQ0Esd0VBQXdFLDBEQUFnQjtBQUN4RixLQUFLO0FBQ0w7QUFDQSwwQkFBMEIsNkVBQTBCLEdBQUc7QUFDdkQ7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0Qix5RUFBa0I7O0FBRTlDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsbURBQW1ELHNFQUE2Qjs7QUFFaEY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUUsb0VBQTJCO0FBQ3ZDO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDBCQUEwQixrREFBYywrQ0FBK0MsK0NBQVc7QUFDbEcsWUFBWSxtREFBVztBQUN2Qix5QkFBeUI7QUFDekIsS0FBSztBQUNMOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxhQUFhLDJEQUFrQjtBQUMvQjs7QUFFQSxJQUFJLGFBQW9CLEtBQUssaURBQVEsSUFBSSxhQUFvQjtBQUM3RDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHO0FBQ0g7O0FBRUEsaUVBQWUsR0FBRyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uLi8uLi9jb21wb25lbnRzL0FwcC50c3g/MDYyNCJdLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgX19hd2FpdGVyID0gdGhpcyAmJiB0aGlzLl9fYXdhaXRlciB8fCBmdW5jdGlvbiAodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XG4gIGZ1bmN0aW9uIGFkb3B0KHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUCA/IHZhbHVlIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHtcbiAgICAgIHJlc29sdmUodmFsdWUpO1xuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvci5uZXh0KHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZWplY3RlZCh2YWx1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZWplY3QoZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHtcbiAgICAgIHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogYWRvcHQocmVzdWx0LnZhbHVlKS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpO1xuICAgIH1cblxuICAgIHN0ZXAoKGdlbmVyYXRvciA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSkubmV4dCgpKTtcbiAgfSk7XG59O1xuXG5pbXBvcnQgeyBqc3ggYXMgX2pzeCwganN4cyBhcyBfanN4cywgRnJhZ21lbnQgYXMgX0ZyYWdtZW50IH0gZnJvbSBcInJlYWN0L2pzeC1ydW50aW1lXCI7XG5pbXBvcnQgUmVhY3QsIHsgdXNlQ29udGV4dCB9IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHsgZmx1c2hTeW5jIH0gZnJvbSBcInJlYWN0LWRvbVwiO1xuaW1wb3J0IHJvdWdoIGZyb20gXCJyb3VnaGpzL2Jpbi9yb3VnaFwiO1xuaW1wb3J0IGNsc3ggZnJvbSBcImNsc3hcIjtcbmltcG9ydCB7IG5hbm9pZCB9IGZyb20gXCJuYW5vaWRcIjtcbmltcG9ydCB7IGFjdGlvbkFkZFRvTGlicmFyeSwgYWN0aW9uQnJpbmdGb3J3YXJkLCBhY3Rpb25CcmluZ1RvRnJvbnQsIGFjdGlvbkNvcHksIGFjdGlvbkNvcHlBc1BuZywgYWN0aW9uQ29weUFzU3ZnLCBjb3B5VGV4dCwgYWN0aW9uQ29weVN0eWxlcywgYWN0aW9uQ3V0LCBhY3Rpb25EZWxldGVTZWxlY3RlZCwgYWN0aW9uRHVwbGljYXRlU2VsZWN0aW9uLCBhY3Rpb25GaW5hbGl6ZSwgYWN0aW9uRmxpcEhvcml6b250YWwsIGFjdGlvbkZsaXBWZXJ0aWNhbCwgYWN0aW9uR3JvdXAsIGFjdGlvblBhc3RlU3R5bGVzLCBhY3Rpb25TZWxlY3RBbGwsIGFjdGlvblNlbmRCYWNrd2FyZCwgYWN0aW9uU2VuZFRvQmFjaywgYWN0aW9uVG9nZ2xlR3JpZE1vZGUsIGFjdGlvblRvZ2dsZVN0YXRzLCBhY3Rpb25Ub2dnbGVaZW5Nb2RlLCBhY3Rpb25VbmJpbmRUZXh0LCBhY3Rpb25CaW5kVGV4dCwgYWN0aW9uVW5ncm91cCwgYWN0aW9uTGluaywgYWN0aW9uVG9nZ2xlRWxlbWVudExvY2ssIGFjdGlvblRvZ2dsZUxpbmVhckVkaXRvciwgYWN0aW9uVG9nZ2xlT2JqZWN0c1NuYXBNb2RlIH0gZnJvbSBcIi4uL2FjdGlvbnNcIjtcbmltcG9ydCB7IGNyZWF0ZVJlZG9BY3Rpb24sIGNyZWF0ZVVuZG9BY3Rpb24gfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25IaXN0b3J5XCI7XG5pbXBvcnQgeyBBY3Rpb25NYW5hZ2VyIH0gZnJvbSBcIi4uL2FjdGlvbnMvbWFuYWdlclwiO1xuaW1wb3J0IHsgYWN0aW9ucyB9IGZyb20gXCIuLi9hY3Rpb25zL3JlZ2lzdGVyXCI7XG5pbXBvcnQgeyB0cmFja0V2ZW50IH0gZnJvbSBcIi4uL2FuYWx5dGljc1wiO1xuaW1wb3J0IHsgZ2V0RGVmYXVsdEFwcFN0YXRlLCBpc0VyYXNlckFjdGl2ZSwgaXNIYW5kVG9vbEFjdGl2ZSB9IGZyb20gXCIuLi9hcHBTdGF0ZVwiO1xuaW1wb3J0IHsgcGFyc2VDbGlwYm9hcmQgfSBmcm9tIFwiLi4vY2xpcGJvYXJkXCI7XG5pbXBvcnQgeyBBUFBfTkFNRSwgQ1VSU09SX1RZUEUsIERFRkFVTFRfTUFYX0lNQUdFX1dJRFRIX09SX0hFSUdIVCwgREVGQVVMVF9VSV9PUFRJT05TLCBERUZBVUxUX1ZFUlRJQ0FMX0FMSUdOLCBEUkFHR0lOR19USFJFU0hPTEQsIEVMRU1FTlRfUkVBRFlfVE9fRVJBU0VfT1BBQ0lUWSwgRUxFTUVOVF9TSElGVF9UUkFOU0xBVEVfQU1PVU5ULCBFTEVNRU5UX1RSQU5TTEFURV9BTU9VTlQsIEVOViwgRVZFTlQsIEZSQU1FX1NUWUxFLCBHUklEX1NJWkUsIElNQUdFX01JTUVfVFlQRVMsIElNQUdFX1JFTkRFUl9USU1FT1VULCBpc0FuZHJvaWQsIGlzQnJhdmUsIExJTkVfQ09ORklSTV9USFJFU0hPTEQsIE1BWF9BTExPV0VEX0ZJTEVfQllURVMsIE1JTUVfVFlQRVMsIE1RX01BWF9IRUlHSFRfTEFORFNDQVBFLCBNUV9NQVhfV0lEVEhfTEFORFNDQVBFLCBNUV9NQVhfV0lEVEhfUE9SVFJBSVQsIE1RX1JJR0hUX1NJREVCQVJfTUlOX1dJRFRILCBNUV9TTV9NQVhfV0lEVEgsIFBPSU5URVJfQlVUVE9OLCBST1VORE5FU1MsIFNDUk9MTF9USU1FT1VULCBUQVBfVFdJQ0VfVElNRU9VVCwgVEVYVF9UT19DRU5URVJfU05BUF9USFJFU0hPTEQsIFRIRU1FLCBUSEVNRV9GSUxURVIsIFRPVUNIX0NUWF9NRU5VX1RJTUVPVVQsIFZFUlRJQ0FMX0FMSUdOLCBZT1VUVUJFX1NUQVRFUywgWk9PTV9TVEVQLCBQT0lOVEVSX0VWRU5UUyB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGV4cG9ydEFzSW1hZ2UsIGxvYWRGcm9tQmxvYiB9IGZyb20gXCIuLi9kYXRhXCI7XG5pbXBvcnQgTGlicmFyeSwgeyBkaXN0cmlidXRlTGlicmFyeUl0ZW1zT25TcXVhcmVHcmlkIH0gZnJvbSBcIi4uL2RhdGEvbGlicmFyeVwiO1xuaW1wb3J0IHsgcmVzdG9yZSwgcmVzdG9yZUVsZW1lbnRzIH0gZnJvbSBcIi4uL2RhdGEvcmVzdG9yZVwiO1xuaW1wb3J0IHsgZHJhZ05ld0VsZW1lbnQsIGRyYWdTZWxlY3RlZEVsZW1lbnRzLCBkdXBsaWNhdGVFbGVtZW50LCBnZXRDb21tb25Cb3VuZHMsIGdldEN1cnNvckZvclJlc2l6aW5nRWxlbWVudCwgZ2V0RHJhZ09mZnNldFhZLCBnZXRFbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUsIGdldE5vcm1hbGl6ZWREaW1lbnNpb25zLCBnZXRSZXNpemVBcnJvd0RpcmVjdGlvbiwgZ2V0UmVzaXplT2Zmc2V0WFksIGdldExvY2tlZExpbmVhckN1cnNvckFsaWduU2l6ZSwgZ2V0VHJhbnNmb3JtSGFuZGxlVHlwZUZyb21Db29yZHMsIGhpdFRlc3QsIGlzSGl0dGluZ0VsZW1lbnRCb3VuZGluZ0JveFdpdGhvdXRIaXR0aW5nRWxlbWVudCwgaXNJbnZpc2libHlTbWFsbEVsZW1lbnQsIGlzTm9uRGVsZXRlZEVsZW1lbnQsIGlzVGV4dEVsZW1lbnQsIG5ld0VsZW1lbnQsIG5ld0xpbmVhckVsZW1lbnQsIG5ld1RleHRFbGVtZW50LCBuZXdJbWFnZUVsZW1lbnQsIHRleHRXeXNpd3lnLCB0cmFuc2Zvcm1FbGVtZW50cywgdXBkYXRlVGV4dEVsZW1lbnQsIHJlZHJhd1RleHRCb3VuZGluZ0JveCB9IGZyb20gXCIuLi9lbGVtZW50XCI7XG5pbXBvcnQgeyBiaW5kT3JVbmJpbmRMaW5lYXJFbGVtZW50LCBiaW5kT3JVbmJpbmRTZWxlY3RlZEVsZW1lbnRzLCBmaXhCaW5kaW5nc0FmdGVyRGVsZXRpb24sIGZpeEJpbmRpbmdzQWZ0ZXJEdXBsaWNhdGlvbiwgZ2V0RWxpZ2libGVFbGVtZW50c0ZvckJpbmRpbmcsIGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZywgaXNCaW5kaW5nRW5hYmxlZCwgaXNMaW5lYXJFbGVtZW50U2ltcGxlQW5kQWxyZWFkeUJvdW5kLCBtYXliZUJpbmRMaW5lYXJFbGVtZW50LCBzaG91bGRFbmFibGVCaW5kaW5nRm9yUG9pbnRlckV2ZW50LCB1bmJpbmRMaW5lYXJFbGVtZW50cywgdXBkYXRlQm91bmRFbGVtZW50cyB9IGZyb20gXCIuLi9lbGVtZW50L2JpbmRpbmdcIjtcbmltcG9ydCB7IExpbmVhckVsZW1lbnRFZGl0b3IgfSBmcm9tIFwiLi4vZWxlbWVudC9saW5lYXJFbGVtZW50RWRpdG9yXCI7XG5pbXBvcnQgeyBtdXRhdGVFbGVtZW50LCBuZXdFbGVtZW50V2l0aCB9IGZyb20gXCIuLi9lbGVtZW50L211dGF0ZUVsZW1lbnRcIjtcbmltcG9ydCB7IGRlZXBDb3B5RWxlbWVudCwgZHVwbGljYXRlRWxlbWVudHMsIG5ld0ZyYW1lRWxlbWVudCwgbmV3RnJlZURyYXdFbGVtZW50LCBuZXdFbWJlZGRhYmxlRWxlbWVudCB9IGZyb20gXCIuLi9lbGVtZW50L25ld0VsZW1lbnRcIjtcbmltcG9ydCB7IGhhc0JvdW5kVGV4dEVsZW1lbnQsIGlzQXJyb3dFbGVtZW50LCBpc0JpbmRpbmdFbGVtZW50LCBpc0JpbmRpbmdFbGVtZW50VHlwZSwgaXNCb3VuZFRvQ29udGFpbmVyLCBpc0ZyYW1lRWxlbWVudCwgaXNJbWFnZUVsZW1lbnQsIGlzRW1iZWRkYWJsZUVsZW1lbnQsIGlzSW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQsIGlzTGluZWFyRWxlbWVudCwgaXNMaW5lYXJFbGVtZW50VHlwZSwgaXNVc2luZ0FkYXB0aXZlUmFkaXVzIH0gZnJvbSBcIi4uL2VsZW1lbnQvdHlwZUNoZWNrc1wiO1xuaW1wb3J0IHsgZ2V0Q2VudGVyLCBnZXREaXN0YW5jZSB9IGZyb20gXCIuLi9nZXN0dXJlXCI7XG5pbXBvcnQgeyBlZGl0R3JvdXBGb3JTZWxlY3RlZEVsZW1lbnQsIGdldEVsZW1lbnRzSW5Hcm91cCwgZ2V0U2VsZWN0ZWRHcm91cElkRm9yRWxlbWVudCwgZ2V0U2VsZWN0ZWRHcm91cElkcywgaXNFbGVtZW50SW5Hcm91cCwgaXNTZWxlY3RlZFZpYUdyb3VwLCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzIH0gZnJvbSBcIi4uL2dyb3Vwc1wiO1xuaW1wb3J0IEhpc3RvcnkgZnJvbSBcIi4uL2hpc3RvcnlcIjtcbmltcG9ydCB7IGRlZmF1bHRMYW5nLCBnZXRMYW5ndWFnZSwgbGFuZ3VhZ2VzLCBzZXRMYW5ndWFnZSwgdCB9IGZyb20gXCIuLi9pMThuXCI7XG5pbXBvcnQgeyBDT0RFUywgc2hvdWxkUmVzaXplRnJvbUNlbnRlciwgc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbywgc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUsIGlzQXJyb3dLZXksIEtFWVMgfSBmcm9tIFwiLi4va2V5c1wiO1xuaW1wb3J0IHsgaXNFbGVtZW50SW5WaWV3cG9ydCB9IGZyb20gXCIuLi9lbGVtZW50L3NpemVIZWxwZXJzXCI7XG5pbXBvcnQgeyBkaXN0YW5jZTJkLCBnZXRDb3JuZXJSYWRpdXMsIGdldEdyaWRQb2ludCwgaXNQYXRoQUxvb3AgfSBmcm9tIFwiLi4vbWF0aFwiO1xuaW1wb3J0IHsgY2xlYXJSZW5kZXJDYWNoZSB9IGZyb20gXCIuLi9yZW5kZXJlci9yZW5kZXJFbGVtZW50XCI7XG5pbXBvcnQgeyBjYWxjdWxhdGVTY3JvbGxDZW50ZXIsIGdldEVsZW1lbnRzQXRQb3NpdGlvbiwgZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24sIGdldE5vcm1hbGl6ZWRab29tLCBnZXRTZWxlY3RlZEVsZW1lbnRzLCBoYXNCYWNrZ3JvdW5kLCBpc092ZXJTY3JvbGxCYXJzLCBpc1NvbWVFbGVtZW50U2VsZWN0ZWQgfSBmcm9tIFwiLi4vc2NlbmVcIjtcbmltcG9ydCBTY2VuZSBmcm9tIFwiLi4vc2NlbmUvU2NlbmVcIjtcbmltcG9ydCB7IGdldFN0YXRlRm9yWm9vbSB9IGZyb20gXCIuLi9zY2VuZS96b29tXCI7XG5pbXBvcnQgeyBmaW5kU2hhcGVCeUtleSB9IGZyb20gXCIuLi9zaGFwZXNcIjtcbmltcG9ydCB7IGRlYm91bmNlLCBkaXN0YW5jZSwgZ2V0Rm9udFN0cmluZywgZ2V0TmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIsIGlzSW5wdXRMaWtlLCBpc1Rvb2xJY29uLCBpc1dyaXRhYmxlRWxlbWVudCwgcmVzZXRDdXJzb3IsIHJlc29sdmFibGVQcm9taXNlLCBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMsIHNldEN1cnNvciwgc2V0Q3Vyc29yRm9yU2hhcGUsIHR1cGxlVG9Db29ycywgdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzLCB3aXRoQmF0Y2hlZFVwZGF0ZXMsIHdyYXBFdmVudCwgd2l0aEJhdGNoZWRVcGRhdGVzVGhyb3R0bGVkLCB1cGRhdGVPYmplY3QsIHNldEVyYXNlckN1cnNvciwgdXBkYXRlQWN0aXZlVG9vbCwgZ2V0U2hvcnRjdXRLZXksIGlzVHJhbnNwYXJlbnQsIGVhc2VUb1ZhbHVlc1JBRiwgbXV0ZUZTQWJvcnRFcnJvciwgaXNUZXN0RW52LCBlYXNlT3V0IH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgeyBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yLCBleHRyYWN0U3JjLCBnZXRFbWJlZExpbmsgfSBmcm9tIFwiLi4vZWxlbWVudC9lbWJlZGRhYmxlXCI7XG5pbXBvcnQgeyBDb250ZXh0TWVudSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiB9IGZyb20gXCIuL0NvbnRleHRNZW51XCI7XG5pbXBvcnQgTGF5ZXJVSSBmcm9tIFwiLi9MYXllclVJXCI7XG5pbXBvcnQgeyBUb2FzdCB9IGZyb20gXCIuL1RvYXN0XCI7XG5pbXBvcnQgeyBhY3Rpb25Ub2dnbGVWaWV3TW9kZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvblRvZ2dsZVZpZXdNb2RlXCI7XG5pbXBvcnQgeyBkYXRhVVJMVG9GaWxlLCBnZW5lcmF0ZUlkRnJvbUZpbGUsIGdldERhdGFVUkwsIGdldEZpbGVGcm9tRXZlbnQsIGlzSW1hZ2VGaWxlSGFuZGxlLCBpc1N1cHBvcnRlZEltYWdlRmlsZSwgbG9hZFNjZW5lT3JMaWJyYXJ5RnJvbUJsb2IsIG5vcm1hbGl6ZUZpbGUsIHBhcnNlTGlicmFyeUpTT04sIHJlc2l6ZUltYWdlRmlsZSwgU1ZHU3RyaW5nVG9GaWxlIH0gZnJvbSBcIi4uL2RhdGEvYmxvYlwiO1xuaW1wb3J0IHsgZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzLCBsb2FkSFRNTEltYWdlRWxlbWVudCwgbm9ybWFsaXplU1ZHLCB1cGRhdGVJbWFnZUNhY2hlIGFzIF91cGRhdGVJbWFnZUNhY2hlIH0gZnJvbSBcIi4uL2VsZW1lbnQvaW1hZ2VcIjtcbmltcG9ydCB0aHJvdHRsZSBmcm9tIFwibG9kYXNoLnRocm90dGxlXCI7XG5pbXBvcnQgeyBmaWxlT3BlbiB9IGZyb20gXCIuLi9kYXRhL2ZpbGVzeXN0ZW1cIjtcbmltcG9ydCB7IGJpbmRUZXh0VG9TaGFwZUFmdGVyRHVwbGljYXRpb24sIGdldEFwcHJveE1pbkxpbmVIZWlnaHQsIGdldEFwcHJveE1pbkxpbmVXaWR0aCwgZ2V0Qm91bmRUZXh0RWxlbWVudCwgZ2V0Q29udGFpbmVyQ2VudGVyLCBnZXRDb250YWluZXJFbGVtZW50LCBnZXREZWZhdWx0TGluZUhlaWdodCwgZ2V0TGluZUhlaWdodEluUHgsIGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24sIGlzTWVhc3VyZVRleHRTdXBwb3J0ZWQsIGlzVmFsaWRUZXh0Q29udGFpbmVyIH0gZnJvbSBcIi4uL2VsZW1lbnQvdGV4dEVsZW1lbnRcIjtcbmltcG9ydCB7IGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnQvY29sbGlzaW9uXCI7XG5pbXBvcnQgeyBzaG93SHlwZXJsaW5rVG9vbHRpcCwgaGlkZUh5cGVybGlua1Rvb2xpcCwgSHlwZXJsaW5rLCBpc1BvaW50SGl0dGluZ0xpbmssIGlzUG9pbnRIaXR0aW5nTGlua0ljb24gfSBmcm9tIFwiLi4vZWxlbWVudC9IeXBlcmxpbmtcIjtcbmltcG9ydCB7IGlzTG9jYWxMaW5rLCBub3JtYWxpemVMaW5rLCB0b1ZhbGlkVVJMIH0gZnJvbSBcIi4uL2RhdGEvdXJsXCI7XG5pbXBvcnQgeyBzaG91bGRTaG93Qm91bmRpbmdCb3ggfSBmcm9tIFwiLi4vZWxlbWVudC90cmFuc2Zvcm1IYW5kbGVzXCI7XG5pbXBvcnQgeyBhY3Rpb25VbmxvY2tBbGxFbGVtZW50cyB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkVsZW1lbnRMb2NrXCI7XG5pbXBvcnQgeyBGb250cyB9IGZyb20gXCIuLi9zY2VuZS9Gb250c1wiO1xuaW1wb3J0IHsgZ2V0RnJhbWVFbGVtZW50cywgaXNDdXJzb3JJbkZyYW1lLCBiaW5kRWxlbWVudHNUb0ZyYW1lc0FmdGVyRHVwbGljYXRpb24sIGFkZEVsZW1lbnRzVG9GcmFtZSwgcmVwbGFjZUFsbEVsZW1lbnRzSW5GcmFtZSwgcmVtb3ZlRWxlbWVudHNGcm9tRnJhbWUsIGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lLCBnZXRFbGVtZW50c0luTmV3RnJhbWUsIGdldENvbnRhaW5pbmdGcmFtZSwgZWxlbWVudE92ZXJsYXBzV2l0aEZyYW1lLCB1cGRhdGVGcmFtZU1lbWJlcnNoaXBPZlNlbGVjdGVkRWxlbWVudHMsIGlzRWxlbWVudEluRnJhbWUgfSBmcm9tIFwiLi4vZnJhbWVcIjtcbmltcG9ydCB7IGV4Y2x1ZGVFbGVtZW50c0luRnJhbWVzRnJvbVNlbGVjdGlvbiwgbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMgfSBmcm9tIFwiLi4vc2NlbmUvc2VsZWN0aW9uXCI7XG5pbXBvcnQgeyBhY3Rpb25QYXN0ZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkNsaXBib2FyZFwiO1xuaW1wb3J0IHsgYWN0aW9uUmVtb3ZlQWxsRWxlbWVudHNGcm9tRnJhbWUsIGFjdGlvblNlbGVjdEFsbEVsZW1lbnRzSW5GcmFtZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkZyYW1lXCI7XG5pbXBvcnQgeyBhY3Rpb25Ub2dnbGVIYW5kVG9vbCwgem9vbVRvRml0IH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uQ2FudmFzXCI7XG5pbXBvcnQgeyBqb3RhaVN0b3JlIH0gZnJvbSBcIi4uL2pvdGFpXCI7XG5pbXBvcnQgeyBhY3RpdmVDb25maXJtRGlhbG9nQXRvbSB9IGZyb20gXCIuL0FjdGl2ZUNvbmZpcm1EaWFsb2dcIjtcbmltcG9ydCB7IGdldFNuYXBMaW5lc0F0UG9pbnRlciwgc25hcERyYWdnZWRFbGVtZW50cywgaXNBY3RpdmVUb29sTm9uTGluZWFyU25hcHBhYmxlLCBzbmFwTmV3RWxlbWVudCwgc25hcFJlc2l6aW5nRWxlbWVudHMsIGlzU25hcHBpbmdFbmFibGVkLCBnZXRWaXNpYmxlR2FwcywgZ2V0UmVmZXJlbmNlU25hcFBvaW50cywgU25hcENhY2hlIH0gZnJvbSBcIi4uL3NuYXBwaW5nXCI7XG5pbXBvcnQgeyBhY3Rpb25XcmFwVGV4dEluQ29udGFpbmVyIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uQm91bmRUZXh0XCI7XG5pbXBvcnQgQnJhdmVNZWFzdXJlVGV4dEVycm9yIGZyb20gXCIuL0JyYXZlTWVhc3VyZVRleHRFcnJvclwiO1xuaW1wb3J0IHsgYWN0aXZlRXllRHJvcHBlckF0b20gfSBmcm9tIFwiLi9FeWVEcm9wcGVyXCI7XG5pbXBvcnQgeyBjb252ZXJ0VG9FeGNhbGlkcmF3RWxlbWVudHMgfSBmcm9tIFwiLi4vZGF0YS90cmFuc2Zvcm1cIjtcbmltcG9ydCB7IGlzU2lkZWJhckRvY2tlZEF0b20gfSBmcm9tIFwiLi9TaWRlYmFyL1NpZGViYXJcIjtcbmltcG9ydCB7IFN0YXRpY0NhbnZhcywgSW50ZXJhY3RpdmVDYW52YXMgfSBmcm9tIFwiLi9jYW52YXNlc1wiO1xuaW1wb3J0IHsgUmVuZGVyZXIgfSBmcm9tIFwiLi4vc2NlbmUvUmVuZGVyZXJcIjtcbmltcG9ydCB7IFNoYXBlQ2FjaGUgfSBmcm9tIFwiLi4vc2NlbmUvU2hhcGVDYWNoZVwiO1xuaW1wb3J0IHsgRW1pdHRlciB9IGZyb20gXCIuLi9lbWl0dGVyXCI7XG5jb25zdCBBcHBDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChudWxsKTtcbmNvbnN0IEFwcFByb3BzQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQobnVsbCk7XG5jb25zdCBkZXZpY2VDb250ZXh0SW5pdGlhbFZhbHVlID0ge1xuICBpc1NtU2NyZWVuOiBmYWxzZSxcbiAgaXNNb2JpbGU6IGZhbHNlLFxuICBpc1RvdWNoU2NyZWVuOiBmYWxzZSxcbiAgY2FuRGV2aWNlRml0U2lkZWJhcjogZmFsc2UsXG4gIGlzTGFuZHNjYXBlOiBmYWxzZVxufTtcbmNvbnN0IERldmljZUNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KGRldmljZUNvbnRleHRJbml0aWFsVmFsdWUpO1xuRGV2aWNlQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRGV2aWNlQ29udGV4dFwiO1xuZXhwb3J0IGNvbnN0IEV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dCh7XG4gIGNvbnRhaW5lcjogbnVsbCxcbiAgaWQ6IG51bGxcbn0pO1xuRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChbXSk7XG5FeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldERlZmF1bHRBcHBTdGF0ZSgpKSwge1xuICB3aWR0aDogMCxcbiAgaGVpZ2h0OiAwLFxuICBvZmZzZXRMZWZ0OiAwLFxuICBvZmZzZXRUb3A6IDBcbn0pKTtcbkV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KCgpID0+IHtcbiAgY29uc29sZS53YXJuKFwidW5pdGlhbGl6ZWQgRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dCBjb250ZXh0IVwiKTtcbn0pO1xuRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChudWxsKTtcbkV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0XCI7XG5leHBvcnQgY29uc3QgdXNlQXBwID0gKCkgPT4gdXNlQ29udGV4dChBcHBDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VBcHBQcm9wcyA9ICgpID0+IHVzZUNvbnRleHQoQXBwUHJvcHNDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VEZXZpY2UgPSAoKSA9PiB1c2VDb250ZXh0KERldmljZUNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdDb250YWluZXIgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3RWxlbWVudHMgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdFbGVtZW50c0NvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdBcHBTdGF0ZSA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd1NldEFwcFN0YXRlID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3QWN0aW9uTWFuYWdlciA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0KTtcbmxldCBkaWRUYXBUd2ljZSA9IGZhbHNlO1xubGV0IHRhcHBlZFR3aWNlVGltZXIgPSAwO1xubGV0IGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG5sZXQgaXNQYW5uaW5nID0gZmFsc2U7XG5sZXQgaXNEcmFnZ2luZ1Njcm9sbEJhciA9IGZhbHNlO1xubGV0IGN1cnJlbnRTY3JvbGxCYXJzID0ge1xuICBob3Jpem9udGFsOiBudWxsLFxuICB2ZXJ0aWNhbDogbnVsbFxufTtcbmxldCB0b3VjaFRpbWVvdXQgPSAwO1xubGV0IGludmFsaWRhdGVDb250ZXh0TWVudSA9IGZhbHNlO1xuLyoqXG4gKiBNYXAgb2YgeW91dHViZSBlbWJlZCB2aWRlbyBzdGF0ZXNcbiAqL1xuXG5jb25zdCBZT1VUVUJFX1ZJREVPX1NUQVRFUyA9IG5ldyBNYXAoKTtcbmxldCBJU19QTEFJTl9QQVNURSA9IGZhbHNlO1xubGV0IElTX1BMQUlOX1BBU1RFX1RJTUVSID0gMDtcbmxldCBQTEFJTl9QQVNURV9UT0FTVF9TSE9XTiA9IGZhbHNlO1xubGV0IGxhc3RQb2ludGVyVXAgPSBudWxsO1xuY29uc3QgZ2VzdHVyZSA9IHtcbiAgcG9pbnRlcnM6IG5ldyBNYXAoKSxcbiAgbGFzdENlbnRlcjogbnVsbCxcbiAgaW5pdGlhbERpc3RhbmNlOiBudWxsLFxuICBpbml0aWFsU2NhbGU6IG51bGxcbn07XG5cbmNsYXNzIEFwcCBleHRlbmRzIFJlYWN0LkNvbXBvbmVudCB7XG4gIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgdmFyIF9hO1xuXG4gICAgc3VwZXIocHJvcHMpO1xuICAgIHRoaXMuaW50ZXJhY3RpdmVDYW52YXMgPSBudWxsO1xuICAgIHRoaXMudW5tb3VudGVkID0gZmFsc2U7XG4gICAgdGhpcy5kZXZpY2UgPSBkZXZpY2VDb250ZXh0SW5pdGlhbFZhbHVlO1xuICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZiA9IFJlYWN0LmNyZWF0ZVJlZigpO1xuICAgIHRoaXMuZmlsZXMgPSB7fTtcbiAgICB0aGlzLmltYWdlQ2FjaGUgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5pRnJhbWVSZWZzID0gbmV3IE1hcCgpO1xuICAgIHRoaXMubGFzdFBvaW50ZXJEb3duID0gbnVsbDtcbiAgICB0aGlzLmxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24gPSB7XG4gICAgICB4OiAwLFxuICAgICAgeTogMFxuICAgIH07XG4gICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyVXBFbWl0dGVyID0gbmV3IEVtaXR0ZXIoKTtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBlbWJlZGRhYmxlRWxlbWVudHMgPSBuZXcgTWFwKCk7XG4gICAgICBsZXQgdXBkYXRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgZW1iZWRkYWJsZUVsZW1lbnRzLnNldChlbGVtZW50LmlkLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50LnZhbGlkYXRlZCA9PSBudWxsKSB7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlZCA9IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IoZWxlbWVudC5saW5rLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSk7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgdmFsaWRhdGVkXG4gICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWQpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgfSAvLyBHQ1xuXG5cbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5mb3JFYWNoKChyZWYsIGlkKSA9PiB7XG4gICAgICAgIGlmICghZW1iZWRkYWJsZUVsZW1lbnRzLmhhcyhpZCkpIHtcbiAgICAgICAgICB0aGlzLmlGcmFtZVJlZnMuZGVsZXRlKGlkKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQgPSBmcmFtZUVsZW1lbnQgPT4ge1xuICAgICAgcmV0dXJuIGAke3RoaXMuaWR9LWZyYW1lLW5hbWUtJHtmcmFtZUVsZW1lbnQuaWR9YDtcbiAgICB9O1xuXG4gICAgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSA9IHtcbiAgICAgIGdldDogZnJhbWVFbGVtZW50ID0+IHtcbiAgICAgICAgbGV0IGJvdW5kcyA9IHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLmdldChmcmFtZUVsZW1lbnQuaWQpO1xuXG4gICAgICAgIGlmICghYm91bmRzIHx8IGJvdW5kcy56b29tICE9PSB0aGlzLnN0YXRlLnpvb20udmFsdWUgfHwgYm91bmRzLnZlcnNpb25Ob25jZSAhPT0gZnJhbWVFbGVtZW50LnZlcnNpb25Ob25jZSkge1xuICAgICAgICAgIGNvbnN0IGZyYW1lTmFtZURpdiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQoZnJhbWVFbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoZnJhbWVOYW1lRGl2KSB7XG4gICAgICAgICAgICBjb25zdCBib3ggPSBmcmFtZU5hbWVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBjb25zdCBib3hTY2VuZVRvcExlZnQgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgICBjbGllbnRYOiBib3gueCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LnlcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3QgYm94U2NlbmVCb3R0b21SaWdodCA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICAgIGNsaWVudFg6IGJveC5yaWdodCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LmJvdHRvbVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBib3VuZHMgPSB7XG4gICAgICAgICAgICAgIHg6IGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICB5OiBib3hTY2VuZVRvcExlZnQueSxcbiAgICAgICAgICAgICAgd2lkdGg6IGJveFNjZW5lQm90dG9tUmlnaHQueCAtIGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICBoZWlnaHQ6IGJveFNjZW5lQm90dG9tUmlnaHQueSAtIGJveFNjZW5lVG9wTGVmdC55LFxuICAgICAgICAgICAgICBhbmdsZTogMCxcbiAgICAgICAgICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLnZhbHVlLFxuICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IGZyYW1lRWxlbWVudC52ZXJzaW9uTm9uY2VcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLnNldChmcmFtZUVsZW1lbnQuaWQsIGJvdW5kcyk7XG5cbiAgICAgICAgICAgIHJldHVybiBib3VuZHM7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYm91bmRzO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICovXG4gICAgICBfY2FjaGU6IG5ldyBNYXAoKVxuICAgIH07XG5cbiAgICB0aGlzLnJlbmRlckZyYW1lTmFtZXMgPSAoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCB8fCAhdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc0RhcmtUaGVtZSA9IHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiO1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLm1hcCgoZiwgaW5kZXgpID0+IHtcbiAgICAgICAgaWYgKCFpc0VsZW1lbnRJblZpZXdwb3J0KGYsIHRoaXMuY2FudmFzLndpZHRoIC8gd2luZG93LmRldmljZVBpeGVsUmF0aW8sIHRoaXMuY2FudmFzLmhlaWdodCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLCB7XG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb21cbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAvLyBpZiBmcmFtZSBub3QgdmlzaWJsZSwgZG9uJ3QgcmVuZGVyIGl0cyBuYW1lXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogeDEsXG4gICAgICAgICAgeTogeTFcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBmLngsXG4gICAgICAgICAgc2NlbmVZOiBmLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB4MlxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IGYueCArIGYud2lkdGgsXG4gICAgICAgICAgc2NlbmVZOiBmLnkgKyBmLmhlaWdodFxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9HQVAgPSAyMDtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgPSA2O1xuXG4gICAgICAgIGNvbnN0IHJlc2V0ID0gKCkgPT4ge1xuICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgIGlmICgoKF9hID0gZi5uYW1lKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudHJpbSgpKSA9PT0gXCJcIikge1xuICAgICAgICAgICAgbXV0YXRlRWxlbWVudChmLCB7XG4gICAgICAgICAgICAgIG5hbWU6IG51bGxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0ZyYW1lOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbGV0IGZyYW1lTmFtZUpTWDtcblxuICAgICAgICBpZiAoZi5pZCA9PT0gdGhpcy5zdGF0ZS5lZGl0aW5nRnJhbWUpIHtcbiAgICAgICAgICBjb25zdCBmcmFtZU5hbWVJbkVkaXQgPSBmLm5hbWUgPT0gbnVsbCA/IGBGcmFtZSAke2luZGV4ICsgMX1gIDogZi5uYW1lO1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IF9qc3goXCJpbnB1dFwiLCB7XG4gICAgICAgICAgICBhdXRvRm9jdXM6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogZnJhbWVOYW1lSW5FZGl0LFxuICAgICAgICAgICAgb25DaGFuZ2U6IGUgPT4ge1xuICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGYsIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBlLnRhcmdldC52YWx1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkJsdXI6ICgpID0+IHJlc2V0KCksXG4gICAgICAgICAgICBvbktleURvd246IGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgLy8gZm9yIHNvbWUgaW5leHBsaWNhYmxlIHJlYXNvbiwgYG9uQmx1cmAgdHJpZ2dlcmVkIG9uIEVTQ1xuICAgICAgICAgICAgICAvLyBkb2VzIG5vdCByZXNldCBgc3RhdGUuZWRpdGluZ0ZyYW1lYCBkZXNwaXRlIGJlaW5nIGNhbGxlZCxcbiAgICAgICAgICAgICAgLy8gYW5kIHdlIG5lZWQgdG8gcmVzZXQgaXQgaGVyZSBhcyB3ZWxsXG4gICAgICAgICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuRVNDQVBFIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5FTlRFUikge1xuICAgICAgICAgICAgICAgIHJlc2V0KCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLnZpZXdCYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgICAgIGZpbHRlcjogaXNEYXJrVGhlbWUgPyBUSEVNRV9GSUxURVIgOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgekluZGV4OiAyLFxuICAgICAgICAgICAgICBib3JkZXI6IFwibm9uZVwiLFxuICAgICAgICAgICAgICBkaXNwbGF5OiBcImJsb2NrXCIsXG4gICAgICAgICAgICAgIHBhZGRpbmc6IGAke0ZSQU1FX05BTUVfRURJVF9QQURESU5HfXB4YCxcbiAgICAgICAgICAgICAgYm9yZGVyUmFkaXVzOiA0LFxuICAgICAgICAgICAgICBib3hTaGFkb3c6IFwiaW5zZXQgMCAwIDAgMXB4IHZhcigtLWNvbG9yLXByaW1hcnkpXCIsXG4gICAgICAgICAgICAgIGZvbnRGYW1pbHk6IFwiQXNzaXN0YW50XCIsXG4gICAgICAgICAgICAgIGZvbnRTaXplOiBcIjE0cHhcIixcbiAgICAgICAgICAgICAgdHJhbnNmb3JtOiBgdHJhbnNsYXRlWSgtJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weClgLFxuICAgICAgICAgICAgICBjb2xvcjogXCJ2YXIoLS1jb2xvci1ncmF5LTgwKVwiLFxuICAgICAgICAgICAgICBvdmVyZmxvdzogXCJoaWRkZW5cIixcbiAgICAgICAgICAgICAgbWF4V2lkdGg6IGAke01hdGgubWluKHgyIC0geDEgLSBGUkFNRV9OQU1FX0VESVRfUEFERElORywgZG9jdW1lbnQuYm9keS5jbGllbnRXaWR0aCAtIHgxIC0gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcpfXB4YFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNpemU6IGZyYW1lTmFtZUluRWRpdC5sZW5ndGggKyAxIHx8IDEsXG4gICAgICAgICAgICBkaXI6IFwiYXV0b1wiLFxuICAgICAgICAgICAgYXV0b0NvbXBsZXRlOiBcIm9mZlwiLFxuICAgICAgICAgICAgYXV0b0NhcGl0YWxpemU6IFwib2ZmXCIsXG4gICAgICAgICAgICBhdXRvQ29ycmVjdDogXCJvZmZcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IGYubmFtZSA9PSBudWxsIHx8IGYubmFtZS50cmltKCkgPT09IFwiXCIgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZS50cmltKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBpZDogdGhpcy5nZXRGcmFtZU5hbWVET01JZChmKSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgcG9zaXRpb246IFwiYWJzb2x1dGVcIixcbiAgICAgICAgICAgIHRvcDogYCR7eTEgLSBGUkFNRV9OQU1FX0dBUCAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wfXB4YCxcbiAgICAgICAgICAgIGxlZnQ6IGAke3gxIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0IC0gKHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID09PSBmLmlkID8gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgOiAwKX1weGAsXG4gICAgICAgICAgICB6SW5kZXg6IDIsXG4gICAgICAgICAgICBmb250U2l6ZTogXCIxNHB4XCIsXG4gICAgICAgICAgICBjb2xvcjogaXNEYXJrVGhlbWUgPyBcInZhcigtLWNvbG9yLWdyYXktNjApXCIgOiBcInZhcigtLWNvbG9yLWdyYXktNTApXCIsXG4gICAgICAgICAgICB3aWR0aDogXCJtYXgtY29udGVudFwiLFxuICAgICAgICAgICAgbWF4V2lkdGg6IGAke3gyIC0geDEgKyBGUkFNRV9OQU1FX0VESVRfUEFERElORyAqIDJ9cHhgLFxuICAgICAgICAgICAgb3ZlcmZsb3c6IGYuaWQgPT09IHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID8gXCJ2aXNpYmxlXCIgOiBcImhpZGRlblwiLFxuICAgICAgICAgICAgd2hpdGVTcGFjZTogXCJub3dyYXBcIixcbiAgICAgICAgICAgIHRleHRPdmVyZmxvdzogXCJlbGxpcHNpc1wiLFxuICAgICAgICAgICAgY3Vyc29yOiBDVVJTT1JfVFlQRS5NT1ZFLFxuICAgICAgICAgICAgcG9pbnRlckV2ZW50czogdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQgPyBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZCA6IFBPSU5URVJfRVZFTlRTLmVuYWJsZWRcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uUG9pbnRlckRvd246IGV2ZW50ID0+IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24oZXZlbnQpLFxuICAgICAgICAgIG9uV2hlZWw6IGV2ZW50ID0+IHRoaXMuaGFuZGxlV2hlZWwoZXZlbnQpLFxuICAgICAgICAgIG9uQ29udGV4dE1lbnU6IHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUsXG4gICAgICAgICAgb25Eb3VibGVDbGljazogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogZi5pZFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IGZyYW1lTmFtZUpTWFxuICAgICAgICB9KSwgZi5pZCk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5mb2N1c0NvbnRhaW5lciA9ICgpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5mb2N1cygpO1xuICAgIH07XG5cbiAgICB0aGlzLmdldFNjZW5lRWxlbWVudHNJbmNsdWRpbmdEZWxldGVkID0gKCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0U2NlbmVFbGVtZW50cyA9ICgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgIH07XG5cbiAgICB0aGlzLm9uSW5zZXJ0RWxlbWVudHMgPSBlbGVtZW50cyA9PiB7XG4gICAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5KHtcbiAgICAgICAgZWxlbWVudHMsXG4gICAgICAgIHBvc2l0aW9uOiBcImNlbnRlclwiLFxuICAgICAgICBmaWxlczogbnVsbFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMub25FeHBvcnRJbWFnZSA9ICh0eXBlLCBlbGVtZW50cykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdHJhY2tFdmVudChcImV4cG9ydFwiLCB0eXBlLCBcInVpXCIpO1xuICAgICAgY29uc3QgZmlsZUhhbmRsZSA9IHlpZWxkIGV4cG9ydEFzSW1hZ2UodHlwZSwgZWxlbWVudHMsIHRoaXMuc3RhdGUsIHRoaXMuZmlsZXMsIHtcbiAgICAgICAgZXhwb3J0QmFja2dyb3VuZDogdGhpcy5zdGF0ZS5leHBvcnRCYWNrZ3JvdW5kLFxuICAgICAgICBuYW1lOiB0aGlzLnN0YXRlLm5hbWUsXG4gICAgICAgIHZpZXdCYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUudmlld0JhY2tncm91bmRDb2xvclxuICAgICAgfSkuY2F0Y2gobXV0ZUZTQWJvcnRFcnJvcikuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmV4cG9ydEVtYmVkU2NlbmUgJiYgZmlsZUhhbmRsZSAmJiBpc0ltYWdlRmlsZUhhbmRsZShmaWxlSGFuZGxlKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBmaWxlSGFuZGxlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5vcGVuRXllRHJvcHBlciA9ICh7XG4gICAgICB0eXBlXG4gICAgfSkgPT4ge1xuICAgICAgam90YWlTdG9yZS5zZXQoYWN0aXZlRXllRHJvcHBlckF0b20sIHtcbiAgICAgICAgc3dhcFByZXZpZXdPbkFsdDogdHJ1ZSxcbiAgICAgICAgY29sb3JQaWNrZXJUeXBlOiB0eXBlID09PSBcInN0cm9rZVwiID8gXCJlbGVtZW50U3Ryb2tlXCIgOiBcImVsZW1lbnRCYWNrZ3JvdW5kXCIsXG4gICAgICAgIG9uU2VsZWN0OiAoY29sb3IsIGV2ZW50KSA9PiB7XG4gICAgICAgICAgY29uc3Qgc2hvdWxkVXBkYXRlU3Ryb2tlQ29sb3IgPSB0eXBlID09PSBcImJhY2tncm91bmRcIiAmJiBldmVudC5hbHRLZXkgfHwgdHlwZSA9PT0gXCJzdHJva2VcIiAmJiAhZXZlbnQuYWx0S2V5O1xuICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgICBpZiAoIXNlbGVjdGVkRWxlbWVudHMubGVuZ3RoIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgICAgICBpZiAoc2hvdWxkVXBkYXRlU3Ryb2tlQ29sb3IpIHtcbiAgICAgICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KHtcbiAgICAgICAgICAgICAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAgICAgICAgICAgY3VycmVudEl0ZW1TdHJva2VDb2xvcjogY29sb3JcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoe1xuICAgICAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgICBjdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcjogY29sb3JcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlU2NlbmUoe1xuICAgICAgICAgICAgICBlbGVtZW50czogdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWwgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1tlbC5pZF0pIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbCwge1xuICAgICAgICAgICAgICAgICAgICBbc2hvdWxkVXBkYXRlU3Ryb2tlQ29sb3IgPyBcInN0cm9rZUNvbG9yXCIgOiBcImJhY2tncm91bmRDb2xvclwiXTogY29sb3JcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBlbDtcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAga2VlcE9wZW5PbkFsdDogZmFsc2VcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoYWN0aW9uUmVzdWx0ID0+IHtcbiAgICAgIHZhciBfYSwgX2IsIF9jLCBfZCwgX2UsIF9mLCBfZywgX2gsIF9qO1xuXG4gICAgICBpZiAodGhpcy51bm1vdW50ZWQgfHwgYWN0aW9uUmVzdWx0ID09PSBmYWxzZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGxldCBlZGl0aW5nRWxlbWVudCA9IG51bGw7XG5cbiAgICAgIGlmIChhY3Rpb25SZXN1bHQuZWxlbWVudHMpIHtcbiAgICAgICAgYWN0aW9uUmVzdWx0LmVsZW1lbnRzLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgdmFyIF9hO1xuXG4gICAgICAgICAgaWYgKCgoX2EgPSB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaWQpID09PSBlbGVtZW50LmlkICYmIHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQgIT09IGVsZW1lbnQgJiYgaXNOb25EZWxldGVkRWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICAgICAgZWRpdGluZ0VsZW1lbnQgPSBlbGVtZW50O1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGFjdGlvblJlc3VsdC5lbGVtZW50cyk7XG5cbiAgICAgICAgaWYgKGFjdGlvblJlc3VsdC5jb21taXRUb0hpc3RvcnkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5maWxlcykge1xuICAgICAgICB0aGlzLmZpbGVzID0gYWN0aW9uUmVzdWx0LnJlcGxhY2VGaWxlcyA/IGFjdGlvblJlc3VsdC5maWxlcyA6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5maWxlcyksIGFjdGlvblJlc3VsdC5maWxlcyk7XG4gICAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3Rpb25SZXN1bHQuYXBwU3RhdGUgfHwgZWRpdGluZ0VsZW1lbnQgfHwgdGhpcy5zdGF0ZS5jb250ZXh0TWVudSkge1xuICAgICAgICBpZiAoYWN0aW9uUmVzdWx0LmNvbW1pdFRvSGlzdG9yeSkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCB2aWV3TW9kZUVuYWJsZWQgPSAoKF9hID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eudmlld01vZGVFbmFibGVkKSB8fCBmYWxzZTtcbiAgICAgICAgbGV0IHplbk1vZGVFbmFibGVkID0gKChfYiA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnplbk1vZGVFbmFibGVkKSB8fCBmYWxzZTtcbiAgICAgICAgbGV0IGdyaWRTaXplID0gKChfYyA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmdyaWRTaXplKSB8fCBudWxsO1xuICAgICAgICBjb25zdCB0aGVtZSA9ICgoX2QgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC50aGVtZSkgfHwgdGhpcy5wcm9wcy50aGVtZSB8fCBUSEVNRS5MSUdIVDtcbiAgICAgICAgbGV0IG5hbWUgPSAoX2YgPSAoX2UgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5uYW1lKSAhPT0gbnVsbCAmJiBfZiAhPT0gdm9pZCAwID8gX2YgOiB0aGlzLnN0YXRlLm5hbWU7XG4gICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IChfaCA9IChfZyA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2cgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9nLmVycm9yTWVzc2FnZSkgIT09IG51bGwgJiYgX2ggIT09IHZvaWQgMCA/IF9oIDogdGhpcy5zdGF0ZS5lcnJvck1lc3NhZ2U7XG5cbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLnByb3BzLnZpZXdNb2RlRW5hYmxlZCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIHZpZXdNb2RlRW5hYmxlZCA9IHRoaXMucHJvcHMudmlld01vZGVFbmFibGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLnByb3BzLnplbk1vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgemVuTW9kZUVuYWJsZWQgPSB0aGlzLnByb3BzLnplbk1vZGVFbmFibGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIGdyaWRTaXplID0gdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLnByb3BzLm5hbWUgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICBuYW1lID0gdGhpcy5wcm9wcy5uYW1lO1xuICAgICAgICB9XG5cbiAgICAgICAgZWRpdGluZ0VsZW1lbnQgPSBlZGl0aW5nRWxlbWVudCB8fCAoKF9qID0gYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfaiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2ouZWRpdGluZ0VsZW1lbnQpIHx8IG51bGw7XG5cbiAgICAgICAgaWYgKGVkaXRpbmdFbGVtZW50ID09PSBudWxsIHx8IGVkaXRpbmdFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlZGl0aW5nRWxlbWVudC5pc0RlbGV0ZWQpIHtcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudCA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IHtcbiAgICAgICAgICAvLyB1c2luZyBPYmplY3QuYXNzaWduIGluc3RlYWQgb2Ygc3ByZWFkIHRvIGZvb2wgVFMgNC4yLjIrIGludG9cbiAgICAgICAgICAvLyByZWdhcmRpbmcgdGhlIHJlc3VsdGluZyB0eXBlIGFzIG5vdCBjb250YWluaW5nIHVuZGVmaW5lZFxuICAgICAgICAgIC8vICh3aGljaCB0aGUgZm9sbG93aW5nIGV4cHJlc3Npb24gd2lsbCBuZXZlciBjb250YWluKVxuICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKGFjdGlvblJlc3VsdC5hcHBTdGF0ZSB8fCB7fSwge1xuICAgICAgICAgICAgLy8gTk9URSB0aGlzIHdpbGwgcHJldmVudCBvcGVuaW5nIGNvbnRleHQgbWVudSB1c2luZyBhbiBhY3Rpb25cbiAgICAgICAgICAgIC8vIG9yIHByb2dyYW1tYXRpY2FsbHkgZnJvbSB0aGUgaG9zdCwgc28gaXQgd2lsbCBuZWVkIHRvIGJlXG4gICAgICAgICAgICAvLyByZXdyaXR0ZW4gbGF0ZXJcbiAgICAgICAgICAgIGNvbnRleHRNZW51OiBudWxsLFxuICAgICAgICAgICAgZWRpdGluZ0VsZW1lbnQsXG4gICAgICAgICAgICB2aWV3TW9kZUVuYWJsZWQsXG4gICAgICAgICAgICB6ZW5Nb2RlRW5hYmxlZCxcbiAgICAgICAgICAgIGdyaWRTaXplLFxuICAgICAgICAgICAgdGhlbWUsXG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICBpZiAoYWN0aW9uUmVzdWx0LnN5bmNIaXN0b3J5KSB7XG4gICAgICAgICAgICB0aGlzLmhpc3Rvcnkuc2V0Q3VycmVudFN0YXRlKHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7IC8vIExpZmVjeWNsZVxuXG4gICAgdGhpcy5vbkJsdXIgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoKCkgPT4ge1xuICAgICAgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiB0cnVlXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIHRoaXMub25VbmxvYWQgPSAoKSA9PiB7XG4gICAgICB0aGlzLm9uQmx1cigpO1xuICAgIH07XG5cbiAgICB0aGlzLmRpc2FibGVFdmVudCA9IGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzZXRIaXN0b3J5ID0gKCkgPT4ge1xuICAgICAgdGhpcy5oaXN0b3J5LmNsZWFyKCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXNldHMgc2NlbmUgJiBoaXN0b3J5LlxuICAgICAqICEgRG8gbm90IHVzZSB0byBjbGVhciBzY2VuZSB1c2VyIGFjdGlvbiAhXG4gICAgICovXG5cblxuICAgIHRoaXMucmVzZXRTY2VuZSA9IHdpdGhCYXRjaGVkVXBkYXRlcyhvcHRzID0+IHtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFtdKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXREZWZhdWx0QXBwU3RhdGUoKSksIHtcbiAgICAgICAgaXNMb2FkaW5nOiAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnJlc2V0TG9hZGluZ1N0YXRlKSA/IGZhbHNlIDogc3RhdGUuaXNMb2FkaW5nLFxuICAgICAgICB0aGVtZTogdGhpcy5zdGF0ZS50aGVtZVxuICAgICAgfSkpO1xuICAgICAgdGhpcy5yZXNldEhpc3RvcnkoKTtcbiAgICB9KTtcblxuICAgIHRoaXMuaW5pdGlhbGl6ZVNjZW5lID0gKCkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdmFyIF9iO1xuXG4gICAgICBpZiAoXCJsYXVuY2hRdWV1ZVwiIGluIHdpbmRvdyAmJiBcIkxhdW5jaFBhcmFtc1wiIGluIHdpbmRvdykge1xuICAgICAgICB3aW5kb3cubGF1bmNoUXVldWUuc2V0Q29uc3VtZXIobGF1bmNoUGFyYW1zID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgICAgICBpZiAoIWxhdW5jaFBhcmFtcy5maWxlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBmaWxlSGFuZGxlID0gbGF1bmNoUGFyYW1zLmZpbGVzWzBdO1xuICAgICAgICAgIGNvbnN0IGJsb2IgPSB5aWVsZCBmaWxlSGFuZGxlLmdldEZpbGUoKTtcbiAgICAgICAgICB0aGlzLmxvYWRGaWxlVG9DYW52YXMobmV3IEZpbGUoW2Jsb2JdLCBibG9iLm5hbWUgfHwgXCJcIiwge1xuICAgICAgICAgICAgdHlwZTogYmxvYi50eXBlXG4gICAgICAgICAgfSksIGZpbGVIYW5kbGUpO1xuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnByb3BzLnRoZW1lKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHRoZW1lOiB0aGlzLnByb3BzLnRoZW1lXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUuaXNMb2FkaW5nKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGlzTG9hZGluZzogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgbGV0IGluaXRpYWxEYXRhID0gbnVsbDtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgaW5pdGlhbERhdGEgPSAoeWllbGQgdGhpcy5wcm9wcy5pbml0aWFsRGF0YSkgfHwgbnVsbDtcblxuICAgICAgICBpZiAoaW5pdGlhbERhdGEgPT09IG51bGwgfHwgaW5pdGlhbERhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGluaXRpYWxEYXRhLmxpYnJhcnlJdGVtcykge1xuICAgICAgICAgIHRoaXMubGlicmFyeS51cGRhdGVMaWJyYXJ5KHtcbiAgICAgICAgICAgIGxpYnJhcnlJdGVtczogaW5pdGlhbERhdGEubGlicmFyeUl0ZW1zLFxuICAgICAgICAgICAgbWVyZ2U6IHRydWVcbiAgICAgICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgIGluaXRpYWxEYXRhID0ge1xuICAgICAgICAgIGFwcFN0YXRlOiB7XG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UgfHwgXCJFbmNvdW50ZXJlZCBhbiBlcnJvciBkdXJpbmcgaW1wb3J0aW5nIG9yIHJlc3RvcmluZyBzY2VuZSBkYXRhXCJcbiAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNjZW5lID0gcmVzdG9yZShpbml0aWFsRGF0YSwgbnVsbCwgbnVsbCwge1xuICAgICAgICByZXBhaXJCaW5kaW5nczogdHJ1ZVxuICAgICAgfSk7XG4gICAgICBzY2VuZS5hcHBTdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCB7XG4gICAgICAgIHRoZW1lOiB0aGlzLnByb3BzLnRoZW1lIHx8IHNjZW5lLmFwcFN0YXRlLnRoZW1lLFxuICAgICAgICAvLyB3ZSdyZSBmYWxsaW5nIGJhY2sgdG8gY3VycmVudCAocHJlLWluaXQpIHN0YXRlIHdoZW4gZGVjaWRpbmdcbiAgICAgICAgLy8gd2hldGhlciB0byBvcGVuIHRoZSBsaWJyYXJ5LCB0byBoYW5kbGUgYSBjYXNlIHdoZXJlIHdlXG4gICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUgb3V0c2lkZSBvZiBpbml0aWFsRGF0YSAoZS5nLiB3aGVuIGxvYWRpbmcgdGhlIGFwcFxuICAgICAgICAvLyB3aXRoIGEgbGlicmFyeSBpbnN0YWxsIGxpbmssIHdoaWNoIHNob3VsZCBhdXRvLW9wZW4gdGhlIGxpYnJhcnkpXG4gICAgICAgIG9wZW5TaWRlYmFyOiAoKF9iID0gc2NlbmUuYXBwU3RhdGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5vcGVuU2lkZWJhcikgfHwgdGhpcy5zdGF0ZS5vcGVuU2lkZWJhcixcbiAgICAgICAgYWN0aXZlVG9vbDogc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImltYWdlXCIgPyBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlLmFjdGl2ZVRvb2wpLCB7XG4gICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICB9KSA6IHNjZW5lLmFwcFN0YXRlLmFjdGl2ZVRvb2wsXG4gICAgICAgIGlzTG9hZGluZzogZmFsc2UsXG4gICAgICAgIHRvYXN0OiB0aGlzLnN0YXRlLnRvYXN0XG4gICAgICB9KTtcblxuICAgICAgaWYgKGluaXRpYWxEYXRhID09PSBudWxsIHx8IGluaXRpYWxEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpbml0aWFsRGF0YS5zY3JvbGxUb0NvbnRlbnQpIHtcbiAgICAgICAgc2NlbmUuYXBwU3RhdGUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlKSwgY2FsY3VsYXRlU2Nyb2xsQ2VudGVyKHNjZW5lLmVsZW1lbnRzLCBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlKSwge1xuICAgICAgICAgIHdpZHRoOiB0aGlzLnN0YXRlLndpZHRoLFxuICAgICAgICAgIGhlaWdodDogdGhpcy5zdGF0ZS5oZWlnaHQsXG4gICAgICAgICAgb2Zmc2V0VG9wOiB0aGlzLnN0YXRlLm9mZnNldFRvcCxcbiAgICAgICAgICBvZmZzZXRMZWZ0OiB0aGlzLnN0YXRlLm9mZnNldExlZnRcbiAgICAgICAgfSkpKTtcbiAgICAgIH0gLy8gRm9udEZhY2VTZXQgbG9hZGluZ2RvbmUgZXZlbnQgd2UgbGlzdGVuIG9uIG1heSBub3QgYWx3YXlzIGZpcmVcbiAgICAgIC8vIChsb29raW5nIGF0IHlvdSBTYWZhcmkpLCBzbyBvbiBpbml0IHdlIG1hbnVhbGx5IGxvYWQgZm9udHMgZm9yIGN1cnJlbnRcbiAgICAgIC8vIHRleHQgZWxlbWVudHMgb24gY2FudmFzLCBhbmQgcmVyZW5kZXIgdGhlbSBvbmNlIGRvbmUuIFRoaXMgYWxzb1xuICAgICAgLy8gc2VlbXMgZmFzdGVyIGV2ZW4gaW4gYnJvd3NlcnMgdGhhdCBkbyBmaXJlIHRoZSBsb2FkaW5nZG9uZSBldmVudC5cblxuXG4gICAgICB0aGlzLmZvbnRzLmxvYWRGb250c0ZvckVsZW1lbnRzKHNjZW5lLmVsZW1lbnRzKTtcblxuICAgICAgaWYgKChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEuc2Nyb2xsWCkgIT0gbnVsbCkge1xuICAgICAgICBzY2VuZS5hcHBTdGF0ZS5zY3JvbGxYID0gaW5pdGlhbERhdGEuc2Nyb2xsWDtcbiAgICAgIH1cblxuICAgICAgaWYgKChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEuc2Nyb2xsWSkgIT0gbnVsbCkge1xuICAgICAgICBzY2VuZS5hcHBTdGF0ZS5zY3JvbGxZID0gaW5pdGlhbERhdGEuc2Nyb2xsWTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5yZXNldEhpc3RvcnkoKTtcbiAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lKSwge1xuICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRoaXMucmVmcmVzaERldmljZVN0YXRlID0gY29udGFpbmVyID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgd2lkdGgsXG4gICAgICAgIGhlaWdodFxuICAgICAgfSA9IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGNvbnN0IHNpZGViYXJCcmVha3BvaW50ID0gdGhpcy5wcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT0gbnVsbCA/IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50IDogTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEg7XG4gICAgICB0aGlzLmRldmljZSA9IHVwZGF0ZU9iamVjdCh0aGlzLmRldmljZSwge1xuICAgICAgICBpc0xhbmRzY2FwZTogd2lkdGggPiBoZWlnaHQsXG4gICAgICAgIGlzU21TY3JlZW46IHdpZHRoIDwgTVFfU01fTUFYX1dJRFRILFxuICAgICAgICBpc01vYmlsZTogd2lkdGggPCBNUV9NQVhfV0lEVEhfUE9SVFJBSVQgfHwgaGVpZ2h0IDwgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUgJiYgd2lkdGggPCBNUV9NQVhfV0lEVEhfTEFORFNDQVBFLFxuICAgICAgICBjYW5EZXZpY2VGaXRTaWRlYmFyOiB3aWR0aCA+IHNpZGViYXJCcmVha3BvaW50XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5vblJlc2l6ZSA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZvckVhY2goZWxlbWVudCA9PiBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHt9KTtcbiAgICB9KTtcblxuICAgIHRoaXMub25Gb250c0xvYWRpbmdEb25lID0gZXZlbnQgPT4ge1xuICAgICAgY29uc3QgbG9hZGVkRm9udEZhY2VzID0gZXZlbnQuZm9udGZhY2VzO1xuICAgICAgdGhpcy5mb250cy5vbkZvbnRzTG9hZGVkKGxvYWRlZEZvbnRGYWNlcyk7XG4gICAgfTtcblxuICAgIHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrID0gKHtcbiAgICAgIGF0TGVhc3RPbmVWaXNpYmxlRWxlbWVudCxcbiAgICAgIHNjcm9sbEJhcnMsXG4gICAgICBlbGVtZW50c1xuICAgIH0pID0+IHtcbiAgICAgIGlmIChzY3JvbGxCYXJzKSB7XG4gICAgICAgIGN1cnJlbnRTY3JvbGxCYXJzID0gc2Nyb2xsQmFycztcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2Nyb2xsZWRPdXRzaWRlID0gLy8gaGlkZSB3aGVuIGVkaXRpbmcgdGV4dFxuICAgICAgaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA/IGZhbHNlIDogIWF0TGVhc3RPbmVWaXNpYmxlRWxlbWVudCAmJiBlbGVtZW50cy5sZW5ndGggPiAwO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zY3JvbGxlZE91dHNpZGUgIT09IHNjcm9sbGVkT3V0c2lkZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzY3JvbGxlZE91dHNpZGVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2NoZWR1bGVJbWFnZVJlZnJlc2goKTtcbiAgICB9O1xuXG4gICAgdGhpcy5vblNjcm9sbCA9IGRlYm91bmNlKCgpID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgb2Zmc2V0VG9wLFxuICAgICAgICBvZmZzZXRMZWZ0XG4gICAgICB9ID0gdGhpcy5nZXRDYW52YXNPZmZzZXRzKCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IHtcbiAgICAgICAgaWYgKHN0YXRlLm9mZnNldExlZnQgPT09IG9mZnNldExlZnQgJiYgc3RhdGUub2Zmc2V0VG9wID09PSBvZmZzZXRUb3ApIHtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgb2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnRcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH0sIFNDUk9MTF9USU1FT1VUKTsgLy8gQ29weS9wYXN0ZVxuXG4gICAgdGhpcy5vbkN1dCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IGlzRXhjYWxpZHJhd0FjdGl2ZSA9IChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY29udGFpbnMoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCk7XG5cbiAgICAgIGlmICghaXNFeGNhbGlkcmF3QWN0aXZlIHx8IGlzV3JpdGFibGVFbGVtZW50KGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmN1dEFsbCgpO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH0pO1xuICAgIHRoaXMub25Db3B5ID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaXNFeGNhbGlkcmF3QWN0aXZlID0gKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jb250YWlucyhkb2N1bWVudC5hY3RpdmVFbGVtZW50KTtcblxuICAgICAgaWYgKCFpc0V4Y2FsaWRyYXdBY3RpdmUgfHwgaXNXcml0YWJsZUVsZW1lbnQoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuY29weUFsbCgpO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5jdXRBbGwgPSAoKSA9PiB7XG4gICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25DdXQsIFwia2V5Ym9hcmRcIik7XG4gICAgfTtcblxuICAgIHRoaXMuY29weUFsbCA9ICgpID0+IHtcbiAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkNvcHksIFwia2V5Ym9hcmRcIik7XG4gICAgfTtcblxuICAgIHRoaXMub25Ub3VjaFN0YXJ0ID0gZXZlbnQgPT4ge1xuICAgICAgLy8gZml4IGZvciBBcHBsZSBQZW5jaWwgU2NyaWJibGVcbiAgICAgIC8vIE9uIEFuZHJvaWQsIHByZXZlbnRpbmcgdGhlIGV2ZW50IHdvdWxkIGRpc2FibGUgY29udGV4dE1lbnUgb24gdGFwLWhvbGRcbiAgICAgIGlmICghaXNBbmRyb2lkKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghZGlkVGFwVHdpY2UpIHtcbiAgICAgICAgZGlkVGFwVHdpY2UgPSB0cnVlO1xuICAgICAgICBjbGVhclRpbWVvdXQodGFwcGVkVHdpY2VUaW1lcik7XG4gICAgICAgIHRhcHBlZFR3aWNlVGltZXIgPSB3aW5kb3cuc2V0VGltZW91dChBcHAucmVzZXRUYXBUd2ljZSwgVEFQX1RXSUNFX1RJTUVPVVQpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIGluc2VydCB0ZXh0IG9ubHkgaWYgd2UgdGFwcGVkIHR3aWNlIHdpdGggYSBzaW5nbGUgZmluZ2VyXG4gICAgICAvLyBldmVudC50b3VjaGVzLmxlbmd0aCA9PT0gMSB3aWxsIGFsc28gcHJldmVudCBpbnNlcnRpbmcgdGV4dCB3aGVuIHVzZXIncyB6b29taW5nXG5cblxuICAgICAgaWYgKGRpZFRhcFR3aWNlICYmIGV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIGNvbnN0IHRvdWNoID0gZXZlbnQudG91Y2hlc1swXTsgLy8gQHRzLWlnbm9yZVxuXG4gICAgICAgIHRoaXMuaGFuZGxlQ2FudmFzRG91YmxlQ2xpY2soe1xuICAgICAgICAgIGNsaWVudFg6IHRvdWNoLmNsaWVudFgsXG4gICAgICAgICAgY2xpZW50WTogdG91Y2guY2xpZW50WVxuICAgICAgICB9KTtcbiAgICAgICAgZGlkVGFwVHdpY2UgPSBmYWxzZTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRhcHBlZFR3aWNlVGltZXIpO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNBbmRyb2lkKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC50b3VjaGVzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLm9uVG91Y2hFbmQgPSBldmVudCA9PiB7XG4gICAgICB0aGlzLnJlc2V0Q29udGV4dE1lbnVUaW1lcigpO1xuXG4gICAgICBpZiAoZXZlbnQudG91Y2hlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB7fSxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHRoaXMuc3RhdGUucHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHMsIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZ2VzdHVyZS5wb2ludGVycy5jbGVhcigpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB2YXIgX2MsIF9kLCBfZTtcblxuICAgICAgY29uc3QgaXNQbGFpblBhc3RlID0gISEoSVNfUExBSU5fUEFTVEUgJiYgZXZlbnQpOyAvLyAjNjg2XG5cbiAgICAgIGNvbnN0IHRhcmdldCA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG4gICAgICBjb25zdCBpc0V4Y2FsaWRyYXdBY3RpdmUgPSAoX2MgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmNvbnRhaW5zKHRhcmdldCk7XG5cbiAgICAgIGlmIChldmVudCAmJiAhaXNFeGNhbGlkcmF3QWN0aXZlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudFVuZGVyQ3Vyc29yID0gZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludCh0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSk7XG5cbiAgICAgIGlmIChldmVudCAmJiAoIShlbGVtZW50VW5kZXJDdXJzb3IgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCkgfHwgaXNXcml0YWJsZUVsZW1lbnQodGFyZ2V0KSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBtdXN0IGJlIGNhbGxlZCBpbiB0aGUgc2FtZSBmcmFtZSAodGh1cyBiZWZvcmUgYW55IGF3YWl0cykgYXMgdGhlIHBhc3RlXG4gICAgICAvLyBldmVudCBlbHNlIHNvbWUgYnJvd3NlcnMgKEZGLi4uKSB3aWxsIGNsZWFyIHRoZSBjbGlwYm9hcmREYXRhXG4gICAgICAvLyAoc29tZXRoaW5nIHNvbWV0aGluZyBzZWN1cml0eSlcblxuXG4gICAgICBsZXQgZmlsZSA9IChfZCA9IGV2ZW50ID09PSBudWxsIHx8IGV2ZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBldmVudC5jbGlwYm9hcmREYXRhKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuZmlsZXNbMF07XG4gICAgICBjb25zdCBkYXRhID0geWllbGQgcGFyc2VDbGlwYm9hcmQoZXZlbnQsIGlzUGxhaW5QYXN0ZSk7XG5cbiAgICAgIGlmICghZmlsZSAmJiBkYXRhLnRleHQgJiYgIWlzUGxhaW5QYXN0ZSkge1xuICAgICAgICBjb25zdCBzdHJpbmcgPSBkYXRhLnRleHQudHJpbSgpO1xuXG4gICAgICAgIGlmIChzdHJpbmcuc3RhcnRzV2l0aChcIjxzdmdcIikgJiYgc3RyaW5nLmVuZHNXaXRoKFwiPC9zdmc+XCIpKSB7XG4gICAgICAgICAgLy8gaWdub3JlIFNWRyB2YWxpZGF0aW9uL25vcm1hbGl6YXRpb24gd2hpY2ggd2lsbCBiZSBkb25lIGR1cmluZyBpbWFnZVxuICAgICAgICAgIC8vIGluaXRpYWxpemF0aW9uXG4gICAgICAgICAgZmlsZSA9IFNWR1N0cmluZ1RvRmlsZShzdHJpbmcpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeDogc2NlbmVYLFxuICAgICAgICB5OiBzY2VuZVlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgIGNsaWVudFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueVxuICAgICAgfSwgdGhpcy5zdGF0ZSk7IC8vIHByZWZlciBzcHJlYWRzaGVldCBkYXRhIG92ZXIgaW1hZ2UgZmlsZSAoTVMgT2ZmaWNlL0xpYnJlIE9mZmljZSlcblxuICAgICAgaWYgKGlzU3VwcG9ydGVkSW1hZ2VGaWxlKGZpbGUpICYmICFkYXRhLnNwcmVhZHNoZWV0KSB7XG4gICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50KHtcbiAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgc2NlbmVZXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmluc2VydEltYWdlRWxlbWVudChpbWFnZUVsZW1lbnQsIGZpbGUpO1xuICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnByb3BzLm9uUGFzdGUpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAoKHlpZWxkIHRoaXMucHJvcHMub25QYXN0ZShkYXRhLCBldmVudCkpID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZGF0YS5lcnJvck1lc3NhZ2UpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBkYXRhLmVycm9yTWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5zcHJlYWRzaGVldCAmJiAhaXNQbGFpblBhc3RlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHBhc3RlRGlhbG9nOiB7XG4gICAgICAgICAgICBkYXRhOiBkYXRhLnNwcmVhZHNoZWV0LFxuICAgICAgICAgICAgc2hvd246IHRydWVcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmVsZW1lbnRzKSB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzID0gZGF0YS5wcm9ncmFtbWF0aWNBUEkgPyBjb252ZXJ0VG9FeGNhbGlkcmF3RWxlbWVudHMoZGF0YS5lbGVtZW50cykgOiBkYXRhLmVsZW1lbnRzOyAvLyBUT0RPIHJlbW92ZSBmb3JtYXR0aW5nIGZyb20gZWxlbWVudHMgaWYgaXNQbGFpblBhc3RlXG5cbiAgICAgICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSh7XG4gICAgICAgICAgZWxlbWVudHMsXG4gICAgICAgICAgZmlsZXM6IGRhdGEuZmlsZXMgfHwgbnVsbCxcbiAgICAgICAgICBwb3NpdGlvbjogXCJjdXJzb3JcIixcbiAgICAgICAgICByZXRhaW5TZWVkOiBpc1BsYWluUGFzdGVcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEudGV4dCkge1xuICAgICAgICBjb25zdCBtYXliZVVybCA9IGV4dHJhY3RTcmMoZGF0YS50ZXh0KTtcblxuICAgICAgICBpZiAoIWlzUGxhaW5QYXN0ZSAmJiBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yKG1heWJlVXJsLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSkgJiYgKC9eKGh0dHB8aHR0cHMpOlxcL1xcL1teXFxzLyQuPyNdLlteXFxzXSokLy50ZXN0KG1heWJlVXJsKSB8fCAoKF9lID0gZ2V0RW1iZWRMaW5rKG1heWJlVXJsKSkgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLnR5cGUpID09PSBcInZpZGVvXCIpKSB7XG4gICAgICAgICAgY29uc3QgZW1iZWRkYWJsZSA9IHRoaXMuaW5zZXJ0RW1iZWRkYWJsZUVsZW1lbnQoe1xuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZLFxuICAgICAgICAgICAgbGluazogbm9ybWFsaXplTGluayhtYXliZVVybClcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmIChlbWJlZGRhYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgW2VtYmVkZGFibGUuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuYWRkVGV4dEZyb21QYXN0ZShkYXRhLnRleHQsIGlzUGxhaW5QYXN0ZSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgIH0pO1xuICAgICAgZXZlbnQgPT09IG51bGwgfHwgZXZlbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSkpO1xuXG4gICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSA9IG9wdHMgPT4ge1xuICAgICAgY29uc3QgZWxlbWVudHMgPSByZXN0b3JlRWxlbWVudHMob3B0cy5lbGVtZW50cywgbnVsbCwgdW5kZWZpbmVkKTtcbiAgICAgIGNvbnN0IFttaW5YLCBtaW5ZLCBtYXhYLCBtYXhZXSA9IGdldENvbW1vbkJvdW5kcyhlbGVtZW50cyk7XG4gICAgICBjb25zdCBlbGVtZW50c0NlbnRlclggPSBkaXN0YW5jZShtaW5YLCBtYXhYKSAvIDI7XG4gICAgICBjb25zdCBlbGVtZW50c0NlbnRlclkgPSBkaXN0YW5jZShtaW5ZLCBtYXhZKSAvIDI7XG4gICAgICBjb25zdCBjbGllbnRYID0gdHlwZW9mIG9wdHMucG9zaXRpb24gPT09IFwib2JqZWN0XCIgPyBvcHRzLnBvc2l0aW9uLmNsaWVudFggOiBvcHRzLnBvc2l0aW9uID09PSBcImN1cnNvclwiID8gdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54IDogdGhpcy5zdGF0ZS53aWR0aCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldExlZnQ7XG4gICAgICBjb25zdCBjbGllbnRZID0gdHlwZW9mIG9wdHMucG9zaXRpb24gPT09IFwib2JqZWN0XCIgPyBvcHRzLnBvc2l0aW9uLmNsaWVudFkgOiBvcHRzLnBvc2l0aW9uID09PSBcImN1cnNvclwiID8gdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55IDogdGhpcy5zdGF0ZS5oZWlnaHQgLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRUb3A7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYLFxuICAgICAgICBjbGllbnRZXG4gICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGR4ID0geCAtIGVsZW1lbnRzQ2VudGVyWDtcbiAgICAgIGNvbnN0IGR5ID0geSAtIGVsZW1lbnRzQ2VudGVyWTtcbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KGR4LCBkeSwgdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBuZXdFbGVtZW50cyA9IGR1cGxpY2F0ZUVsZW1lbnRzKGVsZW1lbnRzLm1hcChlbGVtZW50ID0+IHtcbiAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZW1lbnQsIHtcbiAgICAgICAgICB4OiBlbGVtZW50LnggKyBncmlkWCAtIG1pblgsXG4gICAgICAgICAgeTogZWxlbWVudC55ICsgZ3JpZFkgLSBtaW5ZXG4gICAgICAgIH0pO1xuICAgICAgfSksIHtcbiAgICAgICAgcmFuZG9taXplU2VlZDogIW9wdHMucmV0YWluU2VlZFxuICAgICAgfSk7XG4gICAgICBjb25zdCBuZXh0RWxlbWVudHMgPSBbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgLi4ubmV3RWxlbWVudHNdO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dEVsZW1lbnRzKTtcbiAgICAgIG5ld0VsZW1lbnRzLmZvckVhY2gobmV3RWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc1RleHRFbGVtZW50KG5ld0VsZW1lbnQpICYmIGlzQm91bmRUb0NvbnRhaW5lcihuZXdFbGVtZW50KSkge1xuICAgICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IGdldENvbnRhaW5lckVsZW1lbnQobmV3RWxlbWVudCk7XG4gICAgICAgICAgcmVkcmF3VGV4dEJvdW5kaW5nQm94KG5ld0VsZW1lbnQsIGNvbnRhaW5lcik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpZiAob3B0cy5maWxlcykge1xuICAgICAgICB0aGlzLmZpbGVzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgb3B0cy5maWxlcyk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIGNvbnN0IG5leHRFbGVtZW50c1RvU2VsZWN0ID0gZXhjbHVkZUVsZW1lbnRzSW5GcmFtZXNGcm9tU2VsZWN0aW9uKG5ld0VsZW1lbnRzKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCB7XG4gICAgICAgIC8vIGtlZXAgc2lkZWJhciAocHJlc3VtYWJseSB0aGUgbGlicmFyeSkgb3BlbiBpZiBpdCdzIGRvY2tlZCBhbmRcbiAgICAgICAgLy8gY2FuIGZpdC5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gTm90ZSwgd2Ugc2hvdWxkIGNsb3NlIHRoZSBzaWRlYmFyIG9ubHkgaWYgd2UncmUgZHJvcHBpbmcgaXRlbXNcbiAgICAgICAgLy8gZnJvbSBsaWJyYXJ5LCBub3Qgd2hlbiBwYXN0aW5nIGZyb20gY2xpcGJvYXJkLiBBbGFzLlxuICAgICAgICBvcGVuU2lkZWJhcjogdGhpcy5zdGF0ZS5vcGVuU2lkZWJhciAmJiB0aGlzLmRldmljZS5jYW5EZXZpY2VGaXRTaWRlYmFyICYmIGpvdGFpU3RvcmUuZ2V0KGlzU2lkZWJhckRvY2tlZEF0b20pID8gdGhpcy5zdGF0ZS5vcGVuU2lkZWJhciA6IG51bGxcbiAgICAgIH0pLCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dEVsZW1lbnRzVG9TZWxlY3QucmVkdWNlKChhY2MsIGVsZW1lbnQpID0+IHtcbiAgICAgICAgICBpZiAoIWlzQm91bmRUb0NvbnRhaW5lcihlbGVtZW50KSkge1xuICAgICAgICAgICAgYWNjW2VsZW1lbnQuaWRdID0gdHJ1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICB9LCB7fSlcbiAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHRoaXMpKSwgKCkgPT4ge1xuICAgICAgICBpZiAob3B0cy5maWxlcykge1xuICAgICAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy5zZXRBY3RpdmVUb29sKHtcbiAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc2V0QXBwU3RhdGUgPSAoc3RhdGUsIGNhbGxiYWNrKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlLCBjYWxsYmFjayk7XG4gICAgfTtcblxuICAgIHRoaXMucmVtb3ZlUG9pbnRlciA9IGV2ZW50ID0+IHtcbiAgICAgIGlmICh0b3VjaFRpbWVvdXQpIHtcbiAgICAgICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIoKTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5wb2ludGVycy5kZWxldGUoZXZlbnQucG9pbnRlcklkKTtcbiAgICB9O1xuXG4gICAgdGhpcy50b2dnbGVMb2NrID0gKHNvdXJjZSA9IFwidWlcIikgPT4ge1xuICAgICAgaWYgKCF0aGlzLnN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgIHRyYWNrRXZlbnQoXCJ0b29sYmFyXCIsIFwidG9nZ2xlTG9ja1wiLCBgJHtzb3VyY2V9ICgke3RoaXMuZGV2aWNlLmlzTW9iaWxlID8gXCJtb2JpbGVcIiA6IFwiZGVza3RvcFwifSlgKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuYWN0aXZlVG9vbCksIHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwgcHJldlN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkID8ge1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0gOiBwcmV2U3RhdGUuYWN0aXZlVG9vbCkpLCB7XG4gICAgICAgICAgICBsb2NrZWQ6ICFwcmV2U3RhdGUuYWN0aXZlVG9vbC5sb2NrZWRcbiAgICAgICAgICB9KVxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMudXBkYXRlRnJhbWVSZW5kZXJpbmcgPSBvcHRzID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kO1xuXG4gICAgICAgIGNvbnN0IG5leHQgPSB0eXBlb2Ygb3B0cyA9PT0gXCJmdW5jdGlvblwiID8gb3B0cyhwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcpIDogb3B0cztcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBmcmFtZVJlbmRlcmluZzoge1xuICAgICAgICAgICAgZW5hYmxlZDogKF9hID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0LmVuYWJsZWQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5lbmFibGVkLFxuICAgICAgICAgICAgY2xpcDogKF9iID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0LmNsaXApICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5jbGlwLFxuICAgICAgICAgICAgbmFtZTogKF9jID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0Lm5hbWUpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lLFxuICAgICAgICAgICAgb3V0bGluZTogKF9kID0gbmV4dCA9PT0gbnVsbCB8fCBuZXh0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0Lm91dGxpbmUpICE9PSBudWxsICYmIF9kICE9PSB2b2lkIDAgPyBfZCA6IHByZXZTdGF0ZS5mcmFtZVJlbmRlcmluZy5vdXRsaW5lXG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMudG9nZ2xlUGVuTW9kZSA9ICgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBwZW5Nb2RlOiAhcHJldlN0YXRlLnBlbk1vZGVcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLm9uSGFuZFRvb2xUb2dnbGUgPSAoKSA9PiB7XG4gICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25Ub2dnbGVIYW5kVG9vbCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBab29tcyBvbiBjYW52YXMgdmlld3BvcnQgY2VudGVyXG4gICAgICovXG5cblxuICAgIHRoaXMuem9vbUNhbnZhcyA9IChcbiAgICAvKiogZGVjaW1hbCBmcmFjdGlvbiBiZXR3ZWVuIDAuMSAoMTAlIHpvb20pIGFuZCAzMCAoMzAwMCUgem9vbSkgKi9cbiAgICB2YWx1ZSkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKHt9LCBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICB2aWV3cG9ydFg6IHRoaXMuc3RhdGUud2lkdGggLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICB2aWV3cG9ydFk6IHRoaXMuc3RhdGUuaGVpZ2h0IC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20odmFsdWUpXG4gICAgICB9LCB0aGlzLnN0YXRlKSkpO1xuICAgIH07XG5cbiAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9IG51bGw7XG5cbiAgICB0aGlzLnNjcm9sbFRvQ29udGVudCA9ICh0YXJnZXQgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBvcHRzKSA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAoX2EgPSB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwodGhpcyk7IC8vIGNvbnZlcnQgcHJvdmlkZWQgdGFyZ2V0IGludG8gRXhjYWxpZHJhd0VsZW1lbnRbXSBpZiBuZWNlc3NhcnlcblxuICAgICAgY29uc3QgdGFyZ2V0RWxlbWVudHMgPSBBcnJheS5pc0FycmF5KHRhcmdldCkgPyB0YXJnZXQgOiBbdGFyZ2V0XTtcbiAgICAgIGxldCB6b29tID0gdGhpcy5zdGF0ZS56b29tO1xuICAgICAgbGV0IHNjcm9sbFggPSB0aGlzLnN0YXRlLnNjcm9sbFg7XG4gICAgICBsZXQgc2Nyb2xsWSA9IHRoaXMuc3RhdGUuc2Nyb2xsWTtcblxuICAgICAgaWYgKChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZml0VG9Db250ZW50KSB8fCAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvVmlld3BvcnQpKSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBhcHBTdGF0ZVxuICAgICAgICB9ID0gem9vbVRvRml0KHtcbiAgICAgICAgICB0YXJnZXRFbGVtZW50cyxcbiAgICAgICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgICAgICBmaXRUb1ZpZXdwb3J0OiAhIShvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZml0VG9WaWV3cG9ydCksXG4gICAgICAgICAgdmlld3BvcnRab29tRmFjdG9yOiBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMudmlld3BvcnRab29tRmFjdG9yXG4gICAgICAgIH0pO1xuICAgICAgICB6b29tID0gYXBwU3RhdGUuem9vbTtcbiAgICAgICAgc2Nyb2xsWCA9IGFwcFN0YXRlLnNjcm9sbFg7XG4gICAgICAgIHNjcm9sbFkgPSBhcHBTdGF0ZS5zY3JvbGxZO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gY29tcHV0ZSBvbmx5IHRoZSB2aWV3cG9ydCBsb2NhdGlvbiwgd2l0aG91dCBhbnkgem9vbSBhZGp1c3RtZW50XG4gICAgICAgIGNvbnN0IHNjcm9sbCA9IGNhbGN1bGF0ZVNjcm9sbENlbnRlcih0YXJnZXRFbGVtZW50cywgdGhpcy5zdGF0ZSk7XG4gICAgICAgIHNjcm9sbFggPSBzY3JvbGwuc2Nyb2xsWDtcbiAgICAgICAgc2Nyb2xsWSA9IHNjcm9sbC5zY3JvbGxZO1xuICAgICAgfSAvLyB3aGVuIGFuaW1hdGluZywgd2UgdXNlIFJlcXVlc3RBbmltYXRpb25GcmFtZSB0byBwcmV2ZW50IHRoZSBhbmltYXRpb25cbiAgICAgIC8vIGZyb20gc2xvd2luZyBkb3duIG90aGVyIHByb2Nlc3Nlc1xuXG5cbiAgICAgIGlmIChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuYW5pbWF0ZSkge1xuICAgICAgICBjb25zdCBvcmlnU2Nyb2xsWCA9IHRoaXMuc3RhdGUuc2Nyb2xsWDtcbiAgICAgICAgY29uc3Qgb3JpZ1Njcm9sbFkgPSB0aGlzLnN0YXRlLnNjcm9sbFk7XG4gICAgICAgIGNvbnN0IG9yaWdab29tID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgICBjb25zdCBjYW5jZWwgPSBlYXNlVG9WYWx1ZXNSQUYoe1xuICAgICAgICAgIGZyb21WYWx1ZXM6IHtcbiAgICAgICAgICAgIHNjcm9sbFg6IG9yaWdTY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWTogb3JpZ1Njcm9sbFksXG4gICAgICAgICAgICB6b29tOiBvcmlnWm9vbVxuICAgICAgICAgIH0sXG4gICAgICAgICAgdG9WYWx1ZXM6IHtcbiAgICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgem9vbTogem9vbS52YWx1ZVxuICAgICAgICAgIH0sXG4gICAgICAgICAgaW50ZXJwb2xhdGVWYWx1ZTogKGZyb20sIHRvLCBwcm9ncmVzcywga2V5KSA9PiB7XG4gICAgICAgICAgICAvLyBmb3Igem9vbSwgdXNlIGRpZmZlcmVudCBlYXNpbmdcbiAgICAgICAgICAgIGlmIChrZXkgPT09IFwiem9vbVwiKSB7XG4gICAgICAgICAgICAgIHJldHVybiBmcm9tICogTWF0aC5wb3codG8gLyBmcm9tLCBlYXNlT3V0KHByb2dyZXNzKSk7XG4gICAgICAgICAgICB9IC8vIGhhbmRsZSB1c2luZyBkZWZhdWx0XG5cblxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uU3RlcDogKHtcbiAgICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgem9vbVxuICAgICAgICAgIH0pID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgICBzY3JvbGxZLFxuICAgICAgICAgICAgICB6b29tOiB7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHpvb21cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblN0YXJ0OiAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uRW5kOiAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvbkNhbmNlbDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgZHVyYXRpb246IChfYiA9IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5kdXJhdGlvbikgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogNTAwXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uID0gKCkgPT4ge1xuICAgICAgICAgIGNhbmNlbCgpO1xuICAgICAgICAgIHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uID0gbnVsbDtcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNjcm9sbFgsXG4gICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICB6b29tXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG4gICAgLyoqIHVzZSB3aGVuIGNoYW5naW5nIHNjcm9sbFgvc2Nyb2xsWS96b29tIGJhc2VkIG9uIHVzZXIgaW50ZXJhY3Rpb24gKi9cblxuXG4gICAgdGhpcy50cmFuc2xhdGVDYW52YXMgPSBzdGF0ZSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIChfYSA9IHRoaXMuY2FuY2VsSW5Qcm9ncmVzQW5pbWF0aW9uKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY2FsbCh0aGlzKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUpO1xuICAgIH07XG5cbiAgICB0aGlzLnNldFRvYXN0ID0gdG9hc3QgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHRvYXN0XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXN0b3JlRmlsZUZyb21TaGFyZSA9ICgpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHdlYlNoYXJlVGFyZ2V0Q2FjaGUgPSB5aWVsZCBjYWNoZXMub3BlbihcIndlYi1zaGFyZS10YXJnZXRcIik7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0geWllbGQgd2ViU2hhcmVUYXJnZXRDYWNoZS5tYXRjaChcInNoYXJlZC1maWxlXCIpO1xuXG4gICAgICAgIGlmIChyZXNwb25zZSkge1xuICAgICAgICAgIGNvbnN0IGJsb2IgPSB5aWVsZCByZXNwb25zZS5ibG9iKCk7XG4gICAgICAgICAgY29uc3QgZmlsZSA9IG5ldyBGaWxlKFtibG9iXSwgYmxvYi5uYW1lIHx8IFwiXCIsIHtcbiAgICAgICAgICAgIHR5cGU6IGJsb2IudHlwZVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhmaWxlLCBudWxsKTtcbiAgICAgICAgICB5aWVsZCB3ZWJTaGFyZVRhcmdldENhY2hlLmRlbGV0ZShcInNoYXJlZC1maWxlXCIpO1xuICAgICAgICAgIHdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZShudWxsLCBBUFBfTkFNRSwgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIC8qKiBhZGRzIHN1cHBsaWVkIGZpbGVzIHRvIGV4aXN0aW5nIGZpbGVzIGluIHRoZSBhcHBTdGF0ZSAqL1xuXG5cbiAgICB0aGlzLmFkZEZpbGVzID0gd2l0aEJhdGNoZWRVcGRhdGVzKGZpbGVzID0+IHtcbiAgICAgIGNvbnN0IGZpbGVzTWFwID0gZmlsZXMucmVkdWNlKChhY2MsIGZpbGVEYXRhKSA9PiB7XG4gICAgICAgIGFjYy5zZXQoZmlsZURhdGEuaWQsIGZpbGVEYXRhKTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIG5ldyBNYXAoKSk7XG4gICAgICB0aGlzLmZpbGVzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgT2JqZWN0LmZyb21FbnRyaWVzKGZpbGVzTWFwKSk7XG4gICAgICB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGVsZW1lbnQpICYmIGZpbGVzTWFwLmhhcyhlbGVtZW50LmZpbGVJZCkpIHtcbiAgICAgICAgICB0aGlzLmltYWdlQ2FjaGUuZGVsZXRlKGVsZW1lbnQuZmlsZUlkKTtcbiAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLmluZm9ybU11dGF0aW9uKCk7XG4gICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgIH0pO1xuICAgIHRoaXMudXBkYXRlU2NlbmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoc2NlbmVEYXRhID0+IHtcbiAgICAgIGlmIChzY2VuZURhdGEuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNjZW5lRGF0YS5hcHBTdGF0ZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHNjZW5lRGF0YS5hcHBTdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuZWxlbWVudHMpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoc2NlbmVEYXRhLmVsZW1lbnRzKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNjZW5lRGF0YS5jb2xsYWJvcmF0b3JzKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbGxhYm9yYXRvcnM6IHNjZW5lRGF0YS5jb2xsYWJvcmF0b3JzXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5vblNjZW5lVXBkYXRlZCA9ICgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe30pO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybnMgd2hldGhlciB0aGUgbWVudSB3YXMgdG9nZ2xlZCBvbiBvciBvZmZcbiAgICAgKi9cblxuXG4gICAgdGhpcy50b2dnbGVTaWRlYmFyID0gKHtcbiAgICAgIG5hbWUsXG4gICAgICB0YWIsXG4gICAgICBmb3JjZVxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgbGV0IG5leHROYW1lO1xuXG4gICAgICBpZiAoZm9yY2UgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBuZXh0TmFtZSA9ICgoX2EgPSB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EubmFtZSkgPT09IG5hbWUgPyBudWxsIDogbmFtZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5leHROYW1lID0gZm9yY2UgPyBuYW1lIDogbnVsbDtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG9wZW5TaWRlYmFyOiBuZXh0TmFtZSA/IHtcbiAgICAgICAgICBuYW1lOiBuZXh0TmFtZSxcbiAgICAgICAgICB0YWJcbiAgICAgICAgfSA6IG51bGxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuICEhbmV4dE5hbWU7XG4gICAgfTtcblxuICAgIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnkgPSBldmVudC5jbGllbnRZO1xuICAgIH0pOyAvLyBJbnB1dCBoYW5kbGluZ1xuXG4gICAgdGhpcy5vbktleURvd24gPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgLy8gbm9ybWFsaXplIGBldmVudC5rZXlgIHdoZW4gQ2Fwc0xvY2sgaXMgcHJlc3NlZCAjMjM3MlxuICAgICAgaWYgKFwiUHJveHlcIiBpbiB3aW5kb3cgJiYgKCFldmVudC5zaGlmdEtleSAmJiAvXltBLVpdJC8udGVzdChldmVudC5rZXkpIHx8IGV2ZW50LnNoaWZ0S2V5ICYmIC9eW2Etel0kLy50ZXN0KGV2ZW50LmtleSkpKSB7XG4gICAgICAgIGV2ZW50ID0gbmV3IFByb3h5KGV2ZW50LCB7XG4gICAgICAgICAgZ2V0KGV2LCBwcm9wKSB7XG4gICAgICAgICAgICBjb25zdCB2YWx1ZSA9IGV2W3Byb3BdO1xuXG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgLy8gZml4IGZvciBQcm94aWVzIGhpamFja2luZyBgdGhpc2BcbiAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlLmJpbmQoZXYpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcHJvcCA9PT0gXCJrZXlcIiA/IC8vIENhcHNMb2NrIGludmVydHMgY2FwaXRhbGl6YXRpb24gYmFzZWQgb24gU2hpZnRLZXksIHNvIGludmVydFxuICAgICAgICAgICAgLy8gaXQgYmFja1xuICAgICAgICAgICAgZXZlbnQuc2hpZnRLZXkgPyBldi5rZXkudG9VcHBlckNhc2UoKSA6IGV2LmtleS50b0xvd2VyQ2FzZSgpIDogdmFsdWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgZXZlbnQua2V5LnRvTG93ZXJDYXNlKCkgPT09IEtFWVMuVikge1xuICAgICAgICBJU19QTEFJTl9QQVNURSA9IGV2ZW50LnNoaWZ0S2V5O1xuICAgICAgICBjbGVhclRpbWVvdXQoSVNfUExBSU5fUEFTVEVfVElNRVIpOyAvLyByZXNldCAoMTAwbXMgdG8gYmUgc2FmZSB0aGF0IHdlIGl0IHJ1bnMgYWZ0ZXIgdGhlIGVuc3VpbmdcbiAgICAgICAgLy8gcGFzdGUgZXZlbnQpLiBUaG91Z2gsIHRlY2huaWNhbGx5IHVubmVjZXNzYXJ5IHRvIHJlc2V0IHNpbmNlIHdlXG4gICAgICAgIC8vIChyZSlzZXQgdGhlIGZsYWcgYmVmb3JlIGVhY2ggcGFzdGUgZXZlbnQuXG5cbiAgICAgICAgSVNfUExBSU5fUEFTVEVfVElNRVIgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgSVNfUExBSU5fUEFTVEUgPSBmYWxzZTtcbiAgICAgICAgfSwgMTAwKTtcbiAgICAgIH0gLy8gcHJldmVudCBicm93c2VyIHpvb20gaW4gaW5wdXQgZmllbGRzXG5cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIGlzV3JpdGFibGVFbGVtZW50KGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgaWYgKGV2ZW50LmNvZGUgPT09IENPREVTLk1JTlVTIHx8IGV2ZW50LmNvZGUgPT09IENPREVTLkVRVUFMKSB7XG4gICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gLy8gYmFpbCBpZlxuXG5cbiAgICAgIGlmICggLy8gaW5zaWRlIGFuIGlucHV0XG4gICAgICBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpICYmIC8vIHVubGVzcyBwcmVzc2luZyBlc2NhcGUgKGZpbmFsaXplIGFjdGlvbilcbiAgICAgIGV2ZW50LmtleSAhPT0gS0VZUy5FU0NBUEUgfHwgLy8gb3IgdW5sZXNzIHVzaW5nIGFycm93cyAodG8gbW92ZSBiZXR3ZWVuIGJ1dHRvbnMpXG4gICAgICBpc0Fycm93S2V5KGV2ZW50LmtleSkgJiYgaXNJbnB1dExpa2UoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuUVVFU1RJT05fTUFSSykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBvcGVuRGlhbG9nOiBcImhlbHBcIlxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkudG9Mb3dlckNhc2UoKSA9PT0gS0VZUy5FICYmIGV2ZW50LnNoaWZ0S2V5ICYmIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIG9wZW5EaWFsb2c6IFwiaW1hZ2VFeHBvcnRcIlxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfVVAgfHwgZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfRE9XTikge1xuICAgICAgICBsZXQgb2Zmc2V0ID0gKGV2ZW50LnNoaWZ0S2V5ID8gdGhpcy5zdGF0ZS53aWR0aCA6IHRoaXMuc3RhdGUuaGVpZ2h0KSAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlBBR0VfRE9XTikge1xuICAgICAgICAgIG9mZnNldCA9IC1vZmZzZXQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2Nyb2xsWDogc3RhdGUuc2Nyb2xsWCArIG9mZnNldFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2Nyb2xsWTogc3RhdGUuc2Nyb2xsWSArIG9mZnNldFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5hY3Rpb25NYW5hZ2VyLmhhbmRsZUtleURvd24oZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIHRoaXMuc3RhdGUuaXNCaW5kaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzQXJyb3dLZXkoZXZlbnQua2V5KSkge1xuICAgICAgICBjb25zdCBzdGVwID0gdGhpcy5zdGF0ZS5ncmlkU2l6ZSAmJiAoZXZlbnQuc2hpZnRLZXkgPyBFTEVNRU5UX1RSQU5TTEFURV9BTU9VTlQgOiB0aGlzLnN0YXRlLmdyaWRTaXplKSB8fCAoZXZlbnQuc2hpZnRLZXkgPyBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQgOiBFTEVNRU5UX1RSQU5TTEFURV9BTU9VTlQpO1xuICAgICAgICBsZXQgb2Zmc2V0WCA9IDA7XG4gICAgICAgIGxldCBvZmZzZXRZID0gMDtcblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX0xFRlQpIHtcbiAgICAgICAgICBvZmZzZXRYID0gLXN0ZXA7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX1JJR0hUKSB7XG4gICAgICAgICAgb2Zmc2V0WCA9IHN0ZXA7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkFSUk9XX1VQKSB7XG4gICAgICAgICAgb2Zmc2V0WSA9IC1zdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19ET1dOKSB7XG4gICAgICAgICAgb2Zmc2V0WSA9IHN0ZXA7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzLFxuICAgICAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlLFxuICAgICAgICAgIGluY2x1ZGVFbGVtZW50c0luRnJhbWVzOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICBzZWxlY3RlZEVsZW1lbnRzLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICB4OiBlbGVtZW50LnggKyBvZmZzZXRYLFxuICAgICAgICAgICAgeTogZWxlbWVudC55ICsgb2Zmc2V0WVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHVwZGF0ZUJvdW5kRWxlbWVudHMoZWxlbWVudCwge1xuICAgICAgICAgICAgc2ltdWx0YW5lb3VzbHlVcGRhdGVkOiBzZWxlY3RlZEVsZW1lbnRzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5FTlRFUikge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudCA9IHNlbGVjdGVkRWxlbWVudHNbMF07XG5cbiAgICAgICAgICBpZiAoZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgICAgIGlmIChpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgIT09IHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3Ioc2VsZWN0ZWRFbGVtZW50LCB0aGlzLnNjZW5lKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkgfHwgaXNWYWxpZFRleHRDb250YWluZXIoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgbGV0IGNvbnRhaW5lcjtcblxuICAgICAgICAgICAgaWYgKCFpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgY29udGFpbmVyID0gc2VsZWN0ZWRFbGVtZW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBtaWRQb2ludCA9IGdldENvbnRhaW5lckNlbnRlcihzZWxlY3RlZEVsZW1lbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3Qgc2NlbmVYID0gbWlkUG9pbnQueDtcbiAgICAgICAgICAgIGNvbnN0IHNjZW5lWSA9IG1pZFBvaW50Lnk7XG4gICAgICAgICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICAgIHNjZW5lWSxcbiAgICAgICAgICAgICAgY29udGFpbmVyXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSBlbHNlIGlmIChpc0ZyYW1lRWxlbWVudChzZWxlY3RlZEVsZW1lbnQpKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0ZyYW1lOiBzZWxlY3RlZEVsZW1lbnQuaWRcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICghZXZlbnQuY3RybEtleSAmJiAhZXZlbnQuYWx0S2V5ICYmICFldmVudC5tZXRhS2V5ICYmIHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50ID09PSBudWxsKSB7XG4gICAgICAgIGNvbnN0IHNoYXBlID0gZmluZFNoYXBlQnlLZXkoZXZlbnQua2V5KTtcblxuICAgICAgICBpZiAoc2hhcGUpIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IHNoYXBlKSB7XG4gICAgICAgICAgICB0cmFja0V2ZW50KFwidG9vbGJhclwiLCBzaGFwZSwgYGtleWJvYXJkICgke3RoaXMuZGV2aWNlLmlzTW9iaWxlID8gXCJtb2JpbGVcIiA6IFwiZGVza3RvcFwifSlgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldEFjdGl2ZVRvb2woe1xuICAgICAgICAgICAgdHlwZTogc2hhcGVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkgPT09IEtFWVMuUSkge1xuICAgICAgICAgIHRoaXMudG9nZ2xlTG9jayhcImtleWJvYXJkXCIpO1xuICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuU1BBQ0UgJiYgZ2VzdHVyZS5wb2ludGVycy5zaXplID09PSAwKSB7XG4gICAgICAgIGlzSG9sZGluZ1NwYWNlID0gdHJ1ZTtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoKGV2ZW50LmtleSA9PT0gS0VZUy5HIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5TKSAmJiAhZXZlbnQuYWx0S2V5ICYmICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiAhc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLkcgJiYgKGhhc0JhY2tncm91bmQodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUpIHx8IHNlbGVjdGVkRWxlbWVudHMuc29tZShlbGVtZW50ID0+IGhhc0JhY2tncm91bmQoZWxlbWVudC50eXBlKSkpKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBvcGVuUG9wdXA6IFwiZWxlbWVudEJhY2tncm91bmRcIlxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5TKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBvcGVuUG9wdXA6IFwiZWxlbWVudFN0cm9rZVwiXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIChldmVudC5rZXkgPT09IEtFWVMuQkFDS1NQQUNFIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5ERUxFVEUpKSB7XG4gICAgICAgIGpvdGFpU3RvcmUuc2V0KGFjdGl2ZUNvbmZpcm1EaWFsb2dBdG9tLCBcImNsZWFyQ2FudmFzXCIpO1xuICAgICAgfSAvLyBleWUgZHJvcHBlclxuICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gICAgICBjb25zdCBsb3dlckNhc2VkID0gZXZlbnQua2V5LnRvTG9jYWxlTG93ZXJDYXNlKCk7XG4gICAgICBjb25zdCBpc1BpY2tpbmdTdHJva2UgPSBsb3dlckNhc2VkID09PSBLRVlTLlMgJiYgZXZlbnQuc2hpZnRLZXk7XG4gICAgICBjb25zdCBpc1BpY2tpbmdCYWNrZ3JvdW5kID0gZXZlbnQua2V5ID09PSBLRVlTLkkgfHwgbG93ZXJDYXNlZCA9PT0gS0VZUy5HICYmIGV2ZW50LnNoaWZ0S2V5O1xuXG4gICAgICBpZiAoaXNQaWNraW5nU3Ryb2tlIHx8IGlzUGlja2luZ0JhY2tncm91bmQpIHtcbiAgICAgICAgdGhpcy5vcGVuRXllRHJvcHBlcih7XG4gICAgICAgICAgdHlwZTogaXNQaWNraW5nU3Ryb2tlID8gXCJzdHJva2VcIiA6IFwiYmFja2dyb3VuZFwiXG4gICAgICAgIH0pO1xuICAgICAgfSAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgfSk7XG4gICAgdGhpcy5vbldoZWVsID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIHByZXZlbnQgYnJvd3NlciBwaW5jaCB6b29tIG9uIERPTSBlbGVtZW50c1xuICAgICAgaWYgKCEoZXZlbnQudGFyZ2V0IGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQpICYmIGV2ZW50LmN0cmxLZXkpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLm9uS2V5VXAgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5TUEFDRSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUuaXNCaW5kaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNBcnJvd0tleShldmVudC5rZXkpKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgPyBiaW5kT3JVbmJpbmRTZWxlY3RlZEVsZW1lbnRzKHNlbGVjdGVkRWxlbWVudHMpIDogdW5iaW5kTGluZWFyRWxlbWVudHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuc2V0QWN0aXZlVG9vbCA9IHRvb2wgPT4ge1xuICAgICAgY29uc3QgbmV4dEFjdGl2ZVRvb2wgPSB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHRvb2wpO1xuXG4gICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSA9PT0gXCJoYW5kXCIpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgfSBlbHNlIGlmICghaXNIb2xkaW5nU3BhY2UpIHtcbiAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc1Rvb2xJY29uKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpKSB7XG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc0xpbmVhckVsZW1lbnRUeXBlKG5leHRBY3RpdmVUb29sLnR5cGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICB0aGlzLm9uSW1hZ2VBY3Rpb24oKTtcbiAgICAgIH1cblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICBhY3RpdmVUb29sOiBuZXh0QWN0aXZlVG9vbCxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICBzbmFwTGluZXM6IFtdLFxuICAgICAgICAgIG9yaWdpblNuYXBPZmZzZXQ6IG51bGxcbiAgICAgICAgfSkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2wsXG4gICAgICAgICAgc25hcExpbmVzOiBbXSxcbiAgICAgICAgICBvcmlnaW5TbmFwT2Zmc2V0OiBudWxsLFxuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuc2V0Q3Vyc29yID0gY3Vyc29yID0+IHtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBjdXJzb3IpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0Q3Vyc29yID0gKCkgPT4ge1xuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiByZXR1cm5zIHdoZXRoZXIgdXNlciBpcyBtYWtpbmcgYSBnZXN0dXJlIHdpdGggPj0gMiBmaW5nZXJzIChwb2ludHMpXG4gICAgICogb24gbyB0b3VjaCBzY3JlZW4gKG5vdCBvbiBhIHRyYWNrcGFkKS4gQ3VycmVudGx5IG9ubHkgcmVsYXRlcyB0byBEYXJ3aW5cbiAgICAgKiAoaU9TL2lQYWRPUyxNYWNPUyksIGJ1dCBtYXkgd29yayBvbiBvdGhlciBkZXZpY2VzIGluIHRoZSBmdXR1cmUgaWZcbiAgICAgKiBHZXN0dXJlRXZlbnQgaXMgc3RhbmRhcmRpemVkLlxuICAgICAqL1xuXG5cbiAgICB0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSA9ICgpID0+IHtcbiAgICAgIC8vIHdlIGRvbid0IHdhbnQgdG8gZGVzZWxlY3Qgd2hlbiB1c2luZyB0cmFja3BhZCwgYW5kIG11bHRpLXBvaW50IGdlc3R1cmVzXG4gICAgICAvLyBvbmx5IHdvcmsgb24gdG91Y2ggc2NyZWVucywgc28gY2hlY2tpbmcgZm9yID49IHBvaW50ZXJzIG1lYW5zIHdlJ3JlIG9uIGFcbiAgICAgIC8vIHRvdWNoc2NyZWVuXG4gICAgICByZXR1cm4gZ2VzdHVyZS5wb2ludGVycy5zaXplID49IDI7XG4gICAgfTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuXG4gICAgdGhpcy5vbkdlc3R1cmVTdGFydCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyB3ZSBvbmx5IHdhbnQgdG8gZGVzZWxlY3Qgb24gdG91Y2ggc2NyZWVucyBiZWNhdXNlIHVzZXIgbWF5IGhhdmUgc2VsZWN0ZWRcbiAgICAgIC8vIGVsZW1lbnRzIGJ5IG1pc3Rha2Ugd2hpbGUgem9vbWluZ1xuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICB9KTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuICAgIHRoaXMub25HZXN0dXJlQ2hhbmdlID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIG9uR2VzdHVyZUNoYW5nZSBvbmx5IGhhcyB6b29tIGZhY3RvciBidXQgbm90IHRoZSBjZW50ZXIuXG4gICAgICAvLyBJZiB3ZSdyZSBvbiBpUGFkIG9yIGlQaG9uZSwgdGhlbiB3ZSByZWNvZ25pemUgbXVsdGktdG91Y2ggYW5kIHdpbGxcbiAgICAgIC8vIHpvb20gaW4gYXQgdGhlIHJpZ2h0IGxvY2F0aW9uIGluIHRoZSB0b3VjaG1vdmUgaGFuZGxlclxuICAgICAgLy8gKGhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlKS5cbiAgICAgIC8vXG4gICAgICAvLyBPbiBNYWNib29rIHRyYWNrcGFkLCB3ZSBkb24ndCBoYXZlIHRob3NlIGV2ZW50cyBzbyB3aWxsIHpvb20gaW4gYXQgdGhlXG4gICAgICAvLyBjdXJyZW50IGxvY2F0aW9uIGluc3RlYWQuXG4gICAgICAvL1xuICAgICAgLy8gQXMgc3VjaCwgYmFpbCBmcm9tIHRoaXMgaGFuZGxlciBvbiB0b3VjaCBkZXZpY2VzLlxuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGluaXRpYWxTY2FsZSA9IGdlc3R1cmUuaW5pdGlhbFNjYWxlO1xuXG4gICAgICBpZiAoaW5pdGlhbFNjYWxlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgICB2aWV3cG9ydFg6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCxcbiAgICAgICAgICB2aWV3cG9ydFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSxcbiAgICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20oaW5pdGlhbFNjYWxlICogZXZlbnQuc2NhbGUpXG4gICAgICAgIH0sIHN0YXRlKSkpO1xuICAgICAgfVxuICAgIH0pOyAvLyBmaXJlcyBvbmx5IG9uIFNhZmFyaVxuXG4gICAgdGhpcy5vbkdlc3R1cmVFbmQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gcmVzZWxlY3QgZWxlbWVudHMgb25seSBvbiB0b3VjaCBzY3JlZW5zIChzZWUgb25HZXN0dXJlU3RhcnQpXG5cbiAgICAgIGlmICh0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSgpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB7fSxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHRoaXMuc3RhdGUucHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHMsIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IG51bGw7XG4gICAgfSk7XG5cbiAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZLFxuICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXIgPSB0cnVlLFxuICAgICAgY29udGFpbmVyXG4gICAgfSkgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgbGV0IHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IGZhbHNlO1xuICAgICAgbGV0IHBhcmVudENlbnRlclBvc2l0aW9uID0gaW5zZXJ0QXRQYXJlbnRDZW50ZXIgJiYgdGhpcy5nZXRUZXh0V3lzaXd5Z1NuYXBwZWRUb0NlbnRlclBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZLCB0aGlzLnN0YXRlLCBjb250YWluZXIpO1xuXG4gICAgICBpZiAoY29udGFpbmVyICYmIHBhcmVudENlbnRlclBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lciA9IGdldEJvdW5kVGV4dEVsZW1lbnQoY29udGFpbmVyKTtcblxuICAgICAgICBpZiAoIWJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lcikge1xuICAgICAgICAgIHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgbGV0IGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBudWxsO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIGlmIChpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHNlbGVjdGVkRWxlbWVudHNbMF07XG4gICAgICAgIH0gZWxzZSBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IGdldEJvdW5kVGV4dEVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZm9udEZhbWlseSA9IChleGlzdGluZ1RleHRFbGVtZW50ID09PSBudWxsIHx8IGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nVGV4dEVsZW1lbnQuZm9udEZhbWlseSkgfHwgdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRGYW1pbHk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gKGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IG51bGwgfHwgZXhpc3RpbmdUZXh0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhpc3RpbmdUZXh0RWxlbWVudC5saW5lSGVpZ2h0KSB8fCBnZXREZWZhdWx0TGluZUhlaWdodChmb250RmFtaWx5KTtcbiAgICAgIGNvbnN0IGZvbnRTaXplID0gdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRTaXplO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyICYmIGNvbnRhaW5lciAmJiAhaXNBcnJvd0VsZW1lbnQoY29udGFpbmVyKSkge1xuICAgICAgICBjb25zdCBmb250U3RyaW5nID0ge1xuICAgICAgICAgIGZvbnRTaXplLFxuICAgICAgICAgIGZvbnRGYW1pbHlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgbWluV2lkdGggPSBnZXRBcHByb3hNaW5MaW5lV2lkdGgoZ2V0Rm9udFN0cmluZyhmb250U3RyaW5nKSwgbGluZUhlaWdodCk7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IGdldEFwcHJveE1pbkxpbmVIZWlnaHQoZm9udFNpemUsIGxpbmVIZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdIZWlnaHQgPSBNYXRoLm1heChjb250YWluZXIuaGVpZ2h0LCBtaW5IZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdXaWR0aCA9IE1hdGgubWF4KGNvbnRhaW5lci53aWR0aCwgbWluV2lkdGgpO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGNvbnRhaW5lciwge1xuICAgICAgICAgIGhlaWdodDogbmV3SGVpZ2h0LFxuICAgICAgICAgIHdpZHRoOiBuZXdXaWR0aFxuICAgICAgICB9KTtcbiAgICAgICAgc2NlbmVYID0gY29udGFpbmVyLnggKyBuZXdXaWR0aCAvIDI7XG4gICAgICAgIHNjZW5lWSA9IGNvbnRhaW5lci55ICsgbmV3SGVpZ2h0IC8gMjtcblxuICAgICAgICBpZiAocGFyZW50Q2VudGVyUG9zaXRpb24pIHtcbiAgICAgICAgICBwYXJlbnRDZW50ZXJQb3NpdGlvbiA9IHRoaXMuZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwgdGhpcy5zdGF0ZSwgY29udGFpbmVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBleGlzdGluZ1RleHRFbGVtZW50ID8gZXhpc3RpbmdUZXh0RWxlbWVudCA6IG5ld1RleHRFbGVtZW50KHtcbiAgICAgICAgeDogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWCA6IHNjZW5lWCxcbiAgICAgICAgeTogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWSA6IHNjZW5lWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIHRleHQ6IFwiXCIsXG4gICAgICAgIGZvbnRTaXplLFxuICAgICAgICBmb250RmFtaWx5LFxuICAgICAgICB0ZXh0QWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gXCJjZW50ZXJcIiA6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1UZXh0QWxpZ24sXG4gICAgICAgIHZlcnRpY2FsQWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gVkVSVElDQUxfQUxJR04uTUlERExFIDogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgICAgY29udGFpbmVySWQ6IHNob3VsZEJpbmRUb0NvbnRhaW5lciA/IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5pZCA6IHVuZGVmaW5lZCxcbiAgICAgICAgZ3JvdXBJZHM6IChfYSA9IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5ncm91cElkcykgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogW10sXG4gICAgICAgIGxpbmVIZWlnaHQsXG4gICAgICAgIGFuZ2xlOiAoX2IgPSBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuYW5nbGUpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDAsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfSk7XG5cbiAgICAgIGlmICghZXhpc3RpbmdUZXh0RWxlbWVudCAmJiBzaG91bGRCaW5kVG9Db250YWluZXIgJiYgY29udGFpbmVyKSB7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoY29udGFpbmVyLCB7XG4gICAgICAgICAgYm91bmRFbGVtZW50czogKGNvbnRhaW5lci5ib3VuZEVsZW1lbnRzIHx8IFtdKS5jb25jYXQoe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGNvbnRhaW5lciAmJiBzaG91bGRCaW5kVG9Db250YWluZXIpIHtcbiAgICAgICAgICBjb25zdCBjb250YWluZXJJbmRleCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudEluZGV4KGNvbnRhaW5lci5pZCk7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50QXRJbmRleChlbGVtZW50LCBjb250YWluZXJJbmRleCArIDEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuICAgICAgdGhpcy5oYW5kbGVUZXh0V3lzaXd5ZyhlbGVtZW50LCB7XG4gICAgICAgIGlzRXhpc3RpbmdFbGVtZW50OiAhIWV4aXN0aW5nVGV4dEVsZW1lbnRcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrID0gZXZlbnQgPT4ge1xuICAgICAgLy8gY2FzZTogZG91YmxlLWNsaWNraW5nIHdpdGggYXJyb3cvbGluZSB0b29sIHNlbGVjdGVkIHdvdWxkIGJvdGggY3JlYXRlXG4gICAgICAvLyB0ZXh0IGFuZCBlbnRlciBtdWx0aUVsZW1lbnQgbW9kZVxuICAgICAgaWYgKHRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gd2Ugc2hvdWxkIG9ubHkgYmUgYWJsZSB0byBkb3VibGUgY2xpY2sgd2hlbiBtb2RlIGlzIHNlbGVjdGlvblxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkpIHtcbiAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICghdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCAhPT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3Ioc2VsZWN0ZWRFbGVtZW50c1swXSwgdGhpcy5zY2VuZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCA9PT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgIGxldCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkR3JvdXBJZHMgPSBnZXRTZWxlY3RlZEdyb3VwSWRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRHcm91cElkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRHcm91cElkID0gaGl0RWxlbWVudCAmJiBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50KGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUuc2VsZWN0ZWRHcm91cElkcyk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkR3JvdXBJZCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogc2VsZWN0ZWRHcm91cElkLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICBlbGVtZW50OiBoaXRFbGVtZW50LFxuICAgICAgICAgICAgICBzdGF0ZTogXCJhY3RpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgc2NlbmVYLCBzY2VuZVkpO1xuXG4gICAgICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgICAgICBpZiAoaGFzQm91bmRUZXh0RWxlbWVudChjb250YWluZXIpIHx8ICFpc1RyYW5zcGFyZW50KGNvbnRhaW5lci5iYWNrZ3JvdW5kQ29sb3IpIHx8IGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94KGNvbnRhaW5lciwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgW3NjZW5lWCwgc2NlbmVZXSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG1pZFBvaW50ID0gZ2V0Q29udGFpbmVyQ2VudGVyKGNvbnRhaW5lciwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBzY2VuZVggPSBtaWRQb2ludC54O1xuICAgICAgICAgICAgc2NlbmVZID0gbWlkUG9pbnQueTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXI6ICFldmVudC5hbHRLZXksXG4gICAgICAgICAgY29udGFpbmVyXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbiA9IChzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpID0+IHtcbiAgICAgIC8vIFJldmVyc2luZyBzbyB3ZSB0cmF2ZXJzZSB0aGUgZWxlbWVudHMgaW4gZGVjcmVhc2luZyBvcmRlclxuICAgICAgLy8gb2Ygei1pbmRleFxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLnNsaWNlKCkucmV2ZXJzZSgpO1xuICAgICAgbGV0IGhpdEVsZW1lbnRJbmRleCA9IEluZmluaXR5O1xuICAgICAgcmV0dXJuIGVsZW1lbnRzLmZpbmQoKGVsZW1lbnQsIGluZGV4KSA9PiB7XG4gICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGVsZW1lbnQuaWQgPT09IGhpdEVsZW1lbnQuaWQpIHtcbiAgICAgICAgICBoaXRFbGVtZW50SW5kZXggPSBpbmRleDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGVtZW50LmxpbmsgJiYgaW5kZXggPD0gaGl0RWxlbWVudEluZGV4ICYmIGlzUG9pbnRIaXR0aW5nTGluayhlbGVtZW50LCB0aGlzLnN0YXRlLCBbc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55XSwgdGhpcy5kZXZpY2UuaXNNb2JpbGUpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVkaXJlY3RUb0xpbmsgPSAoZXZlbnQsIGlzVG91Y2hTY3JlZW4pID0+IHtcbiAgICAgIGNvbnN0IGRyYWdnZWREaXN0YW5jZSA9IGRpc3RhbmNlMmQodGhpcy5sYXN0UG9pbnRlckRvd24uY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlckRvd24uY2xpZW50WSwgdGhpcy5sYXN0UG9pbnRlclVwLmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJVcC5jbGllbnRZKTtcblxuICAgICAgaWYgKCF0aGlzLmhpdExpbmtFbGVtZW50IHx8IC8vIEZvciB0b3VjaCBzY3JlZW4gYWxsb3cgZHJhZ2dpbmcgdGhyZXNob2xkIGVsc2Ugc3RyaWN0IGNoZWNrXG4gICAgICBpc1RvdWNoU2NyZWVuICYmIGRyYWdnZWREaXN0YW5jZSA+IERSQUdHSU5HX1RIUkVTSE9MRCB8fCAhaXNUb3VjaFNjcmVlbiAmJiBkcmFnZ2VkRGlzdGFuY2UgIT09IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBsYXN0UG9pbnRlckRvd25Db29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHModGhpcy5sYXN0UG9pbnRlckRvd24sIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJEb3duSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlckRvd25Db29yZHMueCwgbGFzdFBvaW50ZXJEb3duQ29vcmRzLnldLCB0aGlzLmRldmljZS5pc01vYmlsZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHRoaXMubGFzdFBvaW50ZXJVcCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlclVwQ29vcmRzLngsIGxhc3RQb2ludGVyVXBDb29yZHMueV0sIHRoaXMuZGV2aWNlLmlzTW9iaWxlKTtcblxuICAgICAgaWYgKGxhc3RQb2ludGVyRG93bkhpdHRpbmdMaW5rSWNvbiAmJiBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uKSB7XG4gICAgICAgIGxldCB1cmwgPSB0aGlzLmhpdExpbmtFbGVtZW50Lmxpbms7XG5cbiAgICAgICAgaWYgKHVybCkge1xuICAgICAgICAgIHVybCA9IG5vcm1hbGl6ZUxpbmsodXJsKTtcbiAgICAgICAgICBsZXQgY3VzdG9tRXZlbnQ7XG5cbiAgICAgICAgICBpZiAodGhpcy5wcm9wcy5vbkxpbmtPcGVuKSB7XG4gICAgICAgICAgICBjdXN0b21FdmVudCA9IHdyYXBFdmVudChFVkVOVC5FWENBTElEUkFXX0xJTkssIGV2ZW50Lm5hdGl2ZUV2ZW50KTtcbiAgICAgICAgICAgIHRoaXMucHJvcHMub25MaW5rT3BlbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuaGl0TGlua0VsZW1lbnQpLCB7XG4gICAgICAgICAgICAgIGxpbms6IHVybFxuICAgICAgICAgICAgfSksIGN1c3RvbUV2ZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIShjdXN0b21FdmVudCA9PT0gbnVsbCB8fCBjdXN0b21FdmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogY3VzdG9tRXZlbnQuZGVmYXVsdFByZXZlbnRlZCkpIHtcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldCA9IGlzTG9jYWxMaW5rKHVybCkgPyBcIl9zZWxmXCIgOiBcIl9ibGFua1wiO1xuICAgICAgICAgICAgY29uc3QgbmV3V2luZG93ID0gd2luZG93Lm9wZW4odW5kZWZpbmVkLCB0YXJnZXQpOyAvLyBodHRwczovL21hdGhpYXNieW5lbnMuZ2l0aHViLmlvL3JlbC1ub29wZW5lci9cblxuICAgICAgICAgICAgaWYgKG5ld1dpbmRvdykge1xuICAgICAgICAgICAgICBuZXdXaW5kb3cub3BlbmVyID0gbnVsbDtcbiAgICAgICAgICAgICAgbmV3V2luZG93LmxvY2F0aW9uID0gdXJsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzID0gc2NlbmVDb29yZHMgPT4ge1xuICAgICAgY29uc3QgZnJhbWVzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRnJhbWVzKCkuZmlsdGVyKGZyYW1lID0+IGlzQ3Vyc29ySW5GcmFtZShzY2VuZUNvb3JkcywgZnJhbWUpKTtcbiAgICAgIHJldHVybiBmcmFtZXMubGVuZ3RoID8gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXSA6IG51bGw7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIHRoaXMuc3RhdGUuY3Vyc29yQnV0dG9uKTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuaGFzKGV2ZW50LnBvaW50ZXJJZCkpIHtcbiAgICAgICAgZ2VzdHVyZS5wb2ludGVycy5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICAgICAgeDogZXZlbnQuY2xpZW50WCxcbiAgICAgICAgICB5OiBldmVudC5jbGllbnRZXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbml0aWFsU2NhbGUgPSBnZXN0dXJlLmluaXRpYWxTY2FsZTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMiAmJiBnZXN0dXJlLmxhc3RDZW50ZXIgJiYgaW5pdGlhbFNjYWxlICYmIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlKSB7XG4gICAgICAgIGNvbnN0IGNlbnRlciA9IGdldENlbnRlcihnZXN0dXJlLnBvaW50ZXJzKTtcbiAgICAgICAgY29uc3QgZGVsdGFYID0gY2VudGVyLnggLSBnZXN0dXJlLmxhc3RDZW50ZXIueDtcbiAgICAgICAgY29uc3QgZGVsdGFZID0gY2VudGVyLnkgLSBnZXN0dXJlLmxhc3RDZW50ZXIueTtcbiAgICAgICAgZ2VzdHVyZS5sYXN0Q2VudGVyID0gY2VudGVyO1xuICAgICAgICBjb25zdCBkaXN0YW5jZSA9IGdldERpc3RhbmNlKEFycmF5LmZyb20oZ2VzdHVyZS5wb2ludGVycy52YWx1ZXMoKSkpO1xuICAgICAgICBjb25zdCBzY2FsZUZhY3RvciA9IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIgJiYgdGhpcy5zdGF0ZS5wZW5Nb2RlID8gMSA6IGRpc3RhbmNlIC8gZ2VzdHVyZS5pbml0aWFsRGlzdGFuY2U7XG4gICAgICAgIGNvbnN0IG5leHRab29tID0gc2NhbGVGYWN0b3IgPyBnZXROb3JtYWxpemVkWm9vbShpbml0aWFsU2NhbGUgKiBzY2FsZUZhY3RvcikgOiB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIGNvbnN0IHpvb21TdGF0ZSA9IGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgICB2aWV3cG9ydFg6IGNlbnRlci54LFxuICAgICAgICAgICAgdmlld3BvcnRZOiBjZW50ZXIueSxcbiAgICAgICAgICAgIG5leHRab29tXG4gICAgICAgICAgfSwgc3RhdGUpO1xuICAgICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgICAgIHpvb206IHpvb21TdGF0ZS56b29tLFxuICAgICAgICAgICAgc2Nyb2xsWDogem9vbVN0YXRlLnNjcm9sbFggKyBkZWx0YVggLyBuZXh0Wm9vbSxcbiAgICAgICAgICAgIHNjcm9sbFk6IHpvb21TdGF0ZS5zY3JvbGxZICsgZGVsdGFZIC8gbmV4dFpvb20sXG4gICAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlID0gZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNIb2xkaW5nU3BhY2UgfHwgaXNQYW5uaW5nIHx8IGlzRHJhZ2dpbmdTY3JvbGxCYXIgfHwgaXNIYW5kVG9vbEFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzID0gaXNPdmVyU2Nyb2xsQmFycyhjdXJyZW50U2Nyb2xsQmFycywgZXZlbnQuY2xpZW50WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgZXZlbnQuY2xpZW50WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wKTtcbiAgICAgIGNvbnN0IGlzT3ZlclNjcm9sbEJhciA9IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzLmlzT3ZlckVpdGhlcjtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lUG9pbnRlclgsXG4gICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgIH0gPSBzY2VuZVBvaW50ZXI7XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgaXNBY3RpdmVUb29sTm9uTGluZWFyU25hcHBhYmxlKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgb3JpZ2luT2Zmc2V0LFxuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9ID0gZ2V0U25hcExpbmVzQXRQb2ludGVyKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgICAgfSwgZXZlbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXMsXG4gICAgICAgICAgb3JpZ2luU25hcE9mZnNldDogb3JpZ2luT2Zmc2V0XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICBjb25zdCBlZGl0aW5nTGluZWFyRWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlck1vdmUoZXZlbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclksIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChlZGl0aW5nTGluZWFyRWxlbWVudCAmJiBlZGl0aW5nTGluZWFyRWxlbWVudCAhPT0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIC8vIFNpbmNlIHdlIGFyZSByZWFkaW5nIGZyb20gcHJldmlvdXMgc3RhdGUgd2hpY2ggaXMgbm90IHBvc3NpYmxlIHdpdGhcbiAgICAgICAgICAvLyBhdXRvbWF0aWMgYmF0Y2hpbmcgaW4gUmVhY3QgMTggaGVuY2UgdXNpbmcgZmx1c2ggc3luYyB0byBzeW5jaHJvbm91c2x5XG4gICAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZS4gQ2hlY2sgaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzU1MDggZm9yIG1vcmUgZGV0YWlscy5cbiAgICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgoZWRpdGluZ0xpbmVhckVsZW1lbnQgPT09IG51bGwgfHwgZWRpdGluZ0xpbmVhckVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVkaXRpbmdMaW5lYXJFbGVtZW50Lmxhc3RVbmNvbW1pdHRlZFBvaW50KSAhPSBudWxsKSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3Ioc2NlbmVQb2ludGVyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBjYXVzZXMgc3RhY2sgb3ZlcmZsb3cgaWYgbm90IHN5bmNcbiAgICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnRUeXBlKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSkge1xuICAgICAgICAvLyBIb3ZlcmluZyB3aXRoIGEgc2VsZWN0ZWQgdG9vbCBvciBjcmVhdGluZyBuZXcgbGluZWFyIGVsZW1lbnQgdmlhIGNsaWNrXG4gICAgICAgIC8vIGFuZCBwb2ludFxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50XG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuXG4gICAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhkcmFnZ2luZ0VsZW1lbnQsIFtzY2VuZVBvaW50ZXJdLCB0aGlzLnN0YXRlLnN0YXJ0Qm91bmRFbGVtZW50KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdBdEN1cnNvcihzY2VuZVBvaW50ZXIpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgbXVsdGlFbGVtZW50XG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogcngsXG4gICAgICAgICAgeTogcnlcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHBvaW50cyxcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnRcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDtcbiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXTtcbiAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKGxhc3RQb2ludCA9PT0gbGFzdENvbW1pdHRlZFBvaW50KSB7XG4gICAgICAgICAgLy8gaWYgd2UgaGF2ZW4ndCB5ZXQgY3JlYXRlZCBhIHRlbXAgcG9pbnQgYW5kIHdlJ3JlIGJleW9uZCBjb21taXQtem9uZVxuICAgICAgICAgIC8vIHRocmVzaG9sZCwgYWRkIGEgcG9pbnRcbiAgICAgICAgICBpZiAoZGlzdGFuY2UyZChzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeSwgbGFzdFBvaW50WzBdLCBsYXN0UG9pbnRbMV0pID49IExJTkVfQ09ORklSTV9USFJFU0hPTEQpIHtcbiAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW3NjZW5lUG9pbnRlclggLSByeCwgc2NlbmVQb2ludGVyWSAtIHJ5XV1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuUE9JTlRFUik7IC8vIGluIHRoaXMgYnJhbmNoLCB3ZSdyZSBpbnNpZGUgdGhlIGNvbW1pdCB6b25lLCBhbmQgbm8gdW5jb21taXR0ZWRcbiAgICAgICAgICAgIC8vIHBvaW50IGV4aXN0cy4gVGh1cyBkbyBub3RoaW5nIChkb24ndCBhZGQvcmVtb3ZlIHBvaW50cykuXG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHBvaW50cy5sZW5ndGggPiAyICYmIGxhc3RDb21taXR0ZWRQb2ludCAmJiBkaXN0YW5jZTJkKHNjZW5lUG9pbnRlclggLSByeCwgc2NlbmVQb2ludGVyWSAtIHJ5LCBsYXN0Q29tbWl0dGVkUG9pbnRbMF0sIGxhc3RDb21taXR0ZWRQb2ludFsxXSkgPCBMSU5FX0NPTkZJUk1fVEhSRVNIT0xEKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IHBvaW50cy5zbGljZSgwLCAtMSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgICAgICBjb25zdCBbbGFzdENvbW1pdHRlZFgsIGxhc3RDb21taXR0ZWRZXSA9IChfYSA9IG11bHRpRWxlbWVudCA9PT0gbnVsbCB8fCBtdWx0aUVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG11bHRpRWxlbWVudC5sYXN0Q29tbWl0dGVkUG9pbnQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IFswLCAwXTtcbiAgICAgICAgICBsZXQgZHhGcm9tTGFzdENvbW1pdHRlZCA9IGdyaWRYIC0gcnggLSBsYXN0Q29tbWl0dGVkWDtcbiAgICAgICAgICBsZXQgZHlGcm9tTGFzdENvbW1pdHRlZCA9IGdyaWRZIC0gcnkgLSBsYXN0Q29tbWl0dGVkWTtcblxuICAgICAgICAgIGlmIChzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZShldmVudCkpIHtcbiAgICAgICAgICAgICh7XG4gICAgICAgICAgICAgIHdpZHRoOiBkeEZyb21MYXN0Q29tbWl0dGVkLFxuICAgICAgICAgICAgICBoZWlnaHQ6IGR5RnJvbUxhc3RDb21taXR0ZWRcbiAgICAgICAgICAgIH0gPSBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUoIC8vIGFjdHVhbCBjb29yZGluYXRlIG9mIHRoZSBsYXN0IGNvbW1pdHRlZCBwb2ludFxuICAgICAgICAgICAgbGFzdENvbW1pdHRlZFggKyByeCwgbGFzdENvbW1pdHRlZFkgKyByeSwgLy8gY3Vyc29yLWdyaWQgY29vcmRpbmF0ZVxuICAgICAgICAgICAgZ3JpZFgsIGdyaWRZKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGlzUGF0aEFMb29wKHBvaW50cywgdGhpcy5zdGF0ZS56b29tLnZhbHVlKSkge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgIH0gLy8gdXBkYXRlIGxhc3QgdW5jb21taXR0ZWQgcG9pbnRcblxuXG4gICAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cy5zbGljZSgwLCAtMSksIFtsYXN0Q29tbWl0dGVkWCArIGR4RnJvbUxhc3RDb21taXR0ZWQsIGxhc3RDb21taXR0ZWRZICsgZHlGcm9tTGFzdENvbW1pdHRlZF1dXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhhc0Rlc2VsZWN0ZWRCdXR0b24gPSBCb29sZWFuKGV2ZW50LmJ1dHRvbnMpO1xuXG4gICAgICBpZiAoaGFzRGVzZWxlY3RlZEJ1dHRvbiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJ0ZXh0XCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwiZXJhc2VyXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCk7XG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgIWlzT3ZlclNjcm9sbEJhciAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICBjb25zdCBlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgPSBnZXRFbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUoZWxlbWVudHMsIHRoaXMuc3RhdGUsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclksIHRoaXMuc3RhdGUuem9vbSwgZXZlbnQucG9pbnRlclR5cGUpO1xuXG4gICAgICAgIGlmIChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgJiYgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLnRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50KGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSkpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDEgJiYgIWlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICBjb25zdCB0cmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0VHJhbnNmb3JtSGFuZGxlVHlwZUZyb21Db29yZHMoZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZSkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBnZXRDdXJzb3JGb3JSZXNpemluZ0VsZW1lbnQoe1xuICAgICAgICAgICAgdHJhbnNmb3JtSGFuZGxlVHlwZVxuICAgICAgICAgIH0pKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgIHRoaXMuaGl0TGlua0VsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbihzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpO1xuXG4gICAgICBpZiAoaXNFcmFzZXJBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5oaXRMaW5rRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5oaXRMaW5rRWxlbWVudC5pZF0pIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICBzaG93SHlwZXJsaW5rVG9vbHRpcCh0aGlzLmhpdExpbmtFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGhpZGVIeXBlcmxpbmtUb29saXAoKTtcblxuICAgICAgICBpZiAoaGl0RWxlbWVudCAmJiAoaGl0RWxlbWVudC5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkpICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdICYmICF0aGlzLnN0YXRlLmNvbnRleHRNZW51ICYmICF0aGlzLnN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBcImluZm9cIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInRleHRcIikge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBpc1RleHRFbGVtZW50KGhpdEVsZW1lbnQpID8gQ1VSU09SX1RZUEUuVEVYVCA6IENVUlNPUl9UWVBFLkNST1NTSEFJUik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNPdmVyU2Nyb2xsQmFyKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkFVVE8pO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVIb3ZlclNlbGVjdGVkTGluZWFyRWxlbWVudCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSk7XG4gICAgICAgIH0gZWxzZSBpZiAoIC8vIGlmIHVzaW5nIGNtZC9jdHJsLCB3ZSdyZSBub3QgZHJhZ2dpbmdcbiAgICAgICAgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgICAgaWYgKChoaXRFbGVtZW50IHx8IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMoc2NlbmVQb2ludGVyLCBzZWxlY3RlZEVsZW1lbnRzKSkgJiYgIShoaXRFbGVtZW50ID09PSBudWxsIHx8IGhpdEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGhpdEVsZW1lbnQubG9ja2VkKSkge1xuICAgICAgICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSAmJiB0aGlzLmlzRW1iZWRkYWJsZUNlbnRlcihoaXRFbGVtZW50LCBldmVudCwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiB7XG4gICAgICAgICAgICAgICAgICBlbGVtZW50OiBoaXRFbGVtZW50LFxuICAgICAgICAgICAgICAgICAgc3RhdGU6IFwiaG92ZXJcIlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG5cbiAgICAgICAgICAgICAgaWYgKCgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiaG92ZXJcIikge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUVyYXNlciA9IChldmVudCwgcG9pbnRlckRvd25TdGF0ZSwgc2NlbmVQb2ludGVyKSA9PiB7XG4gICAgICBjb25zdCB1cGRhdGVFbGVtZW50SWRzID0gZWxlbWVudHMgPT4ge1xuICAgICAgICBlbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIGlmIChlbGVtZW50LmxvY2tlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlkc1RvVXBkYXRlLnB1c2goZWxlbWVudC5pZCk7XG5cbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlbWVudC5pZF0uZXJhc2UgPSBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKCFwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdKSB7XG4gICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdID0ge1xuICAgICAgICAgICAgICBlcmFzZTogdHJ1ZSxcbiAgICAgICAgICAgICAgb3BhY2l0eTogZWxlbWVudC5vcGFjaXR5XG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9O1xuXG4gICAgICBjb25zdCBpZHNUb1VwZGF0ZSA9IFtdO1xuICAgICAgY29uc3QgZGlzdGFuY2UgPSBkaXN0YW5jZTJkKHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54LCBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSwgc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgIGNvbnN0IHRocmVzaG9sZCA9IDEwIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgY29uc3QgcG9pbnQgPSBPYmplY3QuYXNzaWduKHt9LCBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMpO1xuICAgICAgbGV0IHNhbXBsaW5nSW50ZXJ2YWwgPSAwO1xuXG4gICAgICB3aGlsZSAoc2FtcGxpbmdJbnRlcnZhbCA8PSBkaXN0YW5jZSkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHBvaW50LngsIHBvaW50LnkpO1xuICAgICAgICB1cGRhdGVFbGVtZW50SWRzKGhpdEVsZW1lbnRzKTsgLy8gRXhpdCBzaW5jZSB3ZSByZWFjaGVkIGN1cnJlbnQgcG9pbnRcblxuICAgICAgICBpZiAoc2FtcGxpbmdJbnRlcnZhbCA9PT0gZGlzdGFuY2UpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfSAvLyBDYWxjdWxhdGUgbmV4dCBwb2ludCBpbiB0aGUgbGluZSBhdCBhIGRpc3RhbmNlIG9mIHNhbXBsaW5nIGludGVydmFsXG5cblxuICAgICAgICBzYW1wbGluZ0ludGVydmFsID0gTWF0aC5taW4oc2FtcGxpbmdJbnRlcnZhbCArIHRocmVzaG9sZCwgZGlzdGFuY2UpO1xuICAgICAgICBjb25zdCBkaXN0YW5jZVJhdGlvID0gc2FtcGxpbmdJbnRlcnZhbCAvIGRpc3RhbmNlO1xuICAgICAgICBjb25zdCBuZXh0WCA9ICgxIC0gZGlzdGFuY2VSYXRpbykgKiBwb2ludC54ICsgZGlzdGFuY2VSYXRpbyAqIHNjZW5lUG9pbnRlci54O1xuICAgICAgICBjb25zdCBuZXh0WSA9ICgxIC0gZGlzdGFuY2VSYXRpbykgKiBwb2ludC55ICsgZGlzdGFuY2VSYXRpbyAqIHNjZW5lUG9pbnRlci55O1xuICAgICAgICBwb2ludC54ID0gbmV4dFg7XG4gICAgICAgIHBvaW50LnkgPSBuZXh0WTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGUgPT4ge1xuICAgICAgICBjb25zdCBpZCA9IGlzQm91bmRUb0NvbnRhaW5lcihlbGUpICYmIGlkc1RvVXBkYXRlLmluY2x1ZGVzKGVsZS5jb250YWluZXJJZCkgPyBlbGUuY29udGFpbmVySWQgOiBlbGUuaWQ7XG5cbiAgICAgICAgaWYgKGlkc1RvVXBkYXRlLmluY2x1ZGVzKGlkKSkge1xuICAgICAgICAgIGlmIChldmVudC5hbHRLZXkpIHtcbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXS5lcmFzZSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbaWRdLm9wYWNpdHlcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgICAgb3BhY2l0eTogRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHNjZW5lUG9pbnRlci54O1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBzY2VuZVBvaW50ZXIueTtcbiAgICB9OyAvLyBzZXQgdG91Y2ggbW92aW5nIGZvciBtb2JpbGUgY29udGV4dCBtZW51XG5cblxuICAgIHRoaXMuaGFuZGxlVG91Y2hNb3ZlID0gZXZlbnQgPT4ge1xuICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gdHJ1ZTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyRG93biA9IGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2I7IC8vIHNpbmNlIGNvbnRleHRNZW51IG9wdGlvbnMgYXJlIHBvdGVudGlhbGx5IGV2YWx1YXRlZCBvbiBlYWNoIHJlbmRlcixcbiAgICAgIC8vIGFuZCBhbiBjb250ZXh0TWVudSBhY3Rpb24gbWF5IGRlcGVuZCBvbiBzZWxlY3Rpb24gc3RhdGUsIHdlIG11c3RcbiAgICAgIC8vIGNsb3NlIHRoZSBjb250ZXh0TWVudSBiZWZvcmUgd2UgdXBkYXRlIHRoZSBzZWxlY3Rpb24gb24gcG9pbnRlckRvd25cbiAgICAgIC8vIChlLmcuIHJlc2V0dGluZyBzZWxlY3Rpb24pXG5cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuY29udGV4dE1lbnUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgY29udGV4dE1lbnU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNuYXBMaW5lcykge1xuICAgICAgICB0aGlzLnNldEFwcFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXM6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnVwZGF0ZUdlc3R1cmVPblBvaW50ZXJEb3duKGV2ZW50KTsgLy8gaWYgZHJhZ2dpbmcgZWxlbWVudCBpcyBmcmVlZHJhdyBhbmQgYW5vdGhlciBwb2ludGVyZG93biBldmVudCBvY2N1cnNcbiAgICAgIC8vIGEgc2Vjb25kIGZpbmdlciBpcyBvbiB0aGUgc2NyZWVuXG4gICAgICAvLyBkaXNjYXJkIHRoZSBmcmVlZHJhdyBlbGVtZW50IGlmIGl0IGlzIHZlcnkgc2hvcnQgYmVjYXVzZSBpdCBpcyBsaWtlbHlcbiAgICAgIC8vIGp1c3QgYSBzcGlrZSwgb3RoZXJ3aXNlIGZpbmFsaXplIHRoZSBmcmVlZHJhdyBlbGVtZW50IHdoZW4gdGhlIHNlY29uZFxuICAgICAgLy8gZmluZ2VyIGlzIGxpZnRlZFxuXG4gICAgICBpZiAoZXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIiAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50O1xuICAgICAgICB0aGlzLnVwZGF0ZVNjZW5lKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZWxlbWVudC5wb2ludHMubGVuZ3RoIDwgMTAgPyB7XG4gICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSBlbGVtZW50LmlkKVxuICAgICAgICB9IDoge30pLCB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5rZXlzKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5maWx0ZXIoa2V5ID0+IGtleSAhPT0gZWxlbWVudC5pZCkucmVkdWNlKChvYmosIGtleSkgPT4ge1xuICAgICAgICAgICAgICBvYmpba2V5XSA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2tleV07XG4gICAgICAgICAgICAgIHJldHVybiBvYmo7XG4gICAgICAgICAgICB9LCB7fSksIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gcmVtb3ZlIGFueSBhY3RpdmUgc2VsZWN0aW9uIHdoZW4gd2Ugc3RhcnQgdG8gaW50ZXJhY3Qgd2l0aCBjYW52YXNcbiAgICAgIC8vIChtYWlubHksIHdlIGNhcmUgYWJvdXQgcmVtb3Zpbmcgc2VsZWN0aW9uIG91dHNpZGUgdGhlIGNvbXBvbmVudCB3aGljaFxuICAgICAgLy8gIHdvdWxkIHByZXZlbnQgb3VyIGNvcHkgaGFuZGxpbmcgb3RoZXJ3aXNlKVxuXG5cbiAgICAgIGNvbnN0IHNlbGVjdGlvbiA9IGRvY3VtZW50LmdldFNlbGVjdGlvbigpO1xuXG4gICAgICBpZiAoc2VsZWN0aW9uID09PSBudWxsIHx8IHNlbGVjdGlvbiA9PT0gdm9pZCAwID8gdm9pZCAwIDogc2VsZWN0aW9uLmFuY2hvck5vZGUpIHtcbiAgICAgICAgc2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlT3BlbkNvbnRleHRNZW51QWZ0ZXJQb2ludGVyRG93bk9uVG91Y2hEZXZpY2VzKGV2ZW50KTtcbiAgICAgIHRoaXMubWF5YmVDbGVhbnVwQWZ0ZXJNaXNzaW5nUG9pbnRlclVwKGV2ZW50KTsgLy9maXJlcyBvbmx5IG9uY2UsIGlmIHBlbiBpcyBkZXRlY3RlZCwgcGVuTW9kZSBpcyBlbmFibGVkXG4gICAgICAvL3RoZSB1c2VyIGNhbiBkaXNhYmxlIHRoaXMgYnkgdG9nZ2xpbmcgdGhlIHBlbk1vZGUgYnV0dG9uXG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5wZW5EZXRlY3RlZCAmJiBldmVudC5wb2ludGVyVHlwZSA9PT0gXCJwZW5cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHBlbk1vZGU6IHRydWUsXG4gICAgICAgICAgICBwZW5EZXRlY3RlZDogdHJ1ZVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4gJiYgW1wicGVuXCIsIFwidG91Y2hcIl0uaW5jbHVkZXMoZXZlbnQucG9pbnRlclR5cGUpKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gdXBkYXRlT2JqZWN0KHRoaXMuZGV2aWNlLCB7XG4gICAgICAgICAgaXNUb3VjaFNjcmVlbjogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUGFubmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubGFzdFBvaW50ZXJEb3duID0gZXZlbnQ7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgbGFzdFBvaW50ZXJEb3duV2l0aDogZXZlbnQucG9pbnRlclR5cGUsXG4gICAgICAgIGN1cnNvckJ1dHRvbjogXCJkb3duXCJcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCBcImRvd25cIik7XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZUNhbnZhc1BhblVzaW5nV2hlZWxPclNwYWNlRHJhZyhldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBvbmx5IGhhbmRsZSBsZWZ0IG1vdXNlIGJ1dHRvbiBvciB0b3VjaFxuXG5cbiAgICAgIGlmIChldmVudC5idXR0b24gIT09IFBPSU5URVJfQlVUVE9OLk1BSU4gJiYgZXZlbnQuYnV0dG9uICE9PSBQT0lOVEVSX0JVVFRPTi5UT1VDSCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIGRvbid0IHNlbGVjdCB3aGlsZSBwYW5uaW5nXG5cblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA+IDEpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBTdGF0ZSBmb3IgdGhlIGR1cmF0aW9uIG9mIGEgcG9pbnRlciBpbnRlcmFjdGlvbiwgd2hpY2ggc3RhcnRzIHdpdGggYVxuICAgICAgLy8gcG9pbnRlckRvd24gZXZlbnQsIGVuZHMgd2l0aCBhIHBvaW50ZXJVcCBldmVudCAob3IgYW5vdGhlciBwb2ludGVyRG93bilcblxuXG4gICAgICBjb25zdCBwb2ludGVyRG93blN0YXRlID0gdGhpcy5pbml0aWFsUG9pbnRlckRvd25TdGF0ZShldmVudCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogZmFsc2VcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVEcmFnZ2luZ1Njcm9sbEJhcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmNsZWFyU2VsZWN0aW9uSWZOb3RVc2luZ1NlbGVjdGlvbigpO1xuICAgICAgdGhpcy51cGRhdGVCaW5kaW5nRW5hYmxlZE9uUG9pbnRlck1vdmUoZXZlbnQpO1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVTZWxlY3Rpb25PblBvaW50ZXJEb3duKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGFsbG93T25Qb2ludGVyRG93biA9ICF0aGlzLnN0YXRlLnBlbk1vZGUgfHwgZXZlbnQucG9pbnRlclR5cGUgIT09IFwidG91Y2hcIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIjtcblxuICAgICAgaWYgKCFhbGxvd09uUG9pbnRlckRvd24pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlVGV4dE9uUG9pbnRlckRvd24oZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImFycm93XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGluZVwiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlTGluZWFyRWxlbWVudE9uUG9pbnRlckRvd24oZXZlbnQsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlLCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICAvLyByZXNldCBpbWFnZSBwcmV2aWV3IG9uIHBvaW50ZXJkb3duXG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5DUk9TU0hBSVIpOyAvLyByZXRyaWV2ZSB0aGUgbGF0ZXN0IGVsZW1lbnQgYXMgdGhlIHN0YXRlIG1heSBiZSBzdGFsZVxuXG4gICAgICAgIGNvbnN0IHBlbmRpbmdJbWFnZUVsZW1lbnQgPSB0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCAmJiB0aGlzLnNjZW5lLmdldEVsZW1lbnQodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQpO1xuXG4gICAgICAgIGlmICghcGVuZGluZ0ltYWdlRWxlbWVudCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogcGVuZGluZ0ltYWdlRWxlbWVudCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogcGVuZGluZ0ltYWdlRWxlbWVudCxcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGwsXG4gICAgICAgICAgbXVsdGlFbGVtZW50OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBtdXRhdGVFbGVtZW50KHBlbmRpbmdJbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVGcmVlRHJhd0VsZW1lbnRPblBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImN1c3RvbVwiKSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wuY3VzdG9tVHlwZSA9PT0gXCJjb21tZW50XCIpIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQVVUTyk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUZyYW1lRWxlbWVudE9uUG9pbnRlckRvd24ocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImhhbmRcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUdlbmVyaWNFbGVtZW50T25Qb2ludGVyRG93bih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vblBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIudHJpZ2dlcih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wsIHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB0aGlzLm9uUG9pbnRlck1vdmVGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgY29uc3Qgb25Qb2ludGVyVXAgPSB0aGlzLm9uUG9pbnRlclVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5RG93biA9IHRoaXMub25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5VXAgPSB0aGlzLm9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgbGFzdFBvaW50ZXJVcCA9IG9uUG9pbnRlclVwO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgb25LZXlEb3duKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIG9uS2V5VXApO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSA9IG9uUG9pbnRlck1vdmU7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25VcCA9IG9uUG9pbnRlclVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5VXAgPSBvbktleVVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5RG93biA9IG9uS2V5RG93bjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnJlbW92ZVBvaW50ZXIoZXZlbnQpO1xuICAgICAgdGhpcy5sYXN0UG9pbnRlclVwID0gZXZlbnQ7XG4gICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiBldmVudC5jbGllbnRYLFxuICAgICAgICBjbGllbnRZOiBldmVudC5jbGllbnRZXG4gICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGNsaWNrbGVuZ3RoID0gZXZlbnQudGltZVN0YW1wIC0gKChfYiA9IChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudGltZVN0YW1wKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwKTtcblxuICAgICAgaWYgKHRoaXMuZGV2aWNlLmlzTW9iaWxlICYmIGNsaWNrbGVuZ3RoIDwgMzAwKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG5cbiAgICAgICAgaWYgKGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgZXZlbnQsIHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSkpIHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayhoaXRFbGVtZW50KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4pIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgICAgdGhpcy5oaXRMaW5rRWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudExpbmtBdFBvc2l0aW9uKHNjZW5lUG9pbnRlciwgaGl0RWxlbWVudCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmhpdExpbmtFbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0aGlzLmhpdExpbmtFbGVtZW50LmlkXSkge1xuICAgICAgICBpZiAoY2xpY2tsZW5ndGggPCAzMDAgJiYgdGhpcy5oaXRMaW5rRWxlbWVudC50eXBlID09PSBcImVtYmVkZGFibGVcIiAmJiAhaXNQb2ludEhpdHRpbmdMaW5rSWNvbih0aGlzLmhpdExpbmtFbGVtZW50LCB0aGlzLnN0YXRlLCBbc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55XSkpIHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayh0aGlzLmhpdExpbmtFbGVtZW50KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnJlZGlyZWN0VG9MaW5rKGV2ZW50LCB0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsLFxuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge31cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVPcGVuQ29udGV4dE1lbnVBZnRlclBvaW50ZXJEb3duT25Ub3VjaERldmljZXMgPSBldmVudCA9PiB7XG4gICAgICAvLyBkZWFsIHdpdGggb3BlbmluZyBjb250ZXh0IG1lbnUgb24gdG91Y2ggZGV2aWNlc1xuICAgICAgaWYgKGV2ZW50LnBvaW50ZXJUeXBlID09PSBcInRvdWNoXCIpIHtcbiAgICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKHRvdWNoVGltZW91dCkge1xuICAgICAgICAgIC8vIElmIHRoZXJlJ3MgYWxyZWFkeSBhIHRvdWNoVGltZW91dCwgdGhpcyBtZWFucyB0aGF0IHRoZXJlJ3MgYW5vdGhlclxuICAgICAgICAgIC8vIHRvdWNoIGRvd24gYW5kIHdlIGFyZSBkb2luZyBhbm90aGVyIHRvdWNoLCBzbyB3ZSBzaG91bGRuJ3Qgb3BlbiB0aGVcbiAgICAgICAgICAvLyBjb250ZXh0IG1lbnUuXG4gICAgICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBvcGVuIHRoZSBjb250ZXh0IG1lbnUgd2l0aCB0aGUgZmlyc3QgdG91Y2gncyBjbGllbnRYIGFuZCBjbGllbnRZXG4gICAgICAgICAgLy8gaWYgdGhlIHRvdWNoIGlzIG5vdCBtb3ZpbmdcbiAgICAgICAgICB0b3VjaFRpbWVvdXQgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICB0b3VjaFRpbWVvdXQgPSAwO1xuXG4gICAgICAgICAgICBpZiAoIWludmFsaWRhdGVDb250ZXh0TWVudSkge1xuICAgICAgICAgICAgICB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51KGV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCBUT1VDSF9DVFhfTUVOVV9USU1FT1VUKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0Q29udGV4dE1lbnVUaW1lciA9ICgpID0+IHtcbiAgICAgIGNsZWFyVGltZW91dCh0b3VjaFRpbWVvdXQpO1xuICAgICAgdG91Y2hUaW1lb3V0ID0gMDtcbiAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IGZhbHNlO1xuICAgIH07IC8vIFJldHVybnMgd2hldGhlciB0aGUgZXZlbnQgaXMgYSBwYW5uaW5nXG5cblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUGFuVXNpbmdXaGVlbE9yU3BhY2VEcmFnID0gZXZlbnQgPT4ge1xuICAgICAgaWYgKCEoZ2VzdHVyZS5wb2ludGVycy5zaXplIDw9IDEgJiYgKGV2ZW50LmJ1dHRvbiA9PT0gUE9JTlRFUl9CVVRUT04uV0hFRUwgfHwgZXZlbnQuYnV0dG9uID09PSBQT0lOVEVSX0JVVFRPTi5NQUlOICYmIGlzSG9sZGluZ1NwYWNlIHx8IGlzSGFuZFRvb2xBY3RpdmUodGhpcy5zdGF0ZSkgfHwgdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpKSB8fCBpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgaXNQYW5uaW5nID0gdHJ1ZTtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBsZXQgbmV4dFBhc3RlUHJldmVudGVkID0gZmFsc2U7XG4gICAgICBjb25zdCBpc0xpbnV4ID0gL0xpbnV4Ly50ZXN0KHdpbmRvdy5uYXZpZ2F0b3IucGxhdGZvcm0pO1xuICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUJCSU5HKTtcbiAgICAgIGxldCB7XG4gICAgICAgIGNsaWVudFg6IGxhc3RYLFxuICAgICAgICBjbGllbnRZOiBsYXN0WVxuICAgICAgfSA9IGV2ZW50O1xuICAgICAgY29uc3Qgb25Qb2ludGVyTW92ZSA9IHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZChldmVudCA9PiB7XG4gICAgICAgIGNvbnN0IGRlbHRhWCA9IGxhc3RYIC0gZXZlbnQuY2xpZW50WDtcbiAgICAgICAgY29uc3QgZGVsdGFZID0gbGFzdFkgLSBldmVudC5jbGllbnRZO1xuICAgICAgICBsYXN0WCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICAgIGxhc3RZID0gZXZlbnQuY2xpZW50WTtcbiAgICAgICAgLypcbiAgICAgICAgICogUHJldmVudCBwYXN0ZSBldmVudCBpZiB3ZSBtb3ZlIHdoaWxlIG1pZGRsZSBjbGlja2luZyBvbiBMaW51eC5cbiAgICAgICAgICogU2VlIGlzc3VlICMxMzgzLlxuICAgICAgICAgKi9cblxuICAgICAgICBpZiAoaXNMaW51eCAmJiAhbmV4dFBhc3RlUHJldmVudGVkICYmIChNYXRoLmFicyhkZWx0YVgpID4gMSB8fCBNYXRoLmFicyhkZWx0YVkpID4gMSkpIHtcbiAgICAgICAgICBuZXh0UGFzdGVQcmV2ZW50ZWQgPSB0cnVlO1xuICAgICAgICAgIC8qIFByZXZlbnQgdGhlIG5leHQgcGFzdGUgZXZlbnQgKi9cblxuICAgICAgICAgIGNvbnN0IHByZXZlbnROZXh0UGFzdGUgPSBldmVudCA9PiB7XG4gICAgICAgICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHByZXZlbnROZXh0UGFzdGUpO1xuICAgICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgfTtcbiAgICAgICAgICAvKlxuICAgICAgICAgICAqIFJlZW5hYmxlIG5leHQgcGFzdGUgaW4gY2FzZSBvZiBkaXNhYmxlZCBtaWRkbGUgY2xpY2sgcGFzdGUgZm9yXG4gICAgICAgICAgICogYW55IHJlYXNvbjpcbiAgICAgICAgICAgKiAtIHJpZ2h0IGNsaWNrIHBhc3RlXG4gICAgICAgICAgICogLSBlbXB0eSBjbGlwYm9hcmRcbiAgICAgICAgICAgKi9cblxuXG4gICAgICAgICAgY29uc3QgZW5hYmxlTmV4dFBhc3RlID0gKCkgPT4ge1xuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QQVNURSwgcHJldmVudE5leHRQYXN0ZSk7XG4gICAgICAgICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIGVuYWJsZU5leHRQYXN0ZSk7XG4gICAgICAgICAgICB9LCAxMDApO1xuICAgICAgICAgIH07XG5cbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHByZXZlbnROZXh0UGFzdGUpO1xuICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIGVuYWJsZU5leHRQYXN0ZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyh7XG4gICAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYIC0gZGVsdGFYIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlLFxuICAgICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSAtIGRlbHRhWSAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgICAgY29uc3QgdGVhcmRvd24gPSB3aXRoQmF0Y2hlZFVwZGF0ZXMobGFzdFBvaW50ZXJVcCA9ICgpID0+IHtcbiAgICAgICAgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG4gICAgICAgIGlzUGFubmluZyA9IGZhbHNlO1xuXG4gICAgICAgIGlmICghaXNIb2xkaW5nU3BhY2UpIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5HUkFCKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgY3Vyc29yQnV0dG9uOiBcInVwXCJcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgXCJ1cFwiKTtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGVhcmRvd24pO1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0ZWFyZG93bik7XG4gICAgICAgIG9uUG9pbnRlck1vdmUuZmx1c2goKTtcbiAgICAgIH0pO1xuICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGVhcmRvd24pO1xuICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlLCB7XG4gICAgICAgIHBhc3NpdmU6IHRydWVcbiAgICAgIH0pO1xuICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGVhcmRvd24pO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfTtcblxuICAgIHRoaXMuY2xlYXJTZWxlY3Rpb25JZk5vdFVzaW5nU2VsZWN0aW9uID0gKCkgPT4ge1xuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJucyB3aGV0aGVyIHRoZSBwb2ludGVyIGV2ZW50IGhhcyBiZWVuIGNvbXBsZXRlbHkgaGFuZGxlZFxuICAgICAqL1xuXG5cbiAgICB0aGlzLmhhbmRsZVNlbGVjdGlvbk9uUG9pbnRlckRvd24gPSAoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgPSBnZXRFbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUoZWxlbWVudHMsIHRoaXMuc3RhdGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIHRoaXMuc3RhdGUuem9vbSwgZXZlbnQucG9pbnRlclR5cGUpO1xuXG4gICAgICAgICAgaWYgKGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSAhPSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgcmVzaXppbmdFbGVtZW50OiBlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUuZWxlbWVudFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlID0gZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLnRyYW5zZm9ybUhhbmRsZVR5cGU7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUgPSBnZXRUcmFuc2Zvcm1IYW5kbGVUeXBlRnJvbUNvb3JkcyhnZXRDb21tb25Cb3VuZHMoc2VsZWN0ZWRFbGVtZW50cyksIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIHRoaXMuc3RhdGUuem9vbSwgZXZlbnQucG9pbnRlclR5cGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5pc1Jlc2l6aW5nID0gdHJ1ZTtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5vZmZzZXQgPSB0dXBsZVRvQ29vcnMoZ2V0UmVzaXplT2Zmc2V0WFkocG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSwgc2VsZWN0ZWRFbGVtZW50cywgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkpO1xuXG4gICAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmIGlzTGluZWFyRWxlbWVudChzZWxlY3RlZEVsZW1lbnRzWzBdKSAmJiBzZWxlY3RlZEVsZW1lbnRzWzBdLnBvaW50cy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmFycm93RGlyZWN0aW9uID0gZ2V0UmVzaXplQXJyb3dEaXJlY3Rpb24ocG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSwgc2VsZWN0ZWRFbGVtZW50c1swXSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudEVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQ7XG4gICAgICAgICAgICBjb25zdCByZXQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLCB0aGlzLmhpc3RvcnksIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLCBsaW5lYXJFbGVtZW50RWRpdG9yKTtcblxuICAgICAgICAgICAgaWYgKHJldC5oaXRFbGVtZW50KSB7XG4gICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQgPSByZXQuaGl0RWxlbWVudDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHJldC5saW5lYXJFbGVtZW50RWRpdG9yKSB7XG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogcmV0LmxpbmVhckVsZW1lbnRFZGl0b3JcbiAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50OiByZXQubGluZWFyRWxlbWVudEVkaXRvclxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChyZXQuZGlkQWRkUG9pbnQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBoaXRFbGVtZW50IG1heSBhbHJlYWR5IGJlIHNldCBhYm92ZSwgc28gY2hlY2sgZmlyc3RcblxuXG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCA9IChfYSA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24ocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSk7XG5cbiAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgLy8gRWFybHkgcmV0dXJuIGlmIHBvaW50ZXIgaXMgaGl0dGluZyBsaW5rIGljb25cbiAgICAgICAgICAgIGNvbnN0IGhpdExpbmtFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24oe1xuICAgICAgICAgICAgICB4OiBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LFxuICAgICAgICAgICAgICB5OiBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55XG4gICAgICAgICAgICB9LCBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KTtcblxuICAgICAgICAgICAgaWYgKGhpdExpbmtFbGVtZW50KSB7XG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIEZvciBvdmVybGFwcGVkIGVsZW1lbnRzIG9uZSBwb3NpdGlvbiBtYXkgaGl0XG4gICAgICAgICAgLy8gbXVsdGlwbGUgZWxlbWVudHNcblxuXG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuYWxsSGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbihwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KTtcbiAgICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudDtcbiAgICAgICAgICBjb25zdCBzb21lSGl0RWxlbWVudElzU2VsZWN0ZWQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5hbGxIaXRFbGVtZW50cy5zb21lKGVsZW1lbnQgPT4gdGhpcy5pc0FTZWxlY3RlZEVsZW1lbnQoZWxlbWVudCkpO1xuXG4gICAgICAgICAgaWYgKChoaXRFbGVtZW50ID09PSBudWxsIHx8ICFzb21lSGl0RWxlbWVudElzU2VsZWN0ZWQpICYmICFldmVudC5zaGlmdEtleSAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpIHtcbiAgICAgICAgICAgIHRoaXMuY2xlYXJTZWxlY3Rpb24oaGl0RWxlbWVudCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgICAgICBbdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWRdOiB0cnVlXG4gICAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgICAgICB9KTsgLy8gSWYgd2UgY2xpY2sgb24gc29tZXRoaW5nXG4gICAgICAgICAgfSBlbHNlIGlmIChoaXRFbGVtZW50ICE9IG51bGwpIHtcbiAgICAgICAgICAgIC8vIG9uIENNRC9DVFJMLCBkcmlsbCBkb3duIHRvIGhpdCBlbGVtZW50IHJlZ2FyZGxlc3Mgb2YgZ3JvdXBzIGV0Yy5cbiAgICAgICAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdKSB7XG4gICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQud2FzQWRkZWRUb1NlbGVjdGlvbiA9IHRydWU7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGVkaXRHcm91cEZvclNlbGVjdGVkRWxlbWVudChwcmV2U3RhdGUsIGhpdEVsZW1lbnQpKSwge1xuICAgICAgICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgICB9KSk7IC8vIG1hcmsgYXMgbm90IGNvbXBsZXRlbHkgaGFuZGxlZCBzbyBhcyB0byBhbGxvdyBkcmFnZ2luZyBldGMuXG5cbiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfSAvLyBkZXNlbGVjdCBpZiBpdGVtIGlzIHNlbGVjdGVkXG4gICAgICAgICAgICAvLyBpZiBzaGlmdCBpcyBub3QgY2xpY2tlZCwgdGhpcyB3aWxsIGFsd2F5cyByZXR1cm4gdHJ1ZVxuICAgICAgICAgICAgLy8gb3RoZXJ3aXNlLCBpdCB3aWxsIHRyaWdnZXIgc2VsZWN0aW9uIGJhc2VkIG9uIGN1cnJlbnRcbiAgICAgICAgICAgIC8vIHN0YXRlIG9mIHRoZSBib3hcblxuXG4gICAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdKSB7XG4gICAgICAgICAgICAgIC8vIGlmIHdlIGFyZSBjdXJyZW50bHkgZWRpdGluZyBhIGdyb3VwLCBleGl0aW5nIGVkaXRpbmcgbW9kZSBhbmQgZGVzZWxlY3QgdGhlIGdyb3VwLlxuICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCAmJiAhaXNFbGVtZW50SW5Hcm91cChoaXRFbGVtZW50LCB0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9IC8vIEFkZCBoaXQgZWxlbWVudCB0byBzZWxlY3Rpb24uIEF0IHRoaXMgcG9pbnQgaWYgd2UncmUgbm90IGhvbGRpbmdcbiAgICAgICAgICAgICAgLy8gU0hJRlQgdGhlIHByZXZpb3VzbHkgc2VsZWN0ZWQgZWxlbWVudChzKSB3ZXJlIGRlc2VsZWN0ZWQgYWJvdmVcbiAgICAgICAgICAgICAgLy8gKG1ha2Ugc3VyZSB5b3UgdXNlIHNldFN0YXRlIHVwZGF0ZXIgdG8gdXNlIGxhdGVzdCBzdGF0ZSlcbiAgICAgICAgICAgICAgLy8gV2l0aCBzaGlmdC1zZWxlY3Rpb24sIHdlIHdhbnQgdG8gbWFrZSBzdXJlIHRoYXQgZnJhbWVzIGFuZCB0aGVpciBjb250YWluaW5nXG4gICAgICAgICAgICAgIC8vIGVsZW1lbnRzIGFyZSBub3Qgc2VsZWN0ZWQgYXQgdGhlIHNhbWUgdGltZS5cblxuXG4gICAgICAgICAgICAgIGlmICghc29tZUhpdEVsZW1lbnRJc1NlbGVjdGVkICYmICFwb2ludGVyRG93blN0YXRlLmhpdC5oYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cykge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICBjb25zdCBwcmV2aW91c2x5U2VsZWN0ZWRFbGVtZW50cyA9IFtdO1xuICAgICAgICAgICAgICAgICAgT2JqZWN0LmtleXMocHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcykuZm9yRWFjaChpZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnQoaWQpO1xuICAgICAgICAgICAgICAgICAgICBlbGVtZW50ICYmIHByZXZpb3VzbHlTZWxlY3RlZEVsZW1lbnRzLnB1c2goZWxlbWVudCk7XG4gICAgICAgICAgICAgICAgICB9KTsgLy8gaWYgaGl0RWxlbWVudCBpcyBmcmFtZSwgZGVzZWxlY3QgYWxsIG9mIGl0cyBlbGVtZW50cyBpZiB0aGV5IGFyZSBzZWxlY3RlZFxuXG4gICAgICAgICAgICAgICAgICBpZiAoaGl0RWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgZ2V0RnJhbWVFbGVtZW50cyhwcmV2aW91c2x5U2VsZWN0ZWRFbGVtZW50cywgaGl0RWxlbWVudC5pZCkuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGhpdEVsZW1lbnQuZnJhbWVJZCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBpZiBoaXRFbGVtZW50IGlzIGluIGEgZnJhbWUgYW5kIGl0cyBmcmFtZSBoYXMgYmVlbiBzZWxlY3RlZFxuICAgICAgICAgICAgICAgICAgICAvLyBkaXNhYmxlIHNlbGVjdGlvbiBmb3IgdGhlIGdpdmVuIGVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgaWYgKG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5mcmFtZUlkXSkge1xuICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBoaXRFbGVtZW50IGlzIG5laXRoZXIgYSBmcmFtZSBub3IgYW4gZWxlbWVudCBpbiBhIGZyYW1lXG4gICAgICAgICAgICAgICAgICAgIC8vIGJ1dCBzaW5jZSBoaXRFbGVtZW50IGNvdWxkIGJlIGluIGEgZ3JvdXAgd2l0aCBzb21lIGZyYW1lc1xuICAgICAgICAgICAgICAgICAgICAvLyB0aGlzIG1lYW5zIHNlbGVjdGluZyBoaXRFbGVtZW50IHdpbGwgaGF2ZSB0aGUgZnJhbWVzIHNlbGVjdGVkIGFzIHdlbGxcbiAgICAgICAgICAgICAgICAgICAgLy8gYmVjYXVzZSB3ZSB3YW50IHRvIGtlZXAgdGhlIGludmFyaWFudDpcbiAgICAgICAgICAgICAgICAgICAgLy8gLSBmcmFtZXMgYW5kIHRoZWlyIGVsZW1lbnRzIGFyZSBub3Qgc2VsZWN0ZWQgYXQgdGhlIHNhbWUgdGltZVxuICAgICAgICAgICAgICAgICAgICAvLyB3ZSBkZXNlbGVjdCBlbGVtZW50cyBpbiB0aG9zZSBmcmFtZXMgdGhhdCB3ZXJlIHByZXZpb3VzbHkgc2VsZWN0ZWRcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZ3JvdXBJZHMgPSBoaXRFbGVtZW50Lmdyb3VwSWRzO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBmcmFtZXNJbkdyb3VwcyA9IG5ldyBTZXQoZ3JvdXBJZHMuZmxhdE1hcChnaWQgPT4gZ2V0RWxlbWVudHNJbkdyb3VwKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGdpZCkpLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKS5tYXAoZnJhbWUgPT4gZnJhbWUuaWQpKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoZnJhbWVzSW5Hcm91cHMuc2l6ZSA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICBwcmV2aW91c2x5U2VsZWN0ZWRFbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQuZnJhbWVJZCAmJiBmcmFtZXNJbkdyb3Vwcy5oYXMoZWxlbWVudC5mcmFtZUlkKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBkZXNlbGVjdCBlbGVtZW50IGFuZCBncm91cHMgY29udGFpbmluZyB0aGUgZWxlbWVudFxuICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5ncm91cElkcy5mbGF0TWFwKGdpZCA9PiBnZXRFbGVtZW50c0luR3JvdXAodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZ2lkKSkuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dFNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBoaXRFbGVtZW50LmxpbmsgfHwgaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSA/IFwiaW5mb1wiIDogZmFsc2VcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0Lndhc0FkZGVkVG9TZWxlY3Rpb24gPSB0cnVlO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczogdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlVGV4dE9uUG9pbnRlckRvd24gPSAoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpID0+IHtcbiAgICAgIC8vIGlmIHdlJ3JlIGN1cnJlbnRseSBzdGlsbCBlZGl0aW5nIHRleHQsIGNsaWNraW5nIG91dHNpZGVcbiAgICAgIC8vIHNob3VsZCBvbmx5IGZpbmFsaXplIGl0LCBub3QgY3JlYXRlIGFub3RoZXIgKGlycmVzcGVjdGl2ZVxuICAgICAgLy8gb2Ygc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpXG4gICAgICBpZiAoaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGxldCBzY2VuZVggPSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54O1xuICAgICAgbGV0IHNjZW5lWSA9IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnk7XG4gICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwge1xuICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZVxuICAgICAgfSk7IC8vIEZJWE1FXG5cbiAgICAgIGxldCBjb250YWluZXIgPSBnZXRUZXh0QmluZGFibGVDb250YWluZXJBdFBvc2l0aW9uKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgaWYgKGhhc0JvdW5kVGV4dEVsZW1lbnQoZWxlbWVudCkpIHtcbiAgICAgICAgY29udGFpbmVyID0gZWxlbWVudDtcbiAgICAgICAgc2NlbmVYID0gZWxlbWVudC54ICsgZWxlbWVudC53aWR0aCAvIDI7XG4gICAgICAgIHNjZW5lWSA9IGVsZW1lbnQueSArIGVsZW1lbnQuaGVpZ2h0IC8gMjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zdGFydFRleHRFZGl0aW5nKHtcbiAgICAgICAgc2NlbmVYLFxuICAgICAgICBzY2VuZVksXG4gICAgICAgIGluc2VydEF0UGFyZW50Q2VudGVyOiAhZXZlbnQuYWx0S2V5LFxuICAgICAgICBjb250YWluZXJcbiAgICAgIH0pO1xuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5hY3RpdmVUb29sLmxvY2tlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBhY3RpdmVUb29sOiB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVGcmVlRHJhd0VsZW1lbnRPblBvaW50ZXJEb3duID0gKGV2ZW50LCBlbGVtZW50VHlwZSwgcG9pbnRlckRvd25TdGF0ZSkgPT4ge1xuICAgICAgLy8gQmVnaW4gYSBtYXJrIGNhcHR1cmUuIFRoaXMgZG9lcyBub3QgaGF2ZSB0byB1cGRhdGUgc3RhdGUgeWV0LlxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgbnVsbCk7XG4gICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWVxuICAgICAgfSk7XG4gICAgICBjb25zdCBlbGVtZW50ID0gbmV3RnJlZURyYXdFbGVtZW50KHtcbiAgICAgICAgdHlwZTogZWxlbWVudFR5cGUsXG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIHJvdW5kbmVzczogbnVsbCxcbiAgICAgICAgc2ltdWxhdGVQcmVzc3VyZTogZXZlbnQucHJlc3N1cmUgPT09IDAuNSxcbiAgICAgICAgbG9ja2VkOiBmYWxzZSxcbiAgICAgICAgZnJhbWVJZDogdG9wTGF5ZXJGcmFtZSA/IHRvcExheWVyRnJhbWUuaWQgOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpO1xuICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKG5leHRTZWxlY3RlZEVsZW1lbnRJZHMsIHByZXZTdGF0ZSlcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcHJlc3N1cmVzID0gZWxlbWVudC5zaW11bGF0ZVByZXNzdXJlID8gZWxlbWVudC5wcmVzc3VyZXMgOiBbLi4uZWxlbWVudC5wcmVzc3VyZXMsIGV2ZW50LnByZXNzdXJlXTtcbiAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICBwb2ludHM6IFtbMCwgMF1dLFxuICAgICAgICBwcmVzc3VyZXNcbiAgICAgIH0pO1xuICAgICAgY29uc3QgYm91bmRFbGVtZW50ID0gZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLCB0aGlzLnNjZW5lKTtcbiAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChlbGVtZW50KTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBlbGVtZW50LFxuICAgICAgICBzdGFydEJvdW5kRWxlbWVudDogYm91bmRFbGVtZW50LFxuICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgIH0pO1xuICAgIH07IC8vY3JlYXRlIHJlY3RhbmdsZSBlbGVtZW50IHdpdGggeW91dHViZSB0b3AgbGVmdCBvbiBuZWFyZXN0IGdyaWQgcG9pbnQgd2lkdGggLyBoaWdodCA2NDAvMzYwXG5cblxuICAgIHRoaXMuaW5zZXJ0RW1iZWRkYWJsZUVsZW1lbnQgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZLFxuICAgICAgbGlua1xuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVYLCBzY2VuZVksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hW0tFWVMuQ1RSTF9PUl9DTURdKSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgIGNvbnN0IGVtYmVkTGluayA9IGdldEVtYmVkTGluayhsaW5rKTtcblxuICAgICAgaWYgKCFlbWJlZExpbmspIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZW1iZWRMaW5rLndhcm5pbmcpIHtcbiAgICAgICAgdGhpcy5zZXRUb2FzdCh7XG4gICAgICAgICAgbWVzc2FnZTogZW1iZWRMaW5rLndhcm5pbmcsXG4gICAgICAgICAgY2xvc2FibGU6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdFbWJlZGRhYmxlRWxlbWVudCh7XG4gICAgICAgIHR5cGU6IFwiZW1iZWRkYWJsZVwiLFxuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiBcInRyYW5zcGFyZW50XCIsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogXCJ0cmFuc3BhcmVudFwiLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgcm91bmRuZXNzOiB0aGlzLmdldEN1cnJlbnRJdGVtUm91bmRuZXNzKFwiZW1iZWRkYWJsZVwiKSxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIGxvY2tlZDogZmFsc2UsXG4gICAgICAgIHdpZHRoOiBlbWJlZExpbmsuYXNwZWN0UmF0aW8udyxcbiAgICAgICAgaGVpZ2h0OiBlbWJlZExpbmsuYXNwZWN0UmF0aW8uaCxcbiAgICAgICAgbGluayxcbiAgICAgICAgdmFsaWRhdGVkOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBlbGVtZW50XSk7XG4gICAgICByZXR1cm4gZWxlbWVudDtcbiAgICB9O1xuXG4gICAgdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZXG4gICAgfSkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChzY2VuZVgsIHNjZW5lWSwgKChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0ltYWdlRWxlbWVudCh7XG4gICAgICAgIHR5cGU6IFwiaW1hZ2VcIixcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZUNvbG9yLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgc3Ryb2tlV2lkdGg6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VXaWR0aCxcbiAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICByb3VuZG5lc3M6IG51bGwsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlTGluZWFyRWxlbWVudE9uUG9pbnRlckRvd24gPSAoZXZlbnQsIGVsZW1lbnRUeXBlLCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG11bHRpRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTsgLy8gZmluYWxpemUgaWYgY29tcGxldGluZyBhIGxvb3BcblxuICAgICAgICBpZiAobXVsdGlFbGVtZW50LnR5cGUgPT09IFwibGluZVwiICYmIGlzUGF0aEFMb29wKG11bHRpRWxlbWVudC5wb2ludHMsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50OiBtdWx0aUVsZW1lbnQucG9pbnRzW211bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoIC0gMV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHJ4LFxuICAgICAgICAgIHk6IHJ5LFxuICAgICAgICAgIGxhc3RDb21taXR0ZWRQb2ludFxuICAgICAgICB9ID0gbXVsdGlFbGVtZW50OyAvLyBjbGlja2luZyBpbnNpZGUgY29tbWl0IHpvbmUg4oaSIGZpbmFsaXplIGFycm93XG5cbiAgICAgICAgaWYgKG11bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoID4gMSAmJiBsYXN0Q29tbWl0dGVkUG9pbnQgJiYgZGlzdGFuY2UyZChwb2ludGVyRG93blN0YXRlLm9yaWdpbi54IC0gcngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkgLSByeSwgbGFzdENvbW1pdHRlZFBvaW50WzBdLCBsYXN0Q29tbWl0dGVkUG9pbnRbMV0pIDwgTElORV9DT05GSVJNX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgW211bHRpRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICB9KSwgcHJldlN0YXRlKVxuICAgICAgICB9KSk7IC8vIGNsaWNraW5nIG91dHNpZGUgY29tbWl0IHpvbmUg4oaSIHVwZGF0ZSByZWZlcmVuY2UgZm9yIGxhc3QgY29tbWl0dGVkXG4gICAgICAgIC8vIHBvaW50XG5cbiAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnQ6IG11bHRpRWxlbWVudC5wb2ludHNbbXVsdGlFbGVtZW50LnBvaW50cy5sZW5ndGggLSAxXVxuICAgICAgICB9KTtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgICB5OiBncmlkWVxuICAgICAgICB9KTtcbiAgICAgICAgLyogSWYgYXJyb3cgaXMgcHJlLWFycm93aGVhZHMsIGl0IHdpbGwgaGF2ZSB1bmRlZmluZWQgZm9yIGJvdGggc3RhcnQgYW5kIGVuZCBhcnJvd2hlYWRzLlxuICAgICAgICBJZiBzbywgd2Ugd2FudCBpdCB0byBiZSBudWxsIGZvciBzdGFydCBhbmQgXCJhcnJvd1wiIGZvciBlbmQuIElmIHRoZSBsaW5lYXIgaXRlbSBpcyBub3RcbiAgICAgICAgYW4gYXJyb3csIHdlIHdhbnQgaXQgdG8gYmUgbnVsbCBmb3IgYm90aC4gT3RoZXJ3aXNlLCB3ZSB3YW50IGl0IHRvIHVzZSB0aGVcbiAgICAgICAgdmFsdWVzIGZyb20gYXBwU3RhdGUuICovXG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGN1cnJlbnRJdGVtU3RhcnRBcnJvd2hlYWQsXG4gICAgICAgICAgY3VycmVudEl0ZW1FbmRBcnJvd2hlYWRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGNvbnN0IFtzdGFydEFycm93aGVhZCwgZW5kQXJyb3doZWFkXSA9IGVsZW1lbnRUeXBlID09PSBcImFycm93XCIgPyBbY3VycmVudEl0ZW1TdGFydEFycm93aGVhZCwgY3VycmVudEl0ZW1FbmRBcnJvd2hlYWRdIDogW251bGwsIG51bGxdO1xuICAgICAgICBjb25zdCBlbGVtZW50ID0gbmV3TGluZWFyRWxlbWVudCh7XG4gICAgICAgICAgdHlwZTogZWxlbWVudFR5cGUsXG4gICAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgICAgeTogZ3JpZFksXG4gICAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgICAgcm91bmRuZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91bmRuZXNzID09PSBcInJvdW5kXCIgPyB7XG4gICAgICAgICAgICB0eXBlOiBST1VORE5FU1MuUFJPUE9SVElPTkFMX1JBRElVU1xuICAgICAgICAgIH0gOiBudWxsLFxuICAgICAgICAgIHN0YXJ0QXJyb3doZWFkLFxuICAgICAgICAgIGVuZEFycm93aGVhZCxcbiAgICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTtcbiAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRFbGVtZW50SWRzLCBwcmV2U3RhdGUpXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgIHBvaW50czogWy4uLmVsZW1lbnQucG9pbnRzLCBbMCwgMF1dXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBib3VuZEVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4sIHRoaXMuc2NlbmUpO1xuICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBzdGFydEJvdW5kRWxlbWVudDogYm91bmRFbGVtZW50LFxuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5jcmVhdGVHZW5lcmljRWxlbWVudE9uUG9pbnRlckRvd24gPSAoZWxlbWVudFR5cGUsIHBvaW50ZXJEb3duU3RhdGUpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgKChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgYmFzZUVsZW1lbnRBdHRyaWJ1dGVzID0ge1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFksXG4gICAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICByb3VuZG5lc3M6IHRoaXMuZ2V0Q3VycmVudEl0ZW1Sb3VuZG5lc3MoZWxlbWVudFR5cGUpLFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH07XG4gICAgICBsZXQgZWxlbWVudDtcblxuICAgICAgaWYgKGVsZW1lbnRUeXBlID09PSBcImVtYmVkZGFibGVcIikge1xuICAgICAgICBlbGVtZW50ID0gbmV3RW1iZWRkYWJsZUVsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdHlwZTogXCJlbWJlZGRhYmxlXCIsXG4gICAgICAgICAgdmFsaWRhdGVkOiBudWxsXG4gICAgICAgIH0sIGJhc2VFbGVtZW50QXR0cmlidXRlcykpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWxlbWVudCA9IG5ld0VsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdHlwZTogZWxlbWVudFR5cGVcbiAgICAgICAgfSwgYmFzZUVsZW1lbnRBdHRyaWJ1dGVzKSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbGVtZW50LnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0aW9uRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIG11bHRpRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlRnJhbWVFbGVtZW50T25Qb2ludGVyRG93biA9IHBvaW50ZXJEb3duU3RhdGUgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCAoKF9hID0gdGhpcy5sYXN0UG9pbnRlckRvd24pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVtLRVlTLkNUUkxfT1JfQ01EXSkgPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBmcmFtZSA9IG5ld0ZyYW1lRWxlbWVudChPYmplY3QuYXNzaWduKHtcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgICAgbG9ja2VkOiBmYWxzZVxuICAgICAgfSwgRlJBTUVfU1RZTEUpKTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBmcmFtZV0pO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG11bHRpRWxlbWVudDogbnVsbCxcbiAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBmcmFtZSxcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGZyYW1lXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXN0b3JlUmVhZHlUb0VyYXNlRWxlbWVudHMgPSBwb2ludGVyRG93blN0YXRlID0+IHtcbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWxlID0+IHtcbiAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0uZXJhc2UpIHtcbiAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0ub3BhY2l0eVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGlzQm91bmRUb0NvbnRhaW5lcihlbGUpICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5jb250YWluZXJJZF0uZXJhc2UpIHtcbiAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5jb250YWluZXJJZF0ub3BhY2l0eVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGVsZS5mcmFtZUlkICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgb3BhY2l0eTogcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuZnJhbWVJZF0ub3BhY2l0eVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgIH07XG5cbiAgICB0aGlzLmVyYXNlRWxlbWVudHMgPSBwb2ludGVyRG93blN0YXRlID0+IHtcbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWxlID0+IHtcbiAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0uZXJhc2UpIHtcbiAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICBpc0RlbGV0ZWQ6IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5jb250YWluZXJJZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZWxlLmZyYW1lSWQgJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuZnJhbWVJZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuZnJhbWVJZF0uZXJhc2UpIHtcbiAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICBpc0RlbGV0ZWQ6IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGU7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGVsZW1lbnRzKTtcbiAgICB9O1xuXG4gICAgdGhpcy5pbml0aWFsaXplSW1hZ2UgPSAoe1xuICAgICAgaW1hZ2VGaWxlLFxuICAgICAgaW1hZ2VFbGVtZW50OiBfaW1hZ2VFbGVtZW50LFxuICAgICAgc2hvd0N1cnNvckltYWdlUHJldmlldyA9IGZhbHNlXG4gICAgfSkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdmFyIF9mLCBfZywgX2gsIF9qOyAvLyBhdCB0aGlzIHBvaW50IHRoaXMgc2hvdWxkIGJlIGd1YXJhbnRlZWQgaW1hZ2UgZmlsZSwgYnV0IHdlIGRvIHRoaXMgY2hlY2tcbiAgICAgIC8vIHRvIHNhdGlzZnkgVFMgZG93biB0aGUgbGluZVxuXG5cbiAgICAgIGlmICghaXNTdXBwb3J0ZWRJbWFnZUZpbGUoaW1hZ2VGaWxlKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IodChcImVycm9ycy51bnN1cHBvcnRlZEZpbGVUeXBlXCIpKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbWltZVR5cGUgPSBpbWFnZUZpbGUudHlwZTtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBcIndhaXRcIik7XG5cbiAgICAgIGlmIChtaW1lVHlwZSA9PT0gTUlNRV9UWVBFUy5zdmcpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpbWFnZUZpbGUgPSBTVkdTdHJpbmdUb0ZpbGUoeWllbGQgbm9ybWFsaXplU1ZHKHlpZWxkIGltYWdlRmlsZS50ZXh0KCkpLCBpbWFnZUZpbGUubmFtZSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKGVycm9yKTtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodChcImVycm9ycy5zdmdJbWFnZUluc2VydEVycm9yXCIpKTtcbiAgICAgICAgfVxuICAgICAgfSAvLyBnZW5lcmF0ZSBpbWFnZSBpZCAoYnkgZGVmYXVsdCB0aGUgZmlsZSBkaWdlc3QpIGJlZm9yZSBhbnlcbiAgICAgIC8vIHJlc2l6aW5nL2NvbXByZXNzaW9uIHRha2VzIHBsYWNlIHRvIGtlZXAgaXQgbW9yZSBwb3J0YWJsZVxuXG5cbiAgICAgIGNvbnN0IGZpbGVJZCA9IHlpZWxkICgoX2cgPSAoX2YgPSB0aGlzLnByb3BzKS5nZW5lcmF0ZUlkRm9yRmlsZSkgPT09IG51bGwgfHwgX2cgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9nLmNhbGwoX2YsIGltYWdlRmlsZSkpIHx8IGdlbmVyYXRlSWRGcm9tRmlsZShpbWFnZUZpbGUpO1xuXG4gICAgICBpZiAoIWZpbGVJZCkge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJDb3VsZG4ndCBnZW5lcmF0ZSBmaWxlIGlkIG9yIHRoZSBzdXBwbGllZCBgZ2VuZXJhdGVJZEZvckZpbGVgIGRpZG4ndCByZXNvbHZlIHRvIG9uZS5cIik7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcih0KFwiZXJyb3JzLmltYWdlSW5zZXJ0RXJyb3JcIikpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBleGlzdGluZ0ZpbGVEYXRhID0gdGhpcy5maWxlc1tmaWxlSWRdO1xuXG4gICAgICBpZiAoIShleGlzdGluZ0ZpbGVEYXRhID09PSBudWxsIHx8IGV4aXN0aW5nRmlsZURhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nRmlsZURhdGEuZGF0YVVSTCkpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpbWFnZUZpbGUgPSB5aWVsZCByZXNpemVJbWFnZUZpbGUoaW1hZ2VGaWxlLCB7XG4gICAgICAgICAgICBtYXhXaWR0aE9ySGVpZ2h0OiBERUZBVUxUX01BWF9JTUFHRV9XSURUSF9PUl9IRUlHSFRcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFwiZXJyb3IgdHJ5aW5nIHRvIHJlc2luZyBpbWFnZSBmaWxlIG9uIGluc2VydGlvblwiLCBlcnJvcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW1hZ2VGaWxlLnNpemUgPiBNQVhfQUxMT1dFRF9GSUxFX0JZVEVTKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMuZmlsZVRvb0JpZ1wiLCB7XG4gICAgICAgICAgICBtYXhTaXplOiBgJHtNYXRoLnRydW5jKE1BWF9BTExPV0VEX0ZJTEVfQllURVMgLyAxMDI0IC8gMTAyNCl9TUJgXG4gICAgICAgICAgfSkpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChzaG93Q3Vyc29ySW1hZ2VQcmV2aWV3KSB7XG4gICAgICAgIGNvbnN0IGRhdGFVUkwgPSAoX2ggPSB0aGlzLmZpbGVzW2ZpbGVJZF0pID09PSBudWxsIHx8IF9oID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfaC5kYXRhVVJMOyAvLyBvcHRpbWl6YXRpb24gc28gdGhhdCB3ZSBkb24ndCB1bm5lY2Vzc2FyaWx5IHJlc2l6ZSB0aGUgb3JpZ2luYWxcbiAgICAgICAgLy8gZnVsbC1zaXplIGZpbGUgZm9yIGN1cnNvciBwcmV2aWV3XG4gICAgICAgIC8vIChpdCdzIG11Y2ggZmFzdGVyIHRvIGNvbnZlcnQgdGhlIHJlc2l6ZWQgZGF0YVVSTCB0byBGaWxlKVxuXG4gICAgICAgIGNvbnN0IHJlc2l6ZWRGaWxlID0gZGF0YVVSTCAmJiBkYXRhVVJMVG9GaWxlKGRhdGFVUkwpO1xuICAgICAgICB0aGlzLnNldEltYWdlUHJldmlld0N1cnNvcihyZXNpemVkRmlsZSB8fCBpbWFnZUZpbGUpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBkYXRhVVJMID0gKChfaiA9IHRoaXMuZmlsZXNbZmlsZUlkXSkgPT09IG51bGwgfHwgX2ogPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9qLmRhdGFVUkwpIHx8ICh5aWVsZCBnZXREYXRhVVJMKGltYWdlRmlsZSkpO1xuICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gbXV0YXRlRWxlbWVudChfaW1hZ2VFbGVtZW50LCB7XG4gICAgICAgIGZpbGVJZFxuICAgICAgfSwgZmFsc2UpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgICAgdmFyIF9rO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdGhpcy5maWxlcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5maWxlcyksIHtcbiAgICAgICAgICAgIFtmaWxlSWRdOiB7XG4gICAgICAgICAgICAgIG1pbWVUeXBlLFxuICAgICAgICAgICAgICBpZDogZmlsZUlkLFxuICAgICAgICAgICAgICBkYXRhVVJMLFxuICAgICAgICAgICAgICBjcmVhdGVkOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgICBsYXN0UmV0cmlldmVkOiBEYXRlLm5vdygpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgY29uc3QgY2FjaGVkSW1hZ2VEYXRhID0gdGhpcy5pbWFnZUNhY2hlLmdldChmaWxlSWQpO1xuXG4gICAgICAgICAgaWYgKCFjYWNoZWRJbWFnZURhdGEpIHtcbiAgICAgICAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgICAgICAgICB5aWVsZCB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUoW2ltYWdlRWxlbWVudF0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICgoY2FjaGVkSW1hZ2VEYXRhID09PSBudWxsIHx8IGNhY2hlZEltYWdlRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogY2FjaGVkSW1hZ2VEYXRhLmltYWdlKSBpbnN0YW5jZW9mIFByb21pc2UpIHtcbiAgICAgICAgICAgIHlpZWxkIGNhY2hlZEltYWdlRGF0YS5pbWFnZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQgIT09IGltYWdlRWxlbWVudC5pZCAmJiAoKF9rID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQpID09PSBudWxsIHx8IF9rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfay5pZCkgIT09IGltYWdlRWxlbWVudC5pZCkge1xuICAgICAgICAgICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zKGltYWdlRWxlbWVudCwgdHJ1ZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVzb2x2ZShpbWFnZUVsZW1lbnQpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IodChcImVycm9ycy5pbWFnZUluc2VydEVycm9yXCIpKSk7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgaWYgKCFzaG93Q3Vyc29ySW1hZ2VQcmV2aWV3KSB7XG4gICAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pKTtcbiAgICB9KTtcbiAgICAvKipcbiAgICAgKiBpbnNlcnRzIGltYWdlIGludG8gZWxlbWVudHMgYXJyYXkgYW5kIHJlcmVuZGVyc1xuICAgICAqL1xuXG5cbiAgICB0aGlzLmluc2VydEltYWdlRWxlbWVudCA9IChpbWFnZUVsZW1lbnQsIGltYWdlRmlsZSwgc2hvd0N1cnNvckltYWdlUHJldmlldykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdGhpcy5zY2VuZS5hZGROZXdFbGVtZW50KGltYWdlRWxlbWVudCk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHlpZWxkIHRoaXMuaW5pdGlhbGl6ZUltYWdlKHtcbiAgICAgICAgICBpbWFnZUZpbGUsXG4gICAgICAgICAgaW1hZ2VFbGVtZW50LFxuICAgICAgICAgIHNob3dDdXJzb3JJbWFnZVByZXZpZXdcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UgfHwgdChcImVycm9ycy5pbWFnZUluc2VydEVycm9yXCIpXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5zZXRJbWFnZVByZXZpZXdDdXJzb3IgPSBpbWFnZUZpbGUgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgLy8gbXVzdG4ndCBiZSBsYXJnZXIgdGhhbiAxMjggcHhcbiAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0NTUy9DU1NfQmFzaWNfVXNlcl9JbnRlcmZhY2UvVXNpbmdfVVJMX3ZhbHVlc19mb3JfdGhlX2N1cnNvcl9wcm9wZXJ0eVxuICAgICAgY29uc3QgY3Vyc29ySW1hZ2VTaXplUHggPSA5NjtcbiAgICAgIGNvbnN0IGltYWdlUHJldmlldyA9IHlpZWxkIHJlc2l6ZUltYWdlRmlsZShpbWFnZUZpbGUsIHtcbiAgICAgICAgbWF4V2lkdGhPckhlaWdodDogY3Vyc29ySW1hZ2VTaXplUHhcbiAgICAgIH0pO1xuICAgICAgbGV0IHByZXZpZXdEYXRhVVJMID0geWllbGQgZ2V0RGF0YVVSTChpbWFnZVByZXZpZXcpOyAvLyBTVkcgY2Fubm90IGJlIHJlc2l6ZWQgdmlhIGByZXNpemVJbWFnZUZpbGVgIHNvIHdlIHJlc2l6ZSBieSByZW5kZXJpbmcgdG9cbiAgICAgIC8vIGEgc21hbGwgY2FudmFzXG5cbiAgICAgIGlmIChpbWFnZUZpbGUudHlwZSA9PT0gTUlNRV9UWVBFUy5zdmcpIHtcbiAgICAgICAgY29uc3QgaW1nID0geWllbGQgbG9hZEhUTUxJbWFnZUVsZW1lbnQocHJldmlld0RhdGFVUkwpO1xuICAgICAgICBsZXQgaGVpZ2h0ID0gTWF0aC5taW4oaW1nLmhlaWdodCwgY3Vyc29ySW1hZ2VTaXplUHgpO1xuICAgICAgICBsZXQgd2lkdGggPSBoZWlnaHQgKiAoaW1nLndpZHRoIC8gaW1nLmhlaWdodCk7XG5cbiAgICAgICAgaWYgKHdpZHRoID4gY3Vyc29ySW1hZ2VTaXplUHgpIHtcbiAgICAgICAgICB3aWR0aCA9IGN1cnNvckltYWdlU2l6ZVB4O1xuICAgICAgICAgIGhlaWdodCA9IHdpZHRoICogKGltZy5oZWlnaHQgLyBpbWcud2lkdGgpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodDtcbiAgICAgICAgY2FudmFzLndpZHRoID0gd2lkdGg7XG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xuICAgICAgICBjb250ZXh0LmRyYXdJbWFnZShpbWcsIDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xuICAgICAgICBwcmV2aWV3RGF0YVVSTCA9IGNhbnZhcy50b0RhdGFVUkwoTUlNRV9UWVBFUy5zdmcpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIGB1cmwoJHtwcmV2aWV3RGF0YVVSTH0pIDQgNCwgYXV0b2ApO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5vbkltYWdlQWN0aW9uID0gKHtcbiAgICAgIGluc2VydE9uQ2FudmFzRGlyZWN0bHlcbiAgICB9ID0ge1xuICAgICAgaW5zZXJ0T25DYW52YXNEaXJlY3RseTogZmFsc2VcbiAgICB9KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjbGllbnRYID0gdGhpcy5zdGF0ZS53aWR0aCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldExlZnQ7XG4gICAgICAgIGNvbnN0IGNsaWVudFkgPSB0aGlzLnN0YXRlLmhlaWdodCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldFRvcDtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgICBjbGllbnRYLFxuICAgICAgICAgIGNsaWVudFlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGltYWdlRmlsZSA9IHlpZWxkIGZpbGVPcGVuKHtcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJJbWFnZVwiLFxuICAgICAgICAgIGV4dGVuc2lvbnM6IE9iamVjdC5rZXlzKElNQUdFX01JTUVfVFlQRVMpXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSB0aGlzLmNyZWF0ZUltYWdlRWxlbWVudCh7XG4gICAgICAgICAgc2NlbmVYOiB4LFxuICAgICAgICAgIHNjZW5lWTogeVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoaW5zZXJ0T25DYW52YXNEaXJlY3RseSkge1xuICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlKTtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IGltYWdlRWxlbWVudC5pZFxuICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlLFxuICAgICAgICAgICAgLyogc2hvd0N1cnNvckltYWdlUHJldmlldyAqL1xuICAgICAgICAgICAgdHJ1ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmIChlcnJvci5uYW1lICE9PSBcIkFib3J0RXJyb3JcIikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGwsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMgPSAoaW1hZ2VFbGVtZW50LCBmb3JjZU5hdHVyYWxTaXplID0gZmFsc2UpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaW1hZ2UgPSBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCkgJiYgKChfYSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoaW1hZ2VFbGVtZW50LmZpbGVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pbWFnZSk7XG5cbiAgICAgIGlmICghaW1hZ2UgfHwgaW1hZ2UgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgIGlmIChpbWFnZUVsZW1lbnQud2lkdGggPCBEUkFHR0lOR19USFJFU0hPTEQgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUgJiYgaW1hZ2VFbGVtZW50LmhlaWdodCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkge1xuICAgICAgICAgIGNvbnN0IHBsYWNlaG9sZGVyU2l6ZSA9IDEwMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgICAgeDogaW1hZ2VFbGVtZW50LnggLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgeTogaW1hZ2VFbGVtZW50LnkgLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgd2lkdGg6IHBsYWNlaG9sZGVyU2l6ZSxcbiAgICAgICAgICAgIGhlaWdodDogcGxhY2Vob2xkZXJTaXplXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChmb3JjZU5hdHVyYWxTaXplIHx8IC8vIGlmIHVzZXItY3JlYXRlZCBib3VuZGluZyBib3ggaXMgYmVsb3cgdGhyZXNob2xkLCBhc3N1bWUgdGhlXG4gICAgICAvLyBpbnRlbnRpb24gd2FzIHRvIGNsaWNrIGluc3RlYWQgb2YgZHJhZywgYW5kIHVzZSB0aGUgaW1hZ2Unc1xuICAgICAgLy8gaW50cmluc2ljIHNpemVcbiAgICAgIGltYWdlRWxlbWVudC53aWR0aCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSAmJiBpbWFnZUVsZW1lbnQuaGVpZ2h0IDwgRFJBR0dJTkdfVEhSRVNIT0xEIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlKSB7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IE1hdGgubWF4KHRoaXMuc3RhdGUuaGVpZ2h0IC0gMTIwLCAxNjApOyAvLyBtYXggNjUlIG9mIGNhbnZhcyBoZWlnaHQsIGNsYW1wZWQgdG8gPDMwMHB4LCB2aCAtIDEyMHB4PlxuXG4gICAgICAgIGNvbnN0IG1heEhlaWdodCA9IE1hdGgubWluKG1pbkhlaWdodCwgTWF0aC5mbG9vcih0aGlzLnN0YXRlLmhlaWdodCAqIDAuNSkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUpO1xuICAgICAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1pbihpbWFnZS5uYXR1cmFsSGVpZ2h0LCBtYXhIZWlnaHQpO1xuICAgICAgICBjb25zdCB3aWR0aCA9IGhlaWdodCAqIChpbWFnZS5uYXR1cmFsV2lkdGggLyBpbWFnZS5uYXR1cmFsSGVpZ2h0KTsgLy8gYWRkIGN1cnJlbnQgaW1hZ2VFbGVtZW50IHdpZHRoL2hlaWdodCB0byBhY2NvdW50IGZvciBwcmV2aW91cyBjZW50ZXJpbmdcbiAgICAgICAgLy8gb2YgdGhlIHBsYWNlaG9sZGVyIGltYWdlXG5cbiAgICAgICAgY29uc3QgeCA9IGltYWdlRWxlbWVudC54ICsgaW1hZ2VFbGVtZW50LndpZHRoIC8gMiAtIHdpZHRoIC8gMjtcbiAgICAgICAgY29uc3QgeSA9IGltYWdlRWxlbWVudC55ICsgaW1hZ2VFbGVtZW50LmhlaWdodCAvIDIgLSBoZWlnaHQgLyAyO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeSxcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHRcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcbiAgICAvKiogdXBkYXRlcyBpbWFnZSBjYWNoZSwgcmVmcmVzaGluZyB1cGRhdGVkIGVsZW1lbnRzIGFuZC9vciBzZXR0aW5nIHN0YXR1c1xuICAgICAgICB0byBlcnJvciBmb3IgaW1hZ2VzIHRoYXQgZmFpbCBkdXJpbmcgPGltZz4gZWxlbWVudCBjcmVhdGlvbiAqL1xuXG5cbiAgICB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUgPSAoZWxlbWVudHMsIGZpbGVzID0gdGhpcy5maWxlcykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgY29uc3Qge1xuICAgICAgICB1cGRhdGVkRmlsZXMsXG4gICAgICAgIGVycm9yZWRGaWxlc1xuICAgICAgfSA9IHlpZWxkIF91cGRhdGVJbWFnZUNhY2hlKHtcbiAgICAgICAgaW1hZ2VDYWNoZTogdGhpcy5pbWFnZUNhY2hlLFxuICAgICAgICBmaWxlSWRzOiBlbGVtZW50cy5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgICAgIGZpbGVzXG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplIHx8IGVycm9yZWRGaWxlcy5zaXplKSB7XG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgIGlmICh1cGRhdGVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChlcnJvcmVkRmlsZXMuc2l6ZSkge1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChlbGVtZW50KSAmJiBlcnJvcmVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgc3RhdHVzOiBcImVycm9yXCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBlbGVtZW50O1xuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHVwZGF0ZWRGaWxlcyxcbiAgICAgICAgZXJyb3JlZEZpbGVzXG4gICAgICB9O1xuICAgIH0pO1xuICAgIC8qKiBhZGRzIG5ldyBpbWFnZXMgdG8gaW1hZ2VDYWNoZSBhbmQgcmUtcmVuZGVycyBpZiBuZWVkZWQgKi9cblxuXG4gICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUgPSAoaW1hZ2VFbGVtZW50cyA9IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSwgZmlsZXMgPSB0aGlzLmZpbGVzKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCB1bmNhY2hlZEltYWdlRWxlbWVudHMgPSBpbWFnZUVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+ICFlbGVtZW50LmlzRGVsZXRlZCAmJiAhdGhpcy5pbWFnZUNhY2hlLmhhcyhlbGVtZW50LmZpbGVJZCkpO1xuXG4gICAgICBpZiAodW5jYWNoZWRJbWFnZUVsZW1lbnRzLmxlbmd0aCkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgdXBkYXRlZEZpbGVzXG4gICAgICAgIH0gPSB5aWVsZCB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUodW5jYWNoZWRJbWFnZUVsZW1lbnRzLCBmaWxlcyk7XG5cbiAgICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplKSB7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgLyoqIGdlbmVyYWxseSB5b3Ugc2hvdWxkIHVzZSBgYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKClgIGRpcmVjdGx5IGlmIHlvdSBuZWVkXG4gICAgICogIHRvIHJlbmRlciBuZXcgaW1hZ2VzLiBUaGlzIGlzIGp1c3QgYSBmYWlsc2FmZSAgKi9cblxuXG4gICAgdGhpcy5zY2hlZHVsZUltYWdlUmVmcmVzaCA9IHRocm90dGxlKCgpID0+IHtcbiAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgfSwgSU1BR0VfUkVOREVSX1RJTUVPVVQpO1xuXG4gICAgdGhpcy51cGRhdGVCaW5kaW5nRW5hYmxlZE9uUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICBjb25zdCBzaG91bGRFbmFibGVCaW5kaW5nID0gc2hvdWxkRW5hYmxlQmluZGluZ0ZvclBvaW50ZXJFdmVudChldmVudCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQgIT09IHNob3VsZEVuYWJsZUJpbmRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogc2hvdWxkRW5hYmxlQmluZGluZ1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3IgPSBwb2ludGVyQ29vcmRzID0+IHtcbiAgICAgIGNvbnN0IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckNvb3JkcywgdGhpcy5zY2VuZSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgIT0gbnVsbCA/IFtob3ZlcmVkQmluZGFibGVFbGVtZW50XSA6IFtdXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyA9IChsaW5lYXJFbGVtZW50LFxuICAgIC8qKiBzY2VuZSBjb29yZHMgKi9cbiAgICBwb2ludGVyQ29vcmRzLCAvLyBEdXJpbmcgbGluZSBjcmVhdGlvbiB0aGUgc3RhcnQgYmluZGluZyBoYXNuJ3QgYmVlbiB3cml0dGVuIHlldFxuICAgIC8vIGludG8gYGxpbmVhckVsZW1lbnRgXG4gICAgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50KSA9PiB7XG4gICAgICBpZiAoIXBvaW50ZXJDb29yZHMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3VnZ2VzdGVkQmluZGluZ3MgPSBwb2ludGVyQ29vcmRzLnJlZHVjZSgoYWNjLCBjb29yZHMpID0+IHtcbiAgICAgICAgY29uc3QgaG92ZXJlZEJpbmRhYmxlRWxlbWVudCA9IGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZyhjb29yZHMsIHRoaXMuc2NlbmUpO1xuXG4gICAgICAgIGlmIChob3ZlcmVkQmluZGFibGVFbGVtZW50ICE9IG51bGwgJiYgIWlzTGluZWFyRWxlbWVudFNpbXBsZUFuZEFscmVhZHlCb3VuZChsaW5lYXJFbGVtZW50LCBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQgPT09IG51bGwgfHwgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQuaWQsIGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQpKSB7XG4gICAgICAgICAgYWNjLnB1c2goaG92ZXJlZEJpbmRhYmxlRWxlbWVudCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwgW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVJbnRlcmFjdGl2ZUNhbnZhc1JlZiA9IGNhbnZhcyA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYzsgLy8gY2FudmFzIGlzIG51bGwgd2hlbiB1bm1vdW50aW5nXG5cblxuICAgICAgaWYgKGNhbnZhcyAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzID0gY2FudmFzOyAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAvLyBOT1RFIHdoZWVsLCB0b3VjaHN0YXJ0LCB0b3VjaGVuZCBldmVudHMgbXVzdCBiZSByZWdpc3RlcmVkIG91dHNpZGVcbiAgICAgICAgLy8gb2YgcmVhY3QgYmVjYXVzZSByZWFjdCBiaW5kcyB0aGVtIHRoZW0gcGFzc2l2ZWx5IChzbyB3ZSBjYW4ndCBwcmV2ZW50XG4gICAgICAgIC8vIGRlZmF1bHQgb24gdGhlbSlcblxuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuV0hFRUwsIHRoaXMuaGFuZGxlV2hlZWwpO1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlRPVUNIX0VORCwgdGhpcy5vblRvdWNoRW5kKTsgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIChfYSA9IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLmhhbmRsZVdoZWVsKTtcbiAgICAgICAgKF9iID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgKF9jID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfRU5ELCB0aGlzLm9uVG91Y2hFbmQpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUFwcE9uRHJvcCA9IGV2ZW50ID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfbCwgX20sIF9vLCBfcDsgLy8gbXVzdCBiZSByZXRyaWV2ZWQgZmlyc3QsIGluIHRoZSBzYW1lIGZyYW1lXG5cblxuICAgICAgY29uc3Qge1xuICAgICAgICBmaWxlLFxuICAgICAgICBmaWxlSGFuZGxlXG4gICAgICB9ID0geWllbGQgZ2V0RmlsZUZyb21FdmVudChldmVudCk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKGlzU3VwcG9ydGVkSW1hZ2VGaWxlKGZpbGUpKSB7XG4gICAgICAgICAgLy8gZmlyc3QgYXR0ZW1wdCB0byBkZWNvZGUgc2NlbmUgZnJvbSB0aGUgaW1hZ2UgaWYgaXQncyBlbWJlZGRlZFxuICAgICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAgIGlmICgoZmlsZSA9PT0gbnVsbCB8fCBmaWxlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBmaWxlLnR5cGUpID09PSBNSU1FX1RZUEVTLnBuZyB8fCAoZmlsZSA9PT0gbnVsbCB8fCBmaWxlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBmaWxlLnR5cGUpID09PSBNSU1FX1RZUEVTLnN2Zykge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3Qgc2NlbmUgPSB5aWVsZCBsb2FkRnJvbUJsb2IoZmlsZSwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZmlsZUhhbmRsZSk7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lKSwge1xuICAgICAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlIHx8IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgcmVwbGFjZUZpbGVzOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgIGlmIChlcnJvci5uYW1lICE9PSBcIkVuY29kaW5nRXJyb3JcIikge1xuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBpZiBubyBzY2VuZSBpcyBlbWJlZGRlZCBvciB3ZSBmYWlsIGZvciB3aGF0ZXZlciByZWFzb24sIGZhbGwgYmFja1xuICAgICAgICAgIC8vIHRvIGltcG9ydGluZyBhcyByZWd1bGFyIGltYWdlXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuICAgICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50KHtcbiAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgIHNjZW5lWVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgZmlsZSk7XG4gICAgICAgICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zKGltYWdlRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgICAgW2ltYWdlRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGxpYnJhcnlKU09OID0gZXZlbnQuZGF0YVRyYW5zZmVyLmdldERhdGEoTUlNRV9UWVBFUy5leGNhbGlkcmF3bGliKTtcblxuICAgICAgaWYgKGxpYnJhcnlKU09OICYmIHR5cGVvZiBsaWJyYXJ5SlNPTiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGxpYnJhcnlJdGVtcyA9IHBhcnNlTGlicmFyeUpTT04obGlicmFyeUpTT04pO1xuICAgICAgICAgIHRoaXMuYWRkRWxlbWVudHNGcm9tUGFzdGVPckxpYnJhcnkoe1xuICAgICAgICAgICAgZWxlbWVudHM6IGRpc3RyaWJ1dGVMaWJyYXJ5SXRlbXNPblNxdWFyZUdyaWQobGlicmFyeUl0ZW1zKSxcbiAgICAgICAgICAgIHBvc2l0aW9uOiBldmVudCxcbiAgICAgICAgICAgIGZpbGVzOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGZpbGUpIHtcbiAgICAgICAgLy8gYXRldG1wdCB0byBwYXJzZSBhbiBleGNhbGlkcmF3L2V4Y2FsaWRyYXdsaWIgZmlsZVxuICAgICAgICB5aWVsZCB0aGlzLmxvYWRGaWxlVG9DYW52YXMoZmlsZSwgZmlsZUhhbmRsZSk7XG4gICAgICB9XG5cbiAgICAgIGlmICgoX20gPSAoX2wgPSBldmVudC5kYXRhVHJhbnNmZXIpID09PSBudWxsIHx8IF9sID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfbC50eXBlcykgPT09IG51bGwgfHwgX20gPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9tLmluY2x1ZGVzKFwidGV4dC9wbGFpblwiKSkge1xuICAgICAgICBjb25zdCB0ZXh0ID0gKF9vID0gZXZlbnQuZGF0YVRyYW5zZmVyKSA9PT0gbnVsbCB8fCBfbyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX28uZ2V0RGF0YShcInRleHRcIik7XG5cbiAgICAgICAgaWYgKHRleHQgJiYgZW1iZWRkYWJsZVVSTFZhbGlkYXRvcih0ZXh0LCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSkgJiYgKC9eKGh0dHB8aHR0cHMpOlxcL1xcL1teXFxzLyQuPyNdLlteXFxzXSokLy50ZXN0KHRleHQpIHx8ICgoX3AgPSBnZXRFbWJlZExpbmsodGV4dCkpID09PSBudWxsIHx8IF9wID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfcC50eXBlKSA9PT0gXCJ2aWRlb1wiKSkge1xuICAgICAgICAgIGNvbnN0IGVtYmVkZGFibGUgPSB0aGlzLmluc2VydEVtYmVkZGFibGVFbGVtZW50KHtcbiAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgIHNjZW5lWSxcbiAgICAgICAgICAgIGxpbms6IG5vcm1hbGl6ZUxpbmsodGV4dClcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmIChlbWJlZGRhYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgW2VtYmVkZGFibGUuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5sb2FkRmlsZVRvQ2FudmFzID0gKGZpbGUsIGZpbGVIYW5kbGUpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGZpbGUgPSB5aWVsZCBub3JtYWxpemVGaWxlKGZpbGUpO1xuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXQgPSB5aWVsZCBsb2FkU2NlbmVPckxpYnJhcnlGcm9tQmxvYihmaWxlLCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBmaWxlSGFuZGxlKTtcblxuICAgICAgICBpZiAocmV0LnR5cGUgPT09IE1JTUVfVFlQRVMuZXhjYWxpZHJhdykge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcmV0LmRhdGEpLCB7XG4gICAgICAgICAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCByZXQuZGF0YS5hcHBTdGF0ZSB8fCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHJlcGxhY2VGaWxlczogdHJ1ZSxcbiAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfSBlbHNlIGlmIChyZXQudHlwZSA9PT0gTUlNRV9UWVBFUy5leGNhbGlkcmF3bGliKSB7XG4gICAgICAgICAgeWllbGQgdGhpcy5saWJyYXJ5LnVwZGF0ZUxpYnJhcnkoe1xuICAgICAgICAgICAgbGlicmFyeUl0ZW1zOiBmaWxlLFxuICAgICAgICAgICAgbWVyZ2U6IHRydWUsXG4gICAgICAgICAgICBvcGVuTGlicmFyeU1lbnU6IHRydWVcbiAgICAgICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IHQoXCJlcnJvcnMuaW1wb3J0TGlicmFyeUVycm9yXCIpXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51ID0gZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKChcInBvaW50ZXJUeXBlXCIgaW4gZXZlbnQubmF0aXZlRXZlbnQgJiYgZXZlbnQubmF0aXZlRXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIiB8fCBcInBvaW50ZXJUeXBlXCIgaW4gZXZlbnQubmF0aXZlRXZlbnQgJiYgZXZlbnQubmF0aXZlRXZlbnQucG9pbnRlclR5cGUgPT09IFwicGVuXCIgJiYgLy8gYWx3YXlzIGFsbG93IGlmIHVzZXIgdXNlcyBhIHBlbiBzZWNvbmRhcnkgYnV0dG9uXG4gICAgICBldmVudC5idXR0b24gIT09IFBPSU5URVJfQlVUVE9OLlNFQ09OREFSWSkgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oeCwgeSwge1xuICAgICAgICBwcmVmZXJTZWxlY3RlZDogdHJ1ZSxcbiAgICAgICAgaW5jbHVkZUxvY2tlZEVsZW1lbnRzOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBpc0hpdHRpZ25Db21tb25Cb3VuZEJveCA9IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICB4LFxuICAgICAgICB5XG4gICAgICB9LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgIGNvbnN0IHR5cGUgPSBlbGVtZW50IHx8IGlzSGl0dGlnbkNvbW1vbkJvdW5kQm94ID8gXCJlbGVtZW50XCIgOiBcImNhbnZhc1wiO1xuICAgICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHRvcDogb2Zmc2V0VG9wLFxuICAgICAgICBsZWZ0OiBvZmZzZXRMZWZ0XG4gICAgICB9ID0gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgY29uc3QgbGVmdCA9IGV2ZW50LmNsaWVudFggLSBvZmZzZXRMZWZ0O1xuICAgICAgY29uc3QgdG9wID0gZXZlbnQuY2xpZW50WSAtIG9mZnNldFRvcDtcbiAgICAgIHRyYWNrRXZlbnQoXCJjb250ZXh0TWVudVwiLCBcIm9wZW5Db250ZXh0TWVudVwiLCB0eXBlKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBlbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXSA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIGVkaXRpbmdHcm91cElkOiB0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICBbZWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgfVxuICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogaXNMaW5lYXJFbGVtZW50KGVsZW1lbnQpID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZWxlbWVudCwgdGhpcy5zY2VuZSkgOiBudWxsXG4gICAgICB9KSA6IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZmFsc2VcbiAgICAgIH0pLCAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiB7XG4gICAgICAgICAgICB0b3AsXG4gICAgICAgICAgICBsZWZ0LFxuICAgICAgICAgICAgaXRlbXM6IHRoaXMuZ2V0Q29udGV4dE1lbnVJdGVtcyh0eXBlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudCA9IChwb2ludGVyRG93blN0YXRlLCBldmVudCkgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZTtcblxuICAgICAgY29uc3QgZHJhZ2dpbmdFbGVtZW50ID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQ7XG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzO1xuXG4gICAgICBpZiAoIWRyYWdnaW5nRWxlbWVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJlcmFzZXJcIikge1xuICAgICAgICBkcmFnTmV3RWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckNvb3Jkcy54KSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgcG9pbnRlckNvb3Jkcy55KSwgc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCksIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIoZXZlbnQpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgIGNvbnN0IGltYWdlID0gaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpICYmICgoX2EgPSB0aGlzLmltYWdlQ2FjaGUuZ2V0KGRyYWdnaW5nRWxlbWVudC5maWxlSWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaW1hZ2UpO1xuICAgICAgICBjb25zdCBhc3BlY3RSYXRpbyA9IGltYWdlICYmICEoaW1hZ2UgaW5zdGFuY2VvZiBQcm9taXNlKSA/IGltYWdlLndpZHRoIC8gaW1hZ2UuaGVpZ2h0IDogbnVsbDtcbiAgICAgICAgdGhpcy5tYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgW2RyYWdnaW5nRWxlbWVudF0pO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgc25hcE9mZnNldCxcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSA9IHNuYXBOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZSwgZXZlbnQsIHtcbiAgICAgICAgICB4OiBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54ICsgKChfYyA9IChfYiA9IHRoaXMuc3RhdGUub3JpZ2luU25hcE9mZnNldCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLngpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IDApLFxuICAgICAgICAgIHk6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnkgKyAoKF9lID0gKF9kID0gdGhpcy5zdGF0ZS5vcmlnaW5TbmFwT2Zmc2V0KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QueSkgIT09IG51bGwgJiYgX2UgIT09IHZvaWQgMCA/IF9lIDogMClcbiAgICAgICAgfSwge1xuICAgICAgICAgIHg6IGdyaWRYIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCxcbiAgICAgICAgICB5OiBncmlkWSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnlcbiAgICAgICAgfSk7XG4gICAgICAgIGdyaWRYICs9IHNuYXBPZmZzZXQueDtcbiAgICAgICAgZ3JpZFkgKz0gc25hcE9mZnNldC55O1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSk7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnksIGdyaWRYLCBncmlkWSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCwgZ3JpZFgpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55LCBncmlkWSksIGlzSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgPyAhc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCkgOiBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCksIGFzcGVjdFJhdGlvLCB0aGlzLnN0YXRlLm9yaWdpblNuYXBPZmZzZXQpO1xuICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoW2RyYWdnaW5nRWxlbWVudF0pOyAvLyBoaWdobGlnaHQgZWxlbWVudHMgdGhhdCBhcmUgdG8gYmUgYWRkZWQgdG8gZnJhbWVzIG9uIGZyYW1lcyBjcmVhdGlvblxuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZUhhbmRsZVJlc2l6ZSA9IChwb2ludGVyRG93blN0YXRlLCBldmVudCkgPT4ge1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRnJhbWVzID0gc2VsZWN0ZWRFbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG4gICAgICBjb25zdCB0cmFuc2Zvcm1IYW5kbGVUeXBlID0gcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZTtcblxuICAgICAgaWYgKHNlbGVjdGVkRnJhbWVzLmxlbmd0aCA+IDAgJiYgdHJhbnNmb3JtSGFuZGxlVHlwZSA9PT0gXCJyb3RhdGlvblwiKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIC8vIFRPRE86IHJlbmFtZSB0aGlzIHN0YXRlIGZpZWxkIHRvIFwiaXNTY2FsaW5nXCIgdG8gZGlzdGluZ3Vpc2hcbiAgICAgICAgLy8gaXQgZnJvbSB0aGUgZ2VuZXJpYyBcImlzUmVzaXppbmdcIiB3aGljaCBpbmNsdWRlcyBzY2FsaW5nIGFuZFxuICAgICAgICAvLyByb3RhdGluZ1xuICAgICAgICBpc1Jlc2l6aW5nOiB0cmFuc2Zvcm1IYW5kbGVUeXBlICYmIHRyYW5zZm9ybUhhbmRsZVR5cGUgIT09IFwicm90YXRpb25cIixcbiAgICAgICAgaXNSb3RhdGluZzogdHJhbnNmb3JtSGFuZGxlVHlwZSA9PT0gXCJyb3RhdGlvblwiLFxuICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHM7XG4gICAgICBsZXQgW3Jlc2l6ZVgsIHJlc2l6ZVldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCAtIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldC54LCBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5vZmZzZXQueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcCA9IG5ldyBNYXAoKTtcbiAgICAgIHNlbGVjdGVkRnJhbWVzLmZvckVhY2goZnJhbWUgPT4ge1xuICAgICAgICBjb25zdCBlbGVtZW50c0luRnJhbWUgPSBnZXRGcmFtZUVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLmlkKTtcbiAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgZnJhbWVFbGVtZW50c09mZnNldHNNYXAuc2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCwge1xuICAgICAgICAgICAgeDogZWxlbWVudC54IC0gZnJhbWUueCxcbiAgICAgICAgICAgIHk6IGVsZW1lbnQueSAtIGZyYW1lLnlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTsgLy8gY2hlY2sgbmVlZGVkIGZvciBhdm9pZGluZyBmbGlja2VyaW5nIHdoZW4gYSBrZXkgZ2V0cyBwcmVzc2VkXG4gICAgICAvLyBkdXJpbmcgZHJhZ2dpbmdcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQpIHtcbiAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCBkcmFnT2Zmc2V0ID0ge1xuICAgICAgICAgIHg6IGdyaWRYIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCxcbiAgICAgICAgICB5OiBncmlkWSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3Qgb3JpZ2luYWxFbGVtZW50cyA9IFsuLi5wb2ludGVyRG93blN0YXRlLm9yaWdpbmFsRWxlbWVudHMudmFsdWVzKCldO1xuICAgICAgICB0aGlzLm1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHNuYXBPZmZzZXQsXG4gICAgICAgICAgc25hcExpbmVzXG4gICAgICAgIH0gPSBzbmFwUmVzaXppbmdFbGVtZW50cyhzZWxlY3RlZEVsZW1lbnRzLCBnZXRTZWxlY3RlZEVsZW1lbnRzKG9yaWdpbmFsRWxlbWVudHMsIHRoaXMuc3RhdGUpLCB0aGlzLnN0YXRlLCBldmVudCwgZHJhZ09mZnNldCwgdHJhbnNmb3JtSGFuZGxlVHlwZSk7XG4gICAgICAgIHJlc2l6ZVggKz0gc25hcE9mZnNldC54O1xuICAgICAgICByZXNpemVZICs9IHNuYXBPZmZzZXQueTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAodHJhbnNmb3JtRWxlbWVudHMocG9pbnRlckRvd25TdGF0ZSwgdHJhbnNmb3JtSGFuZGxlVHlwZSwgc2VsZWN0ZWRFbGVtZW50cywgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuYXJyb3dEaXJlY3Rpb24sIHNob3VsZFJvdGF0ZVdpdGhEaXNjcmV0ZUFuZ2xlKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCksIHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmIGlzSW1hZ2VFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pID8gIXNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpIDogc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCksIHJlc2l6ZVgsIHJlc2l6ZVksIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmNlbnRlci54LCBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5jZW50ZXIueSwgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICBjb25zdCBlbGVtZW50c1RvSGlnaGxpZ2h0ID0gbmV3IFNldCgpO1xuICAgICAgICBzZWxlY3RlZEZyYW1lcy5mb3JFYWNoKGZyYW1lID0+IHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50c0luRnJhbWUgPSBnZXRGcmFtZUVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLmlkKTsgLy8ga2VlcCBlbGVtZW50cycgcG9zaXRpb25zIHJlbGF0aXZlIHRvIHRoZWlyIGZyYW1lcyBvbiBmcmFtZXMgcmVzaXppbmdcblxuICAgICAgICAgIGlmICh0cmFuc2Zvcm1IYW5kbGVUeXBlKSB7XG4gICAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZS5pbmNsdWRlcyhcIndcIikpIHtcbiAgICAgICAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgeDogZnJhbWUueCArICgoKF9hID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS54KSB8fCAwKSxcbiAgICAgICAgICAgICAgICAgIHk6IGZyYW1lLnkgKyAoKChfYiA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IueSkgfHwgMClcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0cmFuc2Zvcm1IYW5kbGVUeXBlLmluY2x1ZGVzKFwiblwiKSkge1xuICAgICAgICAgICAgICBlbGVtZW50c0luRnJhbWUuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICB4OiBmcmFtZS54ICsgKCgoX2EgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLngpIHx8IDApLFxuICAgICAgICAgICAgICAgICAgeTogZnJhbWUueSArICgoKF9iID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi55KSB8fCAwKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBmcmFtZSwgdGhpcy5zdGF0ZSkuZm9yRWFjaChlbGVtZW50ID0+IGVsZW1lbnRzVG9IaWdobGlnaHQuYWRkKGVsZW1lbnQpKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVsZW1lbnRzVG9IaWdobGlnaHQ6IFsuLi5lbGVtZW50c1RvSGlnaGxpZ2h0XVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgdGhpcy5nZXRDb250ZXh0TWVudUl0ZW1zID0gdHlwZSA9PiB7XG4gICAgICBjb25zdCBvcHRpb25zID0gW107XG4gICAgICBvcHRpb25zLnB1c2goYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcpOyAvLyBjYW52YXMgY29udGV4dE1lbnVcbiAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAgICAgaWYgKHR5cGUgPT09IFwiY2FudmFzXCIpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgcmV0dXJuIFsuLi5vcHRpb25zLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVG9nZ2xlVmlld01vZGUsIGFjdGlvblRvZ2dsZVN0YXRzXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbYWN0aW9uUGFzdGUsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkNvcHlBc1BuZywgYWN0aW9uQ29weUFzU3ZnLCBjb3B5VGV4dCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uU2VsZWN0QWxsLCBhY3Rpb25VbmxvY2tBbGxFbGVtZW50cywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uVG9nZ2xlR3JpZE1vZGUsIGFjdGlvblRvZ2dsZU9iamVjdHNTbmFwTW9kZSwgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVG9nZ2xlVmlld01vZGUsIGFjdGlvblRvZ2dsZVN0YXRzXTtcbiAgICAgIH0gLy8gZWxlbWVudCBjb250ZXh0TWVudVxuICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbiAgICAgIG9wdGlvbnMucHVzaChjb3B5VGV4dCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICByZXR1cm4gW2FjdGlvbkNvcHksIC4uLm9wdGlvbnNdO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gW2FjdGlvbkN1dCwgYWN0aW9uQ29weSwgYWN0aW9uUGFzdGUsIGFjdGlvblNlbGVjdEFsbEVsZW1lbnRzSW5GcmFtZSwgYWN0aW9uUmVtb3ZlQWxsRWxlbWVudHNGcm9tRnJhbWUsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIC4uLm9wdGlvbnMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkNvcHlTdHlsZXMsIGFjdGlvblBhc3RlU3R5bGVzLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Hcm91cCwgYWN0aW9uVW5iaW5kVGV4dCwgYWN0aW9uQmluZFRleHQsIGFjdGlvbldyYXBUZXh0SW5Db250YWluZXIsIGFjdGlvblVuZ3JvdXAsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkFkZFRvTGlicmFyeSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uU2VuZEJhY2t3YXJkLCBhY3Rpb25CcmluZ0ZvcndhcmQsIGFjdGlvblNlbmRUb0JhY2ssIGFjdGlvbkJyaW5nVG9Gcm9udCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uRmxpcEhvcml6b250YWwsIGFjdGlvbkZsaXBWZXJ0aWNhbCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uVG9nZ2xlTGluZWFyRWRpdG9yLCBhY3Rpb25MaW5rLCBhY3Rpb25EdXBsaWNhdGVTZWxlY3Rpb24sIGFjdGlvblRvZ2dsZUVsZW1lbnRMb2NrLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25EZWxldGVTZWxlY3RlZF07XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlV2hlZWwgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKGlzUGFubmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZGVsdGFYLFxuICAgICAgICBkZWx0YVlcbiAgICAgIH0gPSBldmVudDsgLy8gbm90ZSB0aGF0IGV2ZW50LmN0cmxLZXkgaXMgbmVjZXNzYXJ5IHRvIGhhbmRsZSBwaW5jaCB6b29taW5nXG5cbiAgICAgIGlmIChldmVudC5tZXRhS2V5IHx8IGV2ZW50LmN0cmxLZXkpIHtcbiAgICAgICAgY29uc3Qgc2lnbiA9IE1hdGguc2lnbihkZWx0YVkpO1xuICAgICAgICBjb25zdCBNQVhfU1RFUCA9IFpPT01fU1RFUCAqIDEwMDtcbiAgICAgICAgY29uc3QgYWJzRGVsdGEgPSBNYXRoLmFicyhkZWx0YVkpO1xuICAgICAgICBsZXQgZGVsdGEgPSBkZWx0YVk7XG5cbiAgICAgICAgaWYgKGFic0RlbHRhID4gTUFYX1NURVApIHtcbiAgICAgICAgICBkZWx0YSA9IE1BWF9TVEVQICogc2lnbjtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBuZXdab29tID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlIC0gZGVsdGEgLyAxMDA7IC8vIGluY3JlYXNlIHpvb20gc3RlcHMgdGhlIG1vcmUgem9vbWVkLWluIHdlIGFyZSAoYXBwbGllcyB0byA+MTAwJSBvbmx5KVxuXG4gICAgICAgIG5ld1pvb20gKz0gTWF0aC5sb2cxMChNYXRoLm1heCgxLCB0aGlzLnN0YXRlLnpvb20udmFsdWUpKSAqIC1zaWduICogLy8gcmVkdWNlZCBhbXBsaWZpY2F0aW9uIGZvciBzbWFsbCBkZWx0YXMgKHNtYWxsIG1vdmVtZW50cyBvbiBhIHRyYWNrcGFkKVxuICAgICAgICBNYXRoLm1pbigxLCBhYnNEZWx0YSAvIDIwKTtcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICAgIHZpZXdwb3J0WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgICAgIHZpZXdwb3J0WTogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55LFxuICAgICAgICAgIG5leHRab29tOiBnZXROb3JtYWxpemVkWm9vbShuZXdab29tKVxuICAgICAgICB9LCBzdGF0ZSkpLCB7XG4gICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgIH0pKTtcbiAgICAgICAgdGhpcy5yZXNldFNob3VsZENhY2hlSWdub3JlWm9vbURlYm91bmNlZCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHNjcm9sbCBob3Jpem9udGFsbHkgd2hlbiBzaGlmdCBwcmVzc2VkXG5cblxuICAgICAgaWYgKGV2ZW50LnNoaWZ0S2V5KSB7XG4gICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKCh7XG4gICAgICAgICAgem9vbSxcbiAgICAgICAgICBzY3JvbGxYXG4gICAgICAgIH0pID0+ICh7XG4gICAgICAgICAgLy8gb24gTWFjLCBzaGlmdCt3aGVlbCB0ZW5kcyB0byByZXN1bHQgaW4gZGVsdGFYXG4gICAgICAgICAgc2Nyb2xsWDogc2Nyb2xsWCAtIChkZWx0YVkgfHwgZGVsdGFYKSAvIHpvb20udmFsdWVcbiAgICAgICAgfSkpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKCh7XG4gICAgICAgIHpvb20sXG4gICAgICAgIHNjcm9sbFgsXG4gICAgICAgIHNjcm9sbFlcbiAgICAgIH0pID0+ICh7XG4gICAgICAgIHNjcm9sbFg6IHNjcm9sbFggLSBkZWx0YVggLyB6b29tLnZhbHVlLFxuICAgICAgICBzY3JvbGxZOiBzY3JvbGxZIC0gZGVsdGFZIC8gem9vbS52YWx1ZVxuICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5zYXZlUG9pbnRlciA9ICh4LCB5LCBidXR0b24pID0+IHtcbiAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgIGlmICgheCB8fCAheSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiB4LFxuICAgICAgICBjbGllbnRZOiB5XG4gICAgICB9LCB0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKGlzTmFOKHBvaW50ZXIueCkgfHwgaXNOYU4ocG9pbnRlci55KSkgey8vIHNvbWV0aW1lcyB0aGUgcG9pbnRlciBnb2VzIG9mZiBzY3JlZW5cbiAgICAgIH1cblxuICAgICAgKF9iID0gKF9hID0gdGhpcy5wcm9wcykub25Qb2ludGVyVXBkYXRlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwge1xuICAgICAgICBwb2ludGVyLFxuICAgICAgICBidXR0b24sXG4gICAgICAgIHBvaW50ZXJzTWFwOiBnZXN0dXJlLnBvaW50ZXJzXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldFNob3VsZENhY2hlSWdub3JlWm9vbURlYm91bmNlZCA9IGRlYm91bmNlKCgpID0+IHtcbiAgICAgIGlmICghdGhpcy51bm1vdW50ZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LCAzMDApO1xuXG4gICAgdGhpcy51cGRhdGVET01SZWN0ID0gY2IgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBpZiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkge1xuICAgICAgICBjb25zdCBleGNhbGlkcmF3Q29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgbGVmdDogb2Zmc2V0TGVmdCxcbiAgICAgICAgICB0b3A6IG9mZnNldFRvcFxuICAgICAgICB9ID0gZXhjYWxpZHJhd0NvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHdpZHRoOiBjdXJyZW50V2lkdGgsXG4gICAgICAgICAgaGVpZ2h0OiBjdXJyZW50SGVpZ2h0LFxuICAgICAgICAgIG9mZnNldFRvcDogY3VycmVudE9mZnNldFRvcCxcbiAgICAgICAgICBvZmZzZXRMZWZ0OiBjdXJyZW50T2Zmc2V0TGVmdFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBpZiAod2lkdGggPT09IGN1cnJlbnRXaWR0aCAmJiBoZWlnaHQgPT09IGN1cnJlbnRIZWlnaHQgJiYgb2Zmc2V0TGVmdCA9PT0gY3VycmVudE9mZnNldExlZnQgJiYgb2Zmc2V0VG9wID09PSBjdXJyZW50T2Zmc2V0VG9wKSB7XG4gICAgICAgICAgaWYgKGNiKSB7XG4gICAgICAgICAgICBjYigpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHdpZHRoLFxuICAgICAgICAgIGhlaWdodCxcbiAgICAgICAgICBvZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcFxuICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgY2IgJiYgY2IoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMucmVmcmVzaCA9ICgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5nZXRDYW52YXNPZmZzZXRzKCkpKTtcbiAgICB9O1xuXG4gICAgY29uc3QgZGVmYXVsdEFwcFN0YXRlID0gZ2V0RGVmYXVsdEFwcFN0YXRlKCk7XG4gICAgY29uc3Qge1xuICAgICAgZXhjYWxpZHJhd1JlZixcbiAgICAgIHZpZXdNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgemVuTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIGdyaWRNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgb2JqZWN0c1NuYXBNb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgdGhlbWUgPSBkZWZhdWx0QXBwU3RhdGUudGhlbWUsXG4gICAgICBuYW1lID0gZGVmYXVsdEFwcFN0YXRlLm5hbWVcbiAgICB9ID0gcHJvcHM7XG4gICAgdGhpcy5zdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGRlZmF1bHRBcHBTdGF0ZSksIHtcbiAgICAgIHRoZW1lLFxuICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgfSksIHRoaXMuZ2V0Q2FudmFzT2Zmc2V0cygpKSwge1xuICAgICAgdmlld01vZGVFbmFibGVkLFxuICAgICAgemVuTW9kZUVuYWJsZWQsXG4gICAgICBvYmplY3RzU25hcE1vZGVFbmFibGVkLFxuICAgICAgZ3JpZFNpemU6IGdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGwsXG4gICAgICBuYW1lLFxuICAgICAgd2lkdGg6IHdpbmRvdy5pbm5lcldpZHRoLFxuICAgICAgaGVpZ2h0OiB3aW5kb3cuaW5uZXJIZWlnaHRcbiAgICB9KTtcbiAgICB0aGlzLmlkID0gbmFub2lkKCk7XG4gICAgdGhpcy5saWJyYXJ5ID0gbmV3IExpYnJhcnkodGhpcyk7XG4gICAgdGhpcy5zY2VuZSA9IG5ldyBTY2VuZSgpO1xuICAgIHRoaXMuY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgICB0aGlzLnJjID0gcm91Z2guY2FudmFzKHRoaXMuY2FudmFzKTtcbiAgICB0aGlzLnJlbmRlcmVyID0gbmV3IFJlbmRlcmVyKHRoaXMuc2NlbmUpO1xuXG4gICAgaWYgKGV4Y2FsaWRyYXdSZWYpIHtcbiAgICAgIGNvbnN0IHJlYWR5UHJvbWlzZSA9IFwiY3VycmVudFwiIGluIGV4Y2FsaWRyYXdSZWYgJiYgKChfYSA9IGV4Y2FsaWRyYXdSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnJlYWR5UHJvbWlzZSkgfHwgcmVzb2x2YWJsZVByb21pc2UoKTtcbiAgICAgIGNvbnN0IGFwaSA9IHtcbiAgICAgICAgcmVhZHk6IHRydWUsXG4gICAgICAgIHJlYWR5UHJvbWlzZSxcbiAgICAgICAgdXBkYXRlU2NlbmU6IHRoaXMudXBkYXRlU2NlbmUsXG4gICAgICAgIHVwZGF0ZUxpYnJhcnk6IHRoaXMubGlicmFyeS51cGRhdGVMaWJyYXJ5LFxuICAgICAgICBhZGRGaWxlczogdGhpcy5hZGRGaWxlcyxcbiAgICAgICAgcmVzZXRTY2VuZTogdGhpcy5yZXNldFNjZW5lLFxuICAgICAgICBnZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZDogdGhpcy5nZXRTY2VuZUVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCxcbiAgICAgICAgaGlzdG9yeToge1xuICAgICAgICAgIGNsZWFyOiB0aGlzLnJlc2V0SGlzdG9yeVxuICAgICAgICB9LFxuICAgICAgICBzY3JvbGxUb0NvbnRlbnQ6IHRoaXMuc2Nyb2xsVG9Db250ZW50LFxuICAgICAgICBnZXRTY2VuZUVsZW1lbnRzOiB0aGlzLmdldFNjZW5lRWxlbWVudHMsXG4gICAgICAgIGdldEFwcFN0YXRlOiAoKSA9PiB0aGlzLnN0YXRlLFxuICAgICAgICBnZXRGaWxlczogKCkgPT4gdGhpcy5maWxlcyxcbiAgICAgICAgcmVmcmVzaDogdGhpcy5yZWZyZXNoLFxuICAgICAgICBzZXRUb2FzdDogdGhpcy5zZXRUb2FzdCxcbiAgICAgICAgaWQ6IHRoaXMuaWQsXG4gICAgICAgIHNldEFjdGl2ZVRvb2w6IHRoaXMuc2V0QWN0aXZlVG9vbCxcbiAgICAgICAgc2V0Q3Vyc29yOiB0aGlzLnNldEN1cnNvcixcbiAgICAgICAgcmVzZXRDdXJzb3I6IHRoaXMucmVzZXRDdXJzb3IsXG4gICAgICAgIHVwZGF0ZUZyYW1lUmVuZGVyaW5nOiB0aGlzLnVwZGF0ZUZyYW1lUmVuZGVyaW5nLFxuICAgICAgICB0b2dnbGVTaWRlYmFyOiB0aGlzLnRvZ2dsZVNpZGViYXIsXG4gICAgICAgIGFwcDogdGhpcyxcbiAgICAgICAgb25DaGFuZ2U6IGNiID0+IHRoaXMub25DaGFuZ2VFbWl0dGVyLm9uKGNiKSxcbiAgICAgICAgb25Qb2ludGVyRG93bjogY2IgPT4gdGhpcy5vblBvaW50ZXJEb3duRW1pdHRlci5vbihjYiksXG4gICAgICAgIG9uUG9pbnRlclVwOiBjYiA9PiB0aGlzLm9uUG9pbnRlclVwRW1pdHRlci5vbihjYilcbiAgICAgIH07XG5cbiAgICAgIGlmICh0eXBlb2YgZXhjYWxpZHJhd1JlZiA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgIGV4Y2FsaWRyYXdSZWYoYXBpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGV4Y2FsaWRyYXdSZWYuY3VycmVudCA9IGFwaTtcbiAgICAgIH1cblxuICAgICAgcmVhZHlQcm9taXNlLnJlc29sdmUoYXBpKTtcbiAgICB9XG5cbiAgICB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJWYWx1ZSA9IHtcbiAgICAgIGNvbnRhaW5lcjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQsXG4gICAgICBpZDogdGhpcy5pZFxuICAgIH07XG4gICAgdGhpcy5mb250cyA9IG5ldyBGb250cyh7XG4gICAgICBzY2VuZTogdGhpcy5zY2VuZSxcbiAgICAgIG9uU2NlbmVVcGRhdGVkOiB0aGlzLm9uU2NlbmVVcGRhdGVkXG4gICAgfSk7XG4gICAgdGhpcy5oaXN0b3J5ID0gbmV3IEhpc3RvcnkoKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIgPSBuZXcgQWN0aW9uTWFuYWdlcih0aGlzLnN5bmNBY3Rpb25SZXN1bHQsICgpID0+IHRoaXMuc3RhdGUsICgpID0+IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMpO1xuICAgIHRoaXMuYWN0aW9uTWFuYWdlci5yZWdpc3RlckFsbChhY3Rpb25zKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBY3Rpb24oY3JlYXRlVW5kb0FjdGlvbih0aGlzLmhpc3RvcnkpKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBY3Rpb24oY3JlYXRlUmVkb0FjdGlvbih0aGlzLmhpc3RvcnkpKTtcbiAgfVxuXG4gIG9uV2luZG93TWVzc2FnZShldmVudCkge1xuICAgIGlmIChldmVudC5vcmlnaW4gIT09IFwiaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tXCIgJiYgZXZlbnQub3JpZ2luICE9PSBcImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsZXQgZGF0YSA9IG51bGw7XG5cbiAgICB0cnkge1xuICAgICAgZGF0YSA9IEpTT04ucGFyc2UoZXZlbnQuZGF0YSk7XG4gICAgfSBjYXRjaCAoZSkge31cblxuICAgIGlmICghZGF0YSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHN3aXRjaCAoZXZlbnQub3JpZ2luKSB7XG4gICAgICBjYXNlIFwiaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tXCI6XG4gICAgICAgIC8vQWxsb3dpbmcgZm9yIG11bHRpcGxlIGluc3RhbmNlcyBvZiBFeGNhbGlkcmF3IHJ1bm5pbmcgaW4gdGhlIHdpbmRvd1xuICAgICAgICBpZiAoZGF0YS5tZXRob2QgPT09IFwicGF1c2VkXCIpIHtcbiAgICAgICAgICBsZXQgc291cmNlID0gbnVsbDtcbiAgICAgICAgICBjb25zdCBpZnJhbWVzID0gZG9jdW1lbnQuYm9keS5xdWVyeVNlbGVjdG9yQWxsKFwiaWZyYW1lLmV4Y2FsaWRyYXdfX2VtYmVkZGFibGVcIik7XG5cbiAgICAgICAgICBpZiAoIWlmcmFtZXMpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGZvciAoY29uc3QgaWZyYW1lIG9mIGlmcmFtZXMpIHtcbiAgICAgICAgICAgIGlmIChpZnJhbWUuY29udGVudFdpbmRvdyA9PT0gZXZlbnQuc291cmNlKSB7XG4gICAgICAgICAgICAgIHNvdXJjZSA9IGlmcmFtZS5jb250ZW50V2luZG93O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHNvdXJjZSA9PT0gbnVsbCB8fCBzb3VyY2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHNvdXJjZS5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBtZXRob2Q6IGRhdGEudmFsdWUgPyBcInBsYXlcIiA6IFwicGF1c2VcIixcbiAgICAgICAgICAgIHZhbHVlOiB0cnVlXG4gICAgICAgICAgfSksIFwiKlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlIFwiaHR0cHM6Ly93d3cueW91dHViZS5jb21cIjpcbiAgICAgICAgaWYgKGRhdGEuZXZlbnQgPT09IFwiaW5mb0RlbGl2ZXJ5XCIgJiYgZGF0YS5pbmZvICYmIGRhdGEuaWQgJiYgdHlwZW9mIGRhdGEuaW5mby5wbGF5ZXJTdGF0ZSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAgIGNvbnN0IGlkID0gZGF0YS5pZDtcbiAgICAgICAgICBjb25zdCBwbGF5ZXJTdGF0ZSA9IGRhdGEuaW5mby5wbGF5ZXJTdGF0ZTtcblxuICAgICAgICAgIGlmIChPYmplY3QudmFsdWVzKFlPVVRVQkVfU1RBVEVTKS5pbmNsdWRlcyhwbGF5ZXJTdGF0ZSkpIHtcbiAgICAgICAgICAgIFlPVVRVQkVfVklERU9fU1RBVEVTLnNldChpZCwgcGxheWVyU3RhdGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIHVwZGF0ZUVtYmVkZGFibGVSZWYoaWQsIHJlZikge1xuICAgIGlmIChyZWYpIHtcbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5zZXQoaWQsIHJlZik7XG4gICAgfVxuICB9XG5cbiAgZ2V0SFRNTElGcmFtZUVsZW1lbnQoaWQpIHtcbiAgICByZXR1cm4gdGhpcy5pRnJhbWVSZWZzLmdldChpZCk7XG4gIH1cblxuICBoYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2soZWxlbWVudCkge1xuICAgIHZhciBfYSwgX2IsIF9jLCBfZDtcblxuICAgIGlmICgoKF9hID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgPT09IGVsZW1lbnQgJiYgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJhY3RpdmVcIikge1xuICAgICAgcmV0dXJuO1xuICAgIH0gLy8gVGhlIGRlbGF5IHNlcnZlcyB0d28gcHVycG9zZXNcbiAgICAvLyAxLiBUbyBwcmV2ZW50IGZpcnN0IGNsaWNrIHByb3BhZ2F0aW5nIHRvIGlmcmFtZSBvbiBtb2JpbGUsXG4gICAgLy8gICAgZWxzZSB0aGUgY2xpY2sgd2lsbCBpbW1lZGlhdGVseSBzdGFydCBhbmQgc3RvcCB0aGUgdmlkZW9cbiAgICAvLyAyLiBJZiB0aGUgdXNlciBkb3VibGUgY2xpY2tzIHRoZSBmcmFtZSBjZW50ZXIgdG8gYWN0aXZhdGUgaXRcbiAgICAvLyAgICB3aXRob3V0IHRoZSBkZWxheSB5b3V0dWJlIHdpbGwgaW1tZWRpYXRlbHkgb3BlbiB0aGUgdmlkZW9cbiAgICAvLyAgICBpbiBmdWxsc2NyZWVuIG1vZGVcblxuXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgIGVsZW1lbnQsXG4gICAgICAgICAgc3RhdGU6IFwiYWN0aXZlXCJcbiAgICAgICAgfSxcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgW2VsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgIH0sXG4gICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgc2VsZWN0aW9uRWxlbWVudDogbnVsbFxuICAgICAgfSk7XG4gICAgfSwgMTAwKTtcbiAgICBjb25zdCBpZnJhbWUgPSB0aGlzLmdldEhUTUxJRnJhbWVFbGVtZW50KGVsZW1lbnQuaWQpO1xuXG4gICAgaWYgKCEoaWZyYW1lID09PSBudWxsIHx8IGlmcmFtZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaWZyYW1lLmNvbnRlbnRXaW5kb3cpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlmcmFtZS5zcmMuaW5jbHVkZXMoXCJ5b3V0dWJlXCIpKSB7XG4gICAgICBjb25zdCBzdGF0ZSA9IFlPVVRVQkVfVklERU9fU1RBVEVTLmdldChlbGVtZW50LmlkKTtcblxuICAgICAgaWYgKCFzdGF0ZSkge1xuICAgICAgICBZT1VUVUJFX1ZJREVPX1NUQVRFUy5zZXQoZWxlbWVudC5pZCwgWU9VVFVCRV9TVEFURVMuVU5TVEFSVEVEKTtcbiAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIGV2ZW50OiBcImxpc3RlbmluZ1wiLFxuICAgICAgICAgIGlkOiBlbGVtZW50LmlkXG4gICAgICAgIH0pLCBcIipcIik7XG4gICAgICB9XG5cbiAgICAgIHN3aXRjaCAoc3RhdGUpIHtcbiAgICAgICAgY2FzZSBZT1VUVUJFX1NUQVRFUy5QTEFZSU5HOlxuICAgICAgICBjYXNlIFlPVVRVQkVfU1RBVEVTLkJVRkZFUklORzpcbiAgICAgICAgICAoX2MgPSBpZnJhbWUuY29udGVudFdpbmRvdykgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIGV2ZW50OiBcImNvbW1hbmRcIixcbiAgICAgICAgICAgIGZ1bmM6IFwicGF1c2VWaWRlb1wiLFxuICAgICAgICAgICAgYXJnczogXCJcIlxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAoX2QgPSBpZnJhbWUuY29udGVudFdpbmRvdykgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIGV2ZW50OiBcImNvbW1hbmRcIixcbiAgICAgICAgICAgIGZ1bmM6IFwicGxheVZpZGVvXCIsXG4gICAgICAgICAgICBhcmdzOiBcIlwiXG4gICAgICAgICAgfSksIFwiKlwiKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaWZyYW1lLnNyYy5pbmNsdWRlcyhcInBsYXllci52aW1lby5jb21cIikpIHtcbiAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgbWV0aG9kOiBcInBhdXNlZFwiIC8vdmlkZW8gcGxheS9wYXVzZSBpbiBvbldpbmRvd01lc3NhZ2UgaGFuZGxlclxuXG4gICAgICB9KSwgXCIqXCIpO1xuICAgIH1cbiAgfVxuXG4gIGlzRW1iZWRkYWJsZUNlbnRlcihlbCwgZXZlbnQsIHNjZW5lWCwgc2NlbmVZKSB7XG4gICAgdmFyIF9hLCBfYjtcblxuICAgIHJldHVybiBlbCAmJiAhZXZlbnQuYWx0S2V5ICYmICFldmVudC5zaGlmdEtleSAmJiAhZXZlbnQubWV0YUtleSAmJiAhZXZlbnQuY3RybEtleSAmJiAoKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpICE9PSBlbCB8fCAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImhvdmVyXCIgfHwgIXRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgJiYgc2NlbmVYID49IGVsLnggKyBlbC53aWR0aCAvIDMgJiYgc2NlbmVYIDw9IGVsLnggKyAyICogZWwud2lkdGggLyAzICYmIHNjZW5lWSA+PSBlbC55ICsgZWwuaGVpZ2h0IC8gMyAmJiBzY2VuZVkgPD0gZWwueSArIDIgKiBlbC5oZWlnaHQgLyAzO1xuICB9XG5cbiAgcmVuZGVyRW1iZWRkYWJsZXMoKSB7XG4gICAgY29uc3Qgc2NhbGUgPSB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgY29uc3Qgbm9ybWFsaXplZFdpZHRoID0gdGhpcy5zdGF0ZS53aWR0aDtcbiAgICBjb25zdCBub3JtYWxpemVkSGVpZ2h0ID0gdGhpcy5zdGF0ZS5oZWlnaHQ7XG4gICAgY29uc3QgZW1iZWRkYWJsZUVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWwgPT4gaXNFbWJlZGRhYmxlRWxlbWVudChlbCkgJiYgISFlbC52YWxpZGF0ZWQpO1xuICAgIHJldHVybiBfanN4KF9GcmFnbWVudCwge1xuICAgICAgY2hpbGRyZW46IGVtYmVkZGFibGVFbGVtZW50cy5tYXAoZWwgPT4ge1xuICAgICAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZiwgX2csIF9oO1xuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBlbC54LFxuICAgICAgICAgIHNjZW5lWTogZWwueVxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgZW1iZWRMaW5rID0gZ2V0RW1iZWRMaW5rKHRvVmFsaWRVUkwoZWwubGluayB8fCBcIlwiKSk7XG4gICAgICAgIGNvbnN0IGlzVmlzaWJsZSA9IGlzRWxlbWVudEluVmlld3BvcnQoZWwsIG5vcm1hbGl6ZWRXaWR0aCwgbm9ybWFsaXplZEhlaWdodCwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGlzQWN0aXZlID0gKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpID09PSBlbCAmJiAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImFjdGl2ZVwiO1xuICAgICAgICBjb25zdCBpc0hvdmVyZWQgPSAoKF9jID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZWxlbWVudCkgPT09IGVsICYmICgoX2QgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5zdGF0ZSkgPT09IFwiaG92ZXJcIjtcbiAgICAgICAgcmV0dXJuIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgY2xhc3NOYW1lOiBjbHN4KFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZS1jb250YWluZXJcIiwge1xuICAgICAgICAgICAgXCJpcy1ob3ZlcmVkXCI6IGlzSG92ZXJlZFxuICAgICAgICAgIH0pLFxuICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICB0cmFuc2Zvcm06IGlzVmlzaWJsZSA/IGB0cmFuc2xhdGUoJHt4IC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0fXB4LCAke3kgLSB0aGlzLnN0YXRlLm9mZnNldFRvcH1weCkgc2NhbGUoJHtzY2FsZX0pYCA6IFwibm9uZVwiLFxuICAgICAgICAgICAgZGlzcGxheTogaXNWaXNpYmxlID8gXCJibG9ja1wiIDogXCJub25lXCIsXG4gICAgICAgICAgICBvcGFjaXR5OiBlbC5vcGFjaXR5IC8gMTAwLFxuICAgICAgICAgICAgW1wiLS1lbWJlZGRhYmxlLXJhZGl1c1wiXTogYCR7Z2V0Q29ybmVyUmFkaXVzKE1hdGgubWluKGVsLndpZHRoLCBlbC5oZWlnaHQpLCBlbCl9cHhgXG4gICAgICAgICAgfVxuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IF9qc3hzKFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgLy90aGlzIGlzIGEgaGFjayB0aGF0IGFkZHJlc3NlcyBpc3NlIHdpdGggZW1iZWRkZWQgZXhjYWxpZHJhdy5jb20gZW1iZWRkYWJsZVxuICAgICAgICAgICAgLy9odHRwczovL2dpdGh1Yi5jb20vZXhjYWxpZHJhdy9leGNhbGlkcmF3L3B1bGwvNjY5MSNpc3N1ZWNvbW1lbnQtMTYwNzM4MzkzOFxuXG4gICAgICAgICAgICAvKnJlZj17KHJlZikgPT4ge1xuICAgICAgICAgICAgICBpZiAoIXRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgICAgICAgICBjb25zdCBzaCA9IGNvbnRhaW5lci5zY3JvbGxIZWlnaHQ7XG4gICAgICAgICAgICAgIGNvbnN0IGNoID0gY29udGFpbmVyLmNsaWVudEhlaWdodDtcbiAgICAgICAgICAgICAgaWYgKHNoICE9PSBjaCkge1xuICAgICAgICAgICAgICAgIGNvbnRhaW5lci5zdHlsZS5oZWlnaHQgPSBgJHtzaH1weGA7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICBjb250YWluZXIuc3R5bGUuaGVpZ2h0ID0gYDEwMCVgO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9fSovXG4gICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZS1jb250YWluZXJfX2lubmVyXCIsXG4gICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICB3aWR0aDogaXNWaXNpYmxlID8gYCR7ZWwud2lkdGh9cHhgIDogMCxcbiAgICAgICAgICAgICAgaGVpZ2h0OiBpc1Zpc2libGUgPyBgJHtlbC5oZWlnaHR9cHhgIDogMCxcbiAgICAgICAgICAgICAgdHJhbnNmb3JtOiBpc1Zpc2libGUgPyBgcm90YXRlKCR7ZWwuYW5nbGV9cmFkKWAgOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgcG9pbnRlckV2ZW50czogaXNBY3RpdmUgPyBQT0lOVEVSX0VWRU5UUy5lbmFibGVkIDogUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCB7XG4gICAgICAgICAgICBjaGlsZHJlbjogW2lzSG92ZXJlZCAmJiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZS1oaW50XCJcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IHQoXCJidXR0b25zLmVtYmVkZGFibGVJbnRlcmFjdGlvbkJ1dHRvblwiKVxuICAgICAgICAgICAgfSkpLCBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZV9fb3V0ZXJcIixcbiAgICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgICBwYWRkaW5nOiBgJHtlbC5zdHJva2VXaWR0aH1weGBcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICBjaGlsZHJlbjogKF9nID0gKF9mID0gKF9lID0gdGhpcy5wcm9wcykucmVuZGVyRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2YgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9mLmNhbGwoX2UsIGVsLCB0aGlzLnN0YXRlKSkgIT09IG51bGwgJiYgX2cgIT09IHZvaWQgMCA/IF9nIDogX2pzeChcImlmcmFtZVwiLCB7XG4gICAgICAgICAgICAgICAgcmVmOiByZWYgPT4gdGhpcy51cGRhdGVFbWJlZGRhYmxlUmVmKGVsLmlkLCByZWYpLFxuICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlXCIsXG4gICAgICAgICAgICAgICAgc3JjRG9jOiAoZW1iZWRMaW5rID09PSBudWxsIHx8IGVtYmVkTGluayA9PT0gdm9pZCAwID8gdm9pZCAwIDogZW1iZWRMaW5rLnR5cGUpID09PSBcImRvY3VtZW50XCIgPyBlbWJlZExpbmsuc3JjZG9jKHRoaXMuc3RhdGUudGhlbWUpIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHNyYzogKGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay50eXBlKSAhPT0gXCJkb2N1bWVudFwiID8gKF9oID0gZW1iZWRMaW5rID09PSBudWxsIHx8IGVtYmVkTGluayA9PT0gdm9pZCAwID8gdm9pZCAwIDogZW1iZWRMaW5rLmxpbmspICE9PSBudWxsICYmIF9oICE9PSB2b2lkIDAgPyBfaCA6IFwiXCIgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xLzE4NDcwMDE1XG4gICAgICAgICAgICAgICAgc2Nyb2xsaW5nOiBcIm5vXCIsXG4gICAgICAgICAgICAgICAgcmVmZXJyZXJQb2xpY3k6IFwibm8tcmVmZXJyZXItd2hlbi1kb3duZ3JhZGVcIixcbiAgICAgICAgICAgICAgICB0aXRsZTogXCJFeGNhbGlkcmF3IEVtYmVkZGVkIENvbnRlbnRcIixcbiAgICAgICAgICAgICAgICBhbGxvdzogXCJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlXCIsXG4gICAgICAgICAgICAgICAgYWxsb3dGdWxsU2NyZWVuOiB0cnVlLFxuICAgICAgICAgICAgICAgIHNhbmRib3g6IFwiYWxsb3ctc2FtZS1vcmlnaW4gYWxsb3ctc2NyaXB0cyBhbGxvdy1mb3JtcyBhbGxvdy1wb3B1cHMgYWxsb3ctcG9wdXBzLXRvLWVzY2FwZS1zYW5kYm94IGFsbG93LXByZXNlbnRhdGlvbiBhbGxvdy1kb3dubG9hZHNcIlxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSkpXVxuICAgICAgICAgIH0pKVxuICAgICAgICB9KSwgZWwuaWQpO1xuICAgICAgfSlcbiAgICB9KTtcbiAgfVxuXG4gIHJlbmRlcigpIHtcbiAgICB2YXIgX2EsIF9iLCBfYztcblxuICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgY29uc3Qge1xuICAgICAgcmVuZGVyVG9wUmlnaHRVSSxcbiAgICAgIHJlbmRlckN1c3RvbVN0YXRzXG4gICAgfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3QgdmVyc2lvbk5vbmNlID0gdGhpcy5zY2VuZS5nZXRWZXJzaW9uTm9uY2UoKTtcbiAgICBjb25zdCB7XG4gICAgICBjYW52YXNFbGVtZW50cyxcbiAgICAgIHZpc2libGVFbGVtZW50c1xuICAgIH0gPSB0aGlzLnJlbmRlcmVyLmdldFJlbmRlcmFibGVFbGVtZW50cyh7XG4gICAgICB2ZXJzaW9uTm9uY2UsXG4gICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb20sXG4gICAgICBvZmZzZXRMZWZ0OiB0aGlzLnN0YXRlLm9mZnNldExlZnQsXG4gICAgICBvZmZzZXRUb3A6IHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZLFxuICAgICAgaGVpZ2h0OiB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgIHdpZHRoOiB0aGlzLnN0YXRlLndpZHRoLFxuICAgICAgZWRpdGluZ0VsZW1lbnQ6IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQsXG4gICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkXG4gICAgfSk7XG4gICAgcmV0dXJuIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICBjbGFzc05hbWU6IGNsc3goXCJleGNhbGlkcmF3IGV4Y2FsaWRyYXctY29udGFpbmVyXCIsIHtcbiAgICAgICAgXCJleGNhbGlkcmF3LS12aWV3LW1vZGVcIjogdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQsXG4gICAgICAgIFwiZXhjYWxpZHJhdy0temVuLW1vZGVcIjogdGhpcy5zdGF0ZS56ZW5Nb2RlRW5hYmxlZCxcbiAgICAgICAgXCJleGNhbGlkcmF3LS1tb2JpbGVcIjogdGhpcy5kZXZpY2UuaXNNb2JpbGVcbiAgICAgIH0pLFxuICAgICAgc3R5bGU6IHtcbiAgICAgICAgW1wiLS11aS1wb2ludGVyRXZlbnRzXCJdOiB0aGlzLnN0YXRlLnNlbGVjdGlvbkVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgfHwgdGhpcy5zdGF0ZS5yZXNpemluZ0VsZW1lbnQgfHwgdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAmJiAhaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA/IFBPSU5URVJfRVZFTlRTLmRpc2FibGVkIDogUE9JTlRFUl9FVkVOVFMuZW5hYmxlZFxuICAgICAgfSxcbiAgICAgIHJlZjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLFxuICAgICAgb25Ecm9wOiB0aGlzLmhhbmRsZUFwcE9uRHJvcCxcbiAgICAgIHRhYkluZGV4OiAwLFxuICAgICAgb25LZXlEb3duOiB0aGlzLnByb3BzLmhhbmRsZUtleWJvYXJkR2xvYmFsbHkgPyB1bmRlZmluZWQgOiB0aGlzLm9uS2V5RG93blxuICAgIH0sIHtcbiAgICAgIGNoaWxkcmVuOiBfanN4KEFwcENvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICB2YWx1ZTogdGhpc1xuICAgICAgfSwge1xuICAgICAgICBjaGlsZHJlbjogX2pzeChBcHBQcm9wc0NvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgIHZhbHVlOiB0aGlzLnByb3BzXG4gICAgICAgIH0sIHtcbiAgICAgICAgICBjaGlsZHJlbjogX2pzeChFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICB2YWx1ZTogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWVcbiAgICAgICAgICB9LCB7XG4gICAgICAgICAgICBjaGlsZHJlbjogX2pzeChEZXZpY2VDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuZGV2aWNlXG4gICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLnNldEFwcFN0YXRlXG4gICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICBjaGlsZHJlbjogX2pzeChFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLnN0YXRlXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IF9qc3hzKEV4Y2FsaWRyYXdFbGVtZW50c0NvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKVxuICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW19qc3hzKEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuYWN0aW9uTWFuYWdlclxuICAgICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IFtfanN4KExheWVyVUksIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgICAgICAgb25Ib21lQnV0dG9uQ2xpY2s6IHRoaXMucHJvcHMub25Ib21lQnV0dG9uQ2xpY2sgfHwgKCgpID0+IHt9KSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbnZhczogdGhpcy5jYW52YXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZUNhbnZhczogdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZXM6IHRoaXMuZmlsZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRBcHBTdGF0ZTogdGhpcy5zZXRBcHBTdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGlvbk1hbmFnZXI6IHRoaXMuYWN0aW9uTWFuYWdlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Mb2NrVG9nZ2xlOiB0aGlzLnRvZ2dsZUxvY2ssXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBlbk1vZGVUb2dnbGU6IHRoaXMudG9nZ2xlUGVuTW9kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uSGFuZFRvb2xUb2dnbGU6IHRoaXMub25IYW5kVG9vbFRvZ2dsZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhbmdDb2RlOiBnZXRMYW5ndWFnZSgpLmNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJDdXN0b21TdGF0czogcmVuZGVyQ3VzdG9tU3RhdHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzaG93RXhpdFplbk1vZGVCdG46IHR5cGVvZiAoKF9hID0gdGhpcy5wcm9wcykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnplbk1vZGVFbmFibGVkKSA9PT0gXCJ1bmRlZmluZWRcIiAmJiB0aGlzLnN0YXRlLnplbk1vZGVFbmFibGVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgVUlPcHRpb25zOiB0aGlzLnByb3BzLlVJT3B0aW9ucyxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uRXhwb3J0SW1hZ2U6IHRoaXMub25FeHBvcnRJbWFnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uSW1hZ2VBY3Rpb246IHRoaXMub25JbWFnZUFjdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlcldlbGNvbWVTY3JlZW46ICF0aGlzLnN0YXRlLmlzTG9hZGluZyAmJiB0aGlzLnN0YXRlLnNob3dXZWxjb21lU2NyZWVuICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiICYmICF0aGlzLnN0YXRlLnplbk1vZGVFbmFibGVkICYmICF0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcDogdGhpcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlclRvcFJpZ2h0VUk6IHJlbmRlclRvcFJpZ2h0VUlcbiAgICAgICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogdGhpcy5wcm9wcy5jaGlsZHJlblxuICAgICAgICAgICAgICAgICAgICAgIH0pKSwgX2pzeChcImRpdlwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhdy10ZXh0RWRpdG9yQ29udGFpbmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgX2pzeChcImRpdlwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhdy1jb250ZXh0TWVudUNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctZXllLWRyb3BwZXItY29udGFpbmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgIXRoaXMuc3RhdGUuY29udGV4dE1lbnUgJiYgdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXAgJiYgX2pzeChIeXBlcmxpbmssIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHNlbGVjdGVkRWxlbWVudHNbMF0sXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRBcHBTdGF0ZTogdGhpcy5zZXRBcHBTdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uTGlua09wZW46IHRoaXMucHJvcHMub25MaW5rT3BlbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFRvYXN0OiB0aGlzLnNldFRvYXN0XG4gICAgICAgICAgICAgICAgICAgICAgfSwgc2VsZWN0ZWRFbGVtZW50c1swXS5pZCksIHRoaXMuc3RhdGUudG9hc3QgIT09IG51bGwgJiYgX2pzeChUb2FzdCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogdGhpcy5zdGF0ZS50b2FzdC5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25DbG9zZTogKCkgPT4gdGhpcy5zZXRUb2FzdChudWxsKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiB0aGlzLnN0YXRlLnRvYXN0LmR1cmF0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2xvc2FibGU6IHRoaXMuc3RhdGUudG9hc3QuY2xvc2FibGVcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiBfanN4KENvbnRleHRNZW51LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtczogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS5pdGVtcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvcDogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS50b3AsXG4gICAgICAgICAgICAgICAgICAgICAgICBsZWZ0OiB0aGlzLnN0YXRlLmNvbnRleHRNZW51LmxlZnQsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25NYW5hZ2VyOiB0aGlzLmFjdGlvbk1hbmFnZXJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgX2pzeChTdGF0aWNDYW52YXMsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbnZhczogdGhpcy5jYW52YXMsXG4gICAgICAgICAgICAgICAgICAgICAgICByYzogdGhpcy5yYyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzOiBjYW52YXNFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpc2libGVFbGVtZW50czogdmlzaWJsZUVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmVyc2lvbk5vbmNlOiB2ZXJzaW9uTm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25Ob25jZTogKF9iID0gdGhpcy5zdGF0ZS5zZWxlY3Rpb25FbGVtZW50KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IudmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGU6IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJDb25maWc6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaW1hZ2VDYWNoZTogdGhpcy5pbWFnZUNhY2hlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBpc0V4cG9ydGluZzogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlckdyaWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNhbnZhc0JhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goSW50ZXJhY3RpdmVDYW52YXMsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lclJlZjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmludGVyYWN0aXZlQ2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IGNhbnZhc0VsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZUVsZW1lbnRzOiB2aXNpYmxlRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzOiBzZWxlY3RlZEVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmVyc2lvbk5vbmNlOiB2ZXJzaW9uTm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25Ob25jZTogKF9jID0gdGhpcy5zdGF0ZS5zZWxlY3Rpb25FbGVtZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MudmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGU6IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJJbnRlcmFjdGl2ZVNjZW5lQ2FsbGJhY2s6IHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlQ2FudmFzUmVmOiB0aGlzLmhhbmRsZUludGVyYWN0aXZlQ2FudmFzUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Db250ZXh0TWVudTogdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlck1vdmU6IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJVcDogdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJDYW5jZWw6IHRoaXMucmVtb3ZlUG9pbnRlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uVG91Y2hNb3ZlOiB0aGlzLmhhbmRsZVRvdWNoTW92ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlckRvd246IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24sXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkRvdWJsZUNsaWNrOiB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHRoaXMucmVuZGVyRnJhbWVOYW1lcygpXVxuICAgICAgICAgICAgICAgICAgICB9KSksIHRoaXMucmVuZGVyRW1iZWRkYWJsZXMoKV1cbiAgICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgIH0pKVxuICAgICAgICB9KSlcbiAgICAgIH0pKVxuICAgIH0pKTtcbiAgfVxuXG4gIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgIHZhciBfYSwgX2I7XG5cbiAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlLmNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IEVOVi5URVNUIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICAgICAgICBjb25zdCBzZXRTdGF0ZSA9IHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMod2luZG93LmgsIHtcbiAgICAgICAgICBzdGF0ZToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZ2V0OiAoKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2V0U3RhdGU6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiAoLi4uYXJncykgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSguLi5hcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIGFwcDoge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHRoaXNcbiAgICAgICAgICB9LFxuICAgICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmhpc3RvcnlcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNjZW5lLmFkZENhbGxiYWNrKHRoaXMub25TY2VuZVVwZGF0ZWQpO1xuICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVycygpO1xuXG4gICAgICBpZiAodGhpcy5wcm9wcy5hdXRvRm9jdXMgJiYgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQgJiYgLy8gYm91bmRpbmcgcmVjdHMgZG9uJ3Qgd29yayBpbiB0ZXN0cyBzbyB1cGRhdGluZ1xuICAgICAgLy8gdGhlIHN0YXRlIG9uIGluaXQgd291bGQgcmVzdWx0IGluIG1ha2luZyB0aGUgdGVzdCBlbnZpcm8gcnVuXG4gICAgICAvLyBpbiBtb2JpbGUgYnJlYWtwb2ludCAoMCB3aWR0aC9oZWlnaHQpLCBtYWtpbmcgZXZlcnl0aGluZyBmYWlsXG4gICAgICAhaXNUZXN0RW52KCkpIHtcbiAgICAgICAgdGhpcy5yZWZyZXNoRGV2aWNlU3RhdGUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAoXCJSZXNpemVPYnNlcnZlclwiIGluIHdpbmRvdyAmJiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkpIHtcbiAgICAgICAgdGhpcy5yZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcigoKSA9PiB7XG4gICAgICAgICAgLy8gcmVjb21wdXRlIGRldmljZSBkaW1lbnNpb25zIHN0YXRlXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgICAgdGhpcy5yZWZyZXNoRGV2aWNlU3RhdGUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpOyAvLyByZWZyZXNoIG9mZnNldHNcbiAgICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAgICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgKF9iID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLm9ic2VydmUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgfSBlbHNlIGlmICh3aW5kb3cubWF0Y2hNZWRpYSkge1xuICAgICAgICBjb25zdCBtZFNjcmVlblF1ZXJ5ID0gd2luZG93Lm1hdGNoTWVkaWEoYChtYXgtd2lkdGg6ICR7TVFfTUFYX1dJRFRIX1BPUlRSQUlUfXB4KSwgKG1heC1oZWlnaHQ6ICR7TVFfTUFYX0hFSUdIVF9MQU5EU0NBUEV9cHgpIGFuZCAobWF4LXdpZHRoOiAke01RX01BWF9XSURUSF9MQU5EU0NBUEV9cHgpYCk7XG4gICAgICAgIGNvbnN0IHNtU2NyZWVuUXVlcnkgPSB3aW5kb3cubWF0Y2hNZWRpYShgKG1heC13aWR0aDogJHtNUV9TTV9NQVhfV0lEVEh9cHgpYCk7XG4gICAgICAgIGNvbnN0IGNhbkRldmljZUZpdFNpZGViYXJNZWRpYVF1ZXJ5ID0gd2luZG93Lm1hdGNoTWVkaWEoYChtaW4td2lkdGg6ICR7Ly8gTk9URSB0aGlzIHdvbid0IHVwZGF0ZSBpZiBhIGRpZmZlcmVudCBicmVha3BvaW50IGlzIHN1cHBsaWVkXG4gICAgICAgIC8vIGFmdGVyIG1vdW50XG4gICAgICAgIHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50ICE9IG51bGwgPyB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCA6IE1RX1JJR0hUX1NJREVCQVJfTUlOX1dJRFRIfXB4KWApO1xuXG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgdGhpcy5kZXZpY2UgPSB1cGRhdGVPYmplY3QodGhpcy5kZXZpY2UsIHtcbiAgICAgICAgICAgIGlzU21TY3JlZW46IHNtU2NyZWVuUXVlcnkubWF0Y2hlcyxcbiAgICAgICAgICAgIGlzTW9iaWxlOiBtZFNjcmVlblF1ZXJ5Lm1hdGNoZXMsXG4gICAgICAgICAgICBjYW5EZXZpY2VGaXRTaWRlYmFyOiBjYW5EZXZpY2VGaXRTaWRlYmFyTWVkaWFRdWVyeS5tYXRjaGVzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbWRTY3JlZW5RdWVyeS5hZGRMaXN0ZW5lcihoYW5kbGVyKTtcblxuICAgICAgICB0aGlzLmRldGFjaElzTW9iaWxlTXFIYW5kbGVyID0gKCkgPT4gbWRTY3JlZW5RdWVyeS5yZW1vdmVMaXN0ZW5lcihoYW5kbGVyKTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VhcmNoUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoLnNsaWNlKDEpKTtcblxuICAgICAgaWYgKHNlYXJjaFBhcmFtcy5oYXMoXCJ3ZWItc2hhcmUtdGFyZ2V0XCIpKSB7XG4gICAgICAgIC8vIE9idGFpbiBhIGZpbGUgdGhhdCB3YXMgc2hhcmVkIHZpYSB0aGUgV2ViIFNoYXJlIFRhcmdldCBBUEkuXG4gICAgICAgIHRoaXMucmVzdG9yZUZpbGVGcm9tU2hhcmUoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCh0aGlzLmluaXRpYWxpemVTY2VuZSk7XG4gICAgICB9IC8vIG5vdGUgdGhhdCB0aGlzIGNoZWNrIHNlZW1zIHRvIGFsd2F5cyBwYXNzIGluIGxvY2FsaG9zdFxuXG5cbiAgICAgIGlmIChpc0JyYXZlKCkgJiYgIWlzTWVhc3VyZVRleHRTdXBwb3J0ZWQoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IF9qc3goQnJhdmVNZWFzdXJlVGV4dEVycm9yLCB7fSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICB2YXIgX2E7XG5cbiAgICB0aGlzLnJlbmRlcmVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLnNjZW5lID0gbmV3IFNjZW5lKCk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcbiAgICB0aGlzLmZpbGVzID0ge307XG4gICAgdGhpcy5pbWFnZUNhY2hlLmNsZWFyKCk7XG4gICAgKF9hID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmRpc2Nvbm5lY3QoKTtcbiAgICB0aGlzLnVubW91bnRlZCA9IHRydWU7XG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHRoaXMuc2NlbmUuZGVzdHJveSgpO1xuICAgIHRoaXMubGlicmFyeS5kZXN0cm95KCk7XG4gICAgU2hhcGVDYWNoZS5kZXN0cm95KCk7XG4gICAgU25hcENhY2hlLmRlc3Ryb3koKTtcbiAgICBjbGVhclJlbmRlckNhY2hlKCk7XG4gICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIuZGVzdHJveSgpO1xuICAgIHRoaXMuc2NlbmUgPSBuZXcgU2NlbmUoKTtcbiAgICB0aGlzLmhpc3RvcnkgPSBuZXcgSGlzdG9yeSgpO1xuICAgIHRoaXMuYWN0aW9uTWFuYWdlciA9IG5ldyBBY3Rpb25NYW5hZ2VyKHRoaXMuc3luY0FjdGlvblJlc3VsdCwgKCkgPT4gdGhpcy5zdGF0ZSwgKCkgPT4gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcyk7XG4gICAgdGhpcy5saWJyYXJ5ID0gbmV3IExpYnJhcnkodGhpcyk7IC8vIEB0cy1pZ25vcmVcblxuICAgIHRoaXMuY2FudmFzID0gbnVsbDtcbiAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzID0gbnVsbDsgLy8gQHRzLWlnbm9yZVxuXG4gICAgdGhpcy5yYyA9IG51bGw7IC8vIEB0cy1pZ25vcmVcblxuICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50ID0gdW5kZWZpbmVkO1xuICAgIHRoaXMubmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWUgPSB7XG4gICAgICBjb250YWluZXI6IG51bGwsXG4gICAgICBpZDogXCJ1bm1vdW50ZWRcIlxuICAgIH07XG4gICAgY2xlYXJUaW1lb3V0KHRvdWNoVGltZW91dCk7XG4gICAgaXNTb21lRWxlbWVudFNlbGVjdGVkLmNsZWFyQ2FjaGUoKTtcbiAgICBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzLmNsZWFyQ2FjaGUoKTtcbiAgICB0b3VjaFRpbWVvdXQgPSAwO1xuICB9XG5cbiAgcmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nO1xuXG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0aGlzLnJlbW92ZVBvaW50ZXIpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuQ09QWSwgdGhpcy5vbkNvcHkpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHRoaXMucGFzdGVGcm9tQ2xpcGJvYXJkKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkNVVCwgdGhpcy5vbkN1dCk7XG4gICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLm9uV2hlZWwpO1xuICAgIChfYiA9IHRoaXMubmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlNDUk9MTCwgdGhpcy5vblNjcm9sbCk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlET1dOLCB0aGlzLm9uS2V5RG93biwgZmFsc2UpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuTU9VU0VfTU9WRSwgdGhpcy51cGRhdGVDdXJyZW50Q3Vyc29yUG9zaXRpb24sIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULktFWVVQLCB0aGlzLm9uS2V5VXApO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlJFU0laRSwgdGhpcy5vblJlc2l6ZSwgZmFsc2UpO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlVOTE9BRCwgdGhpcy5vblVubG9hZCwgZmFsc2UpO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkJMVVIsIHRoaXMub25CbHVyLCBmYWxzZSk7XG4gICAgKF9jID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkRSQUdfT1ZFUiwgdGhpcy5kaXNhYmxlRXZlbnQsIGZhbHNlKTtcbiAgICAoX2QgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuRFJPUCwgdGhpcy5kaXNhYmxlRXZlbnQsIGZhbHNlKTtcbiAgICAoX2YgPSAoX2UgPSBkb2N1bWVudC5mb250cykgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLnJlbW92ZUV2ZW50TGlzdGVuZXIpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5jYWxsKF9lLCBcImxvYWRpbmdkb25lXCIsIHRoaXMub25Gb250c0xvYWRpbmdEb25lKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfU1RBUlQsIHRoaXMub25HZXN0dXJlU3RhcnQsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfQ0hBTkdFLCB0aGlzLm9uR2VzdHVyZUNoYW5nZSwgZmFsc2UpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9FTkQsIHRoaXMub25HZXN0dXJlRW5kLCBmYWxzZSk7XG4gICAgKF9nID0gdGhpcy5kZXRhY2hJc01vYmlsZU1xSGFuZGxlcikgPT09IG51bGwgfHwgX2cgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9nLmNhbGwodGhpcyk7XG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuTUVTU0FHRSwgdGhpcy5vbldpbmRvd01lc3NhZ2UsIGZhbHNlKTtcbiAgfVxuXG4gIGFkZEV2ZW50TGlzdGVuZXJzKCkge1xuICAgIHZhciBfYSwgX2IsIF9jLCBfZCwgX2U7XG5cbiAgICB0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXJzKCk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuTUVTU0FHRSwgdGhpcy5vbldpbmRvd01lc3NhZ2UsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRoaXMucmVtb3ZlUG9pbnRlcik7IC8vICMzNTUzXG5cbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkNPUFksIHRoaXMub25Db3B5KTtcbiAgICAoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuV0hFRUwsIHRoaXMub25XaGVlbCwge1xuICAgICAgcGFzc2l2ZTogZmFsc2VcbiAgICB9KTtcblxuICAgIGlmICh0aGlzLnByb3BzLmhhbmRsZUtleWJvYXJkR2xvYmFsbHkpIHtcbiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgdGhpcy5vbktleURvd24sIGZhbHNlKTtcbiAgICB9XG5cbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULktFWVVQLCB0aGlzLm9uS2V5VXAsIHtcbiAgICAgIHBhc3NpdmU6IHRydWVcbiAgICB9KTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULk1PVVNFX01PVkUsIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uKTsgLy8gcmVyZW5kZXIgdGV4dCBlbGVtZW50cyBvbiBmb250IGxvYWQgdG8gZml4ICM2MzcgJiYgIzE1NTNcblxuICAgIChfYyA9IChfYiA9IGRvY3VtZW50LmZvbnRzKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuYWRkRXZlbnRMaXN0ZW5lcikgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmNhbGwoX2IsIFwibG9hZGluZ2RvbmVcIiwgdGhpcy5vbkZvbnRzTG9hZGluZ0RvbmUpOyAvLyBTYWZhcmktb25seSBkZXNrdG9wIHBpbmNoIHpvb21cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9TVEFSVCwgdGhpcy5vbkdlc3R1cmVTdGFydCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9DSEFOR0UsIHRoaXMub25HZXN0dXJlQ2hhbmdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0VORCwgdGhpcy5vbkdlc3R1cmVFbmQsIGZhbHNlKTtcblxuICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHRoaXMucGFzdGVGcm9tQ2xpcGJvYXJkKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkNVVCwgdGhpcy5vbkN1dCk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5kZXRlY3RTY3JvbGwpIHtcbiAgICAgIHRoaXMubmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIgPSBnZXROZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lcih0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCk7XG4gICAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuU0NST0xMLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICB9XG5cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfZCA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9lID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gIH1cblxuICBjb21wb25lbnREaWRVcGRhdGUocHJldlByb3BzLCBwcmV2U3RhdGUpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZjtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMoKTtcblxuICAgIGlmICghdGhpcy5zdGF0ZS5zaG93V2VsY29tZVNjcmVlbiAmJiAhdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5sZW5ndGgpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzaG93V2VsY29tZVNjcmVlbjogdHJ1ZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50ICYmIHByZXZQcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT09IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50KSB7XG4gICAgICB0aGlzLnJlZnJlc2hEZXZpY2VTdGF0ZSh0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZTdGF0ZS5zY3JvbGxYICE9PSB0aGlzLnN0YXRlLnNjcm9sbFggfHwgcHJldlN0YXRlLnNjcm9sbFkgIT09IHRoaXMuc3RhdGUuc2Nyb2xsWSkge1xuICAgICAgKF9iID0gKF9hID0gdGhpcy5wcm9wcykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm9uU2Nyb2xsQ2hhbmdlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwgdGhpcy5zdGF0ZS5zY3JvbGxYLCB0aGlzLnN0YXRlLnNjcm9sbFkpO1xuICAgIH1cblxuICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcykubGVuZ3RoICYmIGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICB9KVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImVyYXNlclwiICYmIHByZXZTdGF0ZS50aGVtZSAhPT0gdGhpcy5zdGF0ZS50aGVtZSkge1xuICAgICAgc2V0RXJhc2VyQ3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUudGhlbWUpO1xuICAgIH0gLy8gSGlkZSBoeXBlcmxpbmsgcG9wdXAgaWYgc2hvd24gd2hlbiBlbGVtZW50IHR5cGUgaXMgbm90IHNlbGVjdGlvblxuXG5cbiAgICBpZiAocHJldlN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZmFsc2VcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMubGFuZ0NvZGUgIT09IHRoaXMucHJvcHMubGFuZ0NvZGUpIHtcbiAgICAgIHRoaXMudXBkYXRlTGFuZ3VhZ2UoKTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLnZpZXdNb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB2aWV3TW9kZUVuYWJsZWQ6ICEhdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWRcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2U3RhdGUudmlld01vZGVFbmFibGVkICE9PSB0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVycygpO1xuICAgICAgdGhpcy5kZXNlbGVjdEVsZW1lbnRzKCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy56ZW5Nb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHplbk1vZGVFbmFibGVkOiAhIXRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWRcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMudGhlbWUgIT09IHRoaXMucHJvcHMudGhlbWUgJiYgdGhpcy5wcm9wcy50aGVtZSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHRoZW1lOiB0aGlzLnByb3BzLnRoZW1lXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLmdyaWRNb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBncmlkU2l6ZTogdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMucHJvcHMuVUlPcHRpb25zLmNhbnZhc0FjdGlvbnMgJiYgdGhpcy5zdGF0ZS5vcGVuTWVudSA9PT0gXCJjYW52YXNcIikge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG9wZW5NZW51OiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5wcm9wcy5uYW1lICYmIHByZXZQcm9wcy5uYW1lICE9PSB0aGlzLnByb3BzLm5hbWUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBuYW1lOiB0aGlzLnByb3BzLm5hbWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIChfYyA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuY2xhc3NMaXN0LnRvZ2dsZShcInRoZW1lLS1kYXJrXCIsIHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiKTtcblxuICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZF0pIHtcbiAgICAgIC8vIGRlZmVyIHNvIHRoYXQgdGhlIGNvbW1pdFRvSGlzdG9yeSBmbGFnIGlzbid0IHJlc2V0IHZpYSBjdXJyZW50IHVwZGF0ZVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIC8vIGV4ZWN1dGUgb25seSBpZiB0aGUgY29uZGl0aW9uIHN0aWxsIGhvbGRzIHdoZW4gdGhlIGRlZmVycmVkIGNhbGxiYWNrXG4gICAgICAgIC8vIGV4ZWN1dGVzIChpdCBjYW4gYmUgc2NoZWR1bGVkIG11bHRpcGxlIHRpbWVzIGRlcGVuZGluZyBvbiBob3dcbiAgICAgICAgLy8gbWFueSB0aW1lcyB0aGUgY29tcG9uZW50IHJlbmRlcnMpXG4gICAgICAgIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgfSk7XG4gICAgfSAvLyBmYWlsc2FmZSBpbiBjYXNlIHRoZSBzdGF0ZSBpcyBiZWluZyB1cGRhdGVkIGluIGluY29ycmVjdCBvcmRlciByZXN1bHRpbmdcbiAgICAvLyBpbiB0aGUgZWRpdGluZ0VsZW1lbnQgYmVpbmcgbm93IGEgZGVsZXRlZCBlbGVtZW50XG5cblxuICAgIGlmICgoX2QgPSB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuaXNEZWxldGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuZWxlbWVudElkXSkge1xuICAgICAgLy8gVG8gbWFrZSBzdXJlIGBzZWxlY3RlZExpbmVhckVsZW1lbnRgIGlzIGluIHN5bmMgd2l0aCBgc2VsZWN0ZWRFbGVtZW50SWRzYCwgaG93ZXZlciB0aGlzIHNob3VsZG4ndCBiZSBuZWVkZWQgb25jZVxuICAgICAgLy8gd2UgaGF2ZSBhIHNpbmdsZSBBUEkgdG8gdXBkYXRlIGBzZWxlY3RlZEVsZW1lbnRJZHNgXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBjb25zdCB7XG4gICAgICBtdWx0aUVsZW1lbnRcbiAgICB9ID0gcHJldlN0YXRlO1xuXG4gICAgaWYgKHByZXZTdGF0ZS5hY3RpdmVUb29sICE9PSB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wgJiYgbXVsdGlFbGVtZW50ICE9IG51bGwgJiYgaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSAmJiBpc0JpbmRpbmdFbGVtZW50KG11bHRpRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICBtYXliZUJpbmRMaW5lYXJFbGVtZW50KG11bHRpRWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZSwgdHVwbGVUb0Nvb3JzKExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0UG9pbnRBdEluZGV4R2xvYmFsQ29vcmRpbmF0ZXMobXVsdGlFbGVtZW50LCAtMSkpKTtcbiAgICB9XG5cbiAgICB0aGlzLmhpc3RvcnkucmVjb3JkKHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkpOyAvLyBEbyBub3Qgbm90aWZ5IGNvbnN1bWVycyBpZiB3ZSdyZSBzdGlsbCBsb2FkaW5nIHRoZSBzY2VuZS4gQW1vbmcgb3RoZXJcbiAgICAvLyBwb3RlbnRpYWwgaXNzdWVzLCB0aGlzIGZpeGVzIGEgY2FzZSB3aGVyZSB0aGUgdGFiIGlzbid0IGZvY3VzZWQgZHVyaW5nXG4gICAgLy8gaW5pdCwgd2hpY2ggd291bGQgdHJpZ2dlciBvbkNoYW5nZSB3aXRoIGVtcHR5IGVsZW1lbnRzLCB3aGljaCB3b3VsZCB0aGVuXG4gICAgLy8gb3ZlcnJpZGUgd2hhdGV2ZXIgaXMgaW4gbG9jYWxTdG9yYWdlIGN1cnJlbnRseS5cblxuICAgIGlmICghdGhpcy5zdGF0ZS5pc0xvYWRpbmcpIHtcbiAgICAgIChfZiA9IChfZSA9IHRoaXMucHJvcHMpLm9uQ2hhbmdlKSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuY2FsbChfZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcywgdGhpcy5wcm9wcy5pZCk7XG4gICAgICB0aGlzLm9uQ2hhbmdlRW1pdHRlci50cmlnZ2VyKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMuc3RhdGUsIHRoaXMuZmlsZXMpO1xuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyByZXNldFRhcFR3aWNlKCkge1xuICAgIGRpZFRhcFR3aWNlID0gZmFsc2U7XG4gIH1cblxuICBhZGRUZXh0RnJvbVBhc3RlKHRleHQsIGlzUGxhaW5QYXN0ZSA9IGZhbHNlKSB7XG4gICAgY29uc3Qge1xuICAgICAgeCxcbiAgICAgIHlcbiAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgIGNsaWVudFg6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCxcbiAgICAgIGNsaWVudFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueVxuICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHRleHRFbGVtZW50UHJvcHMgPSB7XG4gICAgICB4LFxuICAgICAgeSxcbiAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgIHJvdW5kbmVzczogbnVsbCxcbiAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgdGV4dCxcbiAgICAgIGZvbnRTaXplOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRm9udFNpemUsXG4gICAgICBmb250RmFtaWx5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRm9udEZhbWlseSxcbiAgICAgIHRleHRBbGlnbjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVRleHRBbGlnbixcbiAgICAgIHZlcnRpY2FsQWxpZ246IERFRkFVTFRfVkVSVElDQUxfQUxJR04sXG4gICAgICBsb2NrZWQ6IGZhbHNlXG4gICAgfTtcbiAgICBjb25zdCBMSU5FX0dBUCA9IDEwO1xuICAgIGxldCBjdXJyZW50WSA9IHk7XG4gICAgY29uc3QgbGluZXMgPSBpc1BsYWluUGFzdGUgPyBbdGV4dF0gOiB0ZXh0LnNwbGl0KFwiXFxuXCIpO1xuICAgIGNvbnN0IHRleHRFbGVtZW50cyA9IGxpbmVzLnJlZHVjZSgoYWNjLCBsaW5lLCBpZHgpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgdGV4dCA9IGxpbmUudHJpbSgpO1xuICAgICAgY29uc3QgbGluZUhlaWdodCA9IGdldERlZmF1bHRMaW5lSGVpZ2h0KHRleHRFbGVtZW50UHJvcHMuZm9udEZhbWlseSk7XG5cbiAgICAgIGlmICh0ZXh0Lmxlbmd0aCkge1xuICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5OiBjdXJyZW50WVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IG5ld1RleHRFbGVtZW50KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGV4dEVsZW1lbnRQcm9wcyksIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHk6IGN1cnJlbnRZLFxuICAgICAgICAgIHRleHQsXG4gICAgICAgICAgbGluZUhlaWdodCxcbiAgICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgICAgfSkpO1xuICAgICAgICBhY2MucHVzaChlbGVtZW50KTtcbiAgICAgICAgY3VycmVudFkgKz0gZWxlbWVudC5oZWlnaHQgKyBMSU5FX0dBUDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHByZXZMaW5lID0gKF9hID0gbGluZXNbaWR4IC0gMV0pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS50cmltKCk7IC8vIGFkZCBwYXJhZ3JhcGggb25seSBpZiBwcmV2aW91cyBsaW5lIHdhcyBub3QgZW1wdHksIElPVyBkb24ndCBhZGRcbiAgICAgICAgLy8gbW9yZSB0aGFuIG9uZSBlbXB0eSBsaW5lXG5cbiAgICAgICAgaWYgKHByZXZMaW5lKSB7XG4gICAgICAgICAgY3VycmVudFkgKz0gZ2V0TGluZUhlaWdodEluUHgodGV4dEVsZW1lbnRQcm9wcy5mb250U2l6ZSwgbGluZUhlaWdodCkgKyBMSU5FX0dBUDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sIFtdKTtcblxuICAgIGlmICh0ZXh0RWxlbWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgZnJhbWVJZCA9IHRleHRFbGVtZW50c1swXS5mcmFtZUlkO1xuXG4gICAgaWYgKGZyYW1lSWQpIHtcbiAgICAgIHRoaXMuc2NlbmUuaW5zZXJ0RWxlbWVudHNBdEluZGV4KHRleHRFbGVtZW50cywgdGhpcy5zY2VuZS5nZXRFbGVtZW50SW5kZXgoZnJhbWVJZCkpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgLi4udGV4dEVsZW1lbnRzXSk7XG4gICAgfVxuXG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5mcm9tRW50cmllcyh0ZXh0RWxlbWVudHMubWFwKGVsID0+IFtlbC5pZCwgdHJ1ZV0pKSwgdGhpcy5zdGF0ZSlcbiAgICB9KTtcblxuICAgIGlmICghaXNQbGFpblBhc3RlICYmIHRleHRFbGVtZW50cy5sZW5ndGggPiAxICYmIFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID09PSBmYWxzZSAmJiAhdGhpcy5kZXZpY2UuaXNNb2JpbGUpIHtcbiAgICAgIHRoaXMuc2V0VG9hc3Qoe1xuICAgICAgICBtZXNzYWdlOiB0KFwidG9hc3QucGFzdGVBc1NpbmdsZUVsZW1lbnRcIiwge1xuICAgICAgICAgIHNob3J0Y3V0OiBnZXRTaG9ydGN1dEtleShcIkN0cmxPckNtZCtTaGlmdCtWXCIpXG4gICAgICAgIH0pLFxuICAgICAgICBkdXJhdGlvbjogNTAwMFxuICAgICAgfSk7XG4gICAgICBQTEFJTl9QQVNURV9UT0FTVF9TSE9XTiA9IHRydWU7XG4gICAgfVxuXG4gICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICB9XG5cbiAgaGFuZGxlVGV4dFd5c2l3eWcoZWxlbWVudCwge1xuICAgIGlzRXhpc3RpbmdFbGVtZW50ID0gZmFsc2VcbiAgfSkge1xuICAgIGNvbnN0IHVwZGF0ZUVsZW1lbnQgPSAodGV4dCwgb3JpZ2luYWxUZXh0LCBpc0RlbGV0ZWQpID0+IHtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChfZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChfZWxlbWVudC5pZCA9PT0gZWxlbWVudC5pZCAmJiBpc1RleHRFbGVtZW50KF9lbGVtZW50KSkge1xuICAgICAgICAgIHJldHVybiB1cGRhdGVUZXh0RWxlbWVudChfZWxlbWVudCwge1xuICAgICAgICAgICAgdGV4dCxcbiAgICAgICAgICAgIGlzRGVsZXRlZCxcbiAgICAgICAgICAgIG9yaWdpbmFsVGV4dFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF9lbGVtZW50O1xuICAgICAgfSldKTtcbiAgICB9O1xuXG4gICAgdGV4dFd5c2l3eWcoe1xuICAgICAgaWQ6IGVsZW1lbnQuaWQsXG4gICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgZ2V0Vmlld3BvcnRDb29yZHM6ICh4LCB5KSA9PiB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB2aWV3cG9ydFgsXG4gICAgICAgICAgeTogdmlld3BvcnRZXG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogeCxcbiAgICAgICAgICBzY2VuZVk6IHlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIHJldHVybiBbdmlld3BvcnRYIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LCB2aWV3cG9ydFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcF07XG4gICAgICB9LFxuICAgICAgb25DaGFuZ2U6IHdpdGhCYXRjaGVkVXBkYXRlcyh0ZXh0ID0+IHtcbiAgICAgICAgdXBkYXRlRWxlbWVudCh0ZXh0LCB0ZXh0LCBmYWxzZSk7XG5cbiAgICAgICAgaWYgKGlzTm9uRGVsZXRlZEVsZW1lbnQoZWxlbWVudCkpIHtcbiAgICAgICAgICB1cGRhdGVCb3VuZEVsZW1lbnRzKGVsZW1lbnQpO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICAgIG9uU3VibWl0OiB3aXRoQmF0Y2hlZFVwZGF0ZXMoKHtcbiAgICAgICAgdGV4dCxcbiAgICAgICAgdmlhS2V5Ym9hcmQsXG4gICAgICAgIG9yaWdpbmFsVGV4dFxuICAgICAgfSkgPT4ge1xuICAgICAgICBjb25zdCBpc0RlbGV0ZWQgPSAhdGV4dC50cmltKCk7XG4gICAgICAgIHVwZGF0ZUVsZW1lbnQodGV4dCwgb3JpZ2luYWxUZXh0LCBpc0RlbGV0ZWQpOyAvLyBzZWxlY3QgdGhlIGNyZWF0ZWQgdGV4dCBlbGVtZW50IG9ubHkgaWYgc3VibWl0dGluZyB2aWEga2V5Ym9hcmRcbiAgICAgICAgLy8gKHdoZW4gc3VibWl0dGluZyB2aWEgY2xpY2sgaXQgc2hvdWxkIGFjdCBhcyBzaWduYWwgdG8gZGVzZWxlY3QpXG5cbiAgICAgICAgaWYgKCFpc0RlbGV0ZWQgJiYgdmlhS2V5Ym9hcmQpIHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50SWRUb1NlbGVjdCA9IGVsZW1lbnQuY29udGFpbmVySWQgPyBlbGVtZW50LmNvbnRhaW5lcklkIDogZWxlbWVudC5pZDtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgIFtlbGVtZW50SWRUb1NlbGVjdF06IHRydWVcbiAgICAgICAgICAgIH0pLCBwcmV2U3RhdGUpXG4gICAgICAgICAgfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzRGVsZXRlZCkge1xuICAgICAgICAgIGZpeEJpbmRpbmdzQWZ0ZXJEZWxldGlvbih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBbZWxlbWVudF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFpc0RlbGV0ZWQgfHwgaXNFeGlzdGluZ0VsZW1lbnQpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH0pLFxuICAgICAgZWxlbWVudCxcbiAgICAgIGV4Y2FsaWRyYXdDb250YWluZXI6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LFxuICAgICAgYXBwOiB0aGlzXG4gICAgfSk7IC8vIGRlc2VsZWN0IGFsbCBvdGhlciBlbGVtZW50cyB3aGVuIGluc2VydGluZyB0ZXh0XG5cbiAgICB0aGlzLmRlc2VsZWN0RWxlbWVudHMoKTsgLy8gZG8gYW4gaW5pdGlhbCB1cGRhdGUgdG8gcmUtaW5pdGlhbGl6ZSBlbGVtZW50IHBvc2l0aW9uIHNpbmNlIHdlIHdlcmVcbiAgICAvLyBtb2RpZnlpbmcgZWxlbWVudCdzIHgveSBmb3Igc2FrZSBvZiBlZGl0b3IgKGNhc2U6IHN5bmNpbmcgdG8gcmVtb3RlKVxuXG4gICAgdXBkYXRlRWxlbWVudChlbGVtZW50LnRleHQsIGVsZW1lbnQub3JpZ2luYWxUZXh0LCBmYWxzZSk7XG4gIH1cblxuICBkZXNlbGVjdEVsZW1lbnRzKCkge1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgIH0pO1xuICB9XG5cbiAgZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHgsIHkpIHtcbiAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbih4LCB5LCB7XG4gICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZVxuICAgIH0pO1xuXG4gICAgaWYgKGVsZW1lbnQgJiYgaXNUZXh0RWxlbWVudChlbGVtZW50KSAmJiAhZWxlbWVudC5pc0RlbGV0ZWQpIHtcbiAgICAgIHJldHVybiBlbGVtZW50O1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZ2V0RWxlbWVudEF0UG9zaXRpb24oeCwgeSwgb3B0cykge1xuICAgIGNvbnN0IGFsbEhpdEVsZW1lbnRzID0gdGhpcy5nZXRFbGVtZW50c0F0UG9zaXRpb24oeCwgeSwgb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmluY2x1ZGVCb3VuZFRleHRFbGVtZW50LCBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuaW5jbHVkZUxvY2tlZEVsZW1lbnRzKTtcblxuICAgIGlmIChhbGxIaXRFbGVtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICBpZiAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnByZWZlclNlbGVjdGVkKSB7XG4gICAgICAgIGZvciAobGV0IGluZGV4ID0gYWxsSGl0RWxlbWVudHMubGVuZ3RoIC0gMTsgaW5kZXggPiAtMTsgaW5kZXgtLSkge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1thbGxIaXRFbGVtZW50c1tpbmRleF0uaWRdKSB7XG4gICAgICAgICAgICByZXR1cm4gYWxsSGl0RWxlbWVudHNbaW5kZXhdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50V2l0aEhpZ2hlc3RaSW5kZXggPSBhbGxIaXRFbGVtZW50c1thbGxIaXRFbGVtZW50cy5sZW5ndGggLSAxXTsgLy8gSWYgd2UncmUgaGl0dGluZyBlbGVtZW50IHdpdGggaGlnaGVzdCB6LWluZGV4IG9ubHkgb24gaXRzIGJvdW5kaW5nIGJveFxuICAgICAgLy8gd2hpbGUgYWxzbyBoaXR0aW5nIG90aGVyIGVsZW1lbnQgZmlndXJlLCB0aGUgbGF0dGVyIHNob3VsZCBiZSBjb25zaWRlcmVkLlxuXG4gICAgICByZXR1cm4gaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50KGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgeCwgeSkgPyBhbGxIaXRFbGVtZW50c1thbGxIaXRFbGVtZW50cy5sZW5ndGggLSAyXSA6IGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleDtcbiAgICB9XG5cbiAgICBpZiAoYWxsSGl0RWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICByZXR1cm4gYWxsSGl0RWxlbWVudHNbMF07XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBnZXRFbGVtZW50c0F0UG9zaXRpb24oeCwgeSwgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgPSBmYWxzZSwgaW5jbHVkZUxvY2tlZEVsZW1lbnRzID0gZmFsc2UpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGluY2x1ZGVCb3VuZFRleHRFbGVtZW50ICYmIGluY2x1ZGVMb2NrZWRFbGVtZW50cyA/IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkgOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLmZpbHRlcihlbGVtZW50ID0+IChpbmNsdWRlTG9ja2VkRWxlbWVudHMgfHwgIWVsZW1lbnQubG9ja2VkKSAmJiAoaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgfHwgIShpc1RleHRFbGVtZW50KGVsZW1lbnQpICYmIGVsZW1lbnQuY29udGFpbmVySWQpKSk7XG4gICAgcmV0dXJuIGdldEVsZW1lbnRzQXRQb3NpdGlvbihlbGVtZW50cywgZWxlbWVudCA9PiBoaXRUZXN0KGVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHgsIHkpKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAvLyBoaXR0aW5nIGEgZnJhbWUncyBlbGVtZW50IGZyb20gb3V0c2lkZSB0aGUgZnJhbWUgaXMgbm90IGNvbnNpZGVyZWQgYSBoaXRcbiAgICAgIGNvbnN0IGNvbnRhaW5pbmdGcmFtZSA9IGdldENvbnRhaW5pbmdGcmFtZShlbGVtZW50KTtcbiAgICAgIHJldHVybiBjb250YWluaW5nRnJhbWUgJiYgdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5lbmFibGVkICYmIHRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuY2xpcCA/IGlzQ3Vyc29ySW5GcmFtZSh7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0sIGNvbnRhaW5pbmdGcmFtZSkgOiB0cnVlO1xuICAgIH0pO1xuICB9XG5cbiAgaGFuZGxlSG92ZXJTZWxlY3RlZExpbmVhckVsZW1lbnQobGluZWFyRWxlbWVudEVkaXRvciwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmdldEVsZW1lbnQobGluZWFyRWxlbWVudEVkaXRvci5lbGVtZW50SWQpO1xuICAgIGNvbnN0IGJvdW5kVGV4dEVsZW1lbnQgPSBnZXRCb3VuZFRleHRFbGVtZW50KGVsZW1lbnQpO1xuXG4gICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICBsZXQgaG92ZXJQb2ludEluZGV4ID0gLTE7XG4gICAgICBsZXQgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3JkcyA9IG51bGw7XG5cbiAgICAgIGlmIChpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveChlbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBbc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWV0pKSB7XG4gICAgICAgIGhvdmVyUG9pbnRJbmRleCA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0UG9pbnRJbmRleFVuZGVyQ3Vyc29yKGVsZW1lbnQsIHRoaXMuc3RhdGUuem9vbSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSk7XG4gICAgICAgIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmdldFNlZ21lbnRNaWRwb2ludEhpdENvb3JkcyhsaW5lYXJFbGVtZW50RWRpdG9yLCB7XG4gICAgICAgICAgeDogc2NlbmVQb2ludGVyWCxcbiAgICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChob3ZlclBvaW50SW5kZXggPj0gMCB8fCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5NT1ZFKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzaG91bGRTaG93Qm91bmRpbmdCb3goW2VsZW1lbnRdLCB0aGlzLnN0YXRlKSAmJiBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQoZWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgfSBlbHNlIGlmIChib3VuZFRleHRFbGVtZW50ICYmIGhpdFRlc3QoYm91bmRUZXh0RWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaG92ZXJQb2ludEluZGV4ICE9PSBob3ZlclBvaW50SW5kZXgpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgaG92ZXJQb2ludEluZGV4XG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghTGluZWFyRWxlbWVudEVkaXRvci5hcmVQb2ludHNFcXVhbCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5zZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzLCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzXG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICB9XG4gIH1cblxuICBtYXliZUNsZWFudXBBZnRlck1pc3NpbmdQb2ludGVyVXAoZXZlbnQpIHtcbiAgICBpZiAobGFzdFBvaW50ZXJVcCAhPT0gbnVsbCkge1xuICAgICAgLy8gVW5mb3J0dW5hdGVseSwgc29tZXRpbWVzIHdlIGRvbid0IGdldCBhIHBvaW50ZXJ1cCBhZnRlciBhIHBvaW50ZXJkb3duLFxuICAgICAgLy8gdGhpcyBjYW4gaGFwcGVuIHdoZW4gYSBjb250ZXh0dWFsIG1lbnUgb3IgYWxlcnQgaXMgdHJpZ2dlcmVkLiBJbiBvcmRlciB0byBhdm9pZFxuICAgICAgLy8gYmVpbmcgaW4gYSB3ZWlyZCBzdGF0ZSwgd2UgY2xlYW4gdXAgb24gdGhlIG5leHQgcG9pbnRlcmRvd25cbiAgICAgIGxhc3RQb2ludGVyVXAoZXZlbnQpO1xuICAgIH1cbiAgfVxuXG4gIHVwZGF0ZUdlc3R1cmVPblBvaW50ZXJEb3duKGV2ZW50KSB7XG4gICAgZ2VzdHVyZS5wb2ludGVycy5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICB4OiBldmVudC5jbGllbnRYLFxuICAgICAgeTogZXZlbnQuY2xpZW50WVxuICAgIH0pO1xuXG4gICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMikge1xuICAgICAgZ2VzdHVyZS5sYXN0Q2VudGVyID0gZ2V0Q2VudGVyKGdlc3R1cmUucG9pbnRlcnMpO1xuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSA9IGdldERpc3RhbmNlKEFycmF5LmZyb20oZ2VzdHVyZS5wb2ludGVycy52YWx1ZXMoKSkpO1xuICAgIH1cbiAgfVxuXG4gIGluaXRpYWxQb2ludGVyRG93blN0YXRlKGV2ZW50KSB7XG4gICAgY29uc3Qgb3JpZ2luID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IFttaW5YLCBtaW5ZLCBtYXhYLCBtYXhZXSA9IGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICByZXR1cm4ge1xuICAgICAgb3JpZ2luLFxuICAgICAgd2l0aENtZE9yQ3RybDogZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0sXG4gICAgICBvcmlnaW5JbkdyaWQ6IHR1cGxlVG9Db29ycyhnZXRHcmlkUG9pbnQob3JpZ2luLngsIG9yaWdpbi55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKSksXG4gICAgICBzY3JvbGxiYXJzOiBpc092ZXJTY3JvbGxCYXJzKGN1cnJlbnRTY3JvbGxCYXJzLCBldmVudC5jbGllbnRYIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LCBldmVudC5jbGllbnRZIC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3ApLFxuICAgICAgLy8gd2UgbmVlZCB0byBkdXBsaWNhdGUgYmVjYXVzZSB3ZSdsbCBiZSB1cGRhdGluZyB0aGlzIHN0YXRlXG4gICAgICBsYXN0Q29vcmRzOiBPYmplY3QuYXNzaWduKHt9LCBvcmlnaW4pLFxuICAgICAgb3JpZ2luYWxFbGVtZW50czogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5yZWR1Y2UoKGFjYywgZWxlbWVudCkgPT4ge1xuICAgICAgICBhY2Muc2V0KGVsZW1lbnQuaWQsIGRlZXBDb3B5RWxlbWVudChlbGVtZW50KSk7XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCBuZXcgTWFwKCkpLFxuICAgICAgcmVzaXplOiB7XG4gICAgICAgIGhhbmRsZVR5cGU6IGZhbHNlLFxuICAgICAgICBpc1Jlc2l6aW5nOiBmYWxzZSxcbiAgICAgICAgb2Zmc2V0OiB7XG4gICAgICAgICAgeDogMCxcbiAgICAgICAgICB5OiAwXG4gICAgICAgIH0sXG4gICAgICAgIGFycm93RGlyZWN0aW9uOiBcIm9yaWdpblwiLFxuICAgICAgICBjZW50ZXI6IHtcbiAgICAgICAgICB4OiAobWF4WCArIG1pblgpIC8gMixcbiAgICAgICAgICB5OiAobWF4WSArIG1pblkpIC8gMlxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgaGl0OiB7XG4gICAgICAgIGVsZW1lbnQ6IG51bGwsXG4gICAgICAgIGFsbEhpdEVsZW1lbnRzOiBbXSxcbiAgICAgICAgd2FzQWRkZWRUb1NlbGVjdGlvbjogZmFsc2UsXG4gICAgICAgIGhhc0JlZW5EdXBsaWNhdGVkOiBmYWxzZSxcbiAgICAgICAgaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHM6IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMob3JpZ2luLCBzZWxlY3RlZEVsZW1lbnRzKVxuICAgICAgfSxcbiAgICAgIGRyYWc6IHtcbiAgICAgICAgaGFzT2NjdXJyZWQ6IGZhbHNlLFxuICAgICAgICBvZmZzZXQ6IG51bGxcbiAgICAgIH0sXG4gICAgICBldmVudExpc3RlbmVyczoge1xuICAgICAgICBvbk1vdmU6IG51bGwsXG4gICAgICAgIG9uVXA6IG51bGwsXG4gICAgICAgIG9uS2V5VXA6IG51bGwsXG4gICAgICAgIG9uS2V5RG93bjogbnVsbFxuICAgICAgfSxcbiAgICAgIGJveFNlbGVjdGlvbjoge1xuICAgICAgICBoYXNPY2N1cnJlZDogZmFsc2VcbiAgICAgIH0sXG4gICAgICBlbGVtZW50SWRzVG9FcmFzZToge31cbiAgICB9O1xuICB9IC8vIFJldHVybnMgd2hldGhlciB0aGUgZXZlbnQgaXMgYSBkcmFnZ2luZyBhIHNjcm9sbGJhclxuXG5cbiAgaGFuZGxlRHJhZ2dpbmdTY3JvbGxCYXIoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICBpZiAoIShwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVyRWl0aGVyICYmICF0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gdHJ1ZTtcbiAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IGV2ZW50LmNsaWVudFg7XG4gICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBldmVudC5jbGllbnRZO1xuICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQoZXZlbnQgPT4ge1xuICAgICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0O1xuXG4gICAgICBpZiAoISh0YXJnZXQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgIH0pO1xuICAgIGNvbnN0IG9uUG9pbnRlclVwID0gd2l0aEJhdGNoZWRVcGRhdGVzKCgpID0+IHtcbiAgICAgIGlzRHJhZ2dpbmdTY3JvbGxCYXIgPSBmYWxzZTtcbiAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgY3Vyc29yQnV0dG9uOiBcInVwXCJcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICAgIG9uUG9pbnRlck1vdmUuZmx1c2goKTtcbiAgICB9KTtcbiAgICBsYXN0UG9pbnRlclVwID0gb25Qb2ludGVyVXA7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBvblBvaW50ZXJVcCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBpc0FTZWxlY3RlZEVsZW1lbnQoaGl0RWxlbWVudCkge1xuICAgIHJldHVybiBoaXRFbGVtZW50ICE9IG51bGwgJiYgdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF07XG4gIH1cblxuICBpc0hpdHRpbmdDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cyhwb2ludCwgc2VsZWN0ZWRFbGVtZW50cykge1xuICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA8IDIpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IC8vIEhvdyBtYW55IHBpeGVscyBvZmYgdGhlIHNoYXBlIGJvdW5kYXJ5IHdlIHN0aWxsIGNvbnNpZGVyIGEgaGl0XG5cblxuICAgIGNvbnN0IHRocmVzaG9sZCA9IDEwIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgIGNvbnN0IFt4MSwgeTEsIHgyLCB5Ml0gPSBnZXRDb21tb25Cb3VuZHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgcmV0dXJuIHBvaW50LnggPiB4MSAtIHRocmVzaG9sZCAmJiBwb2ludC54IDwgeDIgKyB0aHJlc2hvbGQgJiYgcG9pbnQueSA+IHkxIC0gdGhyZXNob2xkICYmIHBvaW50LnkgPCB5MiArIHRocmVzaG9sZDtcbiAgfVxuXG4gIGdldEN1cnJlbnRJdGVtUm91bmRuZXNzKGVsZW1lbnRUeXBlKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VuZG5lc3MgPT09IFwicm91bmRcIiA/IHtcbiAgICAgIHR5cGU6IGlzVXNpbmdBZGFwdGl2ZVJhZGl1cyhlbGVtZW50VHlwZSkgPyBST1VORE5FU1MuQURBUFRJVkVfUkFESVVTIDogUk9VTkRORVNTLlBST1BPUlRJT05BTF9SQURJVVNcbiAgICB9IDogbnVsbDtcbiAgfVxuXG4gIG1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzLCByZWNvbXB1dGVBbnl3YXlzID0gZmFsc2UpIHtcbiAgICBpZiAoaXNTbmFwcGluZ0VuYWJsZWQoe1xuICAgICAgZXZlbnQsXG4gICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgIHNlbGVjdGVkRWxlbWVudHNcbiAgICB9KSAmJiAocmVjb21wdXRlQW55d2F5cyB8fCAhU25hcENhY2hlLmdldFJlZmVyZW5jZVNuYXBQb2ludHMoKSkpIHtcbiAgICAgIFNuYXBDYWNoZS5zZXRSZWZlcmVuY2VTbmFwUG9pbnRzKGdldFJlZmVyZW5jZVNuYXBQb2ludHModGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgc2VsZWN0ZWRFbGVtZW50cywgdGhpcy5zdGF0ZSkpO1xuICAgIH1cbiAgfVxuXG4gIG1heWJlQ2FjaGVWaXNpYmxlR2FwcyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgcmVjb21wdXRlQW55d2F5cyA9IGZhbHNlKSB7XG4gICAgaWYgKGlzU25hcHBpbmdFbmFibGVkKHtcbiAgICAgIGV2ZW50LFxuICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICBzZWxlY3RlZEVsZW1lbnRzXG4gICAgfSkgJiYgKHJlY29tcHV0ZUFueXdheXMgfHwgIVNuYXBDYWNoZS5nZXRWaXNpYmxlR2FwcygpKSkge1xuICAgICAgU25hcENhY2hlLnNldFZpc2libGVHYXBzKGdldFZpc2libGVHYXBzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHNlbGVjdGVkRWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcbiAgICB9XG4gIH1cblxuICBvbktleURvd25Gcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGlmICh0aGlzLm1heWJlSGFuZGxlUmVzaXplKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubWF5YmVEcmFnTmV3R2VuZXJpY0VsZW1lbnQocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpO1xuICAgIH0pO1xuICB9XG5cbiAgb25LZXlVcEZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSkge1xuICAgIHJldHVybiB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgLy8gUHJldmVudHMgZm9jdXMgZnJvbSBlc2NhcGluZyBleGNhbGlkcmF3IHRhYlxuICAgICAgZXZlbnQua2V5ID09PSBLRVlTLkFMVCAmJiBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uUG9pbnRlck1vdmVGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzVGhyb3R0bGVkKGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2I7IC8vIFdlIG5lZWQgdG8gaW5pdGlhbGl6ZSBkcmFnT2Zmc2V0WFkgb25seSBhZnRlciB3ZSd2ZSB1cGRhdGVkXG4gICAgICAvLyBgc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzYCBvbiBwb2ludGVyRG93bi4gRG9pbmcgaXQgaGVyZSBpbiBwb2ludGVyTW92ZVxuICAgICAgLy8gZXZlbnQgaGFuZGxlciBzaG91bGQgaG9wZWZ1bGx5IGVuc3VyZSB3ZSdyZSBhbHJlYWR5IHdvcmtpbmcgd2l0aFxuICAgICAgLy8gdGhlIHVwZGF0ZWQgc3RhdGUuXG5cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5vZmZzZXQgPT09IG51bGwpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLm9mZnNldCA9IHR1cGxlVG9Db29ycyhnZXREcmFnT2Zmc2V0WFkodGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldDtcblxuICAgICAgaWYgKCEodGFyZ2V0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlRXJhc2VyKGV2ZW50LCBwb2ludGVyRG93blN0YXRlLCBwb2ludGVyQ29vcmRzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7IC8vIGZvciBhcnJvd3MvbGluZXMsIGRvbid0IHN0YXJ0IGRyYWdnaW5nIHVudGlsIGEgZ2l2ZW4gdGhyZXNob2xkXG4gICAgICAvLyB0byBlbnN1cmUgd2UgZG9uJ3QgY3JlYXRlIGEgMi1wb2ludCBhcnJvdyBieSBtaXN0YWtlIHdoZW5cbiAgICAgIC8vIHVzZXIgY2xpY2tzIG1vdXNlIGluIGEgd2F5IHRoYXQgaXQgbW92ZXMgYSB0aW55IGJpdCAodGh1c1xuICAgICAgLy8gdHJpZ2dlcmluZyBwb2ludGVybW92ZSlcblxuICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImFycm93XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGluZVwiKSkge1xuICAgICAgICBpZiAoZGlzdGFuY2UyZChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkgPCBEUkFHR0lOR19USFJFU0hPTEQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmlzUmVzaXppbmcpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuXG4gICAgICAgIGlmICh0aGlzLm1heWJlSGFuZGxlUmVzaXplKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICBjb25zdCBsaW5lYXJFbGVtZW50RWRpdG9yID0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudDtcblxuICAgICAgICBpZiAoTGluZWFyRWxlbWVudEVkaXRvci5zaG91bGRBZGRNaWRwb2ludCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgcG9pbnRlckNvb3JkcywgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgICBjb25zdCByZXQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmFkZE1pZHBvaW50KHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LCBwb2ludGVyQ29vcmRzLCB0aGlzLnN0YXRlLCAhZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pO1xuXG4gICAgICAgICAgaWYgKCFyZXQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9IC8vIFNpbmNlIHdlIGFyZSByZWFkaW5nIGZyb20gcHJldmlvdXMgc3RhdGUgd2hpY2ggaXMgbm90IHBvc3NpYmxlIHdpdGhcbiAgICAgICAgICAvLyBhdXRvbWF0aWMgYmF0Y2hpbmcgaW4gUmVhY3QgMTggaGVuY2UgdXNpbmcgZmx1c2ggc3luYyB0byBzeW5jaHJvbm91c2x5XG4gICAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZS4gQ2hlY2sgaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzU1MDggZm9yIG1vcmUgZGV0YWlscy5cblxuXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlOiByZXQucG9pbnRlckRvd25TdGF0ZSxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkUG9pbnRzSW5kaWNlczogcmV0LnNlbGVjdGVkUG9pbnRzSW5kaWNlc1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZTogcmV0LnBvaW50ZXJEb3duU3RhdGUsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IHJldC5zZWxlY3RlZFBvaW50c0luZGljZXNcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAobGluZWFyRWxlbWVudEVkaXRvci5wb2ludGVyRG93blN0YXRlLnNlZ21lbnRNaWRwb2ludC52YWx1ZSAhPT0gbnVsbCAmJiAhbGluZWFyRWxlbWVudEVkaXRvci5wb2ludGVyRG93blN0YXRlLnNlZ21lbnRNaWRwb2ludC5hZGRlZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRpZERyYWcgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50RHJhZ2dpbmcoZXZlbnQsIHRoaXMuc3RhdGUsIHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCAoZWxlbWVudCwgcG9pbnRzU2NlbmVDb29yZHMpID0+IHtcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdzRm9yTGluZWFyRWxlbWVudEF0Q29vcmRzKGVsZW1lbnQsIHBvaW50c1NjZW5lQ29vcmRzKTtcbiAgICAgICAgfSwgbGluZWFyRWxlbWVudEVkaXRvcik7XG5cbiAgICAgICAgaWYgKGRpZERyYWcpIHtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHBvaW50ZXJDb29yZHMueDtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgPSB0cnVlO1xuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICAgICAgaXNEcmFnZ2luZzogdHJ1ZVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgIGlzRHJhZ2dpbmc6IHRydWVcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNIaXRBU2VsZWN0ZWRFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuYWxsSGl0RWxlbWVudHMuc29tZShlbGVtZW50ID0+IHRoaXMuaXNBU2VsZWN0ZWRFbGVtZW50KGVsZW1lbnQpKTtcbiAgICAgIGNvbnN0IGlzU2VsZWN0aW5nUG9pbnRzSW5MaW5lRWRpdG9yID0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiBldmVudC5zaGlmdEtleSAmJiB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCA9PT0gKChfYSA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pZCk7XG5cbiAgICAgIGlmICgoaGFzSGl0QVNlbGVjdGVkRWxlbWVudCB8fCBwb2ludGVyRG93blN0YXRlLmhpdC5oYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cykgJiYgIWlzU2VsZWN0aW5nUG9pbnRzSW5MaW5lRWRpdG9yKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMuZXZlcnkoZWxlbWVudCA9PiBlbGVtZW50LmxvY2tlZCkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzSGFzQUZyYW1lID0gc2VsZWN0ZWRFbGVtZW50cy5maW5kKGUgPT4gaXNGcmFtZUVsZW1lbnQoZSkpO1xuICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyhwb2ludGVyQ29vcmRzKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZnJhbWVUb0hpZ2hsaWdodDogdG9wTGF5ZXJGcmFtZSAmJiAhc2VsZWN0ZWRFbGVtZW50c0hhc0FGcmFtZSA/IHRvcExheWVyRnJhbWUgOiBudWxsXG4gICAgICAgIH0pOyAvLyBNYXJraW5nIHRoYXQgY2xpY2sgd2FzIHVzZWQgZm9yIGRyYWdnaW5nIHRvIGNoZWNrXG4gICAgICAgIC8vIGlmIGVsZW1lbnRzIHNob3VsZCBiZSBkZXNlbGVjdGVkIG9uIHBvaW50ZXJ1cFxuXG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCA9IHRydWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IHRydWVcbiAgICAgICAgfSk7IC8vIHByZXZlbnQgZHJhZ2dpbmcgZXZlbiBpZiB3ZSdyZSBubyBsb25nZXIgaG9sZGluZyBjbWQvY3RybCBvdGhlcndpc2VcbiAgICAgICAgLy8gaXQgd291bGQgaGF2ZSB3ZWlyZCByZXN1bHRzIChzdHVmZiBqdW1waW5nIGFsbCBvdmVyIHRoZSBzY3JlZW4pXG4gICAgICAgIC8vIENoZWNraW5nIGZvciBlZGl0aW5nRWxlbWVudCB0byBhdm9pZCBqdW1wIHdoaWxlIGVkaXRpbmcgb24gbW9iaWxlICM2NTAzXG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID4gMCAmJiAhcG9pbnRlckRvd25TdGF0ZS53aXRoQ21kT3JDdHJsICYmICF0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgIT09IFwiYWN0aXZlXCIpIHtcbiAgICAgICAgICBjb25zdCBkcmFnT2Zmc2V0ID0ge1xuICAgICAgICAgICAgeDogcG9pbnRlckNvb3Jkcy54IC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCxcbiAgICAgICAgICAgIHk6IHBvaW50ZXJDb29yZHMueSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnlcbiAgICAgICAgICB9O1xuICAgICAgICAgIGNvbnN0IG9yaWdpbmFsRWxlbWVudHMgPSBbLi4ucG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLnZhbHVlcygpXTsgLy8gV2Ugb25seSBkcmFnIGluIG9uZSBkaXJlY3Rpb24gaWYgc2hpZnQgaXMgcHJlc3NlZFxuXG4gICAgICAgICAgY29uc3QgbG9ja0RpcmVjdGlvbiA9IGV2ZW50LnNoaWZ0S2V5O1xuXG4gICAgICAgICAgaWYgKGxvY2tEaXJlY3Rpb24pIHtcbiAgICAgICAgICAgIGNvbnN0IGRpc3RhbmNlWCA9IE1hdGguYWJzKGRyYWdPZmZzZXQueCk7XG4gICAgICAgICAgICBjb25zdCBkaXN0YW5jZVkgPSBNYXRoLmFicyhkcmFnT2Zmc2V0LnkpO1xuICAgICAgICAgICAgY29uc3QgbG9ja1ggPSBsb2NrRGlyZWN0aW9uICYmIGRpc3RhbmNlWCA8IGRpc3RhbmNlWTtcbiAgICAgICAgICAgIGNvbnN0IGxvY2tZID0gbG9ja0RpcmVjdGlvbiAmJiBkaXN0YW5jZVggPiBkaXN0YW5jZVk7XG5cbiAgICAgICAgICAgIGlmIChsb2NrWCkge1xuICAgICAgICAgICAgICBkcmFnT2Zmc2V0LnggPSAwO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAobG9ja1kpIHtcbiAgICAgICAgICAgICAgZHJhZ09mZnNldC55ID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIFNuYXAgY2FjaGUgKm11c3QqIGJlIHN5bmNocm9ub3VzbHkgcG9wdXBsYXRlZCBiZWZvcmUgaW5pdGlhbCBkcmFnLFxuICAgICAgICAgIC8vIG90aGVyd2lzZSB0aGUgZmlyc3QgZHJhZyBldmVuIHdpbGwgbm90IHNuYXAsIGNhdXNpbmcgYSBqdW1wIGJlZm9yZVxuICAgICAgICAgIC8vIGl0IHNuYXBzIHRvIGl0cyBwb3NpdGlvbiBpZiBwcmV2aW91c2x5IHNuYXBwZWQgYWxyZWFkeS5cblxuXG4gICAgICAgICAgdGhpcy5tYXliZUNhY2hlVmlzaWJsZUdhcHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgIHNuYXBPZmZzZXQsXG4gICAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgICB9ID0gc25hcERyYWdnZWRFbGVtZW50cyhnZXRTZWxlY3RlZEVsZW1lbnRzKG9yaWdpbmFsRWxlbWVudHMsIHRoaXMuc3RhdGUpLCBkcmFnT2Zmc2V0LCB0aGlzLnN0YXRlLCBldmVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgICB9KTsgLy8gd2hlbiB3ZSdyZSBlZGl0aW5nIHRoZSBuYW1lIG9mIGEgZnJhbWUsIHdlIHdhbnQgdGhlIHVzZXIgdG8gYmVcbiAgICAgICAgICAvLyBhYmxlIHRvIHNlbGVjdCBhbmQgaW50ZXJhY3Qgd2l0aCB0aGUgdGV4dCBpbnB1dFxuXG4gICAgICAgICAgIXRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lICYmIGRyYWdTZWxlY3RlZEVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUsIHNlbGVjdGVkRWxlbWVudHMsIGRyYWdPZmZzZXQsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUsIHNuYXBPZmZzZXQsIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKTsgLy8gV2UgZHVwbGljYXRlIHRoZSBzZWxlY3RlZCBlbGVtZW50IGlmIGFsdCBpcyBwcmVzc2VkIG9uIHBvaW50ZXIgbW92ZVxuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQpIHtcbiAgICAgICAgICAgIC8vIE1vdmUgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBlbGVtZW50cyB0byB0aGUgdG9wIG9mIHRoZSB6IGluZGV4IHN0YWNrLCBhbmRcbiAgICAgICAgICAgIC8vIHB1dCB0aGUgZHVwbGljYXRlcyB3aGVyZSB0aGUgc2VsZWN0ZWQgZWxlbWVudHMgdXNlZCB0byBiZS5cbiAgICAgICAgICAgIC8vICh0aGUgb3JpZ2luIHBvaW50IHdoZXJlIHRoZSBkcmFnZ2luZyBzdGFydGVkKVxuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29uc3QgbmV4dEVsZW1lbnRzID0gW107XG4gICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvQXBwZW5kID0gW107XG4gICAgICAgICAgICBjb25zdCBncm91cElkTWFwID0gbmV3IE1hcCgpO1xuICAgICAgICAgICAgY29uc3Qgb2xkSWRUb0R1cGxpY2F0ZWRJZCA9IG5ldyBNYXAoKTtcbiAgICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuICAgICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50SWRzID0gbmV3IFNldCh0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzLFxuICAgICAgICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZSxcbiAgICAgICAgICAgICAgaW5jbHVkZUVsZW1lbnRzSW5GcmFtZXM6IHRydWVcbiAgICAgICAgICAgIH0pLm1hcChlbGVtZW50ID0+IGVsZW1lbnQuaWQpKTtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRJZHMuaGFzKGVsZW1lbnQuaWQpIHx8IC8vIGNhc2U6IHRoZSBzdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMgbWlnaHQgbm90IGhhdmUgYmVlblxuICAgICAgICAgICAgICAvLyB1cGRhdGVkIHlldCBieSB0aGUgdGltZSB0aGlzIG1vdXNlbW92ZSBldmVudCBpcyBmaXJlZFxuICAgICAgICAgICAgICBlbGVtZW50LmlkID09PSAoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmlkKSAmJiBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZHVwbGljYXRlZEVsZW1lbnQgPSBkdXBsaWNhdGVFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQsIGdyb3VwSWRNYXAsIGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IG9yaWdFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLmdldChlbGVtZW50LmlkKTtcbiAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGR1cGxpY2F0ZWRFbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICB4OiBvcmlnRWxlbWVudC54LFxuICAgICAgICAgICAgICAgICAgeTogb3JpZ0VsZW1lbnQueVxuICAgICAgICAgICAgICAgIH0pOyAvLyBwdXQgZHVwbGljYXRlZCBlbGVtZW50IHRvIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50c1xuICAgICAgICAgICAgICAgIC8vIHNvIHRoYXQgd2UgY2FuIHNuYXAgdG8gdGhlIGR1cGxpY2F0ZWQgZWxlbWVudCB3aXRob3V0IHJlbGVhc2luZ1xuXG4gICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLnNldChkdXBsaWNhdGVkRWxlbWVudC5pZCwgZHVwbGljYXRlZEVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIG5leHRFbGVtZW50cy5wdXNoKGR1cGxpY2F0ZWRFbGVtZW50KTtcbiAgICAgICAgICAgICAgICBlbGVtZW50c1RvQXBwZW5kLnB1c2goZWxlbWVudCk7XG4gICAgICAgICAgICAgICAgb2xkSWRUb0R1cGxpY2F0ZWRJZC5zZXQoZWxlbWVudC5pZCwgZHVwbGljYXRlZEVsZW1lbnQuaWQpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG5leHRFbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IG5leHRTY2VuZUVsZW1lbnRzID0gWy4uLm5leHRFbGVtZW50cywgLi4uZWxlbWVudHNUb0FwcGVuZF07XG4gICAgICAgICAgICBiaW5kVGV4dFRvU2hhcGVBZnRlckR1cGxpY2F0aW9uKG5leHRFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCk7XG4gICAgICAgICAgICBmaXhCaW5kaW5nc0FmdGVyRHVwbGljYXRpb24obmV4dFNjZW5lRWxlbWVudHMsIGVsZW1lbnRzVG9BcHBlbmQsIG9sZElkVG9EdXBsaWNhdGVkSWQsIFwiZHVwbGljYXRlc1NlcnZlQXNPbGRcIik7XG4gICAgICAgICAgICBiaW5kRWxlbWVudHNUb0ZyYW1lc0FmdGVyRHVwbGljYXRpb24obmV4dFNjZW5lRWxlbWVudHMsIGVsZW1lbnRzVG9BcHBlbmQsIG9sZElkVG9EdXBsaWNhdGVkSWQpO1xuICAgICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dFNjZW5lRWxlbWVudHMpO1xuICAgICAgICAgICAgdGhpcy5tYXliZUNhY2hlVmlzaWJsZUdhcHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMsIHRydWUpO1xuICAgICAgICAgICAgdGhpcy5tYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgdHJ1ZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IC8vIEl0IGlzIHZlcnkgaW1wb3J0YW50IHRvIHJlYWQgdGhpcy5zdGF0ZSB3aXRoaW4gZWFjaCBtb3ZlIGV2ZW50LFxuICAgICAgLy8gb3RoZXJ3aXNlIHdlIHdvdWxkIHJlYWQgYSBzdGFsZSBvbmUhXG5cblxuICAgICAgY29uc3QgZHJhZ2dpbmdFbGVtZW50ID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQ7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgY29uc3QgZHggPSBwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgY29uc3QgZHkgPSBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcbiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9pbnRzLmxlbmd0aCA+IDAgJiYgcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXTtcbiAgICAgICAgY29uc3QgZGlzY2FyZFBvaW50ID0gbGFzdFBvaW50ICYmIGxhc3RQb2ludFswXSA9PT0gZHggJiYgbGFzdFBvaW50WzFdID09PSBkeTtcblxuICAgICAgICBpZiAoIWRpc2NhcmRQb2ludCkge1xuICAgICAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGRyYWdnaW5nRWxlbWVudC5zaW11bGF0ZVByZXNzdXJlID8gZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcyA6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucHJlc3N1cmVzLCBldmVudC5wcmVzc3VyZV07XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dLFxuICAgICAgICAgICAgcHJlc3N1cmVzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoaXNMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgbGV0IGR4ID0gZ3JpZFggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgbGV0IGR5ID0gZ3JpZFkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcblxuICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpICYmIHBvaW50cy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICAoe1xuICAgICAgICAgICAgd2lkdGg6IGR4LFxuICAgICAgICAgICAgaGVpZ2h0OiBkeVxuICAgICAgICAgIH0gPSBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUoZHJhZ2dpbmdFbGVtZW50LngsIGRyYWdnaW5nRWxlbWVudC55LCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBvaW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLCBbZHgsIGR5XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cy5zbGljZSgwLCAtMSksIFtkeCwgZHldXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgICAgICAvLyBXaGVuIGNyZWF0aW5nIGEgbGluZWFyIGVsZW1lbnQgYnkgZHJhZ2dpbmdcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdzRm9yTGluZWFyRWxlbWVudEF0Q29vcmRzKGRyYWdnaW5nRWxlbWVudCwgW3BvaW50ZXJDb29yZHNdLCB0aGlzLnN0YXRlLnN0YXJ0Qm91bmRFbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuICAgICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuYm94U2VsZWN0aW9uLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpOyAvLyBib3gtc2VsZWN0IGxpbmUgZWRpdG9yIHBvaW50c1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVCb3hTZWxlY3Rpb24oZXZlbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKSk7IC8vIHJlZ3VsYXIgYm94LXNlbGVjdFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxldCBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IHRydWU7XG5cbiAgICAgICAgICBpZiAoIWV2ZW50LnNoaWZ0S2V5ICYmIGlzU29tZUVsZW1lbnRTZWxlY3RlZChlbGVtZW50cywgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLndpdGhDbWRPckN0cmwgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgICAgW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uID0gZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24oZWxlbWVudHMsIGRyYWdnaW5nRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2hvdWxkUmV1c2VTZWxlY3Rpb24gJiYgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgIGFjY1tlbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgICAgIHJldHVybiBhY2M7XG4gICAgICAgICAgICB9LCB7fSkpO1xuXG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICAvLyBpZiB1c2luZyBjdHJsL2NtZCwgc2VsZWN0IHRoZSBoaXRFbGVtZW50IG9ubHkgaWYgd2VcbiAgICAgICAgICAgICAgLy8gaGF2ZW4ndCBib3gtc2VsZWN0ZWQgYW55dGhpbmcgZWxzZVxuICAgICAgICAgICAgICBpZiAoIWVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudC5pZF0gPSB0cnVlO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXZTdGF0ZSA9ICFzaG91bGRSZXVzZVNlbGVjdGlvbiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGxcbiAgICAgICAgICAgIH0pIDogcHJldlN0YXRlO1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dFNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgLy8gc2VsZWN0IGxpbmVhciBlbGVtZW50IG9ubHkgd2hlbiB3ZSBoYXZlbid0IGJveC1zZWxlY3RlZCBhbnl0aGluZyBlbHNlXG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24ubGVuZ3RoID09PSAxICYmIGlzTGluZWFyRWxlbWVudChlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSwgdGhpcy5zY2VuZSkgOiBudWxsLFxuICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCA9PT0gMSAmJiAoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0ubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdKSkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9IC8vIFJldHVybnMgd2hldGhlciB0aGUgcG9pbnRlciBtb3ZlIGhhcHBlbmVkIG92ZXIgZWl0aGVyIHNjcm9sbGJhclxuXG5cbiAgaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSkge1xuICAgIGlmIChwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVySG9yaXpvbnRhbCkge1xuICAgICAgY29uc3QgeCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICBjb25zdCBkeCA9IHggLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueDtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYIC0gZHggLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSB4O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJWZXJ0aWNhbCkge1xuICAgICAgY29uc3QgeSA9IGV2ZW50LmNsaWVudFk7XG4gICAgICBjb25zdCBkeSA9IHkgLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueTtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZIC0gZHkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSB5O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgb25Qb2ludGVyVXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGNoaWxkRXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2Y7XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSkge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZS5mbHVzaCgpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIGRyYWdnaW5nRWxlbWVudCxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50LFxuICAgICAgICBtdWx0aUVsZW1lbnQsXG4gICAgICAgIGFjdGl2ZVRvb2wsXG4gICAgICAgIGlzUmVzaXppbmcsXG4gICAgICAgIGlzUm90YXRpbmdcbiAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzUmVzaXppbmc6IGZhbHNlLFxuICAgICAgICBpc1JvdGF0aW5nOiBmYWxzZSxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50OiBudWxsLFxuICAgICAgICBzZWxlY3Rpb25FbGVtZW50OiBudWxsLFxuICAgICAgICBmcmFtZVRvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIixcbiAgICAgICAgLy8gdGV4dCBlbGVtZW50cyBhcmUgcmVzZXQgb24gZmluYWxpemUsIGFuZCByZXNldHRpbmcgb24gcG9pbnRlcnVwXG4gICAgICAgIC8vIG1heSBjYXVzZSBpc3N1ZXMgd2l0aCBkb3VibGUgdGFwc1xuICAgICAgICBlZGl0aW5nRWxlbWVudDogbXVsdGlFbGVtZW50IHx8IGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPyB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50IDogbnVsbCxcbiAgICAgICAgc25hcExpbmVzOiBbXSxcbiAgICAgICAgb3JpZ2luU25hcE9mZnNldDogbnVsbFxuICAgICAgfSk7XG4gICAgICBTbmFwQ2FjaGUuc2V0UmVmZXJlbmNlU25hcFBvaW50cyhudWxsKTtcbiAgICAgIFNuYXBDYWNoZS5zZXRWaXNpYmxlR2FwcyhudWxsKTtcbiAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoY2hpbGRFdmVudC5jbGllbnRYLCBjaGlsZEV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogZmFsc2VcbiAgICAgIH0pO1xuICAgICAgdGhpcy5vblBvaW50ZXJVcEVtaXR0ZXIudHJpZ2dlcih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wsIHBvaW50ZXJEb3duU3RhdGUsIGNoaWxkRXZlbnQpOyAvLyBIYW5kbGUgZW5kIG9mIGRyYWdnaW5nIGEgcG9pbnQgb2YgYSBsaW5lYXIgZWxlbWVudCwgbWlnaHQgY2xvc2UgYSBsb29wXG4gICAgICAvLyBhbmQgc2V0cyBiaW5kaW5nIGVsZW1lbnRcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmJveFNlbGVjdGlvbi5oYXNPY2N1cnJlZCAmJiAoKF9iID0gKF9hID0gcG9pbnRlckRvd25TdGF0ZS5oaXQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuaWQpICE9PSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCkge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBlZGl0aW5nTGluZWFyRWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlclVwKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgICAgaWYgKGVkaXRpbmdMaW5lYXJFbGVtZW50ICE9PSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQsXG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgIGlmICgoKF9kID0gKF9jID0gcG9pbnRlckRvd25TdGF0ZS5oaXQpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5lbGVtZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuaWQpICE9PSB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5lbGVtZW50SWQpIHtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVMZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpOyAvLyBzZXQgc2VsZWN0ZWRMaW5lYXJFbGVtZW50IHRvIG51bGwgaWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSBlbGVtZW50IHNlbGVjdGVkIHNpbmNlIHdlIGRvbid0IHdhbnQgdG8gc2hvdyBsaW5lYXIgZWxlbWVudCBoYW5kbGVzXG5cbiAgICAgICAgICBpZiAoc2VsZWN0ZWRFTGVtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBudWxsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudEVkaXRvciA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlclVwKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICBjb25zdCB7XG4gICAgICAgICAgICBzdGFydEJpbmRpbmdFbGVtZW50LFxuICAgICAgICAgICAgZW5kQmluZGluZ0VsZW1lbnRcbiAgICAgICAgICB9ID0gbGluZWFyRWxlbWVudEVkaXRvcjtcbiAgICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KGxpbmVhckVsZW1lbnRFZGl0b3IuZWxlbWVudElkKTtcblxuICAgICAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgICBiaW5kT3JVbmJpbmRMaW5lYXJFbGVtZW50KGVsZW1lbnQsIHN0YXJ0QmluZGluZ0VsZW1lbnQsIGVuZEJpbmRpbmdFbGVtZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAobGluZWFyRWxlbWVudEVkaXRvciAhPT0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgbGluZWFyRWxlbWVudEVkaXRvciksIHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IG51bGxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSk7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uVXApO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbktleURvd24pO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlVcCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICgoZHJhZ2dpbmdFbGVtZW50ID09PSBudWxsIHx8IGRyYWdnaW5nRWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZHJhZ2dpbmdFbGVtZW50LnR5cGUpID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhjaGlsZEV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgbGV0IGR4ID0gcG9pbnRlckNvb3Jkcy54IC0gZHJhZ2dpbmdFbGVtZW50Lng7XG4gICAgICAgIGxldCBkeSA9IHBvaW50ZXJDb29yZHMueSAtIGRyYWdnaW5nRWxlbWVudC55OyAvLyBBbGxvd3MgZG90cyB0byBhdm9pZCBiZWluZyBmbGFnZ2VkIGFzIGluZmluaXRlbHkgc21hbGxcblxuICAgICAgICBpZiAoZHggPT09IHBvaW50c1swXVswXSAmJiBkeSA9PT0gcG9pbnRzWzBdWzFdKSB7XG4gICAgICAgICAgZHkgKz0gMC4wMDAxO1xuICAgICAgICAgIGR4ICs9IDAuMDAwMTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGRyYWdnaW5nRWxlbWVudC5zaW11bGF0ZVByZXNzdXJlID8gW10gOiBbLi4uZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcywgY2hpbGRFdmVudC5wcmVzc3VyZV07XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLCBbZHgsIGR5XV0sXG4gICAgICAgICAgcHJlc3N1cmVzLFxuICAgICAgICAgIGxhc3RDb21taXR0ZWRQb2ludDogW2R4LCBkeV1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNJbWFnZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSkge1xuICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSBkcmFnZ2luZ0VsZW1lbnQ7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5maWx0ZXIoZWwgPT4gZWwuaWQgIT09IGltYWdlRWxlbWVudC5pZCkpO1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzTGluZWFyRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpKSB7XG4gICAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQucG9pbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmIGRyYWdnaW5nRWxlbWVudCAmJiAhbXVsdGlFbGVtZW50KSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLmRyYWdnaW5nRWxlbWVudC5wb2ludHMsIFtwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueCwgcG9pbnRlckNvb3Jkcy55IC0gZHJhZ2dpbmdFbGVtZW50LnldXVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgbXVsdGlFbGVtZW50OiBkcmFnZ2luZ0VsZW1lbnQsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudDogdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnRcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgIW11bHRpRWxlbWVudCkge1xuICAgICAgICAgIGlmIChpc0JpbmRpbmdFbmFibGVkKHRoaXMuc3RhdGUpICYmIGlzQmluZGluZ0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgICAgICAgIG1heWJlQmluZExpbmVhckVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLCBwb2ludGVyQ29vcmRzKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXSxcbiAgICAgICAgICAgIHN0YXJ0Qm91bmRFbGVtZW50OiBudWxsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBpZiAoIWFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgICAgW2RyYWdnaW5nRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgfSksIHByZXZTdGF0ZSksXG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnNjZW5lKVxuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGxcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgZHJhZ2dpbmdFbGVtZW50ICYmIGlzSW52aXNpYmx5U21hbGxFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgLy8gcmVtb3ZlIGludmlzaWJsZSBlbGVtZW50IHdoaWNoIHdhcyBhZGRlZCBpbiBvblBvaW50ZXJEb3duXG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuc2xpY2UoMCwgLTEpKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQpIHtcbiAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCkge1xuICAgICAgICAgIGNvbnN0IHNjZW5lQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUpOyAvLyB3aGVuIGVkaXRpbmcgdGhlIHBvaW50cyBvZiBhIGxpbmVhciBlbGVtZW50LCB3ZSBjaGVjayBpZiB0aGVcbiAgICAgICAgICAvLyBsaW5lYXIgZWxlbWVudCBzdGlsbCBpcyBpbiB0aGUgZnJhbWUgYWZ0ZXJ3YXJkc1xuICAgICAgICAgIC8vIGlmIG5vdCwgdGhlIGxpbmVhciBlbGVtZW50IHdpbGwgYmUgcmVtb3ZlZCBmcm9tIGl0cyBmcmFtZSAoaWYgYW55KVxuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50ICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgIGNvbnN0IGxpbmVhckVsZW1lbnQgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuZWxlbWVudElkKTtcblxuICAgICAgICAgICAgaWYgKGxpbmVhckVsZW1lbnQgPT09IG51bGwgfHwgbGluZWFyRWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbGluZWFyRWxlbWVudC5mcmFtZUlkKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGZyYW1lID0gZ2V0Q29udGFpbmluZ0ZyYW1lKGxpbmVhckVsZW1lbnQpO1xuXG4gICAgICAgICAgICAgIGlmIChmcmFtZSAmJiBsaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFlbGVtZW50T3ZlcmxhcHNXaXRoRnJhbWUobGluZWFyRWxlbWVudCwgZnJhbWUpKSB7XG4gICAgICAgICAgICAgICAgICAvLyByZW1vdmUgdGhlIGxpbmVhciBlbGVtZW50IGZyb20gYWxsIGdyb3Vwc1xuICAgICAgICAgICAgICAgICAgLy8gYmVmb3JlIHJlbW92aW5nIGl0IGZyb20gdGhlIGZyYW1lIGFzIHdlbGxcbiAgICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQobGluZWFyRWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgICBncm91cElkczogW11cbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMocmVtb3ZlRWxlbWVudHNGcm9tRnJhbWUodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgW2xpbmVhckVsZW1lbnRdLCB0aGlzLnN0YXRlKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHNlbGVjdGVkIGVsZW1lbnRzIGFuZCBmcmFtZXNcbiAgICAgICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHNjZW5lQ29vcmRzKTtcbiAgICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBsZXQgbmV4dEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcblxuICAgICAgICAgICAgY29uc3QgdXBkYXRlR3JvdXBJZHNBZnRlckVkaXRpbmdHcm91cCA9IGVsZW1lbnRzID0+IHtcbiAgICAgICAgICAgICAgaWYgKGVsZW1lbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZWxlbWVudHMpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gZWxlbWVudC5ncm91cElkcy5pbmRleE9mKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQpO1xuICAgICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICAgIGdyb3VwSWRzOiBlbGVtZW50Lmdyb3VwSWRzLnNsaWNlKDAsIGluZGV4KVxuICAgICAgICAgICAgICAgICAgfSwgZmFsc2UpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG5leHRFbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQuZ3JvdXBJZHMubGVuZ3RoICYmIGdldEVsZW1lbnRzSW5Hcm91cChuZXh0RWxlbWVudHMsIGVsZW1lbnQuZ3JvdXBJZHNbZWxlbWVudC5ncm91cElkcy5sZW5ndGggLSAxXSkubGVuZ3RoIDwgMikge1xuICAgICAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgICBncm91cElkczogW11cbiAgICAgICAgICAgICAgICAgICAgfSwgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKHRvcExheWVyRnJhbWUgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RvcExheWVyRnJhbWUuaWRdKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzVG9BZGQgPSBzZWxlY3RlZEVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQuZnJhbWVJZCAhPT0gdG9wTGF5ZXJGcmFtZS5pZCAmJiBpc0VsZW1lbnRJbkZyYW1lKGVsZW1lbnQsIG5leHRFbGVtZW50cywgdGhpcy5zdGF0ZSkpO1xuXG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkKSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlR3JvdXBJZHNBZnRlckVkaXRpbmdHcm91cChlbGVtZW50c1RvQWRkKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIG5leHRFbGVtZW50cyA9IGFkZEVsZW1lbnRzVG9GcmFtZShuZXh0RWxlbWVudHMsIGVsZW1lbnRzVG9BZGQsIHRvcExheWVyRnJhbWUpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICghdG9wTGF5ZXJGcmFtZSkge1xuICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzVG9SZW1vdmUgPSBzZWxlY3RlZEVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQuZnJhbWVJZCAmJiAhaXNFbGVtZW50SW5GcmFtZShlbGVtZW50LCBuZXh0RWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcbiAgICAgICAgICAgICAgICB1cGRhdGVHcm91cElkc0FmdGVyRWRpdGluZ0dyb3VwKGVsZW1lbnRzVG9SZW1vdmUpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG5leHRFbGVtZW50cyA9IHVwZGF0ZUZyYW1lTWVtYmVyc2hpcE9mU2VsZWN0ZWRFbGVtZW50cyhuZXh0RWxlbWVudHMsIHRoaXMuc3RhdGUsIHRoaXMpO1xuICAgICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dEVsZW1lbnRzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZHJhZ2dpbmdFbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzSW5zaWRlRnJhbWUgPSBnZXRFbGVtZW50c0luTmV3RnJhbWUodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZHJhZ2dpbmdFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhhZGRFbGVtZW50c1RvRnJhbWUodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZWxlbWVudHNJbnNpZGVGcmFtZSwgZHJhZ2dpbmdFbGVtZW50KSk7XG4gICAgICAgIH1cblxuICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZ2V0Tm9ybWFsaXplZERpbWVuc2lvbnMoZHJhZ2dpbmdFbGVtZW50KSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChyZXNpemluZ0VsZW1lbnQpIHtcbiAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgfVxuXG4gICAgICBpZiAocmVzaXppbmdFbGVtZW50ICYmIGlzSW52aXNpYmx5U21hbGxFbGVtZW50KHJlc2l6aW5nRWxlbWVudCkpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5maWx0ZXIoZWwgPT4gZWwuaWQgIT09IHJlc2l6aW5nRWxlbWVudC5pZCkpO1xuICAgICAgfSAvLyBoYW5kbGUgZnJhbWUgbWVtYmVyc2hpcCBmb3IgcmVzaXppbmcgZnJhbWVzIGFuZC9vciBzZWxlY3RlZCBlbGVtZW50c1xuXG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5pc1Jlc2l6aW5nKSB7XG4gICAgICAgIGxldCBuZXh0RWxlbWVudHMgPSB1cGRhdGVGcmFtZU1lbWJlcnNoaXBPZlNlbGVjdGVkRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcy5zdGF0ZSwgdGhpcyk7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRnJhbWVzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGZyYW1lIG9mIHNlbGVjdGVkRnJhbWVzKSB7XG4gICAgICAgICAgbmV4dEVsZW1lbnRzID0gcmVwbGFjZUFsbEVsZW1lbnRzSW5GcmFtZShuZXh0RWxlbWVudHMsIGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGZyYW1lLCB0aGlzLnN0YXRlKSwgZnJhbWUsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dEVsZW1lbnRzKTtcbiAgICAgIH0gLy8gQ29kZSBiZWxvdyBoYW5kbGVzIHNlbGVjdGlvbiB3aGVuIGVsZW1lbnQocykgd2VyZW4ndFxuICAgICAgLy8gZHJhZyBvciBhZGRlZCB0byBzZWxlY3Rpb24gb24gcG9pbnRlciBkb3duIHBoYXNlLlxuXG5cbiAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuXG4gICAgICBpZiAoKChfZSA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSA9PT0gbnVsbCB8fCBfZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2UuZWxlbWVudElkKSAhPT0gKGhpdEVsZW1lbnQgPT09IG51bGwgfHwgaGl0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogaGl0RWxlbWVudC5pZCkgJiYgaXNMaW5lYXJFbGVtZW50KGhpdEVsZW1lbnQpKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRUxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7IC8vIHNldCBzZWxlY3RlZExpbmVhckVsZW1lbnQgd2hlbiBubyBvdGhlciBlbGVtZW50IHNlbGVjdGVkIGV4Y2VwdFxuICAgICAgICAvLyB0aGUgb25lIHdlJ3ZlIGhpdFxuXG4gICAgICAgIGlmIChzZWxlY3RlZEVMZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihoaXRFbGVtZW50LCB0aGlzLnNjZW5lKVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICBjb25zdCBkcmFnZ2VkRGlzdGFuY2UgPSBkaXN0YW5jZTJkKHRoaXMubGFzdFBvaW50ZXJEb3duLmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJEb3duLmNsaWVudFksIHRoaXMubGFzdFBvaW50ZXJVcC5jbGllbnRYLCB0aGlzLmxhc3RQb2ludGVyVXAuY2xpZW50WSk7XG5cbiAgICAgICAgaWYgKGRyYWdnZWREaXN0YW5jZSA9PT0gMCkge1xuICAgICAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICBjbGllbnRYOiB0aGlzLmxhc3RQb2ludGVyVXAuY2xpZW50WCxcbiAgICAgICAgICAgIGNsaWVudFk6IHRoaXMubGFzdFBvaW50ZXJVcC5jbGllbnRZXG4gICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgY29uc3QgaGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbihzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpO1xuICAgICAgICAgIGhpdEVsZW1lbnRzLmZvckVhY2goaGl0RWxlbWVudCA9PiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2hpdEVsZW1lbnQuaWRdID0ge1xuICAgICAgICAgICAgZXJhc2U6IHRydWUsXG4gICAgICAgICAgICBvcGFjaXR5OiBoaXRFbGVtZW50Lm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZXJhc2VFbGVtZW50cyhwb2ludGVyRG93blN0YXRlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlKS5sZW5ndGgpIHtcbiAgICAgICAgdGhpcy5yZXN0b3JlUmVhZHlUb0VyYXNlRWxlbWVudHMocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChoaXRFbGVtZW50ICYmICFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lndhc0FkZGVkVG9TZWxlY3Rpb24gJiYgKCAvLyBpZiB3ZSdyZSBlZGl0aW5nIGEgbGluZSwgcG9pbnRlcnVwIHNob3VsZG4ndCBzd2l0Y2ggc2VsZWN0aW9uIGlmXG4gICAgICAvLyBib3ggc2VsZWN0ZWRcbiAgICAgICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8ICFwb2ludGVyRG93blN0YXRlLmJveFNlbGVjdGlvbi5oYXNPY2N1cnJlZCkpIHtcbiAgICAgICAgLy8gd2hlbiBpbnNpZGUgbGluZSBlZGl0b3IsIHNoaWZ0IHNlbGVjdHMgcG9pbnRzIGluc3RlYWRcbiAgICAgICAgaWYgKGNoaWxkRXZlbnQuc2hpZnRLZXkgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF0pIHtcbiAgICAgICAgICAgIGlmIChpc1NlbGVjdGVkVmlhR3JvdXAodGhpcy5zdGF0ZSwgaGl0RWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShfcHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgX3ByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpOyAvLyBXZSB3YW50IHRvIHVuc2VsZWN0IGFsbCBncm91cHMgaGl0RWxlbWVudCBpcyBwYXJ0IG9mXG4gICAgICAgICAgICAgICAgLy8gYXMgd2VsbCBhcyBhbGwgZWxlbWVudHMgdGhhdCBhcmUgcGFydCBvZiB0aGUgZ3JvdXBzXG4gICAgICAgICAgICAgICAgLy8gaGl0RWxlbWVudCBpcyBwYXJ0IG9mXG5cbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGdyb3VwZWRFbGVtZW50IG9mIGhpdEVsZW1lbnQuZ3JvdXBJZHMuZmxhdE1hcChncm91cElkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBncm91cElkKSkpIHtcbiAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2dyb3VwZWRFbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIGhpdEVsZW1lbnQuZ3JvdXBJZHMubWFwKGdJZCA9PiAoe1xuICAgICAgICAgICAgICAgICAgICBbZ0lkXTogZmFsc2VcbiAgICAgICAgICAgICAgICAgIH0pKS5yZWR1Y2UoKHByZXYsIGFjYykgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2KSwgYWNjKSwge30pKSxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMobmV4dFNlbGVjdGVkRWxlbWVudElkcywgX3ByZXZTdGF0ZSlcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICB9KTsgLy8gaWYgbm90IGdyYWdnaW5nIGEgbGluZWFyIGVsZW1lbnQgcG9pbnQgKG91dHNpZGUgZWRpdG9yKVxuICAgICAgICAgICAgfSBlbHNlIGlmICghKChfZiA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuaXNEcmFnZ2luZykpIHtcbiAgICAgICAgICAgICAgLy8gcmVtb3ZlIGVsZW1lbnQgZnJvbSBzZWxlY3Rpb24gd2hpbGVcbiAgICAgICAgICAgICAgLy8ga2VlcGluZyBwcmV2IGVsZW1lbnRzIHNlbGVjdGVkXG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXdTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTtcbiAgICAgICAgICAgICAgICBkZWxldGUgbmV3U2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgIGNvbnN0IG5ld1NlbGVjdGVkRWxlbWVudHMgPSBnZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHtcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV3U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXdTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICAgICAgLy8gc2V0IHNlbGVjdGVkTGluZWFyRWxlbWVudCBvbmx5IGlmIHRoYXRzIHRoZSBvbmx5IGVsZW1lbnQgc2VsZWN0ZWRcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbmV3U2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNMaW5lYXJFbGVtZW50KG5ld1NlbGVjdGVkRWxlbWVudHNbMF0pID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IobmV3U2VsZWN0ZWRFbGVtZW50c1swXSwgdGhpcy5zY2VuZSkgOiBwcmV2U3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSBpZiAoaGl0RWxlbWVudC5mcmFtZUlkICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuZnJhbWVJZF0pIHtcbiAgICAgICAgICAgIC8vIHdoZW4gaGl0RWxlbWVudCBpcyBwYXJ0IG9mIGEgc2VsZWN0ZWQgZnJhbWUsIGRlc2VsZWN0IHRoZSBmcmFtZVxuICAgICAgICAgICAgLy8gdG8gYXZvaWQgZnJhbWUgYW5kIGNvbnRhaW5pbmcgZWxlbWVudHMgc2VsZWN0ZWQgc2ltdWx0YW5lb3VzbHlcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9KTsgLy8gZGVzZWxlY3QgdGhlIGZyYW1lXG5cbiAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5mcmFtZUlkXTsgLy8gZGVzZWxlY3QgZ3JvdXBzIGNvbnRhaW5pbmcgdGhlIGZyYW1lXG5cbiAgICAgICAgICAgICAgKChfYiA9IChfYSA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudChoaXRFbGVtZW50LmZyYW1lSWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZ3JvdXBJZHMpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IFtdKS5mbGF0TWFwKGdpZCA9PiBnZXRFbGVtZW50c0luR3JvdXAodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZ2lkKSkuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBoaXRFbGVtZW50LmxpbmsgfHwgaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSA/IFwiaW5mb1wiIDogZmFsc2VcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gYWRkIGVsZW1lbnQgdG8gc2VsZWN0aW9uIHdoaWxlIGtlZXBpbmcgcHJldiBlbGVtZW50cyBzZWxlY3RlZFxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShfcHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgfSksIF9wcmV2U3RhdGUpXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IGlzTGluZWFyRWxlbWVudChoaXRFbGVtZW50KSAmJiAvLyBEb24ndCBzZXQgYHNlbGVjdGVkTGluZWFyRWxlbWVudGAgaWYgaXRzIHNhbWUgYXMgdGhlIGhpdEVsZW1lbnQsIHRoaXMgaXMgbWFpbmx5IHRvIHByZXZlbnQgcmVzZXR0aW5nIHRoZSBgaG92ZXJQb2ludEluZGV4YCB0byAtMS5cbiAgICAgICAgICAgICAgLy8gRnV0dXJlIHdlIHNob3VsZCB1cGRhdGUgdGhlIEFQSSB0byB0YWtlIGNhcmUgb2Ygc2V0dGluZyB0aGUgY29ycmVjdCBgaG92ZXJQb2ludEluZGV4YCB3aGVuIGluaXRpYWxpemVkXG4gICAgICAgICAgICAgICgoX2EgPSBwcmV2U3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudElkKSAhPT0gaGl0RWxlbWVudC5pZCA/IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKGhpdEVsZW1lbnQsIHRoaXMuc2NlbmUpIDogcHJldlN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgIXRoaXMuc3RhdGUuaXNSZXNpemluZyAmJiAoaGl0RWxlbWVudCAmJiBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQoaGl0RWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkgfHwgIWhpdEVsZW1lbnQgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpKSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIERlc2VsZWN0IHNlbGVjdGVkIGVsZW1lbnRzXG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICghYWN0aXZlVG9vbC5sb2NrZWQgJiYgYWN0aXZlVG9vbC50eXBlICE9PSBcImZyZWVkcmF3XCIgJiYgZHJhZ2dpbmdFbGVtZW50ICYmIGRyYWdnaW5nRWxlbWVudC50eXBlICE9PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICBbZHJhZ2dpbmdFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgIH0pLCBwcmV2U3RhdGUpLFxuICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogaXNFbWJlZGRhYmxlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpICYmICFkcmFnZ2luZ0VsZW1lbnQubGluayA/IFwiZWRpdG9yXCIgOiBwcmV2U3RhdGUuc2hvd0h5cGVybGlua1BvcHVwXG4gICAgICAgIH0pKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiB8fCBpc1NvbWVFbGVtZW50U2VsZWN0ZWQodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgfVxuXG4gICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkIHx8IGlzUmVzaXppbmcgfHwgaXNSb3RhdGluZykge1xuICAgICAgICAoaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSA/IGJpbmRPclVuYmluZFNlbGVjdGVkRWxlbWVudHMgOiB1bmJpbmRMaW5lYXJFbGVtZW50cykodGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFhY3RpdmVUb29sLmxvY2tlZCAmJiBhY3RpdmVUb29sLnR5cGUgIT09IFwiZnJlZWRyYXdcIikge1xuICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXSxcbiAgICAgICAgICBhY3RpdmVUb29sOiB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChoaXRFbGVtZW50ICYmIHRoaXMubGFzdFBvaW50ZXJVcCAmJiB0aGlzLmxhc3RQb2ludGVyRG93biAmJiB0aGlzLmxhc3RQb2ludGVyVXAudGltZVN0YW1wIC0gdGhpcy5sYXN0UG9pbnRlckRvd24udGltZVN0YW1wIDwgMzAwICYmIGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA8PSAxICYmIGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgdGhpcy5sYXN0UG9pbnRlclVwLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSkge1xuICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayhoaXRFbGVtZW50KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIG1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cykge1xuICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDUwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgc3VnZ2VzdGVkQmluZGluZ3MgPSBnZXRFbGlnaWJsZUVsZW1lbnRzRm9yQmluZGluZyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzXG4gICAgfSk7XG4gIH1cblxuICBjbGVhclNlbGVjdGlvbihoaXRFbGVtZW50KSB7XG4gICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHByZXZTdGF0ZSksXG4gICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsLFxuICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAvLyBDb250aW51ZSBlZGl0aW5nIHRoZSBzYW1lIGdyb3VwIGlmIHRoZSB1c2VyIHNlbGVjdGVkIGEgZGlmZmVyZW50XG4gICAgICAvLyBlbGVtZW50IGZyb20gaXRcbiAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQgJiYgaGl0RWxlbWVudCAhPSBudWxsICYmIGlzRWxlbWVudEluR3JvdXAoaGl0RWxlbWVudCwgcHJldlN0YXRlLmVkaXRpbmdHcm91cElkKSA/IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCA6IG51bGxcbiAgICB9KSk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGwsXG4gICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczogdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNcbiAgICB9KTtcbiAgfVxuXG4gIGdldFRleHRXeXNpd3lnU25hcHBlZFRvQ2VudGVyUG9zaXRpb24oeCwgeSwgYXBwU3RhdGUsIGNvbnRhaW5lcikge1xuICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgIGxldCBlbGVtZW50Q2VudGVyWCA9IGNvbnRhaW5lci54ICsgY29udGFpbmVyLndpZHRoIC8gMjtcbiAgICAgIGxldCBlbGVtZW50Q2VudGVyWSA9IGNvbnRhaW5lci55ICsgY29udGFpbmVyLmhlaWdodCAvIDI7XG4gICAgICBjb25zdCBlbGVtZW50Q2VudGVyID0gZ2V0Q29udGFpbmVyQ2VudGVyKGNvbnRhaW5lciwgYXBwU3RhdGUpO1xuXG4gICAgICBpZiAoZWxlbWVudENlbnRlcikge1xuICAgICAgICBlbGVtZW50Q2VudGVyWCA9IGVsZW1lbnRDZW50ZXIueDtcbiAgICAgICAgZWxlbWVudENlbnRlclkgPSBlbGVtZW50Q2VudGVyLnk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRpc3RhbmNlVG9DZW50ZXIgPSBNYXRoLmh5cG90KHggLSBlbGVtZW50Q2VudGVyWCwgeSAtIGVsZW1lbnRDZW50ZXJZKTtcbiAgICAgIGNvbnN0IGlzU25hcHBlZFRvQ2VudGVyID0gZGlzdGFuY2VUb0NlbnRlciA8IFRFWFRfVE9fQ0VOVEVSX1NOQVBfVEhSRVNIT0xEO1xuXG4gICAgICBpZiAoaXNTbmFwcGVkVG9DZW50ZXIpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHZpZXdwb3J0WCxcbiAgICAgICAgICB5OiB2aWV3cG9ydFlcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBlbGVtZW50Q2VudGVyWCxcbiAgICAgICAgICBzY2VuZVk6IGVsZW1lbnRDZW50ZXJZXG4gICAgICAgIH0sIGFwcFN0YXRlKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB2aWV3cG9ydFgsXG4gICAgICAgICAgdmlld3BvcnRZLFxuICAgICAgICAgIGVsZW1lbnRDZW50ZXJYLFxuICAgICAgICAgIGVsZW1lbnRDZW50ZXJZXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZ2V0Q2FudmFzT2Zmc2V0cygpIHtcbiAgICB2YXIgX2E7XG5cbiAgICBpZiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkge1xuICAgICAgY29uc3QgZXhjYWxpZHJhd0NvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgY29uc3Qge1xuICAgICAgICBsZWZ0LFxuICAgICAgICB0b3BcbiAgICAgIH0gPSBleGNhbGlkcmF3Q29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgb2Zmc2V0TGVmdDogbGVmdCxcbiAgICAgICAgb2Zmc2V0VG9wOiB0b3BcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIG9mZnNldExlZnQ6IDAsXG4gICAgICBvZmZzZXRUb3A6IDBcbiAgICB9O1xuICB9XG5cbiAgdXBkYXRlTGFuZ3VhZ2UoKSB7XG4gICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGNvbnN0IGN1cnJlbnRMYW5nID0gbGFuZ3VhZ2VzLmZpbmQobGFuZyA9PiBsYW5nLmNvZGUgPT09IHRoaXMucHJvcHMubGFuZ0NvZGUpIHx8IGRlZmF1bHRMYW5nO1xuICAgICAgeWllbGQgc2V0TGFuZ3VhZ2UoY3VycmVudExhbmcpO1xuICAgICAgdGhpcy5zZXRBcHBTdGF0ZSh7fSk7XG4gICAgfSk7XG4gIH1cblxufVxuXG5BcHAuZGVmYXVsdFByb3BzID0ge1xuICAvLyBuZWVkZWQgZm9yIHRlc3RzIHRvIHBhc3Mgc2luY2Ugd2UgZGlyZWN0bHkgcmVuZGVyIEFwcCBpbiBtYW55IHRlc3RzXG4gIFVJT3B0aW9uczogREVGQVVMVF9VSV9PUFRJT05TXG59O1xuXG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IEVOVi5URVNUIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICB3aW5kb3cuaCA9IHdpbmRvdy5oIHx8IHt9O1xuICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh3aW5kb3cuaCwge1xuICAgIGVsZW1lbnRzOiB7XG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG5cbiAgICAgIGdldCgpIHtcbiAgICAgICAgdmFyIF9hO1xuXG4gICAgICAgIHJldHVybiAoX2EgPSB0aGlzLmFwcCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuICAgICAgfSxcblxuICAgICAgc2V0KGVsZW1lbnRzKSB7XG4gICAgICAgIHZhciBfYTtcblxuICAgICAgICByZXR1cm4gKF9hID0gdGhpcy5hcHApID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgICAgfVxuXG4gICAgfVxuICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgQXBwOyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../components/App.tsx\n");
2243
2243
 
2244
2244
  /***/ }),
2245
2245
 
@@ -4021,7 +4021,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
4021
4021
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4022
4022
 
4023
4023
  "use strict";
4024
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../constants */ \"../../constants.ts\");\n\n\nif (\"development\" !== _constants__WEBPACK_IMPORTED_MODULE_0__.ENV.TEST) {\n /* eslint-disable */\n\n /* global __webpack_public_path__:writable */\n __webpack_require__.p = window.EXCALIDRAW_ASSET_PATH || `https://unpkg.com/${\"@dwelle/excalidraw\"}@${\"0.4.0-ab25481\"}/dist/`;\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9wdWJsaWNQYXRoLmpzLmpzIiwibWFwcGluZ3MiOiI7O0FBQXNDOztBQUV0QyxJQUFJLGFBQW9CLEtBQUssZ0RBQVE7QUFDckM7O0FBRUE7QUFDQSxFQUFFLHFCQUF1Qix3REFBd0Qsb0JBQXlCLENBQUMsR0FBRyxlQUE0QixDQUFDO0FBQzNJIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vcHVibGljUGF0aC5qcz8wZTMxIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEVOViB9IGZyb20gXCIuLi8uLi9jb25zdGFudHNcIjtcblxuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBFTlYuVEVTVCkge1xuICAvKiBlc2xpbnQtZGlzYWJsZSAqL1xuXG4gIC8qIGdsb2JhbCBfX3dlYnBhY2tfcHVibGljX3BhdGhfXzp3cml0YWJsZSAqL1xuICBfX3dlYnBhY2tfcHVibGljX3BhdGhfXyA9IHdpbmRvdy5FWENBTElEUkFXX0FTU0VUX1BBVEggfHwgYGh0dHBzOi8vdW5wa2cuY29tLyR7cHJvY2Vzcy5lbnYuVklURV9QS0dfTkFNRX1AJHtwcm9jZXNzLmVudi5WSVRFX1BLR19WRVJTSU9OfS9kaXN0L2A7XG59Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./publicPath.js\n");
4024
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../constants */ \"../../constants.ts\");\n\n\nif (\"development\" !== _constants__WEBPACK_IMPORTED_MODULE_0__.ENV.TEST) {\n /* eslint-disable */\n\n /* global __webpack_public_path__:writable */\n __webpack_require__.p = window.EXCALIDRAW_ASSET_PATH || `https://unpkg.com/${\"@dwelle/excalidraw\"}@${\"0.4.0-ab8616b\"}/dist/`;\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9wdWJsaWNQYXRoLmpzLmpzIiwibWFwcGluZ3MiOiI7O0FBQXNDOztBQUV0QyxJQUFJLGFBQW9CLEtBQUssZ0RBQVE7QUFDckM7O0FBRUE7QUFDQSxFQUFFLHFCQUF1Qix3REFBd0Qsb0JBQXlCLENBQUMsR0FBRyxlQUE0QixDQUFDO0FBQzNJIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vcHVibGljUGF0aC5qcz8wZTMxIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEVOViB9IGZyb20gXCIuLi8uLi9jb25zdGFudHNcIjtcblxuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBFTlYuVEVTVCkge1xuICAvKiBlc2xpbnQtZGlzYWJsZSAqL1xuXG4gIC8qIGdsb2JhbCBfX3dlYnBhY2tfcHVibGljX3BhdGhfXzp3cml0YWJsZSAqL1xuICBfX3dlYnBhY2tfcHVibGljX3BhdGhfXyA9IHdpbmRvdy5FWENBTElEUkFXX0FTU0VUX1BBVEggfHwgYGh0dHBzOi8vdW5wa2cuY29tLyR7cHJvY2Vzcy5lbnYuVklURV9QS0dfTkFNRX1AJHtwcm9jZXNzLmVudi5WSVRFX1BLR19WRVJTSU9OfS9kaXN0L2A7XG59Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./publicPath.js\n");
4025
4025
 
4026
4026
  /***/ }),
4027
4027
 
@@ -4186,7 +4186,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
4186
4186
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4187
4187
 
4188
4188
  "use strict";
4189
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"SVG_EXPORT_TAG\": () => (/* binding */ SVG_EXPORT_TAG),\n/* harmony export */ \"exportToCanvas\": () => (/* binding */ exportToCanvas),\n/* harmony export */ \"exportToSvg\": () => (/* binding */ exportToSvg),\n/* harmony export */ \"getCanvasSize\": () => (/* binding */ getCanvasSize)\n/* harmony export */ });\n/* harmony import */ var roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! roughjs/bin/rough */ \"../../../node_modules/roughjs/bin/rough.js\");\n/* harmony import */ var _element_bounds__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../element/bounds */ \"../../element/bounds.ts\");\n/* harmony import */ var _renderer_renderScene__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../renderer/renderScene */ \"../../renderer/renderScene.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\n/* harmony import */ var _data_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../data/json */ \"../../data/json.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../element/image */ \"../../element/image.ts\");\n/* harmony import */ var _data_restore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../data/restore */ \"../../data/restore.ts\");\n/* harmony import */ var _Scene__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./Scene */ \"../../scene/Scene.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\nconst SVG_EXPORT_TAG = `<!-- svg-source:excalidraw -->`;\n/**\n * This API is usually used as a precursor to searializing to Blob or PNG,\n * but can also be used to create a canvas for other purposes.\n */\n\nconst exportToCanvas = ({\n data,\n config\n}) => __awaiter(void 0, void 0, void 0, function* () {\n var _a, _b, _c, _d, _e, _f, _g, _h; // initialize defaults\n // ---------------------------------------------------------------------------\n\n\n const {\n elements,\n files\n } = data;\n const appState = (0,_data_restore__WEBPACK_IMPORTED_MODULE_7__.restoreAppState)(data.appState, null); // clone\n\n const cfg = Object.assign({}, config);\n cfg.fit = (_a = cfg.fit) !== null && _a !== void 0 ? _a : cfg.width != null || cfg.height != null || cfg.maxWidthOrHeight != null || cfg.widthOrHeight != null ? \"contain\" : \"none\";\n const containPadding = cfg.fit === \"contain\";\n\n if (cfg.x != null || cfg.x != null) {\n cfg.fit = \"none\";\n }\n\n if (cfg.fit === \"cover\") {\n if (cfg.padding && \"development\" !== _constants__WEBPACK_IMPORTED_MODULE_4__.ENV.PRODUCTION) {\n console.warn(\"`padding` is ignored when `fit` is set to `cover`\");\n }\n\n cfg.padding = 0;\n }\n\n cfg.padding = (_b = cfg.padding) !== null && _b !== void 0 ? _b : 0;\n cfg.scale = (_c = cfg.scale) !== null && _c !== void 0 ? _c : 1;\n cfg.origin = (_d = cfg.origin) !== null && _d !== void 0 ? _d : \"canvas\";\n cfg.position = (_e = cfg.position) !== null && _e !== void 0 ? _e : \"center\";\n\n if (cfg.maxWidthOrHeight != null && cfg.widthOrHeight != null) {\n if (\"development\" !== _constants__WEBPACK_IMPORTED_MODULE_4__.ENV.PRODUCTION) {\n console.warn(\"`maxWidthOrHeight` is ignored when `widthOrHeight` is set\");\n }\n\n cfg.maxWidthOrHeight = undefined;\n }\n\n if ((cfg.maxWidthOrHeight != null || cfg.width != null || cfg.height != null) && cfg.getDimensions) {\n if (\"development\" !== _constants__WEBPACK_IMPORTED_MODULE_4__.ENV.PRODUCTION) {\n console.warn(\"`getDimensions` is ignored when `width`, `height`, or `maxWidthOrHeight` is set\");\n }\n\n cfg.getDimensions = undefined;\n } // ---------------------------------------------------------------------------\n // value used to scale the canvas context. By default, we use this to\n // make the canvas fit into the frame (e.g. for `cfg.fit` set to `contain`).\n // If `cfg.scale` is set, we multiply the resulting canvasScale by it to\n // scale the output further.\n\n\n let canvasScale = 1;\n const origCanvasSize = getCanvasSize(elements); // cfg.x = undefined;\n // cfg.y = undefined;\n // variables for original content bounding box\n\n const [origX, origY, origWidth, origHeight] = origCanvasSize; // variables for target bounding box\n\n let [x, y, width, height] = origCanvasSize;\n\n if (cfg.width != null) {\n width = cfg.width;\n\n if (cfg.padding && containPadding) {\n width -= cfg.padding * 2;\n }\n\n if (cfg.height) {\n height = cfg.height;\n\n if (cfg.padding && containPadding) {\n height -= cfg.padding * 2;\n }\n } else {\n // if height not specified, scale the original height to match the new\n // width while maintaining aspect ratio\n height *= width / origWidth;\n }\n } else if (cfg.height != null) {\n height = cfg.height;\n\n if (cfg.padding && containPadding) {\n height -= cfg.padding * 2;\n } // width not specified, so scale the original width to match the new\n // height while maintaining aspect ratio\n\n\n width *= height / origHeight;\n }\n\n if (cfg.maxWidthOrHeight != null || cfg.widthOrHeight != null) {\n if (containPadding && cfg.padding) {\n if (cfg.maxWidthOrHeight != null) {\n cfg.maxWidthOrHeight -= cfg.padding * 2;\n } else if (cfg.widthOrHeight != null) {\n cfg.widthOrHeight -= cfg.padding * 2;\n }\n }\n\n const max = Math.max(width, height);\n\n if (cfg.widthOrHeight != null) {\n // calculate by how much do we need to scale the canvas to fit into the\n // target dimension (e.g. target: max 50px, actual: 70x100px => scale: 0.5)\n canvasScale = cfg.widthOrHeight / max;\n } else if (cfg.maxWidthOrHeight != null) {\n canvasScale = cfg.maxWidthOrHeight < max ? cfg.maxWidthOrHeight / max : 1;\n }\n\n width *= canvasScale;\n height *= canvasScale;\n } else if (cfg.getDimensions) {\n const ret = cfg.getDimensions(width, height);\n width = ret.width;\n height = ret.height;\n cfg.scale = (_f = ret.scale) !== null && _f !== void 0 ? _f : cfg.scale;\n } else if (containPadding && cfg.padding && cfg.width == null && cfg.height == null) {\n const whRatio = width / height;\n width -= cfg.padding * 2;\n height -= cfg.padding * 2 / whRatio;\n }\n\n if (cfg.fit === \"contain\" && !cfg.maxWidthOrHeight || containPadding && cfg.padding) {\n if (cfg.fit === \"contain\") {\n const wRatio = width / origWidth;\n const hRatio = height / origHeight; // scale the orig canvas to fit in the target frame\n\n canvasScale = Math.min(wRatio, hRatio);\n } else {\n const wRatio = (width - cfg.padding * 2) / width;\n const hRatio = (height - cfg.padding * 2) / height;\n canvasScale = Math.min(wRatio, hRatio);\n }\n } else if (cfg.fit === \"cover\") {\n const wRatio = width / origWidth;\n const hRatio = height / origHeight; // scale the orig canvas to fill the the target frame\n // (opposite of \"contain\")\n\n canvasScale = Math.max(wRatio, hRatio);\n }\n\n x = (_g = cfg.x) !== null && _g !== void 0 ? _g : origX;\n y = (_h = cfg.y) !== null && _h !== void 0 ? _h : origY; // if we switch to \"content\" coords, we need to offset cfg-supplied\n // coords by the x/y of content bounding box\n\n if (cfg.origin === \"content\") {\n if (cfg.x != null) {\n x += origX;\n }\n\n if (cfg.y != null) {\n y += origY;\n }\n } // Centering the content to the frame.\n // We divide width/height by canvasScale so that we calculate in the original\n // aspect ratio dimensions.\n\n\n if (cfg.position === \"center\") {\n x -= width / canvasScale / 2 - (cfg.x == null ? origWidth : width + cfg.padding * 2) / 2;\n y -= height / canvasScale / 2 - (cfg.y == null ? origHeight : height + cfg.padding * 2) / 2;\n }\n\n const canvas = cfg.createCanvas ? cfg.createCanvas() : document.createElement(\"canvas\");\n const onlyExportingSingleFrame = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.isOnlyExportingSingleFrame)(elements); // hack fix until we decide whose responsibility this should be\n\n if (onlyExportingSingleFrame) {\n cfg.padding = 0;\n } // rescale padding based on current canvasScale factor so that the resulting\n // padding is kept the same as supplied by user (with the exception of\n // `cfg.scale` being set, which also scales the padding)\n\n\n const normalizedPadding = cfg.padding / canvasScale; // scale the whole frame by cfg.scale (on top of whatever canvasScale we\n // calculated above)\n\n canvasScale *= cfg.scale;\n width *= cfg.scale;\n height *= cfg.scale;\n canvas.width = width + cfg.padding * 2 * cfg.scale;\n canvas.height = height + cfg.padding * 2 * cfg.scale;\n const {\n imageCache\n } = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_6__.updateImageCache)({\n imageCache: new Map(),\n fileIds: (0,_element_image__WEBPACK_IMPORTED_MODULE_6__.getInitializedImageElements)(elements).map(element => element.fileId),\n files: files || {}\n }); // console.log(elements, width, height, cfg, canvasScale);\n // console.log(elements, width, height, cfg, canvasScale);\n\n (0,_renderer_renderScene__WEBPACK_IMPORTED_MODULE_2__.renderStaticScene)({\n elements,\n visibleElements: elements,\n appState: Object.assign(Object.assign({}, appState), {\n width,\n height,\n offsetLeft: 0,\n offsetTop: 0,\n scrollX: -x + normalizedPadding,\n scrollY: -y + normalizedPadding,\n zoom: {\n value: _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_ZOOM_VALUE\n },\n shouldCacheIgnoreZoom: false,\n theme: cfg.theme || _constants__WEBPACK_IMPORTED_MODULE_4__.THEME.LIGHT\n }),\n rc: roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_0__[\"default\"].canvas(canvas),\n canvas,\n scale: canvasScale,\n renderConfig: {\n canvasBackgroundColor: cfg.canvasBackgroundColor === false ? // null indicates transparent background\n null : cfg.canvasBackgroundColor || appState.viewBackgroundColor || _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_BACKGROUND_COLOR,\n imageCache,\n renderGrid: false,\n isExporting: true\n }\n });\n return canvas;\n});\nconst exportToSvg = (elements, appState, files, opts) => __awaiter(void 0, void 0, void 0, function* () {\n var _j, _k, _l;\n\n const {\n exportPadding = _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_EXPORT_PADDING,\n viewBackgroundColor,\n exportScale = 1,\n exportEmbedScene\n } = appState;\n let metadata = \"\";\n\n if (exportEmbedScene) {\n try {\n metadata = yield (yield Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ../../src/data/image */ \"../../data/image.ts\"))).encodeSvgMetadata({\n text: (opts === null || opts === void 0 ? void 0 : opts.serializeAsJSON) ? (_j = opts === null || opts === void 0 ? void 0 : opts.serializeAsJSON) === null || _j === void 0 ? void 0 : _j.call(opts) : (0,_data_json__WEBPACK_IMPORTED_MODULE_5__.serializeAsJSON)(elements, appState, files || {}, \"local\")\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n let [minX, minY, width, height] = getCanvasSize(elements);\n width += exportPadding * 2;\n height += exportPadding * 2; // initialize SVG root\n\n const svgRoot = document.createElementNS(_constants__WEBPACK_IMPORTED_MODULE_4__.SVG_NS, \"svg\");\n svgRoot.setAttribute(\"version\", \"1.1\");\n svgRoot.setAttribute(\"xmlns\", _constants__WEBPACK_IMPORTED_MODULE_4__.SVG_NS);\n svgRoot.setAttribute(\"viewBox\", `0 0 ${width} ${height}`);\n svgRoot.setAttribute(\"width\", `${width * exportScale}`);\n svgRoot.setAttribute(\"height\", `${height * exportScale}`);\n\n if (appState.exportWithDarkMode) {\n svgRoot.setAttribute(\"filter\", _constants__WEBPACK_IMPORTED_MODULE_4__.THEME_FILTER);\n }\n\n let assetPath = \"https://excalidraw.com/\"; // Asset path needs to be determined only when using package\n\n if (true) {\n assetPath = window.EXCALIDRAW_ASSET_PATH || `https://unpkg.com/${\"@dwelle/excalidraw\"}@${({\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PORTAL_URL\":\"\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"https://app.excalidraw.com\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_ENABLE_SW\":\"\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_DISABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3000\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_PKG_NAME\":\"@dwelle/excalidraw\",\"VITE_PKG_VERSION\":\"0.4.0-ab25481\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).PKG_VERSION}`;\n\n if (assetPath === null || assetPath === void 0 ? void 0 : assetPath.startsWith(\"/\")) {\n assetPath = assetPath.replace(\"/\", `${window.location.origin}/`);\n }\n\n assetPath = `${assetPath}/dist/excalidraw-assets/`;\n } // do not apply clipping when we're exporting the whole scene\n\n\n const isExportingWholeCanvas = ((_l = (_k = _Scene__WEBPACK_IMPORTED_MODULE_8__[\"default\"].getScene(elements[0])) === null || _k === void 0 ? void 0 : _k.getNonDeletedElements()) === null || _l === void 0 ? void 0 : _l.length) === elements.length;\n const onlyExportingSingleFrame = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.isOnlyExportingSingleFrame)(elements);\n const offsetX = -minX + (onlyExportingSingleFrame ? 0 : exportPadding);\n const offsetY = -minY + (onlyExportingSingleFrame ? 0 : exportPadding);\n const exportingFrame = isExportingWholeCanvas || !onlyExportingSingleFrame ? undefined : elements.find(element => element.type === \"frame\");\n let exportingFrameClipPath = \"\";\n\n if (exportingFrame) {\n const [x1, y1, x2, y2] = (0,_element_bounds__WEBPACK_IMPORTED_MODULE_1__.getElementAbsoluteCoords)(exportingFrame);\n const cx = (x2 - x1) / 2 - (exportingFrame.x - x1);\n const cy = (y2 - y1) / 2 - (exportingFrame.y - y1);\n exportingFrameClipPath = `<clipPath id=${exportingFrame.id}>\n <rect transform=\"translate(${exportingFrame.x + offsetX} ${exportingFrame.y + offsetY}) rotate(${exportingFrame.angle} ${cx} ${cy})\"\n width=\"${exportingFrame.width}\"\n height=\"${exportingFrame.height}\"\n >\n </rect>\n </clipPath>`;\n }\n\n svgRoot.innerHTML = `\n ${SVG_EXPORT_TAG}\n ${metadata}\n <defs>\n <style class=\"style-fonts\">\n @font-face {\n font-family: \"Virgil\";\n src: url(\"https://excalidraw.com/Virgil.woff2\");\n }\n @font-face {\n font-family: \"Cascadia\";\n src: url(\"https://excalidraw.com/Cascadia.woff2\");\n }\n </style>\n ${exportingFrameClipPath}\n </defs>\n `; // render background rect\n\n if (appState.exportBackground && viewBackgroundColor) {\n const rect = svgRoot.ownerDocument.createElementNS(_constants__WEBPACK_IMPORTED_MODULE_4__.SVG_NS, \"rect\");\n rect.setAttribute(\"x\", \"0\");\n rect.setAttribute(\"y\", \"0\");\n rect.setAttribute(\"width\", `${width}`);\n rect.setAttribute(\"height\", `${height}`);\n rect.setAttribute(\"fill\", viewBackgroundColor);\n svgRoot.appendChild(rect);\n }\n\n const rsvg = roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_0__[\"default\"].svg(svgRoot);\n (0,_renderer_renderScene__WEBPACK_IMPORTED_MODULE_2__.renderSceneToSvg)(elements, rsvg, svgRoot, files || {}, {\n offsetX,\n offsetY,\n exportWithDarkMode: appState.exportWithDarkMode,\n exportingFrameId: (exportingFrame === null || exportingFrame === void 0 ? void 0 : exportingFrame.id) || null,\n renderEmbeddables: opts === null || opts === void 0 ? void 0 : opts.renderEmbeddables\n });\n return svgRoot;\n}); // calculate smallest area to fit the contents in\n\nconst getCanvasSize = elements => {\n // we should decide if we are exporting the whole canvas\n // if so, we are not clipping elements in the frame\n // and therefore, we should not do anything special\n var _a, _b;\n\n const isExportingWholeCanvas = ((_b = (_a = _Scene__WEBPACK_IMPORTED_MODULE_8__[\"default\"].getScene(elements[0])) === null || _a === void 0 ? void 0 : _a.getNonDeletedElements()) === null || _b === void 0 ? void 0 : _b.length) === elements.length;\n const onlyExportingSingleFrame = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.isOnlyExportingSingleFrame)(elements);\n\n if (!isExportingWholeCanvas || onlyExportingSingleFrame) {\n const frames = elements.filter(element => element.type === \"frame\");\n const exportedFrameIds = frames.reduce((acc, frame) => {\n acc[frame.id] = true;\n return acc;\n }, {}); // elements in a frame do not affect the canvas size if we're not exporting\n // the whole canvas\n\n elements = elements.filter(element => {\n var _a;\n\n return !exportedFrameIds[(_a = element.frameId) !== null && _a !== void 0 ? _a : \"\"];\n });\n }\n\n const [minX, minY, maxX, maxY] = (0,_element_bounds__WEBPACK_IMPORTED_MODULE_1__.getCommonBounds)(elements);\n const width = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.distance)(minX, maxX);\n const height = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.distance)(minY, maxY);\n return [minX, minY, width, height];\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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Q0FBOEMsdURBQWM7QUFDNUQsbUNBQW1DLGtFQUEwQjs7QUFFN0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUssSUFBSSxHQUFHO0FBQ1o7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDs7QUFFQSxtQ0FBbUMsZ0VBQWU7QUFDbEQsZ0JBQWdCLGdEQUFRO0FBQ3hCLGlCQUFpQixnREFBUTtBQUN6QjtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL3NjZW5lL2V4cG9ydC50cz8zZjRlIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX2F3YWl0ZXIgPSB0aGlzICYmIHRoaXMuX19hd2FpdGVyIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcbiAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkge1xuICAgICAgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7XG4gICAgfVxuXG4gICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xuICB9KTtcbn07XG5cbmltcG9ydCByb3VnaCBmcm9tIFwicm91Z2hqcy9iaW4vcm91Z2hcIjtcbmltcG9ydCB7IGdldENvbW1vbkJvdW5kcywgZ2V0RWxlbWVudEFic29sdXRlQ29vcmRzIH0gZnJvbSBcIi4uL2VsZW1lbnQvYm91bmRzXCI7XG5pbXBvcnQgeyByZW5kZXJTdGF0aWNTY2VuZSwgcmVuZGVyU2NlbmVUb1N2ZyB9IGZyb20gXCIuLi9yZW5kZXJlci9yZW5kZXJTY2VuZVwiO1xuaW1wb3J0IHsgZGlzdGFuY2UsIGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgeyBERUZBVUxUX0JBQ0tHUk9VTkRfQ09MT1IsIERFRkFVTFRfRVhQT1JUX1BBRERJTkcsIERFRkFVTFRfWk9PTV9WQUxVRSwgRU5WLCBTVkdfTlMsIFRIRU1FLCBUSEVNRV9GSUxURVIgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBzZXJpYWxpemVBc0pTT04gfSBmcm9tIFwiLi4vZGF0YS9qc29uXCI7XG5pbXBvcnQgeyBnZXRJbml0aWFsaXplZEltYWdlRWxlbWVudHMsIHVwZGF0ZUltYWdlQ2FjaGUgfSBmcm9tIFwiLi4vZWxlbWVudC9pbWFnZVwiO1xuaW1wb3J0IHsgcmVzdG9yZUFwcFN0YXRlIH0gZnJvbSBcIi4uL2RhdGEvcmVzdG9yZVwiO1xuaW1wb3J0IFNjZW5lIGZyb20gXCIuL1NjZW5lXCI7XG5leHBvcnQgY29uc3QgU1ZHX0VYUE9SVF9UQUcgPSBgPCEtLSBzdmctc291cmNlOmV4Y2FsaWRyYXcgLS0+YDtcbi8qKlxuICogVGhpcyBBUEkgaXMgdXN1YWxseSB1c2VkIGFzIGEgcHJlY3Vyc29yIHRvIHNlYXJpYWxpemluZyB0byBCbG9iIG9yIFBORyxcbiAqIGJ1dCBjYW4gYWxzbyBiZSB1c2VkIHRvIGNyZWF0ZSBhIGNhbnZhcyBmb3Igb3RoZXIgcHVycG9zZXMuXG4gKi9cblxuZXhwb3J0IGNvbnN0IGV4cG9ydFRvQ2FudmFzID0gKHtcbiAgZGF0YSxcbiAgY29uZmlnXG59KSA9PiBfX2F3YWl0ZXIodm9pZCAwLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaDsgLy8gaW5pdGlhbGl6ZSBkZWZhdWx0c1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gIGNvbnN0IHtcbiAgICBlbGVtZW50cyxcbiAgICBmaWxlc1xuICB9ID0gZGF0YTtcbiAgY29uc3QgYXBwU3RhdGUgPSByZXN0b3JlQXBwU3RhdGUoZGF0YS5hcHBTdGF0ZSwgbnVsbCk7IC8vIGNsb25lXG5cbiAgY29uc3QgY2ZnID0gT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnKTtcbiAgY2ZnLmZpdCA9IChfYSA9IGNmZy5maXQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IGNmZy53aWR0aCAhPSBudWxsIHx8IGNmZy5oZWlnaHQgIT0gbnVsbCB8fCBjZmcubWF4V2lkdGhPckhlaWdodCAhPSBudWxsIHx8IGNmZy53aWR0aE9ySGVpZ2h0ICE9IG51bGwgPyBcImNvbnRhaW5cIiA6IFwibm9uZVwiO1xuICBjb25zdCBjb250YWluUGFkZGluZyA9IGNmZy5maXQgPT09IFwiY29udGFpblwiO1xuXG4gIGlmIChjZmcueCAhPSBudWxsIHx8IGNmZy54ICE9IG51bGwpIHtcbiAgICBjZmcuZml0ID0gXCJub25lXCI7XG4gIH1cblxuICBpZiAoY2ZnLmZpdCA9PT0gXCJjb3ZlclwiKSB7XG4gICAgaWYgKGNmZy5wYWRkaW5nICYmIHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBFTlYuUFJPRFVDVElPTikge1xuICAgICAgY29uc29sZS53YXJuKFwiYHBhZGRpbmdgIGlzIGlnbm9yZWQgd2hlbiBgZml0YCBpcyBzZXQgdG8gYGNvdmVyYFwiKTtcbiAgICB9XG5cbiAgICBjZmcucGFkZGluZyA9IDA7XG4gIH1cblxuICBjZmcucGFkZGluZyA9IChfYiA9IGNmZy5wYWRkaW5nKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwO1xuICBjZmcuc2NhbGUgPSAoX2MgPSBjZmcuc2NhbGUpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IDE7XG4gIGNmZy5vcmlnaW4gPSAoX2QgPSBjZmcub3JpZ2luKSAhPT0gbnVsbCAmJiBfZCAhPT0gdm9pZCAwID8gX2QgOiBcImNhbnZhc1wiO1xuICBjZmcucG9zaXRpb24gPSAoX2UgPSBjZmcucG9zaXRpb24pICE9PSBudWxsICYmIF9lICE9PSB2b2lkIDAgPyBfZSA6IFwiY2VudGVyXCI7XG5cbiAgaWYgKGNmZy5tYXhXaWR0aE9ySGVpZ2h0ICE9IG51bGwgJiYgY2ZnLndpZHRoT3JIZWlnaHQgIT0gbnVsbCkge1xuICAgIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gRU5WLlBST0RVQ1RJT04pIHtcbiAgICAgIGNvbnNvbGUud2FybihcImBtYXhXaWR0aE9ySGVpZ2h0YCBpcyBpZ25vcmVkIHdoZW4gYHdpZHRoT3JIZWlnaHRgIGlzIHNldFwiKTtcbiAgICB9XG5cbiAgICBjZmcubWF4V2lkdGhPckhlaWdodCA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGlmICgoY2ZnLm1heFdpZHRoT3JIZWlnaHQgIT0gbnVsbCB8fCBjZmcud2lkdGggIT0gbnVsbCB8fCBjZmcuaGVpZ2h0ICE9IG51bGwpICYmIGNmZy5nZXREaW1lbnNpb25zKSB7XG4gICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBFTlYuUFJPRFVDVElPTikge1xuICAgICAgY29uc29sZS53YXJuKFwiYGdldERpbWVuc2lvbnNgIGlzIGlnbm9yZWQgd2hlbiBgd2lkdGhgLCBgaGVpZ2h0YCwgb3IgYG1heFdpZHRoT3JIZWlnaHRgIGlzIHNldFwiKTtcbiAgICB9XG5cbiAgICBjZmcuZ2V0RGltZW5zaW9ucyA9IHVuZGVmaW5lZDtcbiAgfSAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gdmFsdWUgdXNlZCB0byBzY2FsZSB0aGUgY2FudmFzIGNvbnRleHQuIEJ5IGRlZmF1bHQsIHdlIHVzZSB0aGlzIHRvXG4gIC8vIG1ha2UgdGhlIGNhbnZhcyBmaXQgaW50byB0aGUgZnJhbWUgKGUuZy4gZm9yIGBjZmcuZml0YCBzZXQgdG8gYGNvbnRhaW5gKS5cbiAgLy8gSWYgYGNmZy5zY2FsZWAgaXMgc2V0LCB3ZSBtdWx0aXBseSB0aGUgcmVzdWx0aW5nIGNhbnZhc1NjYWxlIGJ5IGl0IHRvXG4gIC8vIHNjYWxlIHRoZSBvdXRwdXQgZnVydGhlci5cblxuXG4gIGxldCBjYW52YXNTY2FsZSA9IDE7XG4gIGNvbnN0IG9yaWdDYW52YXNTaXplID0gZ2V0Q2FudmFzU2l6ZShlbGVtZW50cyk7IC8vIGNmZy54ID0gdW5kZWZpbmVkO1xuICAvLyBjZmcueSA9IHVuZGVmaW5lZDtcbiAgLy8gdmFyaWFibGVzIGZvciBvcmlnaW5hbCBjb250ZW50IGJvdW5kaW5nIGJveFxuXG4gIGNvbnN0IFtvcmlnWCwgb3JpZ1ksIG9yaWdXaWR0aCwgb3JpZ0hlaWdodF0gPSBvcmlnQ2FudmFzU2l6ZTsgLy8gdmFyaWFibGVzIGZvciB0YXJnZXQgYm91bmRpbmcgYm94XG5cbiAgbGV0IFt4LCB5LCB3aWR0aCwgaGVpZ2h0XSA9IG9yaWdDYW52YXNTaXplO1xuXG4gIGlmIChjZmcud2lkdGggIT0gbnVsbCkge1xuICAgIHdpZHRoID0gY2ZnLndpZHRoO1xuXG4gICAgaWYgKGNmZy5wYWRkaW5nICYmIGNvbnRhaW5QYWRkaW5nKSB7XG4gICAgICB3aWR0aCAtPSBjZmcucGFkZGluZyAqIDI7XG4gICAgfVxuXG4gICAgaWYgKGNmZy5oZWlnaHQpIHtcbiAgICAgIGhlaWdodCA9IGNmZy5oZWlnaHQ7XG5cbiAgICAgIGlmIChjZmcucGFkZGluZyAmJiBjb250YWluUGFkZGluZykge1xuICAgICAgICBoZWlnaHQgLT0gY2ZnLnBhZGRpbmcgKiAyO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBpZiBoZWlnaHQgbm90IHNwZWNpZmllZCwgc2NhbGUgdGhlIG9yaWdpbmFsIGhlaWdodCB0byBtYXRjaCB0aGUgbmV3XG4gICAgICAvLyB3aWR0aCB3aGlsZSBtYWludGFpbmluZyBhc3BlY3QgcmF0aW9cbiAgICAgIGhlaWdodCAqPSB3aWR0aCAvIG9yaWdXaWR0aDtcbiAgICB9XG4gIH0gZWxzZSBpZiAoY2ZnLmhlaWdodCAhPSBudWxsKSB7XG4gICAgaGVpZ2h0ID0gY2ZnLmhlaWdodDtcblxuICAgIGlmIChjZmcucGFkZGluZyAmJiBjb250YWluUGFkZGluZykge1xuICAgICAgaGVpZ2h0IC09IGNmZy5wYWRkaW5nICogMjtcbiAgICB9IC8vIHdpZHRoIG5vdCBzcGVjaWZpZWQsIHNvIHNjYWxlIHRoZSBvcmlnaW5hbCB3aWR0aCB0byBtYXRjaCB0aGUgbmV3XG4gICAgLy8gaGVpZ2h0IHdoaWxlIG1haW50YWluaW5nIGFzcGVjdCByYXRpb1xuXG5cbiAgICB3aWR0aCAqPSBoZWlnaHQgLyBvcmlnSGVpZ2h0O1xuICB9XG5cbiAgaWYgKGNmZy5tYXhXaWR0aE9ySGVpZ2h0ICE9IG51bGwgfHwgY2ZnLndpZHRoT3JIZWlnaHQgIT0gbnVsbCkge1xuICAgIGlmIChjb250YWluUGFkZGluZyAmJiBjZmcucGFkZGluZykge1xuICAgICAgaWYgKGNmZy5tYXhXaWR0aE9ySGVpZ2h0ICE9IG51bGwpIHtcbiAgICAgICAgY2ZnLm1heFdpZHRoT3JIZWlnaHQgLT0gY2ZnLnBhZGRpbmcgKiAyO1xuICAgICAgfSBlbHNlIGlmIChjZmcud2lkdGhPckhlaWdodCAhPSBudWxsKSB7XG4gICAgICAgIGNmZy53aWR0aE9ySGVpZ2h0IC09IGNmZy5wYWRkaW5nICogMjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBtYXggPSBNYXRoLm1heCh3aWR0aCwgaGVpZ2h0KTtcblxuICAgIGlmIChjZmcud2lkdGhPckhlaWdodCAhPSBudWxsKSB7XG4gICAgICAvLyBjYWxjdWxhdGUgYnkgaG93IG11Y2ggZG8gd2UgbmVlZCB0byBzY2FsZSB0aGUgY2FudmFzIHRvIGZpdCBpbnRvIHRoZVxuICAgICAgLy8gdGFyZ2V0IGRpbWVuc2lvbiAoZS5nLiB0YXJnZXQ6IG1heCA1MHB4LCBhY3R1YWw6IDcweDEwMHB4ID0+IHNjYWxlOiAwLjUpXG4gICAgICBjYW52YXNTY2FsZSA9IGNmZy53aWR0aE9ySGVpZ2h0IC8gbWF4O1xuICAgIH0gZWxzZSBpZiAoY2ZnLm1heFdpZHRoT3JIZWlnaHQgIT0gbnVsbCkge1xuICAgICAgY2FudmFzU2NhbGUgPSBjZmcubWF4V2lkdGhPckhlaWdodCA8IG1heCA/IGNmZy5tYXhXaWR0aE9ySGVpZ2h0IC8gbWF4IDogMTtcbiAgICB9XG5cbiAgICB3aWR0aCAqPSBjYW52YXNTY2FsZTtcbiAgICBoZWlnaHQgKj0gY2FudmFzU2NhbGU7XG4gIH0gZWxzZSBpZiAoY2ZnLmdldERpbWVuc2lvbnMpIHtcbiAgICBjb25zdCByZXQgPSBjZmcuZ2V0RGltZW5zaW9ucyh3aWR0aCwgaGVpZ2h0KTtcbiAgICB3aWR0aCA9IHJldC53aWR0aDtcbiAgICBoZWlnaHQgPSByZXQuaGVpZ2h0O1xuICAgIGNmZy5zY2FsZSA9IChfZiA9IHJldC5zY2FsZSkgIT09IG51bGwgJiYgX2YgIT09IHZvaWQgMCA/IF9mIDogY2ZnLnNjYWxlO1xuICB9IGVsc2UgaWYgKGNvbnRhaW5QYWRkaW5nICYmIGNmZy5wYWRkaW5nICYmIGNmZy53aWR0aCA9PSBudWxsICYmIGNmZy5oZWlnaHQgPT0gbnVsbCkge1xuICAgIGNvbnN0IHdoUmF0aW8gPSB3aWR0aCAvIGhlaWdodDtcbiAgICB3aWR0aCAtPSBjZmcucGFkZGluZyAqIDI7XG4gICAgaGVpZ2h0IC09IGNmZy5wYWRkaW5nICogMiAvIHdoUmF0aW87XG4gIH1cblxuICBpZiAoY2ZnLmZpdCA9PT0gXCJjb250YWluXCIgJiYgIWNmZy5tYXhXaWR0aE9ySGVpZ2h0IHx8IGNvbnRhaW5QYWRkaW5nICYmIGNmZy5wYWRkaW5nKSB7XG4gICAgaWYgKGNmZy5maXQgPT09IFwiY29udGFpblwiKSB7XG4gICAgICBjb25zdCB3UmF0aW8gPSB3aWR0aCAvIG9yaWdXaWR0aDtcbiAgICAgIGNvbnN0IGhSYXRpbyA9IGhlaWdodCAvIG9yaWdIZWlnaHQ7IC8vIHNjYWxlIHRoZSBvcmlnIGNhbnZhcyB0byBmaXQgaW4gdGhlIHRhcmdldCBmcmFtZVxuXG4gICAgICBjYW52YXNTY2FsZSA9IE1hdGgubWluKHdSYXRpbywgaFJhdGlvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3Qgd1JhdGlvID0gKHdpZHRoIC0gY2ZnLnBhZGRpbmcgKiAyKSAvIHdpZHRoO1xuICAgICAgY29uc3QgaFJhdGlvID0gKGhlaWdodCAtIGNmZy5wYWRkaW5nICogMikgLyBoZWlnaHQ7XG4gICAgICBjYW52YXNTY2FsZSA9IE1hdGgubWluKHdSYXRpbywgaFJhdGlvKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoY2ZnLmZpdCA9PT0gXCJjb3ZlclwiKSB7XG4gICAgY29uc3Qgd1JhdGlvID0gd2lkdGggLyBvcmlnV2lkdGg7XG4gICAgY29uc3QgaFJhdGlvID0gaGVpZ2h0IC8gb3JpZ0hlaWdodDsgLy8gc2NhbGUgdGhlIG9yaWcgY2FudmFzIHRvIGZpbGwgdGhlIHRoZSB0YXJnZXQgZnJhbWVcbiAgICAvLyAob3Bwb3NpdGUgb2YgXCJjb250YWluXCIpXG5cbiAgICBjYW52YXNTY2FsZSA9IE1hdGgubWF4KHdSYXRpbywgaFJhdGlvKTtcbiAgfVxuXG4gIHggPSAoX2cgPSBjZmcueCkgIT09IG51bGwgJiYgX2cgIT09IHZvaWQgMCA/IF9nIDogb3JpZ1g7XG4gIHkgPSAoX2ggPSBjZmcueSkgIT09IG51bGwgJiYgX2ggIT09IHZvaWQgMCA/IF9oIDogb3JpZ1k7IC8vIGlmIHdlIHN3aXRjaCB0byBcImNvbnRlbnRcIiBjb29yZHMsIHdlIG5lZWQgdG8gb2Zmc2V0IGNmZy1zdXBwbGllZFxuICAvLyBjb29yZHMgYnkgdGhlIHgveSBvZiBjb250ZW50IGJvdW5kaW5nIGJveFxuXG4gIGlmIChjZmcub3JpZ2luID09PSBcImNvbnRlbnRcIikge1xuICAgIGlmIChjZmcueCAhPSBudWxsKSB7XG4gICAgICB4ICs9IG9yaWdYO1xuICAgIH1cblxuICAgIGlmIChjZmcueSAhPSBudWxsKSB7XG4gICAgICB5ICs9IG9yaWdZO1xuICAgIH1cbiAgfSAvLyBDZW50ZXJpbmcgdGhlIGNvbnRlbnQgdG8gdGhlIGZyYW1lLlxuICAvLyBXZSBkaXZpZGUgd2lkdGgvaGVpZ2h0IGJ5IGNhbnZhc1NjYWxlIHNvIHRoYXQgd2UgY2FsY3VsYXRlIGluIHRoZSBvcmlnaW5hbFxuICAvLyBhc3BlY3QgcmF0aW8gZGltZW5zaW9ucy5cblxuXG4gIGlmIChjZmcucG9zaXRpb24gPT09IFwiY2VudGVyXCIpIHtcbiAgICB4IC09IHdpZHRoIC8gY2FudmFzU2NhbGUgLyAyIC0gKGNmZy54ID09IG51bGwgPyBvcmlnV2lkdGggOiB3aWR0aCArIGNmZy5wYWRkaW5nICogMikgLyAyO1xuICAgIHkgLT0gaGVpZ2h0IC8gY2FudmFzU2NhbGUgLyAyIC0gKGNmZy55ID09IG51bGwgPyBvcmlnSGVpZ2h0IDogaGVpZ2h0ICsgY2ZnLnBhZGRpbmcgKiAyKSAvIDI7XG4gIH1cblxuICBjb25zdCBjYW52YXMgPSBjZmcuY3JlYXRlQ2FudmFzID8gY2ZnLmNyZWF0ZUNhbnZhcygpIDogZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgY29uc3Qgb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID0gaXNPbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUoZWxlbWVudHMpOyAvLyBoYWNrIGZpeCB1bnRpbCB3ZSBkZWNpZGUgd2hvc2UgcmVzcG9uc2liaWxpdHkgdGhpcyBzaG91bGQgYmVcblxuICBpZiAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKSB7XG4gICAgY2ZnLnBhZGRpbmcgPSAwO1xuICB9IC8vIHJlc2NhbGUgcGFkZGluZyBiYXNlZCBvbiBjdXJyZW50IGNhbnZhc1NjYWxlIGZhY3RvciBzbyB0aGF0IHRoZSByZXN1bHRpbmdcbiAgLy8gcGFkZGluZyBpcyBrZXB0IHRoZSBzYW1lIGFzIHN1cHBsaWVkIGJ5IHVzZXIgKHdpdGggdGhlIGV4Y2VwdGlvbiBvZlxuICAvLyBgY2ZnLnNjYWxlYCBiZWluZyBzZXQsIHdoaWNoIGFsc28gc2NhbGVzIHRoZSBwYWRkaW5nKVxuXG5cbiAgY29uc3Qgbm9ybWFsaXplZFBhZGRpbmcgPSBjZmcucGFkZGluZyAvIGNhbnZhc1NjYWxlOyAvLyBzY2FsZSB0aGUgd2hvbGUgZnJhbWUgYnkgY2ZnLnNjYWxlIChvbiB0b3Agb2Ygd2hhdGV2ZXIgY2FudmFzU2NhbGUgd2VcbiAgLy8gY2FsY3VsYXRlZCBhYm92ZSlcblxuICBjYW52YXNTY2FsZSAqPSBjZmcuc2NhbGU7XG4gIHdpZHRoICo9IGNmZy5zY2FsZTtcbiAgaGVpZ2h0ICo9IGNmZy5zY2FsZTtcbiAgY2FudmFzLndpZHRoID0gd2lkdGggKyBjZmcucGFkZGluZyAqIDIgKiBjZmcuc2NhbGU7XG4gIGNhbnZhcy5oZWlnaHQgPSBoZWlnaHQgKyBjZmcucGFkZGluZyAqIDIgKiBjZmcuc2NhbGU7XG4gIGNvbnN0IHtcbiAgICBpbWFnZUNhY2hlXG4gIH0gPSB5aWVsZCB1cGRhdGVJbWFnZUNhY2hlKHtcbiAgICBpbWFnZUNhY2hlOiBuZXcgTWFwKCksXG4gICAgZmlsZUlkczogZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzKGVsZW1lbnRzKS5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgZmlsZXM6IGZpbGVzIHx8IHt9XG4gIH0pOyAvLyBjb25zb2xlLmxvZyhlbGVtZW50cywgd2lkdGgsIGhlaWdodCwgY2ZnLCBjYW52YXNTY2FsZSk7XG4gIC8vIGNvbnNvbGUubG9nKGVsZW1lbnRzLCB3aWR0aCwgaGVpZ2h0LCBjZmcsIGNhbnZhc1NjYWxlKTtcblxuICByZW5kZXJTdGF0aWNTY2VuZSh7XG4gICAgZWxlbWVudHMsXG4gICAgdmlzaWJsZUVsZW1lbnRzOiBlbGVtZW50cyxcbiAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBhcHBTdGF0ZSksIHtcbiAgICAgIHdpZHRoLFxuICAgICAgaGVpZ2h0LFxuICAgICAgb2Zmc2V0TGVmdDogMCxcbiAgICAgIG9mZnNldFRvcDogMCxcbiAgICAgIHNjcm9sbFg6IC14ICsgbm9ybWFsaXplZFBhZGRpbmcsXG4gICAgICBzY3JvbGxZOiAteSArIG5vcm1hbGl6ZWRQYWRkaW5nLFxuICAgICAgem9vbToge1xuICAgICAgICB2YWx1ZTogREVGQVVMVF9aT09NX1ZBTFVFXG4gICAgICB9LFxuICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZSxcbiAgICAgIHRoZW1lOiBjZmcudGhlbWUgfHwgVEhFTUUuTElHSFRcbiAgICB9KSxcbiAgICByYzogcm91Z2guY2FudmFzKGNhbnZhcyksXG4gICAgY2FudmFzLFxuICAgIHNjYWxlOiBjYW52YXNTY2FsZSxcbiAgICByZW5kZXJDb25maWc6IHtcbiAgICAgIGNhbnZhc0JhY2tncm91bmRDb2xvcjogY2ZnLmNhbnZhc0JhY2tncm91bmRDb2xvciA9PT0gZmFsc2UgPyAvLyBudWxsIGluZGljYXRlcyB0cmFuc3BhcmVudCBiYWNrZ3JvdW5kXG4gICAgICBudWxsIDogY2ZnLmNhbnZhc0JhY2tncm91bmRDb2xvciB8fCBhcHBTdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yIHx8IERFRkFVTFRfQkFDS0dST1VORF9DT0xPUixcbiAgICAgIGltYWdlQ2FjaGUsXG4gICAgICByZW5kZXJHcmlkOiBmYWxzZSxcbiAgICAgIGlzRXhwb3J0aW5nOiB0cnVlXG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIGNhbnZhcztcbn0pO1xuZXhwb3J0IGNvbnN0IGV4cG9ydFRvU3ZnID0gKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMsIG9wdHMpID0+IF9fYXdhaXRlcih2b2lkIDAsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICB2YXIgX2osIF9rLCBfbDtcblxuICBjb25zdCB7XG4gICAgZXhwb3J0UGFkZGluZyA9IERFRkFVTFRfRVhQT1JUX1BBRERJTkcsXG4gICAgdmlld0JhY2tncm91bmRDb2xvcixcbiAgICBleHBvcnRTY2FsZSA9IDEsXG4gICAgZXhwb3J0RW1iZWRTY2VuZVxuICB9ID0gYXBwU3RhdGU7XG4gIGxldCBtZXRhZGF0YSA9IFwiXCI7XG5cbiAgaWYgKGV4cG9ydEVtYmVkU2NlbmUpIHtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSB5aWVsZCAoeWllbGQgaW1wb3J0KFxuICAgICAgLyogd2VicGFja0NodW5rTmFtZTogXCJpbWFnZVwiICovXG4gICAgICBcIi4uLy4uL3NyYy9kYXRhL2ltYWdlXCIpKS5lbmNvZGVTdmdNZXRhZGF0YSh7XG4gICAgICAgIHRleHQ6IChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuc2VyaWFsaXplQXNKU09OKSA/IChfaiA9IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5zZXJpYWxpemVBc0pTT04pID09PSBudWxsIHx8IF9qID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfai5jYWxsKG9wdHMpIDogc2VyaWFsaXplQXNKU09OKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMgfHwge30sIFwibG9jYWxcIilcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICB9XG4gIH1cblxuICBsZXQgW21pblgsIG1pblksIHdpZHRoLCBoZWlnaHRdID0gZ2V0Q2FudmFzU2l6ZShlbGVtZW50cyk7XG4gIHdpZHRoICs9IGV4cG9ydFBhZGRpbmcgKiAyO1xuICBoZWlnaHQgKz0gZXhwb3J0UGFkZGluZyAqIDI7IC8vIGluaXRpYWxpemUgU1ZHIHJvb3RcblxuICBjb25zdCBzdmdSb290ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgXCJzdmdcIik7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwidmVyc2lvblwiLCBcIjEuMVwiKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJ4bWxuc1wiLCBTVkdfTlMpO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcInZpZXdCb3hcIiwgYDAgMCAke3dpZHRofSAke2hlaWdodH1gKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJ3aWR0aFwiLCBgJHt3aWR0aCAqIGV4cG9ydFNjYWxlfWApO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcImhlaWdodFwiLCBgJHtoZWlnaHQgKiBleHBvcnRTY2FsZX1gKTtcblxuICBpZiAoYXBwU3RhdGUuZXhwb3J0V2l0aERhcmtNb2RlKSB7XG4gICAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJmaWx0ZXJcIiwgVEhFTUVfRklMVEVSKTtcbiAgfVxuXG4gIGxldCBhc3NldFBhdGggPSBcImh0dHBzOi8vZXhjYWxpZHJhdy5jb20vXCI7IC8vIEFzc2V0IHBhdGggbmVlZHMgdG8gYmUgZGV0ZXJtaW5lZCBvbmx5IHdoZW4gdXNpbmcgcGFja2FnZVxuXG4gIGlmIChwcm9jZXNzLmVudi5WSVRFX0lTX0VYQ0FMSURSQVdfTlBNX1BBQ0tBR0UpIHtcbiAgICBhc3NldFBhdGggPSB3aW5kb3cuRVhDQUxJRFJBV19BU1NFVF9QQVRIIHx8IGBodHRwczovL3VucGtnLmNvbS8ke3Byb2Nlc3MuZW52LlZJVEVfUEtHX05BTUV9QCR7cHJvY2Vzcy5lbnYuUEtHX1ZFUlNJT059YDtcblxuICAgIGlmIChhc3NldFBhdGggPT09IG51bGwgfHwgYXNzZXRQYXRoID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhc3NldFBhdGguc3RhcnRzV2l0aChcIi9cIikpIHtcbiAgICAgIGFzc2V0UGF0aCA9IGFzc2V0UGF0aC5yZXBsYWNlKFwiL1wiLCBgJHt3aW5kb3cubG9jYXRpb24ub3JpZ2lufS9gKTtcbiAgICB9XG5cbiAgICBhc3NldFBhdGggPSBgJHthc3NldFBhdGh9L2Rpc3QvZXhjYWxpZHJhdy1hc3NldHMvYDtcbiAgfSAvLyBkbyBub3QgYXBwbHkgY2xpcHBpbmcgd2hlbiB3ZSdyZSBleHBvcnRpbmcgdGhlIHdob2xlIHNjZW5lXG5cblxuICBjb25zdCBpc0V4cG9ydGluZ1dob2xlQ2FudmFzID0gKChfbCA9IChfayA9IFNjZW5lLmdldFNjZW5lKGVsZW1lbnRzWzBdKSkgPT09IG51bGwgfHwgX2sgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9rLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSA9PT0gbnVsbCB8fCBfbCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2wubGVuZ3RoKSA9PT0gZWxlbWVudHMubGVuZ3RoO1xuICBjb25zdCBvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPSBpc09ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZShlbGVtZW50cyk7XG4gIGNvbnN0IG9mZnNldFggPSAtbWluWCArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyk7XG4gIGNvbnN0IG9mZnNldFkgPSAtbWluWSArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyk7XG4gIGNvbnN0IGV4cG9ydGluZ0ZyYW1lID0gaXNFeHBvcnRpbmdXaG9sZUNhbnZhcyB8fCAhb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gdW5kZWZpbmVkIDogZWxlbWVudHMuZmluZChlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKTtcbiAgbGV0IGV4cG9ydGluZ0ZyYW1lQ2xpcFBhdGggPSBcIlwiO1xuXG4gIGlmIChleHBvcnRpbmdGcmFtZSkge1xuICAgIGNvbnN0IFt4MSwgeTEsIHgyLCB5Ml0gPSBnZXRFbGVtZW50QWJzb2x1dGVDb29yZHMoZXhwb3J0aW5nRnJhbWUpO1xuICAgIGNvbnN0IGN4ID0gKHgyIC0geDEpIC8gMiAtIChleHBvcnRpbmdGcmFtZS54IC0geDEpO1xuICAgIGNvbnN0IGN5ID0gKHkyIC0geTEpIC8gMiAtIChleHBvcnRpbmdGcmFtZS55IC0geTEpO1xuICAgIGV4cG9ydGluZ0ZyYW1lQ2xpcFBhdGggPSBgPGNsaXBQYXRoIGlkPSR7ZXhwb3J0aW5nRnJhbWUuaWR9PlxuICAgICAgICAgICAgPHJlY3QgdHJhbnNmb3JtPVwidHJhbnNsYXRlKCR7ZXhwb3J0aW5nRnJhbWUueCArIG9mZnNldFh9ICR7ZXhwb3J0aW5nRnJhbWUueSArIG9mZnNldFl9KSByb3RhdGUoJHtleHBvcnRpbmdGcmFtZS5hbmdsZX0gJHtjeH0gJHtjeX0pXCJcbiAgICAgICAgICB3aWR0aD1cIiR7ZXhwb3J0aW5nRnJhbWUud2lkdGh9XCJcbiAgICAgICAgICBoZWlnaHQ9XCIke2V4cG9ydGluZ0ZyYW1lLmhlaWdodH1cIlxuICAgICAgICAgID5cbiAgICAgICAgICA8L3JlY3Q+XG4gICAgICAgIDwvY2xpcFBhdGg+YDtcbiAgfVxuXG4gIHN2Z1Jvb3QuaW5uZXJIVE1MID0gYFxuICAke1NWR19FWFBPUlRfVEFHfVxuICAke21ldGFkYXRhfVxuICA8ZGVmcz5cbiAgICA8c3R5bGUgY2xhc3M9XCJzdHlsZS1mb250c1wiPlxuICAgICAgQGZvbnQtZmFjZSB7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBcIlZpcmdpbFwiO1xuICAgICAgICBzcmM6IHVybChcImh0dHBzOi8vZXhjYWxpZHJhdy5jb20vVmlyZ2lsLndvZmYyXCIpO1xuICAgICAgfVxuICAgICAgQGZvbnQtZmFjZSB7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBcIkNhc2NhZGlhXCI7XG4gICAgICAgIHNyYzogdXJsKFwiaHR0cHM6Ly9leGNhbGlkcmF3LmNvbS9DYXNjYWRpYS53b2ZmMlwiKTtcbiAgICAgIH1cbiAgICA8L3N0eWxlPlxuICAgICR7ZXhwb3J0aW5nRnJhbWVDbGlwUGF0aH1cbiAgPC9kZWZzPlxuICBgOyAvLyByZW5kZXIgYmFja2dyb3VuZCByZWN0XG5cbiAgaWYgKGFwcFN0YXRlLmV4cG9ydEJhY2tncm91bmQgJiYgdmlld0JhY2tncm91bmRDb2xvcikge1xuICAgIGNvbnN0IHJlY3QgPSBzdmdSb290Lm93bmVyRG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgXCJyZWN0XCIpO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwieFwiLCBcIjBcIik7XG4gICAgcmVjdC5zZXRBdHRyaWJ1dGUoXCJ5XCIsIFwiMFwiKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcIndpZHRoXCIsIGAke3dpZHRofWApO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwiaGVpZ2h0XCIsIGAke2hlaWdodH1gKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcImZpbGxcIiwgdmlld0JhY2tncm91bmRDb2xvcik7XG4gICAgc3ZnUm9vdC5hcHBlbmRDaGlsZChyZWN0KTtcbiAgfVxuXG4gIGNvbnN0IHJzdmcgPSByb3VnaC5zdmcoc3ZnUm9vdCk7XG4gIHJlbmRlclNjZW5lVG9TdmcoZWxlbWVudHMsIHJzdmcsIHN2Z1Jvb3QsIGZpbGVzIHx8IHt9LCB7XG4gICAgb2Zmc2V0WCxcbiAgICBvZmZzZXRZLFxuICAgIGV4cG9ydFdpdGhEYXJrTW9kZTogYXBwU3RhdGUuZXhwb3J0V2l0aERhcmtNb2RlLFxuICAgIGV4cG9ydGluZ0ZyYW1lSWQ6IChleHBvcnRpbmdGcmFtZSA9PT0gbnVsbCB8fCBleHBvcnRpbmdGcmFtZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhwb3J0aW5nRnJhbWUuaWQpIHx8IG51bGwsXG4gICAgcmVuZGVyRW1iZWRkYWJsZXM6IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yZW5kZXJFbWJlZGRhYmxlc1xuICB9KTtcbiAgcmV0dXJuIHN2Z1Jvb3Q7XG59KTsgLy8gY2FsY3VsYXRlIHNtYWxsZXN0IGFyZWEgdG8gZml0IHRoZSBjb250ZW50cyBpblxuXG5leHBvcnQgY29uc3QgZ2V0Q2FudmFzU2l6ZSA9IGVsZW1lbnRzID0+IHtcbiAgLy8gd2Ugc2hvdWxkIGRlY2lkZSBpZiB3ZSBhcmUgZXhwb3J0aW5nIHRoZSB3aG9sZSBjYW52YXNcbiAgLy8gaWYgc28sIHdlIGFyZSBub3QgY2xpcHBpbmcgZWxlbWVudHMgaW4gdGhlIGZyYW1lXG4gIC8vIGFuZCB0aGVyZWZvcmUsIHdlIHNob3VsZCBub3QgZG8gYW55dGhpbmcgc3BlY2lhbFxuICB2YXIgX2EsIF9iO1xuXG4gIGNvbnN0IGlzRXhwb3J0aW5nV2hvbGVDYW52YXMgPSAoKF9iID0gKF9hID0gU2NlbmUuZ2V0U2NlbmUoZWxlbWVudHNbMF0pKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5sZW5ndGgpID09PSBlbGVtZW50cy5sZW5ndGg7XG4gIGNvbnN0IG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA9IGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKGVsZW1lbnRzKTtcblxuICBpZiAoIWlzRXhwb3J0aW5nV2hvbGVDYW52YXMgfHwgb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKSB7XG4gICAgY29uc3QgZnJhbWVzID0gZWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuICAgIGNvbnN0IGV4cG9ydGVkRnJhbWVJZHMgPSBmcmFtZXMucmVkdWNlKChhY2MsIGZyYW1lKSA9PiB7XG4gICAgICBhY2NbZnJhbWUuaWRdID0gdHJ1ZTtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwge30pOyAvLyBlbGVtZW50cyBpbiBhIGZyYW1lIGRvIG5vdCBhZmZlY3QgdGhlIGNhbnZhcyBzaXplIGlmIHdlJ3JlIG5vdCBleHBvcnRpbmdcbiAgICAvLyB0aGUgd2hvbGUgY2FudmFzXG5cbiAgICBlbGVtZW50cyA9IGVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgcmV0dXJuICFleHBvcnRlZEZyYW1lSWRzWyhfYSA9IGVsZW1lbnQuZnJhbWVJZCkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogXCJcIl07XG4gICAgfSk7XG4gIH1cblxuICBjb25zdCBbbWluWCwgbWluWSwgbWF4WCwgbWF4WV0gPSBnZXRDb21tb25Cb3VuZHMoZWxlbWVudHMpO1xuICBjb25zdCB3aWR0aCA9IGRpc3RhbmNlKG1pblgsIG1heFgpO1xuICBjb25zdCBoZWlnaHQgPSBkaXN0YW5jZShtaW5ZLCBtYXhZKTtcbiAgcmV0dXJuIFttaW5YLCBtaW5ZLCB3aWR0aCwgaGVpZ2h0XTtcbn07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../scene/export.ts\n");
4189
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"SVG_EXPORT_TAG\": () => (/* binding */ SVG_EXPORT_TAG),\n/* harmony export */ \"exportToCanvas\": () => (/* binding */ exportToCanvas),\n/* harmony export */ \"exportToSvg\": () => (/* binding */ exportToSvg),\n/* harmony export */ \"getCanvasSize\": () => (/* binding */ getCanvasSize)\n/* harmony export */ });\n/* harmony import */ var roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! roughjs/bin/rough */ \"../../../node_modules/roughjs/bin/rough.js\");\n/* harmony import */ var _element_bounds__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../element/bounds */ \"../../element/bounds.ts\");\n/* harmony import */ var _renderer_renderScene__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../renderer/renderScene */ \"../../renderer/renderScene.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\n/* harmony import */ var _data_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../data/json */ \"../../data/json.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../element/image */ \"../../element/image.ts\");\n/* harmony import */ var _data_restore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../data/restore */ \"../../data/restore.ts\");\n/* harmony import */ var _Scene__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./Scene */ \"../../scene/Scene.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\nconst SVG_EXPORT_TAG = `<!-- svg-source:excalidraw -->`;\n/**\n * This API is usually used as a precursor to searializing to Blob or PNG,\n * but can also be used to create a canvas for other purposes.\n */\n\nconst exportToCanvas = ({\n data,\n config\n}) => __awaiter(void 0, void 0, void 0, function* () {\n var _a, _b, _c, _d, _e, _f, _g, _h; // initialize defaults\n // ---------------------------------------------------------------------------\n\n\n const {\n elements,\n files\n } = data;\n const appState = (0,_data_restore__WEBPACK_IMPORTED_MODULE_7__.restoreAppState)(data.appState, null); // clone\n\n const cfg = Object.assign({}, config);\n cfg.fit = (_a = cfg.fit) !== null && _a !== void 0 ? _a : cfg.width != null || cfg.height != null || cfg.maxWidthOrHeight != null || cfg.widthOrHeight != null ? \"contain\" : \"none\";\n const containPadding = cfg.fit === \"contain\";\n\n if (cfg.x != null || cfg.x != null) {\n cfg.fit = \"none\";\n }\n\n if (cfg.fit === \"cover\") {\n if (cfg.padding && \"development\" !== _constants__WEBPACK_IMPORTED_MODULE_4__.ENV.PRODUCTION) {\n console.warn(\"`padding` is ignored when `fit` is set to `cover`\");\n }\n\n cfg.padding = 0;\n }\n\n cfg.padding = (_b = cfg.padding) !== null && _b !== void 0 ? _b : 0;\n cfg.scale = (_c = cfg.scale) !== null && _c !== void 0 ? _c : 1;\n cfg.origin = (_d = cfg.origin) !== null && _d !== void 0 ? _d : \"canvas\";\n cfg.position = (_e = cfg.position) !== null && _e !== void 0 ? _e : \"center\";\n\n if (cfg.maxWidthOrHeight != null && cfg.widthOrHeight != null) {\n if (\"development\" !== _constants__WEBPACK_IMPORTED_MODULE_4__.ENV.PRODUCTION) {\n console.warn(\"`maxWidthOrHeight` is ignored when `widthOrHeight` is set\");\n }\n\n cfg.maxWidthOrHeight = undefined;\n }\n\n if ((cfg.maxWidthOrHeight != null || cfg.width != null || cfg.height != null) && cfg.getDimensions) {\n if (\"development\" !== _constants__WEBPACK_IMPORTED_MODULE_4__.ENV.PRODUCTION) {\n console.warn(\"`getDimensions` is ignored when `width`, `height`, or `maxWidthOrHeight` is set\");\n }\n\n cfg.getDimensions = undefined;\n } // ---------------------------------------------------------------------------\n // value used to scale the canvas context. By default, we use this to\n // make the canvas fit into the frame (e.g. for `cfg.fit` set to `contain`).\n // If `cfg.scale` is set, we multiply the resulting canvasScale by it to\n // scale the output further.\n\n\n let canvasScale = 1;\n const origCanvasSize = getCanvasSize(elements); // cfg.x = undefined;\n // cfg.y = undefined;\n // variables for original content bounding box\n\n const [origX, origY, origWidth, origHeight] = origCanvasSize; // variables for target bounding box\n\n let [x, y, width, height] = origCanvasSize;\n\n if (cfg.width != null) {\n width = cfg.width;\n\n if (cfg.padding && containPadding) {\n width -= cfg.padding * 2;\n }\n\n if (cfg.height) {\n height = cfg.height;\n\n if (cfg.padding && containPadding) {\n height -= cfg.padding * 2;\n }\n } else {\n // if height not specified, scale the original height to match the new\n // width while maintaining aspect ratio\n height *= width / origWidth;\n }\n } else if (cfg.height != null) {\n height = cfg.height;\n\n if (cfg.padding && containPadding) {\n height -= cfg.padding * 2;\n } // width not specified, so scale the original width to match the new\n // height while maintaining aspect ratio\n\n\n width *= height / origHeight;\n }\n\n if (cfg.maxWidthOrHeight != null || cfg.widthOrHeight != null) {\n if (containPadding && cfg.padding) {\n if (cfg.maxWidthOrHeight != null) {\n cfg.maxWidthOrHeight -= cfg.padding * 2;\n } else if (cfg.widthOrHeight != null) {\n cfg.widthOrHeight -= cfg.padding * 2;\n }\n }\n\n const max = Math.max(width, height);\n\n if (cfg.widthOrHeight != null) {\n // calculate by how much do we need to scale the canvas to fit into the\n // target dimension (e.g. target: max 50px, actual: 70x100px => scale: 0.5)\n canvasScale = cfg.widthOrHeight / max;\n } else if (cfg.maxWidthOrHeight != null) {\n canvasScale = cfg.maxWidthOrHeight < max ? cfg.maxWidthOrHeight / max : 1;\n }\n\n width *= canvasScale;\n height *= canvasScale;\n } else if (cfg.getDimensions) {\n const ret = cfg.getDimensions(width, height);\n width = ret.width;\n height = ret.height;\n cfg.scale = (_f = ret.scale) !== null && _f !== void 0 ? _f : cfg.scale;\n } else if (containPadding && cfg.padding && cfg.width == null && cfg.height == null) {\n const whRatio = width / height;\n width -= cfg.padding * 2;\n height -= cfg.padding * 2 / whRatio;\n }\n\n if (cfg.fit === \"contain\" && !cfg.maxWidthOrHeight || containPadding && cfg.padding) {\n if (cfg.fit === \"contain\") {\n const wRatio = width / origWidth;\n const hRatio = height / origHeight; // scale the orig canvas to fit in the target frame\n\n canvasScale = Math.min(wRatio, hRatio);\n } else {\n const wRatio = (width - cfg.padding * 2) / width;\n const hRatio = (height - cfg.padding * 2) / height;\n canvasScale = Math.min(wRatio, hRatio);\n }\n } else if (cfg.fit === \"cover\") {\n const wRatio = width / origWidth;\n const hRatio = height / origHeight; // scale the orig canvas to fill the the target frame\n // (opposite of \"contain\")\n\n canvasScale = Math.max(wRatio, hRatio);\n }\n\n x = (_g = cfg.x) !== null && _g !== void 0 ? _g : origX;\n y = (_h = cfg.y) !== null && _h !== void 0 ? _h : origY; // if we switch to \"content\" coords, we need to offset cfg-supplied\n // coords by the x/y of content bounding box\n\n if (cfg.origin === \"content\") {\n if (cfg.x != null) {\n x += origX;\n }\n\n if (cfg.y != null) {\n y += origY;\n }\n } // Centering the content to the frame.\n // We divide width/height by canvasScale so that we calculate in the original\n // aspect ratio dimensions.\n\n\n if (cfg.position === \"center\") {\n x -= width / canvasScale / 2 - (cfg.x == null ? origWidth : width + cfg.padding * 2) / 2;\n y -= height / canvasScale / 2 - (cfg.y == null ? origHeight : height + cfg.padding * 2) / 2;\n }\n\n const canvas = cfg.createCanvas ? cfg.createCanvas() : document.createElement(\"canvas\");\n const onlyExportingSingleFrame = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.isOnlyExportingSingleFrame)(elements); // hack fix until we decide whose responsibility this should be\n\n if (onlyExportingSingleFrame) {\n cfg.padding = 0;\n } // rescale padding based on current canvasScale factor so that the resulting\n // padding is kept the same as supplied by user (with the exception of\n // `cfg.scale` being set, which also scales the padding)\n\n\n const normalizedPadding = cfg.padding / canvasScale; // scale the whole frame by cfg.scale (on top of whatever canvasScale we\n // calculated above)\n\n canvasScale *= cfg.scale;\n width *= cfg.scale;\n height *= cfg.scale;\n canvas.width = width + cfg.padding * 2 * cfg.scale;\n canvas.height = height + cfg.padding * 2 * cfg.scale;\n const {\n imageCache\n } = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_6__.updateImageCache)({\n imageCache: new Map(),\n fileIds: (0,_element_image__WEBPACK_IMPORTED_MODULE_6__.getInitializedImageElements)(elements).map(element => element.fileId),\n files: files || {}\n }); // console.log(elements, width, height, cfg, canvasScale);\n // console.log(elements, width, height, cfg, canvasScale);\n\n (0,_renderer_renderScene__WEBPACK_IMPORTED_MODULE_2__.renderStaticScene)({\n elements,\n visibleElements: elements,\n appState: Object.assign(Object.assign({}, appState), {\n width,\n height,\n offsetLeft: 0,\n offsetTop: 0,\n scrollX: -x + normalizedPadding,\n scrollY: -y + normalizedPadding,\n zoom: {\n value: _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_ZOOM_VALUE\n },\n shouldCacheIgnoreZoom: false,\n theme: cfg.theme || _constants__WEBPACK_IMPORTED_MODULE_4__.THEME.LIGHT\n }),\n rc: roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_0__[\"default\"].canvas(canvas),\n canvas,\n scale: canvasScale,\n renderConfig: {\n canvasBackgroundColor: cfg.canvasBackgroundColor === false ? // null indicates transparent background\n null : cfg.canvasBackgroundColor || appState.viewBackgroundColor || _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_BACKGROUND_COLOR,\n imageCache,\n renderGrid: false,\n isExporting: true\n }\n });\n return canvas;\n});\nconst exportToSvg = (elements, appState, files, opts) => __awaiter(void 0, void 0, void 0, function* () {\n var _j, _k, _l;\n\n const {\n exportPadding = _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_EXPORT_PADDING,\n viewBackgroundColor,\n exportScale = 1,\n exportEmbedScene\n } = appState;\n let metadata = \"\";\n\n if (exportEmbedScene) {\n try {\n metadata = yield (yield Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ../../src/data/image */ \"../../data/image.ts\"))).encodeSvgMetadata({\n text: (opts === null || opts === void 0 ? void 0 : opts.serializeAsJSON) ? (_j = opts === null || opts === void 0 ? void 0 : opts.serializeAsJSON) === null || _j === void 0 ? void 0 : _j.call(opts) : (0,_data_json__WEBPACK_IMPORTED_MODULE_5__.serializeAsJSON)(elements, appState, files || {}, \"local\")\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n let [minX, minY, width, height] = getCanvasSize(elements);\n width += exportPadding * 2;\n height += exportPadding * 2; // initialize SVG root\n\n const svgRoot = document.createElementNS(_constants__WEBPACK_IMPORTED_MODULE_4__.SVG_NS, \"svg\");\n svgRoot.setAttribute(\"version\", \"1.1\");\n svgRoot.setAttribute(\"xmlns\", _constants__WEBPACK_IMPORTED_MODULE_4__.SVG_NS);\n svgRoot.setAttribute(\"viewBox\", `0 0 ${width} ${height}`);\n svgRoot.setAttribute(\"width\", `${width * exportScale}`);\n svgRoot.setAttribute(\"height\", `${height * exportScale}`);\n\n if (appState.exportWithDarkMode) {\n svgRoot.setAttribute(\"filter\", _constants__WEBPACK_IMPORTED_MODULE_4__.THEME_FILTER);\n }\n\n let assetPath = \"https://excalidraw.com/\"; // Asset path needs to be determined only when using package\n\n if (true) {\n assetPath = window.EXCALIDRAW_ASSET_PATH || `https://unpkg.com/${\"@dwelle/excalidraw\"}@${({\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PORTAL_URL\":\"\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"https://app.excalidraw.com\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_ENABLE_SW\":\"\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_DISABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3000\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_PKG_NAME\":\"@dwelle/excalidraw\",\"VITE_PKG_VERSION\":\"0.4.0-ab8616b\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).PKG_VERSION}`;\n\n if (assetPath === null || assetPath === void 0 ? void 0 : assetPath.startsWith(\"/\")) {\n assetPath = assetPath.replace(\"/\", `${window.location.origin}/`);\n }\n\n assetPath = `${assetPath}/dist/excalidraw-assets/`;\n } // do not apply clipping when we're exporting the whole scene\n\n\n const isExportingWholeCanvas = ((_l = (_k = _Scene__WEBPACK_IMPORTED_MODULE_8__[\"default\"].getScene(elements[0])) === null || _k === void 0 ? void 0 : _k.getNonDeletedElements()) === null || _l === void 0 ? void 0 : _l.length) === elements.length;\n const onlyExportingSingleFrame = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.isOnlyExportingSingleFrame)(elements);\n const offsetX = -minX + (onlyExportingSingleFrame ? 0 : exportPadding);\n const offsetY = -minY + (onlyExportingSingleFrame ? 0 : exportPadding);\n const exportingFrame = isExportingWholeCanvas || !onlyExportingSingleFrame ? undefined : elements.find(element => element.type === \"frame\");\n let exportingFrameClipPath = \"\";\n\n if (exportingFrame) {\n const [x1, y1, x2, y2] = (0,_element_bounds__WEBPACK_IMPORTED_MODULE_1__.getElementAbsoluteCoords)(exportingFrame);\n const cx = (x2 - x1) / 2 - (exportingFrame.x - x1);\n const cy = (y2 - y1) / 2 - (exportingFrame.y - y1);\n exportingFrameClipPath = `<clipPath id=${exportingFrame.id}>\n <rect transform=\"translate(${exportingFrame.x + offsetX} ${exportingFrame.y + offsetY}) rotate(${exportingFrame.angle} ${cx} ${cy})\"\n width=\"${exportingFrame.width}\"\n height=\"${exportingFrame.height}\"\n >\n </rect>\n </clipPath>`;\n }\n\n svgRoot.innerHTML = `\n ${SVG_EXPORT_TAG}\n ${metadata}\n <defs>\n <style class=\"style-fonts\">\n @font-face {\n font-family: \"Virgil\";\n src: url(\"https://excalidraw.com/Virgil.woff2\");\n }\n @font-face {\n font-family: \"Cascadia\";\n src: url(\"https://excalidraw.com/Cascadia.woff2\");\n }\n </style>\n ${exportingFrameClipPath}\n </defs>\n `; // render background rect\n\n if (appState.exportBackground && viewBackgroundColor) {\n const rect = svgRoot.ownerDocument.createElementNS(_constants__WEBPACK_IMPORTED_MODULE_4__.SVG_NS, \"rect\");\n rect.setAttribute(\"x\", \"0\");\n rect.setAttribute(\"y\", \"0\");\n rect.setAttribute(\"width\", `${width}`);\n rect.setAttribute(\"height\", `${height}`);\n rect.setAttribute(\"fill\", viewBackgroundColor);\n svgRoot.appendChild(rect);\n }\n\n const rsvg = roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_0__[\"default\"].svg(svgRoot);\n (0,_renderer_renderScene__WEBPACK_IMPORTED_MODULE_2__.renderSceneToSvg)(elements, rsvg, svgRoot, files || {}, {\n offsetX,\n offsetY,\n exportWithDarkMode: appState.exportWithDarkMode,\n exportingFrameId: (exportingFrame === null || exportingFrame === void 0 ? void 0 : exportingFrame.id) || null,\n renderEmbeddables: opts === null || opts === void 0 ? void 0 : opts.renderEmbeddables\n });\n return svgRoot;\n}); // calculate smallest area to fit the contents in\n\nconst getCanvasSize = elements => {\n // we should decide if we are exporting the whole canvas\n // if so, we are not clipping elements in the frame\n // and therefore, we should not do anything special\n var _a, _b;\n\n const isExportingWholeCanvas = ((_b = (_a = _Scene__WEBPACK_IMPORTED_MODULE_8__[\"default\"].getScene(elements[0])) === null || _a === void 0 ? void 0 : _a.getNonDeletedElements()) === null || _b === void 0 ? void 0 : _b.length) === elements.length;\n const onlyExportingSingleFrame = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.isOnlyExportingSingleFrame)(elements);\n\n if (!isExportingWholeCanvas || onlyExportingSingleFrame) {\n const frames = elements.filter(element => element.type === \"frame\");\n const exportedFrameIds = frames.reduce((acc, frame) => {\n acc[frame.id] = true;\n return acc;\n }, {}); // elements in a frame do not affect the canvas size if we're not exporting\n // the whole canvas\n\n elements = elements.filter(element => {\n var _a;\n\n return !exportedFrameIds[(_a = element.frameId) !== null && _a !== void 0 ? _a : \"\"];\n });\n }\n\n const [minX, minY, maxX, maxY] = (0,_element_bounds__WEBPACK_IMPORTED_MODULE_1__.getCommonBounds)(elements);\n const width = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.distance)(minX, maxX);\n const height = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.distance)(minY, maxY);\n return [minX, minY, width, height];\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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Q0FBOEMsdURBQWM7QUFDNUQsbUNBQW1DLGtFQUEwQjs7QUFFN0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUssSUFBSSxHQUFHO0FBQ1o7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDs7QUFFQSxtQ0FBbUMsZ0VBQWU7QUFDbEQsZ0JBQWdCLGdEQUFRO0FBQ3hCLGlCQUFpQixnREFBUTtBQUN6QjtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL3NjZW5lL2V4cG9ydC50cz8zZjRlIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX2F3YWl0ZXIgPSB0aGlzICYmIHRoaXMuX19hd2FpdGVyIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcbiAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkge1xuICAgICAgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7XG4gICAgfVxuXG4gICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xuICB9KTtcbn07XG5cbmltcG9ydCByb3VnaCBmcm9tIFwicm91Z2hqcy9iaW4vcm91Z2hcIjtcbmltcG9ydCB7IGdldENvbW1vbkJvdW5kcywgZ2V0RWxlbWVudEFic29sdXRlQ29vcmRzIH0gZnJvbSBcIi4uL2VsZW1lbnQvYm91bmRzXCI7XG5pbXBvcnQgeyByZW5kZXJTdGF0aWNTY2VuZSwgcmVuZGVyU2NlbmVUb1N2ZyB9IGZyb20gXCIuLi9yZW5kZXJlci9yZW5kZXJTY2VuZVwiO1xuaW1wb3J0IHsgZGlzdGFuY2UsIGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgeyBERUZBVUxUX0JBQ0tHUk9VTkRfQ09MT1IsIERFRkFVTFRfRVhQT1JUX1BBRERJTkcsIERFRkFVTFRfWk9PTV9WQUxVRSwgRU5WLCBTVkdfTlMsIFRIRU1FLCBUSEVNRV9GSUxURVIgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBzZXJpYWxpemVBc0pTT04gfSBmcm9tIFwiLi4vZGF0YS9qc29uXCI7XG5pbXBvcnQgeyBnZXRJbml0aWFsaXplZEltYWdlRWxlbWVudHMsIHVwZGF0ZUltYWdlQ2FjaGUgfSBmcm9tIFwiLi4vZWxlbWVudC9pbWFnZVwiO1xuaW1wb3J0IHsgcmVzdG9yZUFwcFN0YXRlIH0gZnJvbSBcIi4uL2RhdGEvcmVzdG9yZVwiO1xuaW1wb3J0IFNjZW5lIGZyb20gXCIuL1NjZW5lXCI7XG5leHBvcnQgY29uc3QgU1ZHX0VYUE9SVF9UQUcgPSBgPCEtLSBzdmctc291cmNlOmV4Y2FsaWRyYXcgLS0+YDtcbi8qKlxuICogVGhpcyBBUEkgaXMgdXN1YWxseSB1c2VkIGFzIGEgcHJlY3Vyc29yIHRvIHNlYXJpYWxpemluZyB0byBCbG9iIG9yIFBORyxcbiAqIGJ1dCBjYW4gYWxzbyBiZSB1c2VkIHRvIGNyZWF0ZSBhIGNhbnZhcyBmb3Igb3RoZXIgcHVycG9zZXMuXG4gKi9cblxuZXhwb3J0IGNvbnN0IGV4cG9ydFRvQ2FudmFzID0gKHtcbiAgZGF0YSxcbiAgY29uZmlnXG59KSA9PiBfX2F3YWl0ZXIodm9pZCAwLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaDsgLy8gaW5pdGlhbGl6ZSBkZWZhdWx0c1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gIGNvbnN0IHtcbiAgICBlbGVtZW50cyxcbiAgICBmaWxlc1xuICB9ID0gZGF0YTtcbiAgY29uc3QgYXBwU3RhdGUgPSByZXN0b3JlQXBwU3RhdGUoZGF0YS5hcHBTdGF0ZSwgbnVsbCk7IC8vIGNsb25lXG5cbiAgY29uc3QgY2ZnID0gT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnKTtcbiAgY2ZnLmZpdCA9IChfYSA9IGNmZy5maXQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IGNmZy53aWR0aCAhPSBudWxsIHx8IGNmZy5oZWlnaHQgIT0gbnVsbCB8fCBjZmcubWF4V2lkdGhPckhlaWdodCAhPSBudWxsIHx8IGNmZy53aWR0aE9ySGVpZ2h0ICE9IG51bGwgPyBcImNvbnRhaW5cIiA6IFwibm9uZVwiO1xuICBjb25zdCBjb250YWluUGFkZGluZyA9IGNmZy5maXQgPT09IFwiY29udGFpblwiO1xuXG4gIGlmIChjZmcueCAhPSBudWxsIHx8IGNmZy54ICE9IG51bGwpIHtcbiAgICBjZmcuZml0ID0gXCJub25lXCI7XG4gIH1cblxuICBpZiAoY2ZnLmZpdCA9PT0gXCJjb3ZlclwiKSB7XG4gICAgaWYgKGNmZy5wYWRkaW5nICYmIHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBFTlYuUFJPRFVDVElPTikge1xuICAgICAgY29uc29sZS53YXJuKFwiYHBhZGRpbmdgIGlzIGlnbm9yZWQgd2hlbiBgZml0YCBpcyBzZXQgdG8gYGNvdmVyYFwiKTtcbiAgICB9XG5cbiAgICBjZmcucGFkZGluZyA9IDA7XG4gIH1cblxuICBjZmcucGFkZGluZyA9IChfYiA9IGNmZy5wYWRkaW5nKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwO1xuICBjZmcuc2NhbGUgPSAoX2MgPSBjZmcuc2NhbGUpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IDE7XG4gIGNmZy5vcmlnaW4gPSAoX2QgPSBjZmcub3JpZ2luKSAhPT0gbnVsbCAmJiBfZCAhPT0gdm9pZCAwID8gX2QgOiBcImNhbnZhc1wiO1xuICBjZmcucG9zaXRpb24gPSAoX2UgPSBjZmcucG9zaXRpb24pICE9PSBudWxsICYmIF9lICE9PSB2b2lkIDAgPyBfZSA6IFwiY2VudGVyXCI7XG5cbiAgaWYgKGNmZy5tYXhXaWR0aE9ySGVpZ2h0ICE9IG51bGwgJiYgY2ZnLndpZHRoT3JIZWlnaHQgIT0gbnVsbCkge1xuICAgIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gRU5WLlBST0RVQ1RJT04pIHtcbiAgICAgIGNvbnNvbGUud2FybihcImBtYXhXaWR0aE9ySGVpZ2h0YCBpcyBpZ25vcmVkIHdoZW4gYHdpZHRoT3JIZWlnaHRgIGlzIHNldFwiKTtcbiAgICB9XG5cbiAgICBjZmcubWF4V2lkdGhPckhlaWdodCA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGlmICgoY2ZnLm1heFdpZHRoT3JIZWlnaHQgIT0gbnVsbCB8fCBjZmcud2lkdGggIT0gbnVsbCB8fCBjZmcuaGVpZ2h0ICE9IG51bGwpICYmIGNmZy5nZXREaW1lbnNpb25zKSB7XG4gICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBFTlYuUFJPRFVDVElPTikge1xuICAgICAgY29uc29sZS53YXJuKFwiYGdldERpbWVuc2lvbnNgIGlzIGlnbm9yZWQgd2hlbiBgd2lkdGhgLCBgaGVpZ2h0YCwgb3IgYG1heFdpZHRoT3JIZWlnaHRgIGlzIHNldFwiKTtcbiAgICB9XG5cbiAgICBjZmcuZ2V0RGltZW5zaW9ucyA9IHVuZGVmaW5lZDtcbiAgfSAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gdmFsdWUgdXNlZCB0byBzY2FsZSB0aGUgY2FudmFzIGNvbnRleHQuIEJ5IGRlZmF1bHQsIHdlIHVzZSB0aGlzIHRvXG4gIC8vIG1ha2UgdGhlIGNhbnZhcyBmaXQgaW50byB0aGUgZnJhbWUgKGUuZy4gZm9yIGBjZmcuZml0YCBzZXQgdG8gYGNvbnRhaW5gKS5cbiAgLy8gSWYgYGNmZy5zY2FsZWAgaXMgc2V0LCB3ZSBtdWx0aXBseSB0aGUgcmVzdWx0aW5nIGNhbnZhc1NjYWxlIGJ5IGl0IHRvXG4gIC8vIHNjYWxlIHRoZSBvdXRwdXQgZnVydGhlci5cblxuXG4gIGxldCBjYW52YXNTY2FsZSA9IDE7XG4gIGNvbnN0IG9yaWdDYW52YXNTaXplID0gZ2V0Q2FudmFzU2l6ZShlbGVtZW50cyk7IC8vIGNmZy54ID0gdW5kZWZpbmVkO1xuICAvLyBjZmcueSA9IHVuZGVmaW5lZDtcbiAgLy8gdmFyaWFibGVzIGZvciBvcmlnaW5hbCBjb250ZW50IGJvdW5kaW5nIGJveFxuXG4gIGNvbnN0IFtvcmlnWCwgb3JpZ1ksIG9yaWdXaWR0aCwgb3JpZ0hlaWdodF0gPSBvcmlnQ2FudmFzU2l6ZTsgLy8gdmFyaWFibGVzIGZvciB0YXJnZXQgYm91bmRpbmcgYm94XG5cbiAgbGV0IFt4LCB5LCB3aWR0aCwgaGVpZ2h0XSA9IG9yaWdDYW52YXNTaXplO1xuXG4gIGlmIChjZmcud2lkdGggIT0gbnVsbCkge1xuICAgIHdpZHRoID0gY2ZnLndpZHRoO1xuXG4gICAgaWYgKGNmZy5wYWRkaW5nICYmIGNvbnRhaW5QYWRkaW5nKSB7XG4gICAgICB3aWR0aCAtPSBjZmcucGFkZGluZyAqIDI7XG4gICAgfVxuXG4gICAgaWYgKGNmZy5oZWlnaHQpIHtcbiAgICAgIGhlaWdodCA9IGNmZy5oZWlnaHQ7XG5cbiAgICAgIGlmIChjZmcucGFkZGluZyAmJiBjb250YWluUGFkZGluZykge1xuICAgICAgICBoZWlnaHQgLT0gY2ZnLnBhZGRpbmcgKiAyO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBpZiBoZWlnaHQgbm90IHNwZWNpZmllZCwgc2NhbGUgdGhlIG9yaWdpbmFsIGhlaWdodCB0byBtYXRjaCB0aGUgbmV3XG4gICAgICAvLyB3aWR0aCB3aGlsZSBtYWludGFpbmluZyBhc3BlY3QgcmF0aW9cbiAgICAgIGhlaWdodCAqPSB3aWR0aCAvIG9yaWdXaWR0aDtcbiAgICB9XG4gIH0gZWxzZSBpZiAoY2ZnLmhlaWdodCAhPSBudWxsKSB7XG4gICAgaGVpZ2h0ID0gY2ZnLmhlaWdodDtcblxuICAgIGlmIChjZmcucGFkZGluZyAmJiBjb250YWluUGFkZGluZykge1xuICAgICAgaGVpZ2h0IC09IGNmZy5wYWRkaW5nICogMjtcbiAgICB9IC8vIHdpZHRoIG5vdCBzcGVjaWZpZWQsIHNvIHNjYWxlIHRoZSBvcmlnaW5hbCB3aWR0aCB0byBtYXRjaCB0aGUgbmV3XG4gICAgLy8gaGVpZ2h0IHdoaWxlIG1haW50YWluaW5nIGFzcGVjdCByYXRpb1xuXG5cbiAgICB3aWR0aCAqPSBoZWlnaHQgLyBvcmlnSGVpZ2h0O1xuICB9XG5cbiAgaWYgKGNmZy5tYXhXaWR0aE9ySGVpZ2h0ICE9IG51bGwgfHwgY2ZnLndpZHRoT3JIZWlnaHQgIT0gbnVsbCkge1xuICAgIGlmIChjb250YWluUGFkZGluZyAmJiBjZmcucGFkZGluZykge1xuICAgICAgaWYgKGNmZy5tYXhXaWR0aE9ySGVpZ2h0ICE9IG51bGwpIHtcbiAgICAgICAgY2ZnLm1heFdpZHRoT3JIZWlnaHQgLT0gY2ZnLnBhZGRpbmcgKiAyO1xuICAgICAgfSBlbHNlIGlmIChjZmcud2lkdGhPckhlaWdodCAhPSBudWxsKSB7XG4gICAgICAgIGNmZy53aWR0aE9ySGVpZ2h0IC09IGNmZy5wYWRkaW5nICogMjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBtYXggPSBNYXRoLm1heCh3aWR0aCwgaGVpZ2h0KTtcblxuICAgIGlmIChjZmcud2lkdGhPckhlaWdodCAhPSBudWxsKSB7XG4gICAgICAvLyBjYWxjdWxhdGUgYnkgaG93IG11Y2ggZG8gd2UgbmVlZCB0byBzY2FsZSB0aGUgY2FudmFzIHRvIGZpdCBpbnRvIHRoZVxuICAgICAgLy8gdGFyZ2V0IGRpbWVuc2lvbiAoZS5nLiB0YXJnZXQ6IG1heCA1MHB4LCBhY3R1YWw6IDcweDEwMHB4ID0+IHNjYWxlOiAwLjUpXG4gICAgICBjYW52YXNTY2FsZSA9IGNmZy53aWR0aE9ySGVpZ2h0IC8gbWF4O1xuICAgIH0gZWxzZSBpZiAoY2ZnLm1heFdpZHRoT3JIZWlnaHQgIT0gbnVsbCkge1xuICAgICAgY2FudmFzU2NhbGUgPSBjZmcubWF4V2lkdGhPckhlaWdodCA8IG1heCA/IGNmZy5tYXhXaWR0aE9ySGVpZ2h0IC8gbWF4IDogMTtcbiAgICB9XG5cbiAgICB3aWR0aCAqPSBjYW52YXNTY2FsZTtcbiAgICBoZWlnaHQgKj0gY2FudmFzU2NhbGU7XG4gIH0gZWxzZSBpZiAoY2ZnLmdldERpbWVuc2lvbnMpIHtcbiAgICBjb25zdCByZXQgPSBjZmcuZ2V0RGltZW5zaW9ucyh3aWR0aCwgaGVpZ2h0KTtcbiAgICB3aWR0aCA9IHJldC53aWR0aDtcbiAgICBoZWlnaHQgPSByZXQuaGVpZ2h0O1xuICAgIGNmZy5zY2FsZSA9IChfZiA9IHJldC5zY2FsZSkgIT09IG51bGwgJiYgX2YgIT09IHZvaWQgMCA/IF9mIDogY2ZnLnNjYWxlO1xuICB9IGVsc2UgaWYgKGNvbnRhaW5QYWRkaW5nICYmIGNmZy5wYWRkaW5nICYmIGNmZy53aWR0aCA9PSBudWxsICYmIGNmZy5oZWlnaHQgPT0gbnVsbCkge1xuICAgIGNvbnN0IHdoUmF0aW8gPSB3aWR0aCAvIGhlaWdodDtcbiAgICB3aWR0aCAtPSBjZmcucGFkZGluZyAqIDI7XG4gICAgaGVpZ2h0IC09IGNmZy5wYWRkaW5nICogMiAvIHdoUmF0aW87XG4gIH1cblxuICBpZiAoY2ZnLmZpdCA9PT0gXCJjb250YWluXCIgJiYgIWNmZy5tYXhXaWR0aE9ySGVpZ2h0IHx8IGNvbnRhaW5QYWRkaW5nICYmIGNmZy5wYWRkaW5nKSB7XG4gICAgaWYgKGNmZy5maXQgPT09IFwiY29udGFpblwiKSB7XG4gICAgICBjb25zdCB3UmF0aW8gPSB3aWR0aCAvIG9yaWdXaWR0aDtcbiAgICAgIGNvbnN0IGhSYXRpbyA9IGhlaWdodCAvIG9yaWdIZWlnaHQ7IC8vIHNjYWxlIHRoZSBvcmlnIGNhbnZhcyB0byBmaXQgaW4gdGhlIHRhcmdldCBmcmFtZVxuXG4gICAgICBjYW52YXNTY2FsZSA9IE1hdGgubWluKHdSYXRpbywgaFJhdGlvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3Qgd1JhdGlvID0gKHdpZHRoIC0gY2ZnLnBhZGRpbmcgKiAyKSAvIHdpZHRoO1xuICAgICAgY29uc3QgaFJhdGlvID0gKGhlaWdodCAtIGNmZy5wYWRkaW5nICogMikgLyBoZWlnaHQ7XG4gICAgICBjYW52YXNTY2FsZSA9IE1hdGgubWluKHdSYXRpbywgaFJhdGlvKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoY2ZnLmZpdCA9PT0gXCJjb3ZlclwiKSB7XG4gICAgY29uc3Qgd1JhdGlvID0gd2lkdGggLyBvcmlnV2lkdGg7XG4gICAgY29uc3QgaFJhdGlvID0gaGVpZ2h0IC8gb3JpZ0hlaWdodDsgLy8gc2NhbGUgdGhlIG9yaWcgY2FudmFzIHRvIGZpbGwgdGhlIHRoZSB0YXJnZXQgZnJhbWVcbiAgICAvLyAob3Bwb3NpdGUgb2YgXCJjb250YWluXCIpXG5cbiAgICBjYW52YXNTY2FsZSA9IE1hdGgubWF4KHdSYXRpbywgaFJhdGlvKTtcbiAgfVxuXG4gIHggPSAoX2cgPSBjZmcueCkgIT09IG51bGwgJiYgX2cgIT09IHZvaWQgMCA/IF9nIDogb3JpZ1g7XG4gIHkgPSAoX2ggPSBjZmcueSkgIT09IG51bGwgJiYgX2ggIT09IHZvaWQgMCA/IF9oIDogb3JpZ1k7IC8vIGlmIHdlIHN3aXRjaCB0byBcImNvbnRlbnRcIiBjb29yZHMsIHdlIG5lZWQgdG8gb2Zmc2V0IGNmZy1zdXBwbGllZFxuICAvLyBjb29yZHMgYnkgdGhlIHgveSBvZiBjb250ZW50IGJvdW5kaW5nIGJveFxuXG4gIGlmIChjZmcub3JpZ2luID09PSBcImNvbnRlbnRcIikge1xuICAgIGlmIChjZmcueCAhPSBudWxsKSB7XG4gICAgICB4ICs9IG9yaWdYO1xuICAgIH1cblxuICAgIGlmIChjZmcueSAhPSBudWxsKSB7XG4gICAgICB5ICs9IG9yaWdZO1xuICAgIH1cbiAgfSAvLyBDZW50ZXJpbmcgdGhlIGNvbnRlbnQgdG8gdGhlIGZyYW1lLlxuICAvLyBXZSBkaXZpZGUgd2lkdGgvaGVpZ2h0IGJ5IGNhbnZhc1NjYWxlIHNvIHRoYXQgd2UgY2FsY3VsYXRlIGluIHRoZSBvcmlnaW5hbFxuICAvLyBhc3BlY3QgcmF0aW8gZGltZW5zaW9ucy5cblxuXG4gIGlmIChjZmcucG9zaXRpb24gPT09IFwiY2VudGVyXCIpIHtcbiAgICB4IC09IHdpZHRoIC8gY2FudmFzU2NhbGUgLyAyIC0gKGNmZy54ID09IG51bGwgPyBvcmlnV2lkdGggOiB3aWR0aCArIGNmZy5wYWRkaW5nICogMikgLyAyO1xuICAgIHkgLT0gaGVpZ2h0IC8gY2FudmFzU2NhbGUgLyAyIC0gKGNmZy55ID09IG51bGwgPyBvcmlnSGVpZ2h0IDogaGVpZ2h0ICsgY2ZnLnBhZGRpbmcgKiAyKSAvIDI7XG4gIH1cblxuICBjb25zdCBjYW52YXMgPSBjZmcuY3JlYXRlQ2FudmFzID8gY2ZnLmNyZWF0ZUNhbnZhcygpIDogZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgY29uc3Qgb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID0gaXNPbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUoZWxlbWVudHMpOyAvLyBoYWNrIGZpeCB1bnRpbCB3ZSBkZWNpZGUgd2hvc2UgcmVzcG9uc2liaWxpdHkgdGhpcyBzaG91bGQgYmVcblxuICBpZiAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKSB7XG4gICAgY2ZnLnBhZGRpbmcgPSAwO1xuICB9IC8vIHJlc2NhbGUgcGFkZGluZyBiYXNlZCBvbiBjdXJyZW50IGNhbnZhc1NjYWxlIGZhY3RvciBzbyB0aGF0IHRoZSByZXN1bHRpbmdcbiAgLy8gcGFkZGluZyBpcyBrZXB0IHRoZSBzYW1lIGFzIHN1cHBsaWVkIGJ5IHVzZXIgKHdpdGggdGhlIGV4Y2VwdGlvbiBvZlxuICAvLyBgY2ZnLnNjYWxlYCBiZWluZyBzZXQsIHdoaWNoIGFsc28gc2NhbGVzIHRoZSBwYWRkaW5nKVxuXG5cbiAgY29uc3Qgbm9ybWFsaXplZFBhZGRpbmcgPSBjZmcucGFkZGluZyAvIGNhbnZhc1NjYWxlOyAvLyBzY2FsZSB0aGUgd2hvbGUgZnJhbWUgYnkgY2ZnLnNjYWxlIChvbiB0b3Agb2Ygd2hhdGV2ZXIgY2FudmFzU2NhbGUgd2VcbiAgLy8gY2FsY3VsYXRlZCBhYm92ZSlcblxuICBjYW52YXNTY2FsZSAqPSBjZmcuc2NhbGU7XG4gIHdpZHRoICo9IGNmZy5zY2FsZTtcbiAgaGVpZ2h0ICo9IGNmZy5zY2FsZTtcbiAgY2FudmFzLndpZHRoID0gd2lkdGggKyBjZmcucGFkZGluZyAqIDIgKiBjZmcuc2NhbGU7XG4gIGNhbnZhcy5oZWlnaHQgPSBoZWlnaHQgKyBjZmcucGFkZGluZyAqIDIgKiBjZmcuc2NhbGU7XG4gIGNvbnN0IHtcbiAgICBpbWFnZUNhY2hlXG4gIH0gPSB5aWVsZCB1cGRhdGVJbWFnZUNhY2hlKHtcbiAgICBpbWFnZUNhY2hlOiBuZXcgTWFwKCksXG4gICAgZmlsZUlkczogZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzKGVsZW1lbnRzKS5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgZmlsZXM6IGZpbGVzIHx8IHt9XG4gIH0pOyAvLyBjb25zb2xlLmxvZyhlbGVtZW50cywgd2lkdGgsIGhlaWdodCwgY2ZnLCBjYW52YXNTY2FsZSk7XG4gIC8vIGNvbnNvbGUubG9nKGVsZW1lbnRzLCB3aWR0aCwgaGVpZ2h0LCBjZmcsIGNhbnZhc1NjYWxlKTtcblxuICByZW5kZXJTdGF0aWNTY2VuZSh7XG4gICAgZWxlbWVudHMsXG4gICAgdmlzaWJsZUVsZW1lbnRzOiBlbGVtZW50cyxcbiAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBhcHBTdGF0ZSksIHtcbiAgICAgIHdpZHRoLFxuICAgICAgaGVpZ2h0LFxuICAgICAgb2Zmc2V0TGVmdDogMCxcbiAgICAgIG9mZnNldFRvcDogMCxcbiAgICAgIHNjcm9sbFg6IC14ICsgbm9ybWFsaXplZFBhZGRpbmcsXG4gICAgICBzY3JvbGxZOiAteSArIG5vcm1hbGl6ZWRQYWRkaW5nLFxuICAgICAgem9vbToge1xuICAgICAgICB2YWx1ZTogREVGQVVMVF9aT09NX1ZBTFVFXG4gICAgICB9LFxuICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZSxcbiAgICAgIHRoZW1lOiBjZmcudGhlbWUgfHwgVEhFTUUuTElHSFRcbiAgICB9KSxcbiAgICByYzogcm91Z2guY2FudmFzKGNhbnZhcyksXG4gICAgY2FudmFzLFxuICAgIHNjYWxlOiBjYW52YXNTY2FsZSxcbiAgICByZW5kZXJDb25maWc6IHtcbiAgICAgIGNhbnZhc0JhY2tncm91bmRDb2xvcjogY2ZnLmNhbnZhc0JhY2tncm91bmRDb2xvciA9PT0gZmFsc2UgPyAvLyBudWxsIGluZGljYXRlcyB0cmFuc3BhcmVudCBiYWNrZ3JvdW5kXG4gICAgICBudWxsIDogY2ZnLmNhbnZhc0JhY2tncm91bmRDb2xvciB8fCBhcHBTdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yIHx8IERFRkFVTFRfQkFDS0dST1VORF9DT0xPUixcbiAgICAgIGltYWdlQ2FjaGUsXG4gICAgICByZW5kZXJHcmlkOiBmYWxzZSxcbiAgICAgIGlzRXhwb3J0aW5nOiB0cnVlXG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIGNhbnZhcztcbn0pO1xuZXhwb3J0IGNvbnN0IGV4cG9ydFRvU3ZnID0gKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMsIG9wdHMpID0+IF9fYXdhaXRlcih2b2lkIDAsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICB2YXIgX2osIF9rLCBfbDtcblxuICBjb25zdCB7XG4gICAgZXhwb3J0UGFkZGluZyA9IERFRkFVTFRfRVhQT1JUX1BBRERJTkcsXG4gICAgdmlld0JhY2tncm91bmRDb2xvcixcbiAgICBleHBvcnRTY2FsZSA9IDEsXG4gICAgZXhwb3J0RW1iZWRTY2VuZVxuICB9ID0gYXBwU3RhdGU7XG4gIGxldCBtZXRhZGF0YSA9IFwiXCI7XG5cbiAgaWYgKGV4cG9ydEVtYmVkU2NlbmUpIHtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSB5aWVsZCAoeWllbGQgaW1wb3J0KFxuICAgICAgLyogd2VicGFja0NodW5rTmFtZTogXCJpbWFnZVwiICovXG4gICAgICBcIi4uLy4uL3NyYy9kYXRhL2ltYWdlXCIpKS5lbmNvZGVTdmdNZXRhZGF0YSh7XG4gICAgICAgIHRleHQ6IChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuc2VyaWFsaXplQXNKU09OKSA/IChfaiA9IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5zZXJpYWxpemVBc0pTT04pID09PSBudWxsIHx8IF9qID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfai5jYWxsKG9wdHMpIDogc2VyaWFsaXplQXNKU09OKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMgfHwge30sIFwibG9jYWxcIilcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICB9XG4gIH1cblxuICBsZXQgW21pblgsIG1pblksIHdpZHRoLCBoZWlnaHRdID0gZ2V0Q2FudmFzU2l6ZShlbGVtZW50cyk7XG4gIHdpZHRoICs9IGV4cG9ydFBhZGRpbmcgKiAyO1xuICBoZWlnaHQgKz0gZXhwb3J0UGFkZGluZyAqIDI7IC8vIGluaXRpYWxpemUgU1ZHIHJvb3RcblxuICBjb25zdCBzdmdSb290ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgXCJzdmdcIik7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwidmVyc2lvblwiLCBcIjEuMVwiKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJ4bWxuc1wiLCBTVkdfTlMpO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcInZpZXdCb3hcIiwgYDAgMCAke3dpZHRofSAke2hlaWdodH1gKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJ3aWR0aFwiLCBgJHt3aWR0aCAqIGV4cG9ydFNjYWxlfWApO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcImhlaWdodFwiLCBgJHtoZWlnaHQgKiBleHBvcnRTY2FsZX1gKTtcblxuICBpZiAoYXBwU3RhdGUuZXhwb3J0V2l0aERhcmtNb2RlKSB7XG4gICAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJmaWx0ZXJcIiwgVEhFTUVfRklMVEVSKTtcbiAgfVxuXG4gIGxldCBhc3NldFBhdGggPSBcImh0dHBzOi8vZXhjYWxpZHJhdy5jb20vXCI7IC8vIEFzc2V0IHBhdGggbmVlZHMgdG8gYmUgZGV0ZXJtaW5lZCBvbmx5IHdoZW4gdXNpbmcgcGFja2FnZVxuXG4gIGlmIChwcm9jZXNzLmVudi5WSVRFX0lTX0VYQ0FMSURSQVdfTlBNX1BBQ0tBR0UpIHtcbiAgICBhc3NldFBhdGggPSB3aW5kb3cuRVhDQUxJRFJBV19BU1NFVF9QQVRIIHx8IGBodHRwczovL3VucGtnLmNvbS8ke3Byb2Nlc3MuZW52LlZJVEVfUEtHX05BTUV9QCR7cHJvY2Vzcy5lbnYuUEtHX1ZFUlNJT059YDtcblxuICAgIGlmIChhc3NldFBhdGggPT09IG51bGwgfHwgYXNzZXRQYXRoID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhc3NldFBhdGguc3RhcnRzV2l0aChcIi9cIikpIHtcbiAgICAgIGFzc2V0UGF0aCA9IGFzc2V0UGF0aC5yZXBsYWNlKFwiL1wiLCBgJHt3aW5kb3cubG9jYXRpb24ub3JpZ2lufS9gKTtcbiAgICB9XG5cbiAgICBhc3NldFBhdGggPSBgJHthc3NldFBhdGh9L2Rpc3QvZXhjYWxpZHJhdy1hc3NldHMvYDtcbiAgfSAvLyBkbyBub3QgYXBwbHkgY2xpcHBpbmcgd2hlbiB3ZSdyZSBleHBvcnRpbmcgdGhlIHdob2xlIHNjZW5lXG5cblxuICBjb25zdCBpc0V4cG9ydGluZ1dob2xlQ2FudmFzID0gKChfbCA9IChfayA9IFNjZW5lLmdldFNjZW5lKGVsZW1lbnRzWzBdKSkgPT09IG51bGwgfHwgX2sgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9rLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSA9PT0gbnVsbCB8fCBfbCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2wubGVuZ3RoKSA9PT0gZWxlbWVudHMubGVuZ3RoO1xuICBjb25zdCBvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPSBpc09ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZShlbGVtZW50cyk7XG4gIGNvbnN0IG9mZnNldFggPSAtbWluWCArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyk7XG4gIGNvbnN0IG9mZnNldFkgPSAtbWluWSArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyk7XG4gIGNvbnN0IGV4cG9ydGluZ0ZyYW1lID0gaXNFeHBvcnRpbmdXaG9sZUNhbnZhcyB8fCAhb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gdW5kZWZpbmVkIDogZWxlbWVudHMuZmluZChlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKTtcbiAgbGV0IGV4cG9ydGluZ0ZyYW1lQ2xpcFBhdGggPSBcIlwiO1xuXG4gIGlmIChleHBvcnRpbmdGcmFtZSkge1xuICAgIGNvbnN0IFt4MSwgeTEsIHgyLCB5Ml0gPSBnZXRFbGVtZW50QWJzb2x1dGVDb29yZHMoZXhwb3J0aW5nRnJhbWUpO1xuICAgIGNvbnN0IGN4ID0gKHgyIC0geDEpIC8gMiAtIChleHBvcnRpbmdGcmFtZS54IC0geDEpO1xuICAgIGNvbnN0IGN5ID0gKHkyIC0geTEpIC8gMiAtIChleHBvcnRpbmdGcmFtZS55IC0geTEpO1xuICAgIGV4cG9ydGluZ0ZyYW1lQ2xpcFBhdGggPSBgPGNsaXBQYXRoIGlkPSR7ZXhwb3J0aW5nRnJhbWUuaWR9PlxuICAgICAgICAgICAgPHJlY3QgdHJhbnNmb3JtPVwidHJhbnNsYXRlKCR7ZXhwb3J0aW5nRnJhbWUueCArIG9mZnNldFh9ICR7ZXhwb3J0aW5nRnJhbWUueSArIG9mZnNldFl9KSByb3RhdGUoJHtleHBvcnRpbmdGcmFtZS5hbmdsZX0gJHtjeH0gJHtjeX0pXCJcbiAgICAgICAgICB3aWR0aD1cIiR7ZXhwb3J0aW5nRnJhbWUud2lkdGh9XCJcbiAgICAgICAgICBoZWlnaHQ9XCIke2V4cG9ydGluZ0ZyYW1lLmhlaWdodH1cIlxuICAgICAgICAgID5cbiAgICAgICAgICA8L3JlY3Q+XG4gICAgICAgIDwvY2xpcFBhdGg+YDtcbiAgfVxuXG4gIHN2Z1Jvb3QuaW5uZXJIVE1MID0gYFxuICAke1NWR19FWFBPUlRfVEFHfVxuICAke21ldGFkYXRhfVxuICA8ZGVmcz5cbiAgICA8c3R5bGUgY2xhc3M9XCJzdHlsZS1mb250c1wiPlxuICAgICAgQGZvbnQtZmFjZSB7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBcIlZpcmdpbFwiO1xuICAgICAgICBzcmM6IHVybChcImh0dHBzOi8vZXhjYWxpZHJhdy5jb20vVmlyZ2lsLndvZmYyXCIpO1xuICAgICAgfVxuICAgICAgQGZvbnQtZmFjZSB7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBcIkNhc2NhZGlhXCI7XG4gICAgICAgIHNyYzogdXJsKFwiaHR0cHM6Ly9leGNhbGlkcmF3LmNvbS9DYXNjYWRpYS53b2ZmMlwiKTtcbiAgICAgIH1cbiAgICA8L3N0eWxlPlxuICAgICR7ZXhwb3J0aW5nRnJhbWVDbGlwUGF0aH1cbiAgPC9kZWZzPlxuICBgOyAvLyByZW5kZXIgYmFja2dyb3VuZCByZWN0XG5cbiAgaWYgKGFwcFN0YXRlLmV4cG9ydEJhY2tncm91bmQgJiYgdmlld0JhY2tncm91bmRDb2xvcikge1xuICAgIGNvbnN0IHJlY3QgPSBzdmdSb290Lm93bmVyRG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgXCJyZWN0XCIpO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwieFwiLCBcIjBcIik7XG4gICAgcmVjdC5zZXRBdHRyaWJ1dGUoXCJ5XCIsIFwiMFwiKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcIndpZHRoXCIsIGAke3dpZHRofWApO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwiaGVpZ2h0XCIsIGAke2hlaWdodH1gKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcImZpbGxcIiwgdmlld0JhY2tncm91bmRDb2xvcik7XG4gICAgc3ZnUm9vdC5hcHBlbmRDaGlsZChyZWN0KTtcbiAgfVxuXG4gIGNvbnN0IHJzdmcgPSByb3VnaC5zdmcoc3ZnUm9vdCk7XG4gIHJlbmRlclNjZW5lVG9TdmcoZWxlbWVudHMsIHJzdmcsIHN2Z1Jvb3QsIGZpbGVzIHx8IHt9LCB7XG4gICAgb2Zmc2V0WCxcbiAgICBvZmZzZXRZLFxuICAgIGV4cG9ydFdpdGhEYXJrTW9kZTogYXBwU3RhdGUuZXhwb3J0V2l0aERhcmtNb2RlLFxuICAgIGV4cG9ydGluZ0ZyYW1lSWQ6IChleHBvcnRpbmdGcmFtZSA9PT0gbnVsbCB8fCBleHBvcnRpbmdGcmFtZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhwb3J0aW5nRnJhbWUuaWQpIHx8IG51bGwsXG4gICAgcmVuZGVyRW1iZWRkYWJsZXM6IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yZW5kZXJFbWJlZGRhYmxlc1xuICB9KTtcbiAgcmV0dXJuIHN2Z1Jvb3Q7XG59KTsgLy8gY2FsY3VsYXRlIHNtYWxsZXN0IGFyZWEgdG8gZml0IHRoZSBjb250ZW50cyBpblxuXG5leHBvcnQgY29uc3QgZ2V0Q2FudmFzU2l6ZSA9IGVsZW1lbnRzID0+IHtcbiAgLy8gd2Ugc2hvdWxkIGRlY2lkZSBpZiB3ZSBhcmUgZXhwb3J0aW5nIHRoZSB3aG9sZSBjYW52YXNcbiAgLy8gaWYgc28sIHdlIGFyZSBub3QgY2xpcHBpbmcgZWxlbWVudHMgaW4gdGhlIGZyYW1lXG4gIC8vIGFuZCB0aGVyZWZvcmUsIHdlIHNob3VsZCBub3QgZG8gYW55dGhpbmcgc3BlY2lhbFxuICB2YXIgX2EsIF9iO1xuXG4gIGNvbnN0IGlzRXhwb3J0aW5nV2hvbGVDYW52YXMgPSAoKF9iID0gKF9hID0gU2NlbmUuZ2V0U2NlbmUoZWxlbWVudHNbMF0pKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5sZW5ndGgpID09PSBlbGVtZW50cy5sZW5ndGg7XG4gIGNvbnN0IG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA9IGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKGVsZW1lbnRzKTtcblxuICBpZiAoIWlzRXhwb3J0aW5nV2hvbGVDYW52YXMgfHwgb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKSB7XG4gICAgY29uc3QgZnJhbWVzID0gZWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuICAgIGNvbnN0IGV4cG9ydGVkRnJhbWVJZHMgPSBmcmFtZXMucmVkdWNlKChhY2MsIGZyYW1lKSA9PiB7XG4gICAgICBhY2NbZnJhbWUuaWRdID0gdHJ1ZTtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwge30pOyAvLyBlbGVtZW50cyBpbiBhIGZyYW1lIGRvIG5vdCBhZmZlY3QgdGhlIGNhbnZhcyBzaXplIGlmIHdlJ3JlIG5vdCBleHBvcnRpbmdcbiAgICAvLyB0aGUgd2hvbGUgY2FudmFzXG5cbiAgICBlbGVtZW50cyA9IGVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgcmV0dXJuICFleHBvcnRlZEZyYW1lSWRzWyhfYSA9IGVsZW1lbnQuZnJhbWVJZCkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogXCJcIl07XG4gICAgfSk7XG4gIH1cblxuICBjb25zdCBbbWluWCwgbWluWSwgbWF4WCwgbWF4WV0gPSBnZXRDb21tb25Cb3VuZHMoZWxlbWVudHMpO1xuICBjb25zdCB3aWR0aCA9IGRpc3RhbmNlKG1pblgsIG1heFgpO1xuICBjb25zdCBoZWlnaHQgPSBkaXN0YW5jZShtaW5ZLCBtYXhZKTtcbiAgcmV0dXJuIFttaW5YLCBtaW5ZLCB3aWR0aCwgaGVpZ2h0XTtcbn07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../scene/export.ts\n");
4190
4190
 
4191
4191
  /***/ }),
4192
4192