@excalidraw/excalidraw 0.16.0-f8b3692 → 0.16.1-4765f55

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.
@@ -2375,7 +2375,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
2375
2375
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2376
2376
 
2377
2377
  "use strict";
2378
- 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\":\"@excalidraw/excalidraw\",\"VITE_PKG_VERSION\":\"0.16.0-f8b3692\",\"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vYW5hbHl0aWNzLnRzLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QyxvQ0FBb0MsZ0NBQWdDOztBQUVwRSx5Q0FBeUMsOHFDQUFXO0FBQ3BEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2FuYWx5dGljcy50cz81NjYxIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCB0cmFja0V2ZW50ID0gKGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSkgPT4ge1xuICB0cnkge1xuICAgIC8vIHBsYWNlIGhlcmUgY2F0ZWdvcmllcyB0aGF0IHlvdSB3YW50IHRvIHRyYWNrIGFzIGV2ZW50c1xuICAgIC8vIEtFRVAgSU4gTUlORCBUSEUgUFJJQ0lOR1xuICAgIGNvbnN0IEFMTE9XRURfQ0FURUdPUklFU19UT19UUkFDSyA9IFtdOyAvLyBVbmNvbW1lbnQgdGhlIG5leHQgbGluZSB0byB0cmFjayBsb2NhbGx5XG4gICAgLy8gY29uc29sZS5sb2coXCJUcmFjayBFdmVudFwiLCB7IGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSB9KTtcblxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSBcInVuZGVmaW5lZFwiIHx8IHByb2Nlc3MuZW52LlZJVEVfV09SS0VSX0lEKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFBTExPV0VEX0NBVEVHT1JJRVNfVE9fVFJBQ0suaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5zYV9ldmVudCkge1xuICAgICAgd2luZG93LnNhX2V2ZW50KGFjdGlvbiwge1xuICAgICAgICBjYXRlZ29yeSxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIHZhbHVlXG4gICAgICB9KTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcImVycm9yIGR1cmluZyBhbmFseXRpY3NcIiwgZXJyb3IpO1xuICB9XG59OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../analytics.ts\n");
2378
+ 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\":\"@excalidraw/excalidraw\",\"VITE_PKG_VERSION\":\"0.16.1-4765f55\",\"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vYW5hbHl0aWNzLnRzLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QyxvQ0FBb0MsZ0NBQWdDOztBQUVwRSx5Q0FBeUMsOHFDQUFXO0FBQ3BEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2FuYWx5dGljcy50cz81NjYxIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCB0cmFja0V2ZW50ID0gKGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSkgPT4ge1xuICB0cnkge1xuICAgIC8vIHBsYWNlIGhlcmUgY2F0ZWdvcmllcyB0aGF0IHlvdSB3YW50IHRvIHRyYWNrIGFzIGV2ZW50c1xuICAgIC8vIEtFRVAgSU4gTUlORCBUSEUgUFJJQ0lOR1xuICAgIGNvbnN0IEFMTE9XRURfQ0FURUdPUklFU19UT19UUkFDSyA9IFtdOyAvLyBVbmNvbW1lbnQgdGhlIG5leHQgbGluZSB0byB0cmFjayBsb2NhbGx5XG4gICAgLy8gY29uc29sZS5sb2coXCJUcmFjayBFdmVudFwiLCB7IGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSB9KTtcblxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSBcInVuZGVmaW5lZFwiIHx8IHByb2Nlc3MuZW52LlZJVEVfV09SS0VSX0lEKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFBTExPV0VEX0NBVEVHT1JJRVNfVE9fVFJBQ0suaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5zYV9ldmVudCkge1xuICAgICAgd2luZG93LnNhX2V2ZW50KGFjdGlvbiwge1xuICAgICAgICBjYXRlZ29yeSxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIHZhbHVlXG4gICAgICB9KTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcImVycm9yIGR1cmluZyBhbmFseXRpY3NcIiwgZXJyb3IpO1xuICB9XG59OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../analytics.ts\n");
2379
2379
 
2380
2380
  /***/ }),
2381
2381
 
@@ -2463,7 +2463,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
2463
2463
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2464
2464
 
2465
2465
  "use strict";
2466
- 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_65__ = __webpack_require__(/*! nanoid */ \"../../../node_modules/nanoid/index.browser.js\");\n/* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../actions */ \"../../actions/index.ts\");\n/* harmony import */ var _actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../actions/actionHistory */ \"../../actions/actionHistory.tsx\");\n/* harmony import */ var _actions_manager__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../actions/manager */ \"../../actions/manager.tsx\");\n/* harmony import */ var _actions_register__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../actions/register */ \"../../actions/register.ts\");\n/* harmony import */ var _analytics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../analytics */ \"../../analytics.ts\");\n/* harmony import */ var _appState__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../appState */ \"../../appState.ts\");\n/* harmony import */ var _clipboard__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../clipboard */ \"../../clipboard.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\n/* harmony import */ var _data__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../data */ \"../../data/index.ts\");\n/* harmony import */ var _data_library__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../data/library */ \"../../data/library.ts\");\n/* harmony import */ var _data_restore__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../data/restore */ \"../../data/restore.ts\");\n/* harmony import */ var _element__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../element */ \"../../element/index.ts\");\n/* harmony import */ var _element_binding__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../element/binding */ \"../../element/binding.ts\");\n/* harmony import */ var _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../element/linearElementEditor */ \"../../element/linearElementEditor.ts\");\n/* harmony import */ var _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../element/mutateElement */ \"../../element/mutateElement.ts\");\n/* harmony import */ var _element_newElement__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../element/newElement */ \"../../element/newElement.ts\");\n/* harmony import */ var _element_typeChecks__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../element/typeChecks */ \"../../element/typeChecks.ts\");\n/* harmony import */ var _gesture__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../gesture */ \"../../gesture.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../groups */ \"../../groups.ts\");\n/* harmony import */ var _history__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../history */ \"../../history.ts\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../i18n */ \"../../i18n.ts\");\n/* harmony import */ var _keys__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ../keys */ \"../../keys.ts\");\n/* harmony import */ var _element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ../element/sizeHelpers */ \"../../element/sizeHelpers.ts\");\n/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ../math */ \"../../math.ts\");\n/* harmony import */ var _scene__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ../scene */ \"../../scene/index.ts\");\n/* harmony import */ var _scene_Scene__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ../scene/Scene */ \"../../scene/Scene.ts\");\n/* harmony import */ var _scene_zoom__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ../scene/zoom */ \"../../scene/zoom.ts\");\n/* harmony import */ var _shapes__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ../shapes */ \"../../shapes.tsx\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _element_embeddable__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ../element/embeddable */ \"../../element/embeddable.ts\");\n/* harmony import */ var _ContextMenu__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ./ContextMenu */ \"../../components/ContextMenu.tsx\");\n/* harmony import */ var _LayerUI__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./LayerUI */ \"../../components/LayerUI.tsx\");\n/* harmony import */ var _Toast__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./Toast */ \"../../components/Toast.tsx\");\n/* harmony import */ var _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ../actions/actionToggleViewMode */ \"../../actions/actionToggleViewMode.tsx\");\n/* harmony import */ var _data_blob__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ../data/blob */ \"../../data/blob.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ../element/image */ \"../../element/image.ts\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! lodash.throttle */ \"../../../node_modules/lodash.throttle/index.js\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default = /*#__PURE__*/__webpack_require__.n(lodash_throttle__WEBPACK_IMPORTED_MODULE_41__);\n/* harmony import */ var _data_filesystem__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! ../data/filesystem */ \"../../data/filesystem.ts\");\n/* harmony import */ var _element_textElement__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ../element/textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _element_collision__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ../element/collision */ \"../../element/collision.ts\");\n/* harmony import */ var _element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! ../element/Hyperlink */ \"../../element/Hyperlink.tsx\");\n/* harmony import */ var _data_url__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! ../data/url */ \"../../data/url.ts\");\n/* harmony import */ var _element_transformHandles__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! ../element/transformHandles */ \"../../element/transformHandles.ts\");\n/* harmony import */ var _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! ../actions/actionElementLock */ \"../../actions/actionElementLock.ts\");\n/* harmony import */ var _scene_Fonts__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! ../scene/Fonts */ \"../../scene/Fonts.ts\");\n/* harmony import */ var _frame__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! ../frame */ \"../../frame.ts\");\n/* harmony import */ var _scene_selection__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! ../scene/selection */ \"../../scene/selection.ts\");\n/* harmony import */ var _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! ../actions/actionClipboard */ \"../../actions/actionClipboard.tsx\");\n/* harmony import */ var _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! ../actions/actionFrame */ \"../../actions/actionFrame.ts\");\n/* harmony import */ var _actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ../actions/actionCanvas */ \"../../actions/actionCanvas.tsx\");\n/* harmony import */ var _jotai__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ../jotai */ \"../../jotai.ts\");\n/* harmony import */ var _ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! ./ActiveConfirmDialog */ \"../../components/ActiveConfirmDialog.tsx\");\n/* harmony import */ var _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ../actions/actionBoundText */ \"../../actions/actionBoundText.tsx\");\n/* harmony import */ var _BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(/*! ./BraveMeasureTextError */ \"../../components/BraveMeasureTextError.tsx\");\n/* harmony import */ var _EyeDropper__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(/*! ./EyeDropper */ \"../../components/EyeDropper.tsx\");\n/* harmony import */ var _data_transform__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(/*! ../data/transform */ \"../../data/transform.ts\");\n/* harmony import */ var _Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(/*! ./Sidebar/Sidebar */ \"../../components/Sidebar/Sidebar.tsx\");\n/* harmony import */ var _canvases__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(/*! ./canvases */ \"../../components/canvases/index.tsx\");\n/* harmony import */ var _scene_Renderer__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(/*! ../scene/Renderer */ \"../../scene/Renderer.ts\");\n/* harmony import */ var _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(/*! ../scene/ShapeCache */ \"../../scene/ShapeCache.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\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\n this.updateEmbeddables = () => {\n const embeddableElements = new Map();\n let updated = false;\n this.scene.getNonDeletedElements().filter(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(element)) {\n embeddableElements.set(element.id, true);\n\n if (element.validated == null) {\n updated = true;\n const validated = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(element.link, this.props.validateEmbeddable);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n validated\n }, false);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__.ShapeCache[\"delete\"](element);\n }\n }\n\n return false;\n });\n\n if (updated) {\n this.scene.informMutation();\n } // GC\n\n\n this.iFrameRefs.forEach((ref, id) => {\n if (!embeddableElements.has(id)) {\n this.iFrameRefs.delete(id);\n }\n });\n };\n\n this.getFrameNameDOMId = frameElement => {\n return `${this.id}-frame-name-${frameElement.id}`;\n };\n\n this.frameNameBoundsCache = {\n get: frameElement => {\n let bounds = this.frameNameBoundsCache._cache.get(frameElement.id);\n\n if (!bounds || bounds.zoom !== this.state.zoom.value || bounds.versionNonce !== frameElement.versionNonce) {\n const frameNameDiv = document.getElementById(this.getFrameNameDOMId(frameElement));\n\n if (frameNameDiv) {\n const box = frameNameDiv.getBoundingClientRect();\n const boxSceneTopLeft = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: box.x,\n clientY: box.y\n }, this.state);\n const boxSceneBottomRight = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: box.right,\n clientY: box.bottom\n }, this.state);\n bounds = {\n x: boxSceneTopLeft.x,\n y: boxSceneTopLeft.y,\n width: boxSceneBottomRight.x - boxSceneTopLeft.x,\n height: boxSceneBottomRight.y - boxSceneTopLeft.y,\n angle: 0,\n zoom: this.state.zoom.value,\n versionNonce: frameElement.versionNonce\n };\n\n this.frameNameBoundsCache._cache.set(frameElement.id, bounds);\n\n return bounds;\n }\n\n return null;\n }\n\n return bounds;\n },\n\n /**\n * @private\n */\n _cache: new Map()\n };\n\n this.renderFrameNames = () => {\n if (!this.state.frameRendering.enabled || !this.state.frameRendering.name) {\n return null;\n }\n\n const isDarkTheme = this.state.theme === \"dark\";\n return this.scene.getNonDeletedFrames().map((f, index) => {\n if (!(0,_element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__.isElementInViewport)(f, this.canvas.width / window.devicePixelRatio, this.canvas.height / window.devicePixelRatio, {\n offsetLeft: this.state.offsetLeft,\n offsetTop: this.state.offsetTop,\n scrollX: this.state.scrollX,\n scrollY: this.state.scrollY,\n zoom: this.state.zoom\n })) {\n // if frame not visible, don't render its name\n return null;\n }\n\n const {\n x: x1,\n y: y1\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: f.x,\n sceneY: f.y\n }, this.state);\n const {\n x: x2\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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.inheritFromUI\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__.exportCanvas)(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_33__.muteFSAbortError).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: error.message\n });\n });\n\n if (this.state.exportEmbedScene && fileHandle && (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isImageFileHandle)(fileHandle)) {\n this.setState({\n fileHandle\n });\n }\n });\n\n this.openEyeDropper = ({\n type\n }) => {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_EyeDropper__WEBPACK_IMPORTED_MODULE_59__.activeEyeDropperAtom, {\n swapPreviewOnAlt: true,\n colorPickerType: type === \"stroke\" ? \"elementStroke\" : \"elementBackground\",\n onSelect: (color, event) => {\n const shouldUpdateStrokeColor = type === \"background\" && event.altKey || type === \"stroke\" && !event.altKey;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (!selectedElements.length || this.state.activeTool.type !== \"selection\") {\n if (shouldUpdateStrokeColor) {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemStrokeColor: color\n }),\n commitToHistory: true\n });\n } else {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemBackgroundColor: color\n }),\n commitToHistory: true\n });\n }\n } else {\n this.updateScene({\n elements: this.scene.getElementsIncludingDeleted().map(el => {\n if (this.state.selectedElementIds[el.id]) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(el, {\n [shouldUpdateStrokeColor ? \"strokeColor\" : \"backgroundColor\"]: color\n });\n }\n\n return el;\n })\n });\n }\n },\n keepOpenOnAlt: false\n });\n };\n\n this.syncActionResult = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(actionResult => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n\n if (this.unmounted || actionResult === false) {\n return;\n }\n\n let editingElement = null;\n\n if (actionResult.elements) {\n actionResult.elements.forEach(element => {\n var _a;\n\n if (((_a = this.state.editingElement) === null || _a === void 0 ? void 0 : _a.id) === element.id && this.state.editingElement !== element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n editingElement = element;\n }\n });\n this.scene.replaceAllElements(actionResult.elements);\n\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n }\n\n if (actionResult.files) {\n this.files = actionResult.replaceFiles ? actionResult.files : Object.assign(Object.assign({}, this.files), actionResult.files);\n this.addNewImagesToImageCache();\n }\n\n if (actionResult.appState || editingElement || this.state.contextMenu) {\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n\n let viewModeEnabled = ((_a = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _a === void 0 ? void 0 : _a.viewModeEnabled) || false;\n let zenModeEnabled = ((_b = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _b === void 0 ? void 0 : _b.zenModeEnabled) || false;\n let gridSize = ((_c = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _c === void 0 ? void 0 : _c.gridSize) || null;\n const theme = ((_d = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _d === void 0 ? void 0 : _d.theme) || this.props.theme || _constants__WEBPACK_IMPORTED_MODULE_12__.THEME.LIGHT;\n let name = (_f = (_e = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : this.state.name;\n const errorMessage = (_h = (_g = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _g === void 0 ? void 0 : _g.errorMessage) !== null && _h !== void 0 ? _h : this.state.errorMessage;\n\n if (typeof this.props.viewModeEnabled !== \"undefined\") {\n viewModeEnabled = this.props.viewModeEnabled;\n }\n\n if (typeof this.props.zenModeEnabled !== \"undefined\") {\n zenModeEnabled = this.props.zenModeEnabled;\n }\n\n if (typeof this.props.gridModeEnabled !== \"undefined\") {\n gridSize = this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null;\n }\n\n if (typeof this.props.name !== \"undefined\") {\n name = this.props.name;\n }\n\n editingElement = editingElement || ((_j = actionResult.appState) === null || _j === void 0 ? void 0 : _j.editingElement) || null;\n\n if (editingElement === null || editingElement === void 0 ? void 0 : editingElement.isDeleted) {\n editingElement = null;\n }\n\n this.setState(state => {\n // using Object.assign instead of spread to fool TS 4.2.2+ into\n // regarding the resulting type as not containing undefined\n // (which the following expression will never contain)\n return Object.assign(actionResult.appState || {}, {\n // NOTE this will prevent opening context menu using an action\n // or programmatically from the host, so it will need to be\n // rewritten later\n contextMenu: null,\n editingElement,\n viewModeEnabled,\n zenModeEnabled,\n gridSize,\n theme,\n name,\n errorMessage\n });\n }, () => {\n if (actionResult.syncHistory) {\n this.history.setCurrentState(this.state, this.scene.getElementsIncludingDeleted());\n }\n });\n }\n }); // Lifecycle\n\n this.onBlur = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isHoldingSpace = false;\n this.setState({\n isBindingEnabled: true\n });\n });\n\n this.onUnload = () => {\n this.onBlur();\n };\n\n this.disableEvent = event => {\n event.preventDefault();\n };\n\n this.resetHistory = () => {\n this.history.clear();\n };\n /**\n * Resets scene & history.\n * ! Do not use to clear scene user action !\n */\n\n\n this.resetScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(opts => {\n this.scene.replaceAllElements([]);\n this.setState(state => Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n isLoading: (opts === null || opts === void 0 ? void 0 : opts.resetLoadingState) ? false : state.isLoading,\n theme: this.state.theme\n }));\n this.resetHistory();\n });\n\n this.initializeScene = () => __awaiter(this, void 0, void 0, function* () {\n var _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_29__.calculateScrollCenter)(scene.elements, Object.assign(Object.assign({}, scene.appState), {\n width: this.state.width,\n height: this.state.height,\n offsetTop: this.state.offsetTop,\n offsetLeft: this.state.offsetLeft\n })));\n } // FontFaceSet loadingdone event we listen on may not always fire\n // (looking at you Safari), so on init we manually load fonts for current\n // text elements on canvas, and rerender them once done. This also\n // seems faster even in browsers that do fire the loadingdone event.\n\n\n this.fonts.loadFontsForElements(scene.elements);\n this.resetHistory();\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n commitToHistory: true\n }));\n });\n\n this.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_33__.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_33__.withBatchedUpdates)(() => {\n this.scene.getElementsIncludingDeleted().forEach(element => _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__.ShapeCache[\"delete\"](element));\n this.setState({});\n });\n\n this.renderInteractiveSceneCallback = ({\n atLeastOneVisibleElement,\n scrollBars,\n elements\n }) => {\n if (scrollBars) {\n currentScrollBars = scrollBars;\n }\n\n const scrolledOutside = // hide when editing text\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? false : !atLeastOneVisibleElement && elements.length > 0;\n\n if (this.state.scrolledOutside !== scrolledOutside) {\n this.setState({\n scrolledOutside\n });\n }\n\n this.scheduleImageRefresh();\n };\n\n this.onScroll = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n const {\n offsetTop,\n offsetLeft\n } = this.getCanvasOffsets();\n this.setState(state => {\n if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {\n return null;\n }\n\n return {\n offsetTop,\n offsetLeft\n };\n });\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.SCROLL_TIMEOUT); // Copy/paste\n\n this.onCut = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.cutAll();\n event.preventDefault();\n event.stopPropagation();\n });\n this.onCopy = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.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_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n };\n\n this.onTouchEnd = event => {\n this.resetContextMenuTimer();\n\n if (event.touches.length > 0) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n } else {\n gesture.pointers.clear();\n }\n };\n\n this.pasteFromClipboard = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => __awaiter(this, void 0, void 0, function* () {\n var _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_33__.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_39__.SVGStringToFile)(string);\n }\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state); // prefer spreadsheet data over image file (MS Office/Libre Office)\n\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.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_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n });\n return;\n }\n\n if (this.props.onPaste) {\n try {\n if ((yield this.props.onPaste(data, event)) === false) {\n return;\n }\n } catch (error) {\n console.error(error);\n }\n }\n\n if (data.errorMessage) {\n this.setState({\n errorMessage: data.errorMessage\n });\n } else if (data.spreadsheet && !isPlainPaste) {\n this.setState({\n pasteDialog: {\n data: data.spreadsheet,\n shown: true\n }\n });\n } else if (data.elements) {\n const elements = data.programmaticAPI ? (0,_data_transform__WEBPACK_IMPORTED_MODULE_60__.convertToExcalidrawElements)(data.elements) : data.elements; // TODO remove formatting from elements if isPlainPaste\n\n this.addElementsFromPasteOrLibrary({\n elements,\n files: data.files || null,\n position: \"cursor\",\n retainSeed: isPlainPaste\n });\n } else if (data.text) {\n const maybeUrl = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.extractSrc)(data.text);\n\n if (!isPlainPaste && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(maybeUrl, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(maybeUrl) || ((_e = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.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_46__.normalizeLink)(maybeUrl)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n\n return;\n }\n\n this.addTextFromPaste(data.text, isPlainPaste);\n }\n\n this.setActiveTool({\n type: \"selection\"\n });\n event === null || event === void 0 ? void 0 : event.preventDefault();\n }));\n\n this.addElementsFromPasteOrLibrary = opts => {\n const elements = (0,_data_restore__WEBPACK_IMPORTED_MODULE_15__.restoreElements)(opts.elements, null, undefined);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(elements);\n const elementsCenterX = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minX, maxX) / 2;\n const elementsCenterY = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minY, maxY) / 2;\n const clientX = typeof opts.position === \"object\" ? opts.position.clientX : opts.position === \"cursor\" ? this.lastViewportPosition.x : this.state.width / 2 + this.state.offsetLeft;\n const clientY = typeof opts.position === \"object\" ? opts.position.clientY : opts.position === \"cursor\" ? this.lastViewportPosition.y : this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const dx = x - elementsCenterX;\n const dy = y - elementsCenterY;\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(dx, dy, this.state.gridSize);\n const newElements = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.duplicateElements)(elements.map(element => {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n x: element.x + gridX - minX,\n y: element.y + gridY - minY\n });\n }), {\n randomizeSeed: !opts.retainSeed\n });\n const nextElements = [...this.scene.getElementsIncludingDeleted(), ...newElements];\n this.scene.replaceAllElements(nextElements);\n newElements.forEach(newElement => {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(newElement) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(newElement)) {\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerElement)(newElement);\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.redrawTextBoundingBox)(newElement, container);\n }\n });\n\n if (opts.files) {\n this.files = Object.assign(Object.assign({}, this.files), opts.files);\n }\n\n this.history.resumeRecording();\n const nextElementsToSelect = (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.excludeElementsInFramesFromSelection)(newElements);\n this.setState(Object.assign(Object.assign(Object.assign({}, this.state), {\n // keep sidebar (presumably the library) open if it's docked and\n // can fit.\n //\n // Note, we should close the sidebar only if we're dropping items\n // from library, not when pasting from clipboard. Alas.\n openSidebar: this.state.openSidebar && this.device.canDeviceFitSidebar && _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.get(_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_61__.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_33__.updateActiveTool)(this.state, prevState.activeTool.locked ? {\n type: \"selection\"\n } : prevState.activeTool)), {\n locked: !prevState.activeTool.locked\n })\n };\n });\n };\n\n this.updateFrameRendering = opts => {\n this.setState(prevState => {\n var _a, _b, _c, _d;\n\n const next = typeof opts === \"function\" ? opts(prevState.frameRendering) : opts;\n return {\n frameRendering: {\n enabled: (_a = next === null || next === void 0 ? void 0 : next.enabled) !== null && _a !== void 0 ? _a : prevState.frameRendering.enabled,\n clip: (_b = next === null || next === void 0 ? void 0 : next.clip) !== null && _b !== void 0 ? _b : prevState.frameRendering.clip,\n name: (_c = next === null || next === void 0 ? void 0 : next.name) !== null && _c !== void 0 ? _c : prevState.frameRendering.name,\n outline: (_d = next === null || next === void 0 ? void 0 : next.outline) !== null && _d !== void 0 ? _d : prevState.frameRendering.outline\n }\n };\n });\n };\n\n this.togglePenMode = () => {\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_54__.actionToggleHandTool);\n };\n /**\n * Zooms on canvas viewport center\n */\n\n\n this.zoomCanvas = (\n /** decimal fraction between 0.1 (10% zoom) and 30 (3000% zoom) */\n value) => {\n this.setState(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.state.width / 2 + this.state.offsetLeft,\n viewportY: this.state.height / 2 + this.state.offsetTop,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(value)\n }, this.state)));\n };\n\n this.cancelInProgresAnimation = null;\n\n this.scrollToContent = (target = this.scene.getNonDeletedElements(), opts) => {\n var _a, _b;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this); // convert provided target into ExcalidrawElement[] if necessary\n\n const targetElements = Array.isArray(target) ? target : [target];\n let zoom = this.state.zoom;\n let scrollX = this.state.scrollX;\n let scrollY = this.state.scrollY;\n\n if ((opts === null || opts === void 0 ? void 0 : opts.fitToContent) || (opts === null || opts === void 0 ? void 0 : opts.fitToViewport)) {\n const {\n appState\n } = (0,_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.zoomToFit)({\n targetElements,\n appState: this.state,\n fitToViewport: !!(opts === null || opts === void 0 ? void 0 : opts.fitToViewport),\n viewportZoomFactor: opts === null || opts === void 0 ? void 0 : opts.viewportZoomFactor\n });\n zoom = appState.zoom;\n scrollX = appState.scrollX;\n scrollY = appState.scrollY;\n } else {\n // compute only the viewport location, without any zoom adjustment\n const scroll = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(targetElements, this.state);\n scrollX = scroll.scrollX;\n scrollY = scroll.scrollY;\n } // when animating, we use RequestAnimationFrame to prevent the animation\n // from slowing down other processes\n\n\n if (opts === null || opts === void 0 ? void 0 : opts.animate) {\n const origScrollX = this.state.scrollX;\n const origScrollY = this.state.scrollY;\n const origZoom = this.state.zoom.value;\n const cancel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeToValuesRAF)({\n fromValues: {\n scrollX: origScrollX,\n scrollY: origScrollY,\n zoom: origZoom\n },\n toValues: {\n scrollX,\n scrollY,\n zoom: zoom.value\n },\n interpolateValue: (from, to, progress, key) => {\n // for zoom, use different easing\n if (key === \"zoom\") {\n return from * Math.pow(to / from, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeOut)(progress));\n } // handle using default\n\n\n return undefined;\n },\n onStep: ({\n scrollX,\n scrollY,\n zoom\n }) => {\n this.setState({\n scrollX,\n scrollY,\n zoom: {\n value: zoom\n }\n });\n },\n onStart: () => {\n this.setState({\n shouldCacheIgnoreZoom: true\n });\n },\n onEnd: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n onCancel: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n duration: (_b = opts === null || opts === void 0 ? void 0 : opts.duration) !== null && _b !== void 0 ? _b : 500\n });\n\n this.cancelInProgresAnimation = () => {\n cancel();\n this.cancelInProgresAnimation = null;\n };\n } else {\n this.setState({\n scrollX,\n scrollY,\n zoom\n });\n }\n };\n /** use when changing scrollX/scrollY/zoom based on user interaction */\n\n\n this.translateCanvas = state => {\n var _a;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this);\n this.setState(state);\n };\n\n this.setToast = toast => {\n this.setState({\n toast\n });\n };\n\n this.restoreFileFromShare = () => __awaiter(this, void 0, void 0, function* () {\n try {\n const webShareTargetCache = yield caches.open(\"web-share-target\");\n const response = yield webShareTargetCache.match(\"shared-file\");\n\n if (response) {\n const blob = yield response.blob();\n const file = new File([blob], blob.name || \"\", {\n type: blob.type\n });\n this.loadFileToCanvas(file, null);\n yield webShareTargetCache.delete(\"shared-file\");\n window.history.replaceState(null, _constants__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, window.location.pathname);\n }\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n });\n /** adds supplied files to existing files in the appState */\n\n\n this.addFiles = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(files => {\n const filesMap = files.reduce((acc, fileData) => {\n acc.set(fileData.id, fileData);\n return acc;\n }, new Map());\n this.files = Object.assign(Object.assign({}, this.files), Object.fromEntries(filesMap));\n this.scene.getNonDeletedElements().forEach(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && filesMap.has(element.fileId)) {\n this.imageCache.delete(element.fileId);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__.ShapeCache[\"delete\"](element);\n }\n });\n this.scene.informMutation();\n this.addNewImagesToImageCache();\n });\n this.updateScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(sceneData => {\n if (sceneData.commitToHistory) {\n this.history.resumeRecording();\n }\n\n if (sceneData.appState) {\n this.setState(sceneData.appState);\n }\n\n if (sceneData.elements) {\n this.scene.replaceAllElements(sceneData.elements);\n }\n\n if (sceneData.collaborators) {\n this.setState({\n collaborators: sceneData.collaborators\n });\n }\n });\n\n this.onSceneUpdated = () => {\n this.setState({});\n };\n /**\n * @returns whether the menu was toggled on or off\n */\n\n\n this.toggleSidebar = ({\n name,\n tab,\n force\n }) => {\n var _a;\n\n let nextName;\n\n if (force === undefined) {\n nextName = ((_a = this.state.openSidebar) === null || _a === void 0 ? void 0 : _a.name) === name ? null : name;\n } else {\n nextName = force ? name : null;\n }\n\n this.setState({\n openSidebar: nextName ? {\n name: nextName,\n tab\n } : null\n });\n return !!nextName;\n };\n\n this.updateCurrentCursorPosition = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n this.lastViewportPosition.x = event.clientX;\n this.lastViewportPosition.y = event.clientY;\n }); // Input handling\n\n this.onKeyDown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // normalize `event.key` when CapsLock is pressed #2372\n if (\"Proxy\" in window && (!event.shiftKey && /^[A-Z]$/.test(event.key) || event.shiftKey && /^[a-z]$/.test(event.key))) {\n event = new Proxy(event, {\n get(ev, prop) {\n const value = ev[prop];\n\n if (typeof value === \"function\") {\n // fix for Proxies hijacking `this`\n return value.bind(ev);\n }\n\n return prop === \"key\" ? // CapsLock inverts capitalization based on ShiftKey, so invert\n // it back\n event.shiftKey ? ev.key.toUpperCase() : ev.key.toLowerCase() : value;\n }\n\n });\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.V) {\n IS_PLAIN_PASTE = event.shiftKey;\n clearTimeout(IS_PLAIN_PASTE_TIMER); // reset (100ms to be safe that we it runs after the ensuing\n // paste event). Though, technically unnecessary to reset since we\n // (re)set the flag before each paste event.\n\n IS_PLAIN_PASTE_TIMER = window.setTimeout(() => {\n IS_PLAIN_PASTE = false;\n }, 100);\n } // prevent browser zoom in input fields\n\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n if (event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.MINUS || event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.EQUAL) {\n event.preventDefault();\n return;\n }\n } // bail if\n\n\n if ( // inside an input\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target) && // unless pressing escape (finalize action)\n event.key !== _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ESCAPE || // or unless using arrows (to move between buttons)\n (0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key) && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isInputLike)(event.target)) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.QUESTION_MARK) {\n this.setState({\n openDialog: \"help\"\n });\n return;\n } else if (event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.E && event.shiftKey && event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n event.preventDefault();\n this.setState({\n openDialog: \"imageExport\"\n });\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_UP || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n let offset = (event.shiftKey ? this.state.width : this.state.height) / this.state.zoom.value;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n offset = -offset;\n }\n\n if (event.shiftKey) {\n this.translateCanvas(state => ({\n scrollX: state.scrollX + offset\n }));\n } else {\n this.translateCanvas(state => ({\n scrollY: state.scrollY + offset\n }));\n }\n }\n\n if (this.actionManager.handleKeyDown(event)) {\n return;\n }\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: false\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const step = this.state.gridSize && (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize) || (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_SHIFT_TRANSLATE_AMOUNT : _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT);\n let offsetX = 0;\n let offsetY = 0;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_LEFT) {\n offsetX = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_RIGHT) {\n offsetX = step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_UP) {\n offsetY = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_DOWN) {\n offsetY = step;\n }\n\n const selectedElements = this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n });\n selectedElements.forEach(element => {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: element.x + offsetX,\n y: element.y + offsetY\n });\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element, {\n simultaneouslyUpdated: selectedElements\n });\n });\n this.maybeSuggestBindingForAll(selectedElements);\n event.preventDefault();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ENTER) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n const selectedElement = selectedElements[0];\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElement)) {\n if (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElement, this.scene)\n });\n }\n }\n } else if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isValidTextContainer)(selectedElement)) {\n let container;\n\n if (!(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement)) {\n container = selectedElement;\n }\n\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(selectedElement, this.state);\n const sceneX = midPoint.x;\n const sceneY = midPoint.y;\n this.startTextEditing({\n sceneX,\n sceneY,\n container\n });\n event.preventDefault();\n return;\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(selectedElement)) {\n this.setState({\n editingFrame: selectedElement.id\n });\n }\n }\n } else if (!event.ctrlKey && !event.altKey && !event.metaKey && this.state.draggingElement === null) {\n const shape = (0,_shapes__WEBPACK_IMPORTED_MODULE_32__.findShapeByKey)(event.key);\n\n if (shape) {\n if (this.state.activeTool.type !== shape) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", shape, `keyboard (${this.device.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n event.preventDefault();\n }\n\n if ((event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (this.state.activeTool.type === \"selection\" && !selectedElements.length) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && ((0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(this.state.activeTool.type) || selectedElements.some(element => (0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(element.type)))) {\n this.setState({\n openPopup: \"elementBackground\"\n });\n event.stopPropagation();\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) {\n this.setState({\n openPopup: \"elementStroke\"\n });\n event.stopPropagation();\n }\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.BACKSPACE || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.DELETE)) {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__.activeConfirmDialogAtom, \"clearCanvas\");\n } // eye dropper\n // -----------------------------------------------------------------------\n\n\n const lowerCased = event.key.toLocaleLowerCase();\n const isPickingStroke = lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S && event.shiftKey;\n const isPickingBackground = event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.I || lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && event.shiftKey;\n\n if (isPickingStroke || isPickingBackground) {\n this.openEyeDropper({\n type: isPickingStroke ? \"stroke\" : \"background\"\n });\n } // -----------------------------------------------------------------------\n\n });\n this.onWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // prevent browser pinch zoom on DOM elements\n if (!(event.target instanceof HTMLCanvasElement) && event.ctrlKey) {\n event.preventDefault();\n }\n });\n this.onKeyUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE) {\n if (this.state.viewModeEnabled) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n isHoldingSpace = false;\n }\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: true\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements)(selectedElements) : (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(selectedElements);\n this.setState({\n suggestedBindings: []\n });\n }\n });\n\n this.setActiveTool = tool => {\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, tool);\n\n if (nextActiveTool.type === \"hand\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (!isHoldingSpace) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_33__.isToolIcon)(document.activeElement)) {\n this.focusContainer();\n }\n\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElementType)(nextActiveTool.type)) {\n this.setState({\n suggestedBindings: []\n });\n }\n\n if (nextActiveTool.type === \"image\") {\n this.onImageAction();\n }\n\n if (nextActiveTool.type !== \"selection\") {\n this.setState({\n activeTool: nextActiveTool,\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n } else {\n this.setState({\n activeTool: nextActiveTool,\n activeEmbeddable: null\n });\n }\n };\n\n this.setCursor = cursor => {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, cursor);\n };\n\n this.resetCursor = () => {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n };\n /**\n * returns whether user is making a gesture with >= 2 fingers (points)\n * on o touch screen (not on a trackpad). Currently only relates to Darwin\n * (iOS/iPadOS,MacOS), but may work on other devices in the future if\n * GestureEvent is standardized.\n */\n\n\n this.isTouchScreenMultiTouchGesture = () => {\n // we don't want to deselect when using trackpad, and multi-point gestures\n // only work on touch screens, so checking for >= pointers means we're on a\n // touchscreen\n return gesture.pointers.size >= 2;\n }; // fires only on Safari\n\n\n this.onGestureStart = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // we only want to deselect on touch screens because user may have selected\n // elements by mistake while zooming\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n\n gesture.initialScale = this.state.zoom.value;\n }); // fires only on Safari\n\n this.onGestureChange = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // onGestureChange only has zoom factor but not the center.\n // If we're on iPad or iPhone, then we recognize multi-touch and will\n // zoom in at the right location in the touchmove handler\n // (handleCanvasPointerMove).\n //\n // On Macbook trackpad, we don't have those events so will zoom in at the\n // current location instead.\n //\n // As such, bail from this handler on touch devices.\n\n if (this.isTouchScreenMultiTouchGesture()) {\n return;\n }\n\n const initialScale = gesture.initialScale;\n\n if (initialScale) {\n this.setState(state => Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * event.scale)\n }, state)));\n }\n }); // fires only on Safari\n\n this.onGestureEnd = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // reselect elements only on touch screens (see onGestureStart)\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n }\n\n gesture.initialScale = null;\n });\n\n this.startTextEditing = ({\n sceneX,\n sceneY,\n insertAtParentCenter = true,\n container\n }) => {\n var _a, _b;\n\n let shouldBindToContainer = false;\n let parentCenterPosition = insertAtParentCenter && this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n\n if (container && parentCenterPosition) {\n const boundTextElementToContainer = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(container);\n\n if (!boundTextElementToContainer) {\n shouldBindToContainer = true;\n }\n }\n\n let existingTextElement = null;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElements[0])) {\n existingTextElement = selectedElements[0];\n } else if (container) {\n existingTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(selectedElements[0]);\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n\n const fontFamily = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.fontFamily) || this.state.currentItemFontFamily;\n const lineHeight = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.lineHeight) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(fontFamily);\n const fontSize = this.state.currentItemFontSize;\n\n if (!existingTextElement && shouldBindToContainer && container && !(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isArrowElement)(container)) {\n const fontString = {\n fontSize,\n fontFamily\n };\n const minWidth = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineWidth)((0,_utils__WEBPACK_IMPORTED_MODULE_33__.getFontString)(fontString), lineHeight);\n const minHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineHeight)(fontSize, lineHeight);\n const newHeight = Math.max(container.height, minHeight);\n const newWidth = Math.max(container.width, minWidth);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n height: newHeight,\n width: newWidth\n });\n sceneX = container.x + newWidth / 2;\n sceneY = container.y + newHeight / 2;\n\n if (parentCenterPosition) {\n parentCenterPosition = this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n }\n }\n\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: sceneX,\n y: sceneY\n });\n const element = existingTextElement ? existingTextElement : (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)({\n x: parentCenterPosition ? parentCenterPosition.elementCenterX : sceneX,\n y: parentCenterPosition ? parentCenterPosition.elementCenterY : sceneY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text: \"\",\n fontSize,\n fontFamily,\n textAlign: parentCenterPosition ? \"center\" : this.state.currentItemTextAlign,\n verticalAlign: parentCenterPosition ? _constants__WEBPACK_IMPORTED_MODULE_12__.VERTICAL_ALIGN.MIDDLE : _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n containerId: shouldBindToContainer ? container === null || container === void 0 ? void 0 : container.id : undefined,\n groupIds: (_a = container === null || container === void 0 ? void 0 : container.groupIds) !== null && _a !== void 0 ? _a : [],\n lineHeight,\n angle: (_b = container === null || container === void 0 ? void 0 : container.angle) !== null && _b !== void 0 ? _b : 0,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n\n if (!existingTextElement && shouldBindToContainer && container) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n boundElements: (container.boundElements || []).concat({\n type: \"text\",\n id: element.id\n })\n });\n }\n\n this.setState({\n editingElement: element\n });\n\n if (!existingTextElement) {\n if (container && shouldBindToContainer) {\n const containerIndex = this.scene.getElementIndex(container.id);\n this.scene.insertElementAtIndex(element, containerIndex + 1);\n } else {\n this.scene.addNewElement(element);\n }\n }\n\n this.setState({\n editingElement: element\n });\n this.handleTextWysiwyg(element, {\n isExistingElement: !!existingTextElement\n });\n };\n\n this.handleCanvasDoubleClick = event => {\n // case: double-clicking with arrow/line tool selected would both create\n // text and enter multiElement mode\n if (this.state.multiElement) {\n return;\n } // we should only be able to double click when mode is selection\n\n\n if (this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0])) {\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id)) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElements[0], this.scene)\n });\n return;\n } else if (this.state.editingLinearElement && this.state.editingLinearElement.elementId === selectedElements[0].id) {\n return;\n }\n }\n\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n let {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedGroupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIds)(this.state);\n\n if (selectedGroupIds.length > 0) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n const selectedGroupId = hitElement && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIdForElement)(hitElement, this.state.selectedGroupIds);\n\n if (selectedGroupId) {\n this.setState(prevState => Object.assign(Object.assign({}, prevState), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: selectedGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)));\n return;\n }\n }\n\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.viewModeEnabled) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) {\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"active\"\n }\n });\n return;\n }\n\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if (container) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(container) || !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTransparent)(container.backgroundColor) || (0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY])) {\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, this.state);\n sceneX = midPoint.x;\n sceneY = midPoint.y;\n }\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n }\n };\n\n this.getElementLinkAtPosition = (scenePointer, hitElement) => {\n // Reversing so we traverse the elements in decreasing order\n // of z-index\n const elements = this.scene.getNonDeletedElements().slice().reverse();\n let hitElementIndex = Infinity;\n return elements.find((element, index) => {\n if (hitElement && element.id === hitElement.id) {\n hitElementIndex = index;\n }\n\n return element.link && index <= hitElementIndex && (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(element, this.state, [scenePointer.x, scenePointer.y], this.device.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_33__.viewportCoordsToSceneCoords)(this.lastPointerDown, this.state);\n const lastPointerDownHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerDownCoords.x, lastPointerDownCoords.y], this.device.isMobile);\n const lastPointerUpCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerUp, this.state);\n const lastPointerUpHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.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_46__.normalizeLink)(url);\n let customEvent;\n\n if (this.props.onLinkOpen) {\n customEvent = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.wrapEvent)(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.EXCALIDRAW_LINK, event.nativeEvent);\n this.props.onLinkOpen(Object.assign(Object.assign({}, this.hitLinkElement), {\n link: url\n }), customEvent);\n }\n\n if (!(customEvent === null || customEvent === void 0 ? void 0 : customEvent.defaultPrevented)) {\n const target = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.isLocalLink)(url) ? \"_self\" : \"_blank\";\n const newWindow = window.open(undefined, target); // https://mathiasbynens.github.io/rel-noopener/\n\n if (newWindow) {\n newWindow.opener = null;\n newWindow.location = url;\n }\n }\n }\n }\n };\n\n this.getTopLayerFrameAtSceneCoords = sceneCoords => {\n const frames = this.scene.getNonDeletedFrames().filter(frame => (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)(sceneCoords, frame));\n return frames.length ? frames[frames.length - 1] : null;\n };\n\n this.handleCanvasPointerMove = event => {\n var _a, _b;\n\n this.savePointer(event.clientX, event.clientY, this.state.cursorButton);\n\n if (gesture.pointers.has(event.pointerId)) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n }\n\n const initialScale = gesture.initialScale;\n\n if (gesture.pointers.size === 2 && gesture.lastCenter && initialScale && gesture.initialDistance) {\n const center = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n const deltaX = center.x - gesture.lastCenter.x;\n const deltaY = center.y - gesture.lastCenter.y;\n gesture.lastCenter = center;\n const distance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n const scaleFactor = this.state.activeTool.type === \"freedraw\" && this.state.penMode ? 1 : distance / gesture.initialDistance;\n const nextZoom = scaleFactor ? (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * scaleFactor) : this.state.zoom.value;\n this.setState(state => {\n const zoomState = (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: center.x,\n viewportY: center.y,\n nextZoom\n }, state);\n this.translateCanvas({\n zoom: zoomState.zoom,\n scrollX: zoomState.scrollX + deltaX / nextZoom,\n scrollY: zoomState.scrollY + deltaY / nextZoom,\n shouldCacheIgnoreZoom: true\n });\n });\n this.resetShouldCacheIgnoreZoomDebounced();\n } else {\n gesture.lastCenter = gesture.initialDistance = gesture.initialScale = null;\n }\n\n if (isHoldingSpace || isPanning || isDraggingScrollBar || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state)) {\n return;\n }\n\n const isPointerOverScrollBars = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop);\n const isOverScrollBar = isPointerOverScrollBars.isOverEither;\n\n if (!this.state.draggingElement && !this.state.multiElement) {\n if (isOverScrollBar) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const {\n x: scenePointerX,\n y: scenePointerY\n } = scenePointer;\n\n if (this.state.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_33__.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_33__.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_33__.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_33__.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_33__.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_33__.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.showHyperlinkTooltip)(this.hitLinkElement, this.state);\n } else {\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.hideHyperlinkToolip)();\n\n if (hitElement && (hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) && this.state.selectedElementIds[hitElement.id] && !this.state.contextMenu && !this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: \"info\"\n });\n } else if (this.state.activeTool.type === \"text\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (isOverScrollBar) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.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_33__.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_33__.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 this.updateGestureOnPointerDown(event); // if dragging element is freedraw and another pointerdown event occurs\n // a second finger is on the screen\n // discard the freedraw element if it is very short because it is likely\n // just a spike, otherwise finalize the freedraw element when the second\n // finger is lifted\n\n if (event.pointerType === \"touch\" && this.state.draggingElement && this.state.draggingElement.type === \"freedraw\") {\n const element = this.state.draggingElement;\n this.updateScene(Object.assign(Object.assign({}, element.points.length < 10 ? {\n elements: this.scene.getElementsIncludingDeleted().filter(el => el.id !== element.id)\n } : {}), {\n appState: {\n draggingElement: null,\n editingElement: null,\n startBoundElement: null,\n suggestedBindings: [],\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.keys(this.state.selectedElementIds).filter(key => key !== element.id).reduce((obj, key) => {\n obj[key] = this.state.selectedElementIds[key];\n return obj;\n }, {}), this.state)\n }\n }));\n return;\n } // remove any active selection when we start to interact with canvas\n // (mainly, we care about removing selection outside the component which\n // would prevent our copy handling otherwise)\n\n\n const selection = document.getSelection();\n\n if (selection === null || selection === void 0 ? void 0 : selection.anchorNode) {\n selection.removeAllRanges();\n }\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices(event);\n this.maybeCleanupAfterMissingPointerUp(event); //fires only once, if pen is detected, penMode is enabled\n //the user can disable this by toggling the penMode button\n\n if (!this.state.penDetected && event.pointerType === \"pen\") {\n this.setState(prevState => {\n return {\n penMode: true,\n penDetected: true\n };\n });\n }\n\n if (!this.device.isTouchScreen && [\"pen\", \"touch\"].includes(event.pointerType)) {\n this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(this.device, {\n isTouchScreen: true\n });\n }\n\n if (isPanning) {\n return;\n }\n\n this.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.CROSSHAIR); // retrieve the latest element as the state may be stale\n\n const pendingImageElement = this.state.pendingImageElementId && this.scene.getElement(this.state.pendingImageElementId);\n\n if (!pendingImageElement) {\n return;\n }\n\n this.setState({\n draggingElement: pendingImageElement,\n editingElement: pendingImageElement,\n pendingImageElementId: null,\n multiElement: null\n });\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n (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 (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\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 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_33__.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_45__.isPointHittingLinkIcon)(this.hitLinkElement, this.state, [scenePointer.x, scenePointer.y])) {\n this.handleEmbeddableCenterClick(this.hitLinkElement);\n } else {\n this.redirectToLink(event, this.device.isTouchScreen);\n }\n } else if (this.state.viewModeEnabled) {\n this.setState({\n activeEmbeddable: null,\n selectedElementIds: {}\n });\n }\n };\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices = event => {\n // deal with opening context menu on touch devices\n if (event.pointerType === \"touch\") {\n invalidateContextMenu = false;\n\n if (touchTimeout) {\n // If there's already a touchTimeout, this means that there's another\n // touch down and we are doing another touch, so we shouldn't open the\n // context menu.\n invalidateContextMenu = true;\n } else {\n // open the context menu with the first touch's clientX and clientY\n // if the touch is not moving\n touchTimeout = window.setTimeout(() => {\n touchTimeout = 0;\n\n if (!invalidateContextMenu) {\n this.handleCanvasContextMenu(event);\n }\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.TOUCH_CTX_MENU_TIMEOUT);\n }\n }\n };\n\n this.resetContextMenuTimer = () => {\n clearTimeout(touchTimeout);\n touchTimeout = 0;\n invalidateContextMenu = false;\n }; // Returns whether the event is a panning\n\n\n this.handleCanvasPanUsingWheelOrSpaceDrag = event => {\n if (!(gesture.pointers.size <= 1 && (event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.WHEEL || event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && isHoldingSpace || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state) || this.state.viewModeEnabled)) || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement)) {\n return false;\n }\n\n isPanning = true;\n event.preventDefault();\n let nextPastePrevented = false;\n const isLinux = /Linux/.test(window.navigator.platform);\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRABBING);\n let {\n clientX: lastX,\n clientY: lastY\n } = event;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const deltaX = lastX - event.clientX;\n const deltaY = lastY - event.clientY;\n lastX = event.clientX;\n lastY = event.clientY;\n /*\n * Prevent paste event if we move while middle clicking on Linux.\n * See issue #1383.\n */\n\n if (isLinux && !nextPastePrevented && (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1)) {\n nextPastePrevented = true;\n /* Prevent the next paste event */\n\n const preventNextPaste = event => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n event.stopPropagation();\n };\n /*\n * Reenable next paste in case of disabled middle click paste for\n * any reason:\n * - right click paste\n * - empty clipboard\n */\n\n\n const enableNextPaste = () => {\n setTimeout(() => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }, 100);\n };\n\n document.body.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }\n\n this.translateCanvas({\n scrollX: this.state.scrollX - deltaX / this.state.zoom.value,\n scrollY: this.state.scrollY - deltaY / this.state.zoom.value\n });\n });\n const teardown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(lastPointerUp = () => {\n lastPointerUp = null;\n isPanning = false;\n\n if (!isHoldingSpace) {\n if (this.state.viewModeEnabled) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n this.setState({\n cursorButton: \"up\"\n });\n this.savePointer(event.clientX, event.clientY, \"up\");\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, teardown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, teardown);\n onPointerMove.flush();\n });\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, teardown);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove, {\n passive: true\n });\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, teardown);\n return true;\n };\n\n this.clearSelectionIfNotUsingSelection = () => {\n if (this.state.activeTool.type !== \"selection\") {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n };\n /**\n * @returns whether the pointer event has been completely handled\n */\n\n\n this.handleSelectionOnPointerDown = (event, pointerDownState) => {\n var _a;\n\n if (this.state.activeTool.type === \"selection\") {\n const elements = this.scene.getNonDeletedElements();\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && !this.state.editingLinearElement) {\n const elementWithTransformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getElementWithTransformHandleType)(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);\n\n if (elementWithTransformHandleType != null) {\n this.setState({\n resizingElement: elementWithTransformHandleType.element\n });\n pointerDownState.resize.handleType = elementWithTransformHandleType.transformHandleType;\n }\n } else if (selectedElements.length > 1) {\n pointerDownState.resize.handleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getTransformHandleTypeFromCoords)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);\n }\n\n if (pointerDownState.resize.handleType) {\n pointerDownState.resize.isResizing = true;\n pointerDownState.resize.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getResizeOffsetXY)(pointerDownState.resize.handleType, selectedElements, pointerDownState.origin.x, pointerDownState.origin.y));\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0]) && selectedElements[0].points.length === 2) {\n pointerDownState.resize.arrowDirection = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getResizeArrowDirection)(pointerDownState.resize.handleType, selectedElements[0]);\n }\n } else {\n if (this.state.selectedLinearElement) {\n const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;\n const ret = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerDown(event, this.state, this.history, pointerDownState.origin, linearElementEditor);\n\n if (ret.hitElement) {\n pointerDownState.hit.element = ret.hitElement;\n }\n\n if (ret.linearElementEditor) {\n this.setState({\n selectedLinearElement: ret.linearElementEditor\n });\n\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: ret.linearElementEditor\n });\n }\n }\n\n if (ret.didAddPoint) {\n return true;\n }\n } // hitElement may already be set above, so check first\n\n\n pointerDownState.hit.element = (_a = pointerDownState.hit.element) !== null && _a !== void 0 ? _a : this.getElementAtPosition(pointerDownState.origin.x, pointerDownState.origin.y);\n\n if (pointerDownState.hit.element) {\n // Early return if pointer is hitting link icon\n const hitLinkElement = this.getElementLinkAtPosition({\n x: pointerDownState.origin.x,\n y: pointerDownState.origin.y\n }, pointerDownState.hit.element);\n\n if (hitLinkElement) {\n return false;\n }\n } // For overlapped elements one position may hit\n // multiple elements\n\n\n pointerDownState.hit.allHitElements = this.getElementsAtPosition(pointerDownState.origin.x, pointerDownState.origin.y);\n const hitElement = pointerDownState.hit.element;\n const someHitElementIsSelected = pointerDownState.hit.allHitElements.some(element => this.isASelectedElement(element));\n\n if ((hitElement === null || !someHitElementIsSelected) && !event.shiftKey && !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) {\n this.clearSelection(hitElement);\n }\n\n if (this.state.editingLinearElement) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [this.state.editingLinearElement.elementId]: true\n }, this.state)\n }); // If we click on something\n } else if (hitElement != null) {\n // on CMD/CTRL, drill down to hit element regardless of groups etc.\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if (!this.state.selectedElementIds[hitElement.id]) {\n pointerDownState.hit.wasAddedToSelection = true;\n }\n\n this.setState(prevState => Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.editGroupForSelectedElement)(prevState, hitElement)), {\n previousSelectedElementIds: this.state.selectedElementIds\n })); // mark as not completely handled so as to allow dragging etc.\n\n return false;\n } // deselect if item is selected\n // if shift is not clicked, this will always return true\n // otherwise, it will trigger selection based on current\n // state of the box\n\n\n if (!this.state.selectedElementIds[hitElement.id]) {\n // if we are currently editing a group, exiting editing mode and deselect the group.\n if (this.state.editingGroupId && !(0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, this.state.editingGroupId)) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n } // Add hit element to selection. At this point if we're not holding\n // SHIFT the previously selected element(s) were deselected above\n // (make sure you use setState updater to use latest state)\n // With shift-selection, we want to make sure that frames and their containing\n // elements are not selected at the same time.\n\n\n if (!someHitElementIsSelected && !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) {\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n });\n const previouslySelectedElements = [];\n Object.keys(prevState.selectedElementIds).forEach(id => {\n const element = this.scene.getElement(id);\n element && previouslySelectedElements.push(element);\n }); // if hitElement is frame, deselect all of its elements if they are selected\n\n if (hitElement.type === \"frame\") {\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.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_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(element)) {\n container = element;\n sceneX = element.x + element.width / 2;\n sceneY = element.y + element.height / 2;\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n\n if (!this.state.activeTool.locked) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n };\n\n this.handleFreeDrawElementOnPointerDown = (event, elementType, pointerDownState) => {\n // Begin a mark capture. This does not have to update state yet.\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, null);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFreeDrawElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: null,\n simulatePressure: event.pressure === 0.5,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n const pressures = element.simulatePressure ? element.pressures : [...element.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [[0, 0]],\n pressures\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }; //create rectangle element with youtube top left on nearest grid point width / hight 640/360\n\n\n this.insertEmbeddableElement = ({\n sceneX,\n sceneY,\n link\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.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_34__.getEmbedLink)(link);\n\n if (!embedLink) {\n return;\n }\n\n if (embedLink.warning) {\n this.setToast({\n message: embedLink.warning,\n closable: true\n });\n }\n\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)({\n type: \"embeddable\",\n x: gridX,\n y: gridY,\n strokeColor: \"transparent\",\n backgroundColor: \"transparent\",\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n roundness: this.getCurrentItemRoundness(\"embeddable\"),\n opacity: this.state.currentItemOpacity,\n locked: false,\n width: embedLink.aspectRatio.w,\n height: embedLink.aspectRatio.h,\n link,\n validated: null\n });\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), element]);\n return element;\n };\n\n this.createImageElement = ({\n sceneX,\n sceneY\n }) => {\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_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [multiElement.id]: true\n }), prevState)\n })); // clicking outside commit zone → update reference for last committed\n // point\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n lastCommittedPoint: multiElement.points[multiElement.points.length - 1]\n });\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.\n If so, we want it to be null for start and \"arrow\" for end. If the linear item is not\n an arrow, we want it to be null for both. Otherwise, we want it to use the\n values from appState. */\n\n const {\n currentItemStartArrowhead,\n currentItemEndArrowhead\n } = this.state;\n const [startArrowhead, endArrowhead] = elementType === \"arrow\" ? [currentItemStartArrowhead, currentItemEndArrowhead] : [null, null];\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newLinearElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.state.currentItemRoundness === \"round\" ? {\n type: _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null,\n startArrowhead,\n endArrowhead,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [...element.points, [0, 0]]\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }\n };\n\n this.createGenericElementOnPointerDown = (elementType, pointerDownState) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.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_39__.isSupportedImageFile)(imageFile)) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.unsupportedFileType\"));\n }\n\n const mimeType = imageFile.type;\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, \"wait\");\n\n if (mimeType === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n try {\n imageFile = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.normalizeSVG)(yield imageFile.text()), imageFile.name);\n } catch (error) {\n console.warn(error);\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.svgImageInsertError\"));\n }\n } // generate image id (by default the file digest) before any\n // resizing/compression takes place to keep it more portable\n\n\n const fileId = yield ((_g = (_f = this.props).generateIdForFile) === null || _g === void 0 ? void 0 : _g.call(_f, imageFile)) || (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.generateIdFromFile)(imageFile);\n\n if (!fileId) {\n console.warn(\"Couldn't generate file id or the supplied `generateIdForFile` didn't resolve to one.\");\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\"));\n }\n\n const existingFileData = this.files[fileId];\n\n if (!(existingFileData === null || existingFileData === void 0 ? void 0 : existingFileData.dataURL)) {\n try {\n imageFile = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT\n });\n } catch (error) {\n console.error(\"error trying to resing image file on insertion\", error);\n }\n\n if (imageFile.size > _constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.fileTooBig\", {\n maxSize: `${Math.trunc(_constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES / 1024 / 1024)}MB`\n }));\n }\n }\n\n if (showCursorImagePreview) {\n const dataURL = (_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_39__.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_39__.getDataURL)(imageFile));\n const imageElement = (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(_imageElement, {\n fileId\n }, false);\n return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {\n var _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_33__.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_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: cursorImageSizePx\n });\n let previewDataURL = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imagePreview); // SVG cannot be resized via `resizeImageFile` so we resize by rendering to\n // a small canvas\n\n if (imageFile.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n const img = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.loadHTMLImageElement)(previewDataURL);\n let height = Math.min(img.height, cursorImageSizePx);\n let width = height * (img.width / img.height);\n\n if (width > cursorImageSizePx) {\n width = cursorImageSizePx;\n height = width * (img.height / img.width);\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.height = height;\n canvas.width = width;\n const context = canvas.getContext(\"2d\");\n context.drawImage(img, 0, 0, width, height);\n previewDataURL = canvas.toDataURL(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg);\n }\n\n if (this.state.pendingImageElementId) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const imageFile = yield (0,_data_filesystem__WEBPACK_IMPORTED_MODULE_42__.fileOpen)({\n description: \"Image\",\n extensions: Object.keys(_constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_MIME_TYPES)\n });\n const imageElement = this.createImageElement({\n sceneX: x,\n sceneY: y\n });\n\n if (insertOnCanvasDirectly) {\n this.insertImageElement(imageElement, imageFile);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } else {\n this.setState({\n pendingImageElementId: imageElement.id\n }, () => {\n this.insertImageElement(imageElement, imageFile,\n /* showCursorImagePreview */\n true);\n });\n }\n } catch (error) {\n if (error.name !== \"AbortError\") {\n console.error(error);\n } else {\n console.warn(error);\n }\n\n this.setState({\n pendingImageElementId: null,\n editingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n }\n });\n\n this.initializeImageDimensions = (imageElement, forceNaturalSize = false) => {\n var _a;\n\n const image = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(imageElement) && ((_a = this.imageCache.get(imageElement.fileId)) === null || _a === void 0 ? void 0 : _a.image);\n\n if (!image || image instanceof Promise) {\n if (imageElement.width < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value && imageElement.height < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value) {\n const placeholderSize = 100 / this.state.zoom.value;\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n x: imageElement.x - placeholderSize / 2,\n y: imageElement.y - placeholderSize / 2,\n width: placeholderSize,\n height: placeholderSize\n });\n }\n\n return;\n }\n\n if (forceNaturalSize || // if user-created bounding box is below threshold, assume the\n // intention was to click instead of drag, and use the image's\n // intrinsic size\n imageElement.width < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value && imageElement.height < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value) {\n const minHeight = Math.max(this.state.height - 120, 160); // max 65% of canvas height, clamped to <300px, vh - 120px>\n\n const maxHeight = Math.min(minHeight, Math.floor(this.state.height * 0.5) / this.state.zoom.value);\n const height = Math.min(image.naturalHeight, maxHeight);\n const width = height * (image.naturalWidth / image.naturalHeight); // add current imageElement width/height to account for previous centering\n // of the placeholder image\n\n const x = imageElement.x + imageElement.width / 2 - width / 2;\n const y = imageElement.y + imageElement.height / 2 - height / 2;\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n x,\n y,\n width,\n height\n });\n }\n };\n /** updates image cache, refreshing updated elements and/or setting status\n to error for images that fail during <img> element creation */\n\n\n this.updateImageCache = (elements, files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const {\n updatedFiles,\n erroredFiles\n } = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.updateImageCache)({\n imageCache: this.imageCache,\n fileIds: elements.map(element => element.fileId),\n files\n });\n\n if (updatedFiles.size || erroredFiles.size) {\n for (const element of elements) {\n if (updatedFiles.has(element.fileId)) {\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__.ShapeCache[\"delete\"](element);\n }\n }\n }\n\n if (erroredFiles.size) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().map(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && erroredFiles.has(element.fileId)) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n status: \"error\"\n });\n }\n\n return element;\n }));\n }\n\n return {\n updatedFiles,\n erroredFiles\n };\n });\n /** adds new images to imageCache and re-renders if needed */\n\n\n this.addNewImagesToImageCache = (imageElements = (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.getInitializedImageElements)(this.scene.getNonDeletedElements()), files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const uncachedImageElements = imageElements.filter(element => !element.isDeleted && !this.imageCache.has(element.fileId));\n\n if (uncachedImageElements.length) {\n const {\n updatedFiles\n } = yield this.updateImageCache(uncachedImageElements, files);\n\n if (updatedFiles.size) {\n this.scene.informMutation();\n }\n }\n });\n /** generally you should use `addNewImagesToImageCache()` directly if you need\n * to render new images. This is just a failsafe */\n\n\n this.scheduleImageRefresh = lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default()(() => {\n this.addNewImagesToImageCache();\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_RENDER_TIMEOUT);\n\n this.updateBindingEnabledOnPointerMove = event => {\n const shouldEnableBinding = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.shouldEnableBindingForPointerEvent)(event);\n\n if (this.state.isBindingEnabled !== shouldEnableBinding) {\n this.setState({\n isBindingEnabled: shouldEnableBinding\n });\n }\n };\n\n this.maybeSuggestBindingAtCursor = pointerCoords => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerCoords, this.scene);\n this.setState({\n suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : []\n });\n };\n\n this.maybeSuggestBindingsForLinearElementAtCoords = (linearElement,\n /** scene coords */\n pointerCoords, // During line creation the start binding hasn't been written yet\n // into `linearElement`\n oppositeBindingBoundElement) => {\n if (!pointerCoords.length) {\n return;\n }\n\n const suggestedBindings = pointerCoords.reduce((acc, coords) => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(coords, this.scene);\n\n if (hoveredBindableElement != null && !(0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isLinearElementSimpleAndAlreadyBound)(linearElement, oppositeBindingBoundElement === null || oppositeBindingBoundElement === void 0 ? void 0 : oppositeBindingBoundElement.id, hoveredBindableElement)) {\n acc.push(hoveredBindableElement);\n }\n\n return acc;\n }, []);\n this.setState({\n suggestedBindings\n });\n };\n\n this.handleInteractiveCanvasRef = canvas => {\n var _a, _b, _c; // canvas is null when unmounting\n\n\n if (canvas !== null) {\n this.interactiveCanvas = canvas; // -----------------------------------------------------------------------\n // NOTE wheel, touchstart, touchend events must be registered outside\n // of react because react binds them them passively (so we can't prevent\n // default on them)\n\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd); // -----------------------------------------------------------------------\n } else {\n (_a = this.interactiveCanvas) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n (_b = this.interactiveCanvas) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n (_c = this.interactiveCanvas) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd);\n }\n };\n\n this.handleAppOnDrop = event => __awaiter(this, void 0, void 0, function* () {\n var _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_39__.getFileFromEvent)(event);\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n try {\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.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_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n });\n return;\n }\n } catch (error) {\n return this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n\n const libraryJSON = event.dataTransfer.getData(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib);\n\n if (libraryJSON && typeof libraryJSON === \"string\") {\n try {\n const libraryItems = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.parseLibraryJSON)(libraryJSON);\n this.addElementsFromPasteOrLibrary({\n elements: (0,_data_library__WEBPACK_IMPORTED_MODULE_14__.distributeLibraryItemsOnSquareGrid)(libraryItems),\n position: event,\n files: null\n });\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n\n return;\n }\n\n if (file) {\n // atetmpt to parse an excalidraw/excalidrawlib file\n yield this.loadFileToCanvas(file, fileHandle);\n }\n\n if ((_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_34__.embeddableURLValidator)(text, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(text) || ((_p = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.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_46__.normalizeLink)(text)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n }\n }\n });\n\n this.loadFileToCanvas = (file, fileHandle) => __awaiter(this, void 0, void 0, function* () {\n file = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.normalizeFile)(file);\n\n try {\n const ret = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.loadSceneOrLibraryFromBlob)(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);\n\n if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidraw) {\n this.setState({\n isLoading: true\n });\n this.syncActionResult(Object.assign(Object.assign({}, ret.data), {\n appState: Object.assign(Object.assign({}, ret.data.appState || this.state), {\n isLoading: false\n }),\n replaceFiles: true,\n commitToHistory: true\n }));\n } else if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib) {\n yield this.library.updateLibrary({\n libraryItems: file,\n merge: true,\n openLibraryMenu: true\n }).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.importLibraryError\")\n });\n });\n }\n } catch (error) {\n this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n });\n\n this.handleCanvasContextMenu = event => {\n event.preventDefault();\n\n if ((\"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"touch\" || \"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"pen\" && // always allow if user uses a pen secondary button\n event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.SECONDARY) && this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const element = this.getElementAtPosition(x, y, {\n preferSelected: true,\n includeLockedElements: true\n });\n const selectedElements = this.scene.getSelectedElements(this.state);\n const isHittignCommonBoundBox = this.isHittingCommonBoundingBoxOfSelectedElements({\n x,\n y\n }, selectedElements);\n const type = element || isHittignCommonBoundBox ? \"element\" : \"canvas\";\n const container = this.excalidrawContainerRef.current;\n const {\n top: offsetTop,\n left: offsetLeft\n } = container.getBoundingClientRect();\n const left = event.clientX - offsetLeft;\n const top = event.clientY - offsetTop;\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"contextMenu\", \"openContextMenu\", type);\n this.setState(Object.assign(Object.assign({}, element && !this.state.selectedElementIds[element.id] ? Object.assign(Object.assign(Object.assign({}, this.state), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: this.state.editingGroupId,\n selectedElementIds: {\n [element.id]: true\n }\n }, this.scene.getNonDeletedElements(), this.state, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(element) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(element, this.scene) : null\n }) : this.state), {\n showHyperlinkPopup: false\n }), () => {\n this.setState({\n contextMenu: {\n top,\n left,\n items: this.getContextMenuItems(type)\n }\n });\n });\n };\n\n this.maybeDragNewGenericElement = (pointerDownState, event) => {\n var _a;\n\n const draggingElement = this.state.draggingElement;\n const pointerCoords = pointerDownState.lastCoords;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"selection\" && this.state.activeTool.type !== \"eraser\") {\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.origin.x, pointerDownState.origin.y, pointerCoords.x, pointerCoords.y, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.x, pointerCoords.x), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.y, pointerCoords.y), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event));\n } else {\n 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 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 (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.originInGrid.x, pointerDownState.originInGrid.y, gridX, gridY, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.x, gridX), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.y, gridY), (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), aspectRatio);\n this.maybeSuggestBindingForAll([draggingElement]); // highlight elements that are to be added to frames on frames creation\n\n if (this.state.activeTool.type === \"frame\") {\n this.setState({\n elementsToHighlight: (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), draggingElement, this.state)\n });\n }\n }\n };\n\n this.maybeHandleResize = (pointerDownState, event) => {\n const selectedElements = this.scene.getSelectedElements(this.state);\n const selectedFrames = selectedElements.filter(element => element.type === \"frame\");\n const transformHandleType = pointerDownState.resize.handleType;\n\n if (selectedFrames.length > 0 && transformHandleType === \"rotation\") {\n return false;\n }\n\n this.setState({\n // TODO: rename this state field to \"isScaling\" to distinguish\n // it from the generic \"isResizing\" which includes scaling and\n // rotating\n isResizing: transformHandleType && transformHandleType !== \"rotation\",\n isRotating: transformHandleType === \"rotation\",\n activeEmbeddable: null\n });\n const pointerCoords = pointerDownState.lastCoords;\n const [resizeX, resizeY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x - pointerDownState.resize.offset.x, pointerCoords.y - pointerDownState.resize.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const frameElementsOffsetsMap = new Map();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.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 });\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)) {\n this.maybeSuggestBindingForAll(selectedElements);\n const elementsToHighlight = new Set();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.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_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), frame, this.state).forEach(element => elementsToHighlight.add(element));\n });\n this.setState({\n elementsToHighlight: [...elementsToHighlight]\n });\n return true;\n }\n\n return false;\n };\n\n this.getContextMenuItems = type => {\n const options = [];\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsPng, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsSvg); // canvas contextMenu\n // -------------------------------------------------------------------------\n\n if (type === \"canvas\") {\n if (this.state.viewModeEnabled) {\n return [...options, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleGridMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n }\n\n return [_actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsPng, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsSvg, _actions__WEBPACK_IMPORTED_MODULE_5__.copyText, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSelectAll, _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_48__.actionUnlockAllElements, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleGridMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n } // element contextMenu\n // -------------------------------------------------------------------------\n\n\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.copyText);\n\n if (this.state.viewModeEnabled) {\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, ...options];\n }\n\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionSelectAllElementsInFrame, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionRemoveAllElementsFromFrame, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, ...options, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyStyles, _actions__WEBPACK_IMPORTED_MODULE_5__.actionPasteStyles, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionGroup, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUnbindText, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBindText, _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_57__.actionWrapTextInContainer, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUngroup, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionAddToLibrary, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendBackward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringForward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendToBack, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringToFront, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipHorizontal, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipVertical, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleLinearEditor, _actions__WEBPACK_IMPORTED_MODULE_5__.actionLink, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDuplicateSelection, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleElementLock, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDeleteSelected];\n };\n\n this.handleWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault();\n\n if (isPanning) {\n return;\n }\n\n const {\n deltaX,\n deltaY\n } = event; // note that event.ctrlKey is necessary to handle pinch zooming\n\n if (event.metaKey || event.ctrlKey) {\n const sign = Math.sign(deltaY);\n const MAX_STEP = _constants__WEBPACK_IMPORTED_MODULE_12__.ZOOM_STEP * 100;\n const absDelta = Math.abs(deltaY);\n let delta = deltaY;\n\n if (absDelta > MAX_STEP) {\n delta = MAX_STEP * sign;\n }\n\n let newZoom = this.state.zoom.value - delta / 100; // increase zoom steps the more zoomed-in we are (applies to >100% only)\n\n newZoom += Math.log10(Math.max(1, this.state.zoom.value)) * -sign * // reduced amplification for small deltas (small movements on a trackpad)\n Math.min(1, absDelta / 20);\n this.translateCanvas(state => Object.assign(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(newZoom)\n }, state)), {\n shouldCacheIgnoreZoom: true\n }));\n this.resetShouldCacheIgnoreZoomDebounced();\n return;\n } // scroll horizontally when shift pressed\n\n\n if (event.shiftKey) {\n this.translateCanvas(({\n zoom,\n scrollX\n }) => ({\n // on Mac, shift+wheel tends to result in deltaX\n scrollX: scrollX - (deltaY || deltaX) / zoom.value\n }));\n return;\n }\n\n this.translateCanvas(({\n zoom,\n scrollX,\n scrollY\n }) => ({\n scrollX: scrollX - deltaX / zoom.value,\n scrollY: scrollY - deltaY / zoom.value\n }));\n });\n\n this.savePointer = (x, y, button) => {\n var _a, _b;\n\n if (!x || !y) {\n return;\n }\n\n const pointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.debounce)(() => {\n if (!this.unmounted) {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n }\n }, 300);\n\n this.updateDOMRect = cb => {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n width,\n height,\n left: offsetLeft,\n top: offsetTop\n } = excalidrawContainer.getBoundingClientRect();\n const {\n width: currentWidth,\n height: currentHeight,\n offsetTop: currentOffsetTop,\n offsetLeft: currentOffsetLeft\n } = this.state;\n\n if (width === currentWidth && height === currentHeight && offsetLeft === currentOffsetLeft && offsetTop === currentOffsetTop) {\n if (cb) {\n cb();\n }\n\n return;\n }\n\n this.setState({\n width,\n height,\n offsetLeft,\n offsetTop\n }, () => {\n cb && cb();\n });\n }\n };\n\n this.refresh = () => {\n this.setState(Object.assign({}, this.getCanvasOffsets()));\n };\n\n const defaultAppState = (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)();\n const {\n excalidrawRef,\n viewModeEnabled = false,\n zenModeEnabled = false,\n gridModeEnabled = 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 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_65__.nanoid)();\n this.library = new _data_library__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this);\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_30__[\"default\"]();\n this.canvas = document.createElement(\"canvas\");\n this.rc = roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_3__[\"default\"].canvas(this.canvas);\n this.renderer = new _scene_Renderer__WEBPACK_IMPORTED_MODULE_63__.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_33__.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 };\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_49__.Fonts({\n scene: this.scene,\n onSceneUpdated: this.onSceneUpdated\n });\n this.history = new _history__WEBPACK_IMPORTED_MODULE_24__[\"default\"]();\n this.actionManager = new _actions_manager__WEBPACK_IMPORTED_MODULE_7__.ActionManager(this.syncActionResult, () => this.state, () => this.scene.getElementsIncludingDeleted(), this);\n this.actionManager.registerAll(_actions_register__WEBPACK_IMPORTED_MODULE_8__.actions);\n this.actionManager.registerAction((0,_actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__.createUndoAction)(this.history));\n this.actionManager.registerAction((0,_actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__.createRedoAction)(this.history));\n }\n\n onWindowMessage(event) {\n if (event.origin !== \"https://player.vimeo.com\" && event.origin !== \"https://www.youtube.com\") {\n return;\n }\n\n let data = null;\n\n try {\n data = JSON.parse(event.data);\n } catch (e) {}\n\n if (!data) {\n return;\n }\n\n switch (event.origin) {\n case \"https://player.vimeo.com\":\n //Allowing for multiple instances of Excalidraw running in the window\n if (data.method === \"paused\") {\n let source = null;\n const iframes = document.body.querySelectorAll(\"iframe.excalidraw__embeddable\");\n\n if (!iframes) {\n break;\n }\n\n for (const iframe of iframes) {\n if (iframe.contentWindow === event.source) {\n source = iframe.contentWindow;\n }\n }\n\n source === null || source === void 0 ? void 0 : source.postMessage(JSON.stringify({\n method: data.value ? \"play\" : \"pause\",\n value: true\n }), \"*\");\n }\n\n break;\n\n case \"https://www.youtube.com\":\n if (data.event === \"infoDelivery\" && data.info && data.id && typeof data.info.playerState === \"number\") {\n const id = data.id;\n const playerState = data.info.playerState;\n\n if (Object.values(_constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES).includes(playerState)) {\n YOUTUBE_VIDEO_STATES.set(id, playerState);\n }\n }\n\n break;\n }\n }\n\n updateEmbeddableRef(id, ref) {\n if (ref) {\n this.iFrameRefs.set(id, ref);\n }\n }\n\n getHTMLIFrameElement(id) {\n return this.iFrameRefs.get(id);\n }\n\n handleEmbeddableCenterClick(element) {\n var _a, _b, _c, _d;\n\n if (((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) === element && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"active\") {\n return;\n } // The delay serves two purposes\n // 1. To prevent first click propagating to iframe on mobile,\n // else the click will immediately start and stop the video\n // 2. If the user double clicks the frame center to activate it\n // without the delay youtube will immediately open the video\n // in fullscreen mode\n\n\n setTimeout(() => {\n this.setState({\n activeEmbeddable: {\n element,\n state: \"active\"\n },\n selectedElementIds: {\n [element.id]: true\n },\n draggingElement: null,\n selectionElement: null\n });\n }, 100);\n const iframe = this.getHTMLIFrameElement(element.id);\n\n if (!(iframe === null || iframe === void 0 ? void 0 : iframe.contentWindow)) {\n return;\n }\n\n if (iframe.src.includes(\"youtube\")) {\n const state = YOUTUBE_VIDEO_STATES.get(element.id);\n\n if (!state) {\n YOUTUBE_VIDEO_STATES.set(element.id, _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.UNSTARTED);\n iframe.contentWindow.postMessage(JSON.stringify({\n event: \"listening\",\n id: element.id\n }), \"*\");\n }\n\n switch (state) {\n case _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.PLAYING:\n case _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.BUFFERING:\n (_c = iframe.contentWindow) === null || _c === void 0 ? void 0 : _c.postMessage(JSON.stringify({\n event: \"command\",\n func: \"pauseVideo\",\n args: \"\"\n }), \"*\");\n break;\n\n default:\n (_d = iframe.contentWindow) === null || _d === void 0 ? void 0 : _d.postMessage(JSON.stringify({\n event: \"command\",\n func: \"playVideo\",\n args: \"\"\n }), \"*\");\n }\n }\n\n if (iframe.src.includes(\"player.vimeo.com\")) {\n iframe.contentWindow.postMessage(JSON.stringify({\n method: \"paused\" //video play/pause in onWindowMessage handler\n\n }), \"*\");\n }\n }\n\n isEmbeddableCenter(el, event, sceneX, sceneY) {\n var _a, _b;\n\n return el && !event.altKey && !event.shiftKey && !event.metaKey && !event.ctrlKey && (((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) !== el || ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"hover\" || !this.state.activeEmbeddable) && sceneX >= el.x + el.width / 3 && sceneX <= el.x + 2 * el.width / 3 && sceneY >= el.y + el.height / 3 && sceneY <= el.y + 2 * el.height / 3;\n }\n\n renderEmbeddables() {\n const scale = this.state.zoom.value;\n const normalizedWidth = this.state.width;\n const normalizedHeight = this.state.height;\n const embeddableElements = this.scene.getNonDeletedElements().filter(el => (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(el) && !!el.validated);\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {\n children: embeddableElements.map(el => {\n var _a, _b, _c, _d, _e, _f, _g, _h;\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: el.x,\n sceneY: el.y\n }, this.state);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)((0,_data_url__WEBPACK_IMPORTED_MODULE_46__.toValidURL)(el.link || \"\"));\n const isVisible = (0,_element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__.isElementInViewport)(el, normalizedWidth, normalizedHeight, this.state);\n const isActive = ((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) === el && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"active\";\n const isHovered = ((_c = this.state.activeEmbeddable) === null || _c === void 0 ? void 0 : _c.element) === el && ((_d = this.state.activeEmbeddable) === null || _d === void 0 ? void 0 : _d.state) === \"hover\";\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: (0,clsx__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\"excalidraw__embeddable-container\", {\n \"is-hovered\": isHovered\n }),\n style: {\n transform: isVisible ? `translate(${x - this.state.offsetLeft}px, ${y - this.state.offsetTop}px) scale(${scale})` : \"none\",\n display: isVisible ? \"block\" : \"none\",\n opacity: el.opacity / 100,\n [\"--embeddable-radius\"]: `${(0,_math__WEBPACK_IMPORTED_MODULE_28__.getCornerRadius)(Math.min(el.width, el.height), el)}px`\n }\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(\"div\", Object.assign({\n //this is a hack that addresses isse with embedded excalidraw.com embeddable\n //https://github.com/excalidraw/excalidraw/pull/6691#issuecomment-1607383938\n\n /*ref={(ref) => {\n if (!this.excalidrawContainerRef.current) {\n return;\n }\n const container = this.excalidrawContainerRef.current;\n const sh = container.scrollHeight;\n const ch = container.clientHeight;\n if (sh !== ch) {\n container.style.height = `${sh}px`;\n setTimeout(() => {\n container.style.height = `100%`;\n });\n }\n }}*/\n className: \"excalidraw__embeddable-container__inner\",\n style: {\n width: isVisible ? `${el.width}px` : 0,\n height: isVisible ? `${el.height}px` : 0,\n transform: isVisible ? `rotate(${el.angle}rad)` : \"none\",\n pointerEvents: isActive ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled\n }\n }, {\n children: [isHovered && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: \"excalidraw__embeddable-hint\"\n }, {\n children: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"buttons.embeddableInteractionButton\")\n })), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: \"excalidraw__embeddable__outer\",\n style: {\n padding: `${el.strokeWidth}px`\n }\n }, {\n children: (_g = (_f = (_e = this.props).renderEmbeddable) === null || _f === void 0 ? void 0 : _f.call(_e, el, this.state)) !== null && _g !== void 0 ? _g : (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"iframe\", {\n ref: ref => this.updateEmbeddableRef(el.id, ref),\n className: \"excalidraw__embeddable\",\n srcDoc: (embedLink === null || embedLink === void 0 ? void 0 : embedLink.type) === \"document\" ? embedLink.srcdoc(this.state.theme) : undefined,\n src: (embedLink === null || embedLink === void 0 ? void 0 : embedLink.type) !== \"document\" ? (_h = embedLink === null || embedLink === void 0 ? void 0 : embedLink.link) !== null && _h !== void 0 ? _h : \"\" : undefined,\n // https://stackoverflow.com/q/18470015\n scrolling: \"no\",\n referrerPolicy: \"no-referrer-when-downgrade\",\n title: \"Excalidraw Embedded Content\",\n allow: \"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\",\n allowFullScreen: true,\n sandbox: \"allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads\"\n })\n }))]\n }))\n }), el.id);\n })\n });\n }\n\n render() {\n var _a, _b, _c;\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n const {\n renderTopRightUI,\n renderCustomStats\n } = this.props;\n const versionNonce = this.scene.getVersionNonce();\n const {\n canvasElements,\n visibleElements\n } = this.renderer.getRenderableElements({\n versionNonce,\n zoom: this.state.zoom,\n offsetLeft: this.state.offsetLeft,\n offsetTop: this.state.offsetTop,\n scrollX: this.state.scrollX,\n scrollY: this.state.scrollY,\n height: this.state.height,\n width: this.state.width,\n editingElement: this.state.editingElement,\n pendingImageElementId: this.state.pendingImageElementId\n });\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: (0,clsx__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\"excalidraw excalidraw-container\", {\n \"excalidraw--view-mode\": this.state.viewModeEnabled,\n \"excalidraw--mobile\": this.device.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_36__[\"default\"], Object.assign({\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 renderTopRightUI: renderTopRightUI,\n renderCustomStats: renderCustomStats,\n showExitZenModeBtn: typeof ((_a = this.props) === null || _a === void 0 ? void 0 : _a.zenModeEnabled) === \"undefined\" && this.state.zenModeEnabled,\n UIOptions: this.props.UIOptions,\n onImageAction: this.onImageAction,\n onExportImage: this.onExportImage,\n renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === \"selection\" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,\n app: this\n }, {\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_45__.Hyperlink, {\n element: selectedElements[0],\n setAppState: this.setAppState,\n onLinkOpen: this.props.onLinkOpen,\n setToast: this.setToast\n }, selectedElements[0].id), this.state.toast !== null && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_Toast__WEBPACK_IMPORTED_MODULE_37__.Toast, {\n message: this.state.toast.message,\n onClose: () => this.setToast(null),\n duration: this.state.toast.duration,\n closable: this.state.toast.closable\n }), this.state.contextMenu && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_ContextMenu__WEBPACK_IMPORTED_MODULE_35__.ContextMenu, {\n items: this.state.contextMenu.items,\n top: this.state.contextMenu.top,\n left: this.state.contextMenu.left,\n actionManager: this.actionManager\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_62__.StaticCanvas, {\n canvas: this.canvas,\n rc: this.rc,\n elements: canvasElements,\n visibleElements: visibleElements,\n versionNonce: versionNonce,\n selectionNonce: (_b = this.state.selectionElement) === null || _b === void 0 ? void 0 : _b.versionNonce,\n scale: window.devicePixelRatio,\n appState: this.state,\n renderConfig: {\n imageCache: this.imageCache,\n isExporting: false,\n renderGrid: true\n }\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_62__.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_33__.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_33__.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_43__.isMeasureTextSupported)()) {\n this.setState({\n errorMessage: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_58__[\"default\"], {})\n });\n }\n });\n }\n\n componentWillUnmount() {\n var _a;\n\n this.renderer.destroy();\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_30__[\"default\"]();\n this.renderer = new _scene_Renderer__WEBPACK_IMPORTED_MODULE_63__.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_64__.ShapeCache.destroy();\n clearTimeout(touchTimeout);\n _scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected.clearCache();\n _groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements.clearCache();\n touchTimeout = 0;\n }\n\n removeEventListeners() {\n var _a, _b, _c, _d, _e;\n\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel);\n (_b = this.nearestScrollableContainer) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n (_e = this.detachIsMobileMqHandler) === null || _e === void 0 ? void 0 : _e.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\", event => {\n const loadedFontFaces = event.fontfaces;\n this.fonts.onFontsLoaded(loadedFontFaces);\n }); // Safari-only desktop pinch zoom\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n\n if (this.props.detectScroll) {\n this.nearestScrollableContainer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getNearestScrollableContainer)(this.excalidrawContainerRef.current);\n this.nearestScrollableContainer.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n }\n\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_e = this.excalidrawContainerRef.current) === null || _e === void 0 ? void 0 : _e.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n }\n\n componentDidUpdate(prevProps, prevState) {\n var _a, _b, _c, _d, _e, _f;\n\n this.updateEmbeddables();\n\n if (!this.state.showWelcomeScreen && !this.scene.getElementsIncludingDeleted().length) {\n this.setState({\n showWelcomeScreen: true\n });\n }\n\n if (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_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n\n if (this.state.activeTool.type === \"eraser\" && prevState.theme !== this.state.theme) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setEraserCursor)(this.interactiveCanvas, this.state.theme);\n } // Hide hyperlink popup if shown when element type is not selection\n\n\n if (prevState.activeTool.type === \"selection\" && this.state.activeTool.type !== \"selection\" && this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: false\n });\n }\n\n if (prevProps.langCode !== this.props.langCode) {\n this.updateLanguage();\n }\n\n if (prevProps.viewModeEnabled !== this.props.viewModeEnabled) {\n this.setState({\n viewModeEnabled: !!this.props.viewModeEnabled\n });\n }\n\n if (prevState.viewModeEnabled !== this.state.viewModeEnabled) {\n this.addEventListeners();\n this.deselectElements();\n }\n\n if (prevProps.zenModeEnabled !== this.props.zenModeEnabled) {\n this.setState({\n zenModeEnabled: !!this.props.zenModeEnabled\n });\n }\n\n if (prevProps.theme !== this.props.theme && this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {\n this.setState({\n gridSize: this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null\n });\n }\n\n if (this.props.name && prevProps.name !== this.props.name) {\n this.setState({\n name: this.props.name\n });\n }\n\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.classList.toggle(\"theme--dark\", this.state.theme === \"dark\");\n\n if (this.state.editingLinearElement && !this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {\n // defer so that the commitToHistory flag isn't reset via current update\n setTimeout(() => {\n // execute only if the condition still holds when the deferred callback\n // executes (it can be scheduled multiple times depending on how\n // many times the component renders)\n this.state.editingLinearElement && this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } // failsafe in case the state is being updated in incorrect order resulting\n // in the editingElement being now a deleted element\n\n\n if ((_d = this.state.editingElement) === null || _d === void 0 ? void 0 : _d.isDeleted) {\n this.setState({\n editingElement: null\n });\n }\n\n if (this.state.selectedLinearElement && !this.state.selectedElementIds[this.state.selectedLinearElement.elementId]) {\n // To make sure `selectedLinearElement` is in sync with `selectedElementIds`, however this shouldn't be needed once\n // we have a single API to update `selectedElementIds`\n this.setState({\n selectedLinearElement: null\n });\n }\n\n const {\n multiElement\n } = prevState;\n\n if (prevState.activeTool !== this.state.activeTool && multiElement != null && (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(multiElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(multiElement, this.state, this.scene, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)(_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1)));\n }\n\n this.history.record(this.state, this.scene.getElementsIncludingDeleted()); // Do not notify consumers if we're still loading the scene. Among other\n // potential issues, this fixes a case where the tab isn't focused during\n // init, which would trigger onChange with empty elements, which would then\n // override whatever is in localStorage currently.\n\n if (!this.state.isLoading) {\n (_f = (_e = this.props).onChange) === null || _f === void 0 ? void 0 : _f.call(_e, this.scene.getElementsIncludingDeleted(), this.state, this.files);\n }\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_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state);\n const textElementProps = {\n x,\n y,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roundness: null,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text,\n fontSize: this.state.currentItemFontSize,\n fontFamily: this.state.currentItemFontFamily,\n textAlign: this.state.currentItemTextAlign,\n verticalAlign: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n locked: false\n };\n const LINE_GAP = 10;\n let currentY = y;\n const lines = isPlainPaste ? [text] : text.split(\"\\n\");\n const textElements = lines.reduce((acc, line, idx) => {\n var _a;\n\n const text = line.trim();\n const lineHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(textElementProps.fontFamily);\n\n if (text.length) {\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x,\n y: currentY\n });\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)(Object.assign(Object.assign({}, textElementProps), {\n x,\n y: currentY,\n text,\n lineHeight,\n frameId: topLayerFrame ? topLayerFrame.id : null\n }));\n acc.push(element);\n currentY += element.height + LINE_GAP;\n } else {\n const prevLine = (_a = lines[idx - 1]) === null || _a === void 0 ? void 0 : _a.trim(); // add paragraph only if previous line was not empty, IOW don't add\n // more than one empty line\n\n if (prevLine) {\n currentY += (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getLineHeightInPx)(textElementProps.fontSize, lineHeight) + LINE_GAP;\n }\n }\n\n return acc;\n }, []);\n\n if (textElements.length === 0) {\n return;\n }\n\n const frameId = textElements[0].frameId;\n\n if (frameId) {\n this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));\n } else {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), ...textElements]);\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.fromEntries(textElements.map(el => [el.id, true])), this.state)\n });\n\n if (!isPlainPaste && textElements.length > 1 && PLAIN_PASTE_TOAST_SHOWN === false && !this.device.isMobile) {\n this.setToast({\n message: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"toast.pasteAsSingleElement\", {\n shortcut: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getShortcutKey)(\"CtrlOrCmd+Shift+V\")\n }),\n duration: 5000\n });\n PLAIN_PASTE_TOAST_SHOWN = true;\n }\n\n this.history.resumeRecording();\n }\n\n handleTextWysiwyg(element, {\n isExistingElement = false\n }) {\n const updateElement = (text, originalText, isDeleted) => {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted().map(_element => {\n if (_element.id === element.id && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(_element)) {\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.updateTextElement)(_element, {\n text,\n isDeleted,\n originalText\n });\n }\n\n return _element;\n })]);\n };\n\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.textWysiwyg)({\n id: element.id,\n canvas: this.canvas,\n getViewportCoords: (x, y) => {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: x,\n sceneY: y\n }, this.state);\n return [viewportX - this.state.offsetLeft, viewportY - this.state.offsetTop];\n },\n onChange: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(text => {\n updateElement(text, text, false);\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element);\n }\n }),\n onSubmit: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(({\n text,\n viaKeyboard,\n originalText\n }) => {\n const isDeleted = !text.trim();\n updateElement(text, originalText, isDeleted); // select the created text element only if submitting via keyboard\n // (when submitting via click it should act as signal to deselect)\n\n if (!isDeleted && viaKeyboard) {\n const elementIdToSelect = element.containerId ? element.containerId : element.id;\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [elementIdToSelect]: true\n }), prevState)\n }));\n }\n\n if (isDeleted) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDeletion)(this.scene.getNonDeletedElements(), [element]);\n }\n\n if (!isDeleted || isExistingElement) {\n this.history.resumeRecording();\n }\n\n this.setState({\n draggingElement: null,\n editingElement: null\n });\n\n if (this.state.activeTool.locked) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n this.focusContainer();\n }),\n element,\n excalidrawContainer: this.excalidrawContainerRef.current,\n app: this\n }); // deselect all other elements when inserting text\n\n this.deselectElements(); // do an initial update to re-initialize element position since we were\n // modifying element's x/y for sake of editor (case: syncing to remote)\n\n updateElement(element.text, element.originalText, false);\n }\n\n deselectElements() {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n getTextElementAtPosition(x, y) {\n const element = this.getElementAtPosition(x, y, {\n includeBoundTextElement: true\n });\n\n if (element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && !element.isDeleted) {\n return element;\n }\n\n return null;\n }\n\n getElementAtPosition(x, y, opts) {\n const allHitElements = this.getElementsAtPosition(x, y, opts === null || opts === void 0 ? void 0 : opts.includeBoundTextElement, opts === null || opts === void 0 ? void 0 : opts.includeLockedElements);\n\n if (allHitElements.length > 1) {\n if (opts === null || opts === void 0 ? void 0 : opts.preferSelected) {\n for (let index = allHitElements.length - 1; index > -1; index--) {\n if (this.state.selectedElementIds[allHitElements[index].id]) {\n return allHitElements[index];\n }\n }\n }\n\n const elementWithHighestZIndex = allHitElements[allHitElements.length - 1]; // If we're hitting element with highest z-index only on its bounding box\n // while also hitting other element figure, the latter should be considered.\n\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(elementWithHighestZIndex, this.state, this.frameNameBoundsCache, x, y) ? allHitElements[allHitElements.length - 2] : elementWithHighestZIndex;\n }\n\n if (allHitElements.length === 1) {\n return allHitElements[0];\n }\n\n return null;\n }\n\n getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {\n const elements = includeBoundTextElement && includeLockedElements ? this.scene.getNonDeletedElements() : this.scene.getNonDeletedElements().filter(element => (includeLockedElements || !element.locked) && (includeBoundTextElement || !((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && element.containerId)));\n return (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsAtPosition)(elements, element => (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(element, this.state, this.frameNameBoundsCache, x, y)).filter(element => {\n // hitting a frame's element from outside the frame is not considered a hit\n const containingFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(element);\n return containingFrame && this.state.frameRendering.enabled && this.state.frameRendering.clip ? (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)({\n x,\n y\n }, containingFrame) : true;\n });\n }\n\n handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {\n const element = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getElement(linearElementEditor.elementId);\n const boundTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(element);\n\n if (!element) {\n return;\n }\n\n if (this.state.selectedLinearElement) {\n let hoverPointIndex = -1;\n let segmentMidPointHoveredCoords = null;\n\n if ((0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(element, this.state, this.frameNameBoundsCache, [scenePointerX, scenePointerY])) {\n hoverPointIndex = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointIndexUnderCursor(element, this.state.zoom, scenePointerX, scenePointerY);\n segmentMidPointHoveredCoords = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, {\n x: scenePointerX,\n y: scenePointerY\n }, this.state);\n\n if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n } else if ((0,_element_transformHandles__WEBPACK_IMPORTED_MODULE_47__.shouldShowBoundingBox)([element], this.state) && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n\n maybeCleanupAfterMissingPointerUp(event) {\n if (lastPointerUp !== null) {\n // Unfortunately, sometimes we don't get a pointerup after a pointerdown,\n // this can happen when a contextual menu or alert is triggered. In order to avoid\n // being in a weird state, we clean up on the next pointerdown\n lastPointerUp(event);\n }\n }\n\n updateGestureOnPointerDown(event) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n\n if (gesture.pointers.size === 2) {\n gesture.lastCenter = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n gesture.initialScale = this.state.zoom.value;\n gesture.initialDistance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n }\n }\n\n initialPointerDownState(event) {\n const origin = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedElements = this.scene.getSelectedElements(this.state);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return {\n origin,\n withCmdOrCtrl: event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD],\n originInGrid: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(origin.x, origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize)),\n scrollbars: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop),\n // we need to duplicate because we'll be updating this state\n lastCoords: Object.assign({}, origin),\n originalElements: this.scene.getNonDeletedElements().reduce((acc, element) => {\n acc.set(element.id, (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.deepCopyElement)(element));\n return acc;\n }, new Map()),\n resize: {\n handleType: false,\n isResizing: false,\n offset: {\n x: 0,\n y: 0\n },\n arrowDirection: \"origin\",\n center: {\n x: (maxX + minX) / 2,\n y: (maxY + minY) / 2\n }\n },\n hit: {\n element: null,\n allHitElements: [],\n wasAddedToSelection: false,\n hasBeenDuplicated: false,\n hasHitCommonBoundingBoxOfSelectedElements: this.isHittingCommonBoundingBoxOfSelectedElements(origin, selectedElements)\n },\n drag: {\n hasOccurred: false,\n offset: null\n },\n eventListeners: {\n onMove: null,\n onUp: null,\n onKeyUp: null,\n onKeyDown: null\n },\n boxSelection: {\n hasOccurred: false\n },\n elementIdsToErase: {}\n };\n } // Returns whether the event is a dragging a scrollbar\n\n\n handleDraggingScrollBar(event, pointerDownState) {\n if (!(pointerDownState.scrollbars.isOverEither && !this.state.multiElement)) {\n return false;\n }\n\n isDraggingScrollBar = true;\n pointerDownState.lastCoords.x = event.clientX;\n pointerDownState.lastCoords.y = event.clientY;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n this.handlePointerMoveOverScrollbars(event, pointerDownState);\n });\n const onPointerUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isDraggingScrollBar = false;\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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 onKeyDownFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onKeyUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // Prevents focus from escaping excalidraw tab\n event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ALT && event.preventDefault();\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onPointerMoveFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n var _a, _b; // We need to initialize dragOffsetXY only after we've updated\n // `state.selectedElementIds` on pointerDown. Doing it here in pointerMove\n // event handler should hopefully ensure we're already working with\n // the updated state.\n\n\n if (pointerDownState.drag.offset === null) {\n pointerDownState.drag.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getDragOffsetXY)(this.scene.getSelectedElements(this.state), pointerDownState.origin.x, pointerDownState.origin.y));\n }\n\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n if (this.handlePointerMoveOverScrollbars(event, pointerDownState)) {\n return;\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.handleEraser(event, pointerDownState, pointerCoords);\n return;\n }\n\n 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 [dragX, dragY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x - pointerDownState.drag.offset.x, pointerCoords.y - pointerDownState.drag.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const [dragDistanceX, dragDistanceY] = [Math.abs(pointerCoords.x - pointerDownState.origin.x), Math.abs(pointerCoords.y - pointerDownState.origin.y)]; // We only drag in one direction if shift is pressed\n\n const lockDirection = event.shiftKey; // 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, dragX, dragY, lockDirection, dragDistanceX, dragDistanceY, this.state, this.scene);\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 [originDragX, originDragY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x - pointerDownState.drag.offset.x, pointerDownState.origin.y - pointerDownState.drag.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(duplicatedElement, {\n x: duplicatedElement.x + (originDragX - dragX),\n y: duplicatedElement.y + (originDragY - dragY)\n });\n nextElements.push(duplicatedElement);\n elementsToAppend.push(element);\n oldIdToDuplicatedId.set(element.id, duplicatedElement.id);\n } else {\n nextElements.push(element);\n }\n }\n\n const nextSceneElements = [...nextElements, ...elementsToAppend];\n (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.bindTextToShapeAfterDuplication)(nextElements, elementsToAppend, oldIdToDuplicatedId);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, \"duplicatesServeAsOld\");\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.bindElementsToFramesAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);\n this.scene.replaceAllElements(nextSceneElements);\n }\n\n return;\n }\n } // It is very important to read this.state within each move event,\n // otherwise we would read a stale one!\n\n\n const draggingElement = this.state.draggingElement;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"freedraw\") {\n const points = draggingElement.points;\n const dx = pointerCoords.x - draggingElement.x;\n const dy = pointerCoords.y - draggingElement.y;\n const lastPoint = points.length > 0 && points[points.length - 1];\n const discardPoint = lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;\n\n if (!discardPoint) {\n const pressures = draggingElement.simulatePressure ? draggingElement.pressures : [...draggingElement.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures\n });\n }\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n });\n const points = draggingElement.points;\n let dx = gridX - draggingElement.x;\n let dy = gridY - draggingElement.y;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event) && points.length === 2) {\n ({\n width: dx,\n height: dy\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)(draggingElement.x, draggingElement.y, pointerCoords.x, pointerCoords.y));\n }\n\n if (points.length === 1) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]]\n });\n } else if (points.length === 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points.slice(0, -1), [dx, dy]]\n });\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n // When creating a linear element by dragging\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [pointerCoords], this.state.startBoundElement);\n }\n } else {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n this.maybeDragNewGenericElement(pointerDownState, event);\n }\n\n if (this.state.activeTool.type === \"selection\") {\n pointerDownState.boxSelection.hasOccurred = true;\n const elements = this.scene.getNonDeletedElements(); // box-select line editor points\n\n if (this.state.editingLinearElement) {\n _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handleBoxSelection(event, this.state, this.setState.bind(this)); // regular box-select\n } else {\n let shouldReuseSelection = true;\n\n if (!event.shiftKey && (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(elements, this.state)) {\n if (pointerDownState.withCmdOrCtrl && pointerDownState.hit.element) {\n this.setState(prevState => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)(Object.assign(Object.assign({}, prevState), {\n selectedElementIds: {\n [pointerDownState.hit.element.id]: true\n }\n }), this.scene.getNonDeletedElements(), prevState, this));\n } else {\n shouldReuseSelection = false;\n }\n }\n\n const elementsWithinSelection = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsWithinSelection)(elements, draggingElement);\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, shouldReuseSelection && prevState.selectedElementIds), elementsWithinSelection.reduce((acc, element) => {\n acc[element.id] = true;\n return acc;\n }, {}));\n\n if (pointerDownState.hit.element) {\n // if using ctrl/cmd, select the hitElement only if we\n // haven't box-selected anything else\n if (!elementsWithinSelection.length) {\n nextSelectedElementIds[pointerDownState.hit.element.id] = true;\n } else {\n delete nextSelectedElementIds[pointerDownState.hit.element.id];\n }\n }\n\n prevState = !shouldReuseSelection ? Object.assign(Object.assign({}, prevState), {\n selectedGroupIds: {},\n editingGroupId: null\n }) : prevState;\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // select linear element only when we haven't box-selected anything else\n selectedLinearElement: elementsWithinSelection.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(elementsWithinSelection[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(elementsWithinSelection[0], this.scene) : null,\n showHyperlinkPopup: elementsWithinSelection.length === 1 && (elementsWithinSelection[0].link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(elementsWithinSelection[0])) ? \"info\" : false\n });\n });\n }\n }\n });\n } // Returns whether the pointer move happened over either scrollbar\n\n\n handlePointerMoveOverScrollbars(event, pointerDownState) {\n if (pointerDownState.scrollbars.isOverHorizontal) {\n const x = event.clientX;\n const dx = x - pointerDownState.lastCoords.x;\n this.translateCanvas({\n scrollX: this.state.scrollX - dx / this.state.zoom.value\n });\n pointerDownState.lastCoords.x = x;\n return true;\n }\n\n if (pointerDownState.scrollbars.isOverVertical) {\n const y = event.clientY;\n const dy = y - pointerDownState.lastCoords.y;\n this.translateCanvas({\n scrollY: this.state.scrollY - dy / this.state.zoom.value\n });\n pointerDownState.lastCoords.y = y;\n return true;\n }\n\n return false;\n }\n\n onPointerUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(childEvent => {\n var _a, _b, _c, _d, _e, _f;\n\n if (pointerDownState.eventListeners.onMove) {\n pointerDownState.eventListeners.onMove.flush();\n }\n\n const {\n draggingElement,\n resizingElement,\n multiElement,\n activeTool,\n isResizing,\n isRotating\n } = this.state;\n this.setState({\n isResizing: false,\n isRotating: false,\n resizingElement: null,\n selectionElement: null,\n frameToHighlight: null,\n elementsToHighlight: null,\n cursorButton: \"up\",\n // text elements are reset on finalize, and resetting on pointerup\n // may cause issues with double taps\n editingElement: multiElement || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? this.state.editingElement : null\n });\n this.savePointer(childEvent.clientX, childEvent.clientY, \"up\");\n this.setState({\n selectedElementsAreBeingDragged: false\n }); // Handle end of dragging a point of a linear element, might close a loop\n // and sets binding element\n\n if (this.state.editingLinearElement) {\n if (!pointerDownState.boxSelection.hasOccurred && ((_b = (_a = pointerDownState.hit) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.id) !== this.state.editingLinearElement.elementId) {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n } else {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state);\n\n if (editingLinearElement !== this.state.editingLinearElement) {\n this.setState({\n editingLinearElement,\n suggestedBindings: []\n });\n }\n }\n } else if (this.state.selectedLinearElement) {\n if (((_d = (_c = pointerDownState.hit) === null || _c === void 0 ? void 0 : _c.element) === null || _d === void 0 ? void 0 : _d.id) !== this.state.selectedLinearElement.elementId) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement to null if there is more than one element selected since we don't want to show linear element handles\n\n if (selectedELements.length > 1) {\n this.setState({\n selectedLinearElement: null\n });\n }\n } else {\n const linearElementEditor = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state);\n const {\n startBindingElement,\n endBindingElement\n } = linearElementEditor;\n const element = this.scene.getElement(linearElementEditor.elementId);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindLinearElement)(element, startBindingElement, endBindingElement);\n }\n\n if (linearElementEditor !== this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, linearElementEditor), {\n selectedPointsIndices: null\n }),\n suggestedBindings: []\n });\n }\n }\n }\n\n lastPointerUp = null;\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, pointerDownState.eventListeners.onMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, pointerDownState.eventListeners.onUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, pointerDownState.eventListeners.onKeyDown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, pointerDownState.eventListeners.onKeyUp);\n\n if (this.state.pendingImageElementId) {\n this.setState({\n pendingImageElementId: null\n });\n }\n\n if ((draggingElement === null || draggingElement === void 0 ? void 0 : draggingElement.type) === \"freedraw\") {\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n const points = draggingElement.points;\n let dx = pointerCoords.x - draggingElement.x;\n let dy = pointerCoords.y - draggingElement.y; // Allows dots to avoid being flagged as infinitely small\n\n if (dx === points[0][0] && dy === points[0][1]) {\n dy += 0.0001;\n dx += 0.0001;\n }\n\n const pressures = draggingElement.simulatePressure ? [] : [...draggingElement.pressures, childEvent.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures,\n lastCommittedPoint: [dx, dy]\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement)) {\n const imageElement = draggingElement;\n\n try {\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } catch (error) {\n console.error(error);\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== imageElement.id));\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n }\n\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n if (draggingElement.points.length > 1) {\n this.history.resumeRecording();\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n\n if (!pointerDownState.drag.hasOccurred && draggingElement && !multiElement) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...draggingElement.points, [pointerCoords.x - draggingElement.x, pointerCoords.y - draggingElement.y]]\n });\n this.setState({\n multiElement: draggingElement,\n editingElement: this.state.draggingElement\n });\n } else if (pointerDownState.drag.hasOccurred && !multiElement) {\n if ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(draggingElement, this.state, this.scene, pointerCoords);\n }\n\n this.setState({\n suggestedBindings: [],\n startBoundElement: null\n });\n\n if (!activeTool.locked) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n this.setState(prevState => ({\n draggingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n }),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(draggingElement, this.scene)\n }));\n } else {\n this.setState(prevState => ({\n draggingElement: null\n }));\n }\n }\n\n return;\n }\n\n if (activeTool.type !== \"selection\" && draggingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(draggingElement)) {\n // remove invisible element which was added in onPointerDown\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().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_33__.viewportCoordsToSceneCoords)(childEvent, this.state); // when editing the points of a linear element, we check if the\n // linear element still is in the frame afterwards\n // if not, the linear element will be removed from its frame (if any)\n\n if (this.state.selectedLinearElement && this.state.selectedLinearElement.isDragging) {\n const linearElement = this.scene.getElement(this.state.selectedLinearElement.elementId);\n\n if (linearElement === null || linearElement === void 0 ? void 0 : linearElement.frameId) {\n const frame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(linearElement);\n\n if (frame && linearElement) {\n if (!(0,_frame__WEBPACK_IMPORTED_MODULE_50__.elementOverlapsWithFrame)(linearElement, frame)) {\n // remove the linear element from all groups\n // before removing it from the frame as well\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(linearElement, {\n groupIds: []\n });\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.removeElementsFromFrame)(this.scene.getElementsIncludingDeleted(), [linearElement], this.state));\n }\n }\n }\n } else {\n // update the relationships between selected elements and frames\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(sceneCoords);\n const selectedElements = this.scene.getSelectedElements(this.state);\n let nextElements = this.scene.getElementsIncludingDeleted();\n\n const updateGroupIdsAfterEditingGroup = elements => {\n if (elements.length > 0) {\n for (const element of elements) {\n const index = element.groupIds.indexOf(this.state.editingGroupId);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: element.groupIds.slice(0, index)\n }, false);\n }\n\n nextElements.forEach(element => {\n if (element.groupIds.length && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(nextElements, element.groupIds[element.groupIds.length - 1]).length < 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: []\n }, false);\n }\n });\n this.setState({\n editingGroupId: null\n });\n }\n };\n\n if (topLayerFrame && !this.state.selectedElementIds[topLayerFrame.id]) {\n const elementsToAdd = selectedElements.filter(element => element.frameId !== topLayerFrame.id && (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n\n if (this.state.editingGroupId) {\n updateGroupIdsAfterEditingGroup(elementsToAdd);\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(nextElements, elementsToAdd, topLayerFrame);\n } else if (!topLayerFrame) {\n if (this.state.editingGroupId) {\n const elementsToRemove = selectedElements.filter(element => element.frameId && !(0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n updateGroupIdsAfterEditingGroup(elementsToRemove);\n }\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(nextElements, this.state, this);\n this.scene.replaceAllElements(nextElements);\n }\n }\n\n if (draggingElement.type === \"frame\") {\n const elementsInsideFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInNewFrame)(this.scene.getElementsIncludingDeleted(), draggingElement);\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(this.scene.getElementsIncludingDeleted(), elementsInsideFrame, draggingElement));\n }\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getNormalizedDimensions)(draggingElement));\n }\n\n if (resizingElement) {\n this.history.resumeRecording();\n }\n\n if (resizingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(resizingElement)) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== resizingElement.id));\n } // handle frame membership for resizing frames and/or selected elements\n\n\n if (pointerDownState.resize.isResizing) {\n let nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(this.scene.getElementsIncludingDeleted(), this.state, this);\n const selectedFrames = this.scene.getSelectedElements(this.state).filter(element => element.type === \"frame\");\n\n for (const frame of selectedFrames) {\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.replaceAllElementsInFrame)(nextElements, (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getElementsIncludingDeleted(), frame, this.state), frame, this.state);\n }\n\n this.scene.replaceAllElements(nextElements);\n } // Code below handles selection when element(s) weren't\n // drag or added to selection on pointer down phase.\n\n\n const hitElement = pointerDownState.hit.element;\n\n if (((_e = this.state.selectedLinearElement) === null || _e === void 0 ? void 0 : _e.elementId) !== (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement)) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement when no other element selected except\n // the one we've hit\n\n if (selectedELements.length === 1) {\n this.setState({\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene)\n });\n }\n }\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDown.clientX, this.lastPointerDown.clientY, this.lastPointerUp.clientX, this.lastPointerUp.clientY);\n\n if (draggedDistance === 0) {\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_51__.makeNextSelectedElementIds)(nextSelectedElementIds, _prevState)\n };\n }); // if not gragging a linear element point (outside editor)\n } else if (!((_f = this.state.selectedLinearElement) === null || _f === void 0 ? void 0 : _f.isDragging)) {\n // remove element from selection while\n // keeping prev elements selected\n this.setState(prevState => {\n const newSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete newSelectedElementIds[hitElement.id];\n const newSelectedElements = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(this.scene.getNonDeletedElements(), {\n selectedElementIds: newSelectedElementIds\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: newSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // set selectedLinearElement only if thats the only element selected\n selectedLinearElement: newSelectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(newSelectedElements[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(newSelectedElements[0], this.scene) : prevState.selectedLinearElement\n });\n });\n }\n } else if (hitElement.frameId && this.state.selectedElementIds[hitElement.frameId]) {\n // when hitElement is part of a selected frame, deselect the frame\n // to avoid frame and containing elements selected simultaneously\n this.setState(prevState => {\n var _a, _b;\n\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n }); // deselect the frame\n\n delete nextSelectedElementIds[hitElement.frameId]; // deselect groups containing the frame\n\n ((_b = (_a = this.scene.getElement(hitElement.frameId)) === null || _a === void 0 ? void 0 : _a.groupIds) !== null && _b !== void 0 ? _b : []).flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n showHyperlinkPopup: hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) ? \"info\" : false\n });\n });\n } else {\n // add element to selection while keeping prev elements selected\n this.setState(_prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, _prevState.selectedElementIds), {\n [hitElement.id]: true\n }), _prevState)\n }));\n }\n } else {\n this.setState(prevState => {\n var _a;\n\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement) && // Don't set `selectedLinearElement` if its same as the hitElement, this is mainly to prevent resetting the `hoverPointIndex` to -1.\n // Future we should update the API to take care of setting the correct `hoverPointIndex` when initialized\n ((_a = prevState.selectedLinearElement) === null || _a === void 0 ? void 0 : _a.elementId) !== hitElement.id ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene) : prevState.selectedLinearElement\n });\n });\n }\n }\n\n if (!pointerDownState.drag.hasOccurred && !this.state.isResizing && (hitElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(hitElement, this.state, this.frameNameBoundsCache, pointerDownState.origin.x, pointerDownState.origin.y) || !hitElement && pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements)) {\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: null\n });\n } else {\n // Deselect selected elements\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\" && draggingElement && draggingElement.type !== \"selection\") {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n showHyperlinkPopup: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(draggingElement) && !draggingElement.link ? \"editor\" : prevState.showHyperlinkPopup\n }));\n }\n\n if (activeTool.type !== \"selection\" || (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(this.scene.getNonDeletedElements(), this.state)) {\n this.history.resumeRecording();\n }\n\n if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {\n ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? _element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements : _element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(this.scene.getSelectedElements(this.state));\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n this.setState({\n draggingElement: null,\n suggestedBindings: [],\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n } else {\n this.setState({\n draggingElement: null,\n suggestedBindings: []\n });\n }\n\n if (hitElement && this.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_51__.makeNextSelectedElementIds)({}, prevState),\n activeEmbeddable: null,\n selectedGroupIds: {},\n // Continue editing the same group if the user selected a different\n // element from it\n editingGroupId: prevState.editingGroupId && hitElement != null && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, prevState.editingGroupId) ? prevState.editingGroupId : null\n }));\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null,\n previousSelectedElementIds: this.state.selectedElementIds\n });\n }\n\n getTextWysiwygSnappedToCenterPosition(x, y, appState, container) {\n if (container) {\n let elementCenterX = container.x + container.width / 2;\n let elementCenterY = container.y + container.height / 2;\n const elementCenter = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, appState);\n\n if (elementCenter) {\n elementCenterX = elementCenter.x;\n elementCenterY = elementCenter.y;\n }\n\n const distanceToCenter = Math.hypot(x - elementCenterX, y - elementCenterY);\n const isSnappedToCenter = distanceToCenter < _constants__WEBPACK_IMPORTED_MODULE_12__.TEXT_TO_CENTER_SNAP_THRESHOLD;\n\n if (isSnappedToCenter) {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: elementCenterX,\n sceneY: elementCenterY\n }, appState);\n return {\n viewportX,\n viewportY,\n elementCenterX,\n elementCenterY\n };\n }\n }\n }\n\n getCanvasOffsets() {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n left,\n top\n } = excalidrawContainer.getBoundingClientRect();\n return {\n offsetLeft: left,\n offsetTop: top\n };\n }\n\n return {\n offsetLeft: 0,\n offsetTop: 0\n };\n }\n\n updateLanguage() {\n return __awaiter(this, void 0, void 0, function* () {\n const currentLang = _i18n__WEBPACK_IMPORTED_MODULE_25__.languages.find(lang => lang.code === this.props.langCode) || _i18n__WEBPACK_IMPORTED_MODULE_25__.defaultLang;\n yield (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.setLanguage)(currentLang);\n this.setAppState({});\n });\n }\n\n}\n\nApp.defaultProps = {\n // needed for tests to pass since we directly render App in many tests\n UIOptions: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_UI_OPTIONS\n};\n\nif (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n window.h = window.h || {};\n Object.defineProperties(window.h, {\n elements: {\n configurable: true,\n\n get() {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.getElementsIncludingDeleted();\n },\n\n set(elements) {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.replaceAllElements(elements);\n }\n\n }\n });\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIseUVBQWtCOztBQUU5QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG1EQUFtRCxzRUFBNkI7O0FBRWhGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLG9FQUEyQjtBQUN2QztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSwwQkFBMEIsa0RBQWMsK0NBQStDLCtDQUFXO0FBQ2xHLFlBQVksbURBQVc7QUFDdkIseUJBQXlCO0FBQ3pCLEtBQUs7QUFDTDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsYUFBYSwyREFBa0I7QUFDL0I7O0FBRUEsSUFBSSxhQUFvQixLQUFLLGlEQUFRLElBQUksYUFBb0I7QUFDN0Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsR0FBRztBQUNIOztBQUVBLGlFQUFlLEdBQUciLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vY29tcG9uZW50cy9BcHAudHN4PzA2MjQiXSwic291cmNlc0NvbnRlbnQiOlsidmFyIF9fYXdhaXRlciA9IHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xuICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7XG4gICAgICByZXNvbHZlKHZhbHVlKTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZWplY3QoZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7XG4gICAgICByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTtcbiAgICB9XG5cbiAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XG4gIH0pO1xufTtcblxuaW1wb3J0IHsganN4IGFzIF9qc3gsIGpzeHMgYXMgX2pzeHMsIEZyYWdtZW50IGFzIF9GcmFnbWVudCB9IGZyb20gXCJyZWFjdC9qc3gtcnVudGltZVwiO1xuaW1wb3J0IFJlYWN0LCB7IHVzZUNvbnRleHQgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCB7IGZsdXNoU3luYyB9IGZyb20gXCJyZWFjdC1kb21cIjtcbmltcG9ydCByb3VnaCBmcm9tIFwicm91Z2hqcy9iaW4vcm91Z2hcIjtcbmltcG9ydCBjbHN4IGZyb20gXCJjbHN4XCI7XG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tIFwibmFub2lkXCI7XG5pbXBvcnQgeyBhY3Rpb25BZGRUb0xpYnJhcnksIGFjdGlvbkJyaW5nRm9yd2FyZCwgYWN0aW9uQnJpbmdUb0Zyb250LCBhY3Rpb25Db3B5LCBhY3Rpb25Db3B5QXNQbmcsIGFjdGlvbkNvcHlBc1N2ZywgY29weVRleHQsIGFjdGlvbkNvcHlTdHlsZXMsIGFjdGlvbkN1dCwgYWN0aW9uRGVsZXRlU2VsZWN0ZWQsIGFjdGlvbkR1cGxpY2F0ZVNlbGVjdGlvbiwgYWN0aW9uRmluYWxpemUsIGFjdGlvbkZsaXBIb3Jpem9udGFsLCBhY3Rpb25GbGlwVmVydGljYWwsIGFjdGlvbkdyb3VwLCBhY3Rpb25QYXN0ZVN0eWxlcywgYWN0aW9uU2VsZWN0QWxsLCBhY3Rpb25TZW5kQmFja3dhcmQsIGFjdGlvblNlbmRUb0JhY2ssIGFjdGlvblRvZ2dsZUdyaWRNb2RlLCBhY3Rpb25Ub2dnbGVTdGF0cywgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVW5iaW5kVGV4dCwgYWN0aW9uQmluZFRleHQsIGFjdGlvblVuZ3JvdXAsIGFjdGlvbkxpbmssIGFjdGlvblRvZ2dsZUVsZW1lbnRMb2NrLCBhY3Rpb25Ub2dnbGVMaW5lYXJFZGl0b3IgfSBmcm9tIFwiLi4vYWN0aW9uc1wiO1xuaW1wb3J0IHsgY3JlYXRlUmVkb0FjdGlvbiwgY3JlYXRlVW5kb0FjdGlvbiB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkhpc3RvcnlcIjtcbmltcG9ydCB7IEFjdGlvbk1hbmFnZXIgfSBmcm9tIFwiLi4vYWN0aW9ucy9tYW5hZ2VyXCI7XG5pbXBvcnQgeyBhY3Rpb25zIH0gZnJvbSBcIi4uL2FjdGlvbnMvcmVnaXN0ZXJcIjtcbmltcG9ydCB7IHRyYWNrRXZlbnQgfSBmcm9tIFwiLi4vYW5hbHl0aWNzXCI7XG5pbXBvcnQgeyBnZXREZWZhdWx0QXBwU3RhdGUsIGlzRXJhc2VyQWN0aXZlLCBpc0hhbmRUb29sQWN0aXZlIH0gZnJvbSBcIi4uL2FwcFN0YXRlXCI7XG5pbXBvcnQgeyBwYXJzZUNsaXBib2FyZCB9IGZyb20gXCIuLi9jbGlwYm9hcmRcIjtcbmltcG9ydCB7IEFQUF9OQU1FLCBDVVJTT1JfVFlQRSwgREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hULCBERUZBVUxUX1VJX09QVElPTlMsIERFRkFVTFRfVkVSVElDQUxfQUxJR04sIERSQUdHSU5HX1RIUkVTSE9MRCwgRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZLCBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQsIEVMRU1FTlRfVFJBTlNMQVRFX0FNT1VOVCwgRU5WLCBFVkVOVCwgRlJBTUVfU1RZTEUsIEdSSURfU0laRSwgSU1BR0VfTUlNRV9UWVBFUywgSU1BR0VfUkVOREVSX1RJTUVPVVQsIGlzQW5kcm9pZCwgaXNCcmF2ZSwgTElORV9DT05GSVJNX1RIUkVTSE9MRCwgTUFYX0FMTE9XRURfRklMRV9CWVRFUywgTUlNRV9UWVBFUywgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9QT1JUUkFJVCwgTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEgsIE1RX1NNX01BWF9XSURUSCwgUE9JTlRFUl9CVVRUT04sIFJPVU5ETkVTUywgU0NST0xMX1RJTUVPVVQsIFRBUF9UV0lDRV9USU1FT1VULCBURVhUX1RPX0NFTlRFUl9TTkFQX1RIUkVTSE9MRCwgVEhFTUUsIFRIRU1FX0ZJTFRFUiwgVE9VQ0hfQ1RYX01FTlVfVElNRU9VVCwgVkVSVElDQUxfQUxJR04sIFlPVVRVQkVfU1RBVEVTLCBaT09NX1NURVAsIFBPSU5URVJfRVZFTlRTIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgZXhwb3J0Q2FudmFzLCBsb2FkRnJvbUJsb2IgfSBmcm9tIFwiLi4vZGF0YVwiO1xuaW1wb3J0IExpYnJhcnksIHsgZGlzdHJpYnV0ZUxpYnJhcnlJdGVtc09uU3F1YXJlR3JpZCB9IGZyb20gXCIuLi9kYXRhL2xpYnJhcnlcIjtcbmltcG9ydCB7IHJlc3RvcmUsIHJlc3RvcmVFbGVtZW50cyB9IGZyb20gXCIuLi9kYXRhL3Jlc3RvcmVcIjtcbmltcG9ydCB7IGRyYWdOZXdFbGVtZW50LCBkcmFnU2VsZWN0ZWRFbGVtZW50cywgZHVwbGljYXRlRWxlbWVudCwgZ2V0Q29tbW9uQm91bmRzLCBnZXRDdXJzb3JGb3JSZXNpemluZ0VsZW1lbnQsIGdldERyYWdPZmZzZXRYWSwgZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLCBnZXROb3JtYWxpemVkRGltZW5zaW9ucywgZ2V0UmVzaXplQXJyb3dEaXJlY3Rpb24sIGdldFJlc2l6ZU9mZnNldFhZLCBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUsIGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzLCBoaXRUZXN0LCBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQsIGlzSW52aXNpYmx5U21hbGxFbGVtZW50LCBpc05vbkRlbGV0ZWRFbGVtZW50LCBpc1RleHRFbGVtZW50LCBuZXdFbGVtZW50LCBuZXdMaW5lYXJFbGVtZW50LCBuZXdUZXh0RWxlbWVudCwgbmV3SW1hZ2VFbGVtZW50LCB0ZXh0V3lzaXd5ZywgdHJhbnNmb3JtRWxlbWVudHMsIHVwZGF0ZVRleHRFbGVtZW50LCByZWRyYXdUZXh0Qm91bmRpbmdCb3ggfSBmcm9tIFwiLi4vZWxlbWVudFwiO1xuaW1wb3J0IHsgYmluZE9yVW5iaW5kTGluZWFyRWxlbWVudCwgYmluZE9yVW5iaW5kU2VsZWN0ZWRFbGVtZW50cywgZml4QmluZGluZ3NBZnRlckRlbGV0aW9uLCBmaXhCaW5kaW5nc0FmdGVyRHVwbGljYXRpb24sIGdldEVsaWdpYmxlRWxlbWVudHNGb3JCaW5kaW5nLCBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcsIGlzQmluZGluZ0VuYWJsZWQsIGlzTGluZWFyRWxlbWVudFNpbXBsZUFuZEFscmVhZHlCb3VuZCwgbWF5YmVCaW5kTGluZWFyRWxlbWVudCwgc2hvdWxkRW5hYmxlQmluZGluZ0ZvclBvaW50ZXJFdmVudCwgdW5iaW5kTGluZWFyRWxlbWVudHMsIHVwZGF0ZUJvdW5kRWxlbWVudHMgfSBmcm9tIFwiLi4vZWxlbWVudC9iaW5kaW5nXCI7XG5pbXBvcnQgeyBMaW5lYXJFbGVtZW50RWRpdG9yIH0gZnJvbSBcIi4uL2VsZW1lbnQvbGluZWFyRWxlbWVudEVkaXRvclwiO1xuaW1wb3J0IHsgbXV0YXRlRWxlbWVudCwgbmV3RWxlbWVudFdpdGggfSBmcm9tIFwiLi4vZWxlbWVudC9tdXRhdGVFbGVtZW50XCI7XG5pbXBvcnQgeyBkZWVwQ29weUVsZW1lbnQsIGR1cGxpY2F0ZUVsZW1lbnRzLCBuZXdGcmFtZUVsZW1lbnQsIG5ld0ZyZWVEcmF3RWxlbWVudCwgbmV3RW1iZWRkYWJsZUVsZW1lbnQgfSBmcm9tIFwiLi4vZWxlbWVudC9uZXdFbGVtZW50XCI7XG5pbXBvcnQgeyBoYXNCb3VuZFRleHRFbGVtZW50LCBpc0Fycm93RWxlbWVudCwgaXNCaW5kaW5nRWxlbWVudCwgaXNCaW5kaW5nRWxlbWVudFR5cGUsIGlzQm91bmRUb0NvbnRhaW5lciwgaXNGcmFtZUVsZW1lbnQsIGlzSW1hZ2VFbGVtZW50LCBpc0VtYmVkZGFibGVFbGVtZW50LCBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50LCBpc0xpbmVhckVsZW1lbnQsIGlzTGluZWFyRWxlbWVudFR5cGUsIGlzVXNpbmdBZGFwdGl2ZVJhZGl1cyB9IGZyb20gXCIuLi9lbGVtZW50L3R5cGVDaGVja3NcIjtcbmltcG9ydCB7IGdldENlbnRlciwgZ2V0RGlzdGFuY2UgfSBmcm9tIFwiLi4vZ2VzdHVyZVwiO1xuaW1wb3J0IHsgZWRpdEdyb3VwRm9yU2VsZWN0ZWRFbGVtZW50LCBnZXRFbGVtZW50c0luR3JvdXAsIGdldFNlbGVjdGVkR3JvdXBJZEZvckVsZW1lbnQsIGdldFNlbGVjdGVkR3JvdXBJZHMsIGlzRWxlbWVudEluR3JvdXAsIGlzU2VsZWN0ZWRWaWFHcm91cCwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyB9IGZyb20gXCIuLi9ncm91cHNcIjtcbmltcG9ydCBIaXN0b3J5IGZyb20gXCIuLi9oaXN0b3J5XCI7XG5pbXBvcnQgeyBkZWZhdWx0TGFuZywgZ2V0TGFuZ3VhZ2UsIGxhbmd1YWdlcywgc2V0TGFuZ3VhZ2UsIHQgfSBmcm9tIFwiLi4vaTE4blwiO1xuaW1wb3J0IHsgQ09ERVMsIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIsIHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8sIHNob3VsZFJvdGF0ZVdpdGhEaXNjcmV0ZUFuZ2xlLCBpc0Fycm93S2V5LCBLRVlTIH0gZnJvbSBcIi4uL2tleXNcIjtcbmltcG9ydCB7IGlzRWxlbWVudEluVmlld3BvcnQgfSBmcm9tIFwiLi4vZWxlbWVudC9zaXplSGVscGVyc1wiO1xuaW1wb3J0IHsgZGlzdGFuY2UyZCwgZ2V0Q29ybmVyUmFkaXVzLCBnZXRHcmlkUG9pbnQsIGlzUGF0aEFMb29wIH0gZnJvbSBcIi4uL21hdGhcIjtcbmltcG9ydCB7IGNhbGN1bGF0ZVNjcm9sbENlbnRlciwgZ2V0RWxlbWVudHNBdFBvc2l0aW9uLCBnZXRFbGVtZW50c1dpdGhpblNlbGVjdGlvbiwgZ2V0Tm9ybWFsaXplZFpvb20sIGdldFNlbGVjdGVkRWxlbWVudHMsIGhhc0JhY2tncm91bmQsIGlzT3ZlclNjcm9sbEJhcnMsIGlzU29tZUVsZW1lbnRTZWxlY3RlZCB9IGZyb20gXCIuLi9zY2VuZVwiO1xuaW1wb3J0IFNjZW5lIGZyb20gXCIuLi9zY2VuZS9TY2VuZVwiO1xuaW1wb3J0IHsgZ2V0U3RhdGVGb3Jab29tIH0gZnJvbSBcIi4uL3NjZW5lL3pvb21cIjtcbmltcG9ydCB7IGZpbmRTaGFwZUJ5S2V5IH0gZnJvbSBcIi4uL3NoYXBlc1wiO1xuaW1wb3J0IHsgZGVib3VuY2UsIGRpc3RhbmNlLCBnZXRGb250U3RyaW5nLCBnZXROZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lciwgaXNJbnB1dExpa2UsIGlzVG9vbEljb24sIGlzV3JpdGFibGVFbGVtZW50LCByZXNldEN1cnNvciwgcmVzb2x2YWJsZVByb21pc2UsIHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcywgc2V0Q3Vyc29yLCBzZXRDdXJzb3JGb3JTaGFwZSwgdHVwbGVUb0Nvb3JzLCB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMsIHdpdGhCYXRjaGVkVXBkYXRlcywgd3JhcEV2ZW50LCB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQsIHVwZGF0ZU9iamVjdCwgc2V0RXJhc2VyQ3Vyc29yLCB1cGRhdGVBY3RpdmVUb29sLCBnZXRTaG9ydGN1dEtleSwgaXNUcmFuc3BhcmVudCwgZWFzZVRvVmFsdWVzUkFGLCBtdXRlRlNBYm9ydEVycm9yLCBpc1Rlc3RFbnYsIGVhc2VPdXQgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IsIGV4dHJhY3RTcmMsIGdldEVtYmVkTGluayB9IGZyb20gXCIuLi9lbGVtZW50L2VtYmVkZGFibGVcIjtcbmltcG9ydCB7IENvbnRleHRNZW51LCBDT05URVhUX01FTlVfU0VQQVJBVE9SIH0gZnJvbSBcIi4vQ29udGV4dE1lbnVcIjtcbmltcG9ydCBMYXllclVJIGZyb20gXCIuL0xheWVyVUlcIjtcbmltcG9ydCB7IFRvYXN0IH0gZnJvbSBcIi4vVG9hc3RcIjtcbmltcG9ydCB7IGFjdGlvblRvZ2dsZVZpZXdNb2RlIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uVG9nZ2xlVmlld01vZGVcIjtcbmltcG9ydCB7IGRhdGFVUkxUb0ZpbGUsIGdlbmVyYXRlSWRGcm9tRmlsZSwgZ2V0RGF0YVVSTCwgZ2V0RmlsZUZyb21FdmVudCwgaXNJbWFnZUZpbGVIYW5kbGUsIGlzU3VwcG9ydGVkSW1hZ2VGaWxlLCBsb2FkU2NlbmVPckxpYnJhcnlGcm9tQmxvYiwgbm9ybWFsaXplRmlsZSwgcGFyc2VMaWJyYXJ5SlNPTiwgcmVzaXplSW1hZ2VGaWxlLCBTVkdTdHJpbmdUb0ZpbGUgfSBmcm9tIFwiLi4vZGF0YS9ibG9iXCI7XG5pbXBvcnQgeyBnZXRJbml0aWFsaXplZEltYWdlRWxlbWVudHMsIGxvYWRIVE1MSW1hZ2VFbGVtZW50LCBub3JtYWxpemVTVkcsIHVwZGF0ZUltYWdlQ2FjaGUgYXMgX3VwZGF0ZUltYWdlQ2FjaGUgfSBmcm9tIFwiLi4vZWxlbWVudC9pbWFnZVwiO1xuaW1wb3J0IHRocm90dGxlIGZyb20gXCJsb2Rhc2gudGhyb3R0bGVcIjtcbmltcG9ydCB7IGZpbGVPcGVuIH0gZnJvbSBcIi4uL2RhdGEvZmlsZXN5c3RlbVwiO1xuaW1wb3J0IHsgYmluZFRleHRUb1NoYXBlQWZ0ZXJEdXBsaWNhdGlvbiwgZ2V0QXBwcm94TWluTGluZUhlaWdodCwgZ2V0QXBwcm94TWluTGluZVdpZHRoLCBnZXRCb3VuZFRleHRFbGVtZW50LCBnZXRDb250YWluZXJDZW50ZXIsIGdldENvbnRhaW5lckVsZW1lbnQsIGdldERlZmF1bHRMaW5lSGVpZ2h0LCBnZXRMaW5lSGVpZ2h0SW5QeCwgZ2V0VGV4dEJpbmRhYmxlQ29udGFpbmVyQXRQb3NpdGlvbiwgaXNNZWFzdXJlVGV4dFN1cHBvcnRlZCwgaXNWYWxpZFRleHRDb250YWluZXIgfSBmcm9tIFwiLi4vZWxlbWVudC90ZXh0RWxlbWVudFwiO1xuaW1wb3J0IHsgaXNIaXR0aW5nRWxlbWVudE5vdENvbnNpZGVyaW5nQm91bmRpbmdCb3ggfSBmcm9tIFwiLi4vZWxlbWVudC9jb2xsaXNpb25cIjtcbmltcG9ydCB7IHNob3dIeXBlcmxpbmtUb29sdGlwLCBoaWRlSHlwZXJsaW5rVG9vbGlwLCBIeXBlcmxpbmssIGlzUG9pbnRIaXR0aW5nTGluaywgaXNQb2ludEhpdHRpbmdMaW5rSWNvbiB9IGZyb20gXCIuLi9lbGVtZW50L0h5cGVybGlua1wiO1xuaW1wb3J0IHsgaXNMb2NhbExpbmssIG5vcm1hbGl6ZUxpbmssIHRvVmFsaWRVUkwgfSBmcm9tIFwiLi4vZGF0YS91cmxcIjtcbmltcG9ydCB7IHNob3VsZFNob3dCb3VuZGluZ0JveCB9IGZyb20gXCIuLi9lbGVtZW50L3RyYW5zZm9ybUhhbmRsZXNcIjtcbmltcG9ydCB7IGFjdGlvblVubG9ja0FsbEVsZW1lbnRzIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uRWxlbWVudExvY2tcIjtcbmltcG9ydCB7IEZvbnRzIH0gZnJvbSBcIi4uL3NjZW5lL0ZvbnRzXCI7XG5pbXBvcnQgeyBnZXRGcmFtZUVsZW1lbnRzLCBpc0N1cnNvckluRnJhbWUsIGJpbmRFbGVtZW50c1RvRnJhbWVzQWZ0ZXJEdXBsaWNhdGlvbiwgYWRkRWxlbWVudHNUb0ZyYW1lLCByZXBsYWNlQWxsRWxlbWVudHNJbkZyYW1lLCByZW1vdmVFbGVtZW50c0Zyb21GcmFtZSwgZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUsIGdldEVsZW1lbnRzSW5OZXdGcmFtZSwgZ2V0Q29udGFpbmluZ0ZyYW1lLCBlbGVtZW50T3ZlcmxhcHNXaXRoRnJhbWUsIHVwZGF0ZUZyYW1lTWVtYmVyc2hpcE9mU2VsZWN0ZWRFbGVtZW50cywgaXNFbGVtZW50SW5GcmFtZSB9IGZyb20gXCIuLi9mcmFtZVwiO1xuaW1wb3J0IHsgZXhjbHVkZUVsZW1lbnRzSW5GcmFtZXNGcm9tU2VsZWN0aW9uLCBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyB9IGZyb20gXCIuLi9zY2VuZS9zZWxlY3Rpb25cIjtcbmltcG9ydCB7IGFjdGlvblBhc3RlIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uQ2xpcGJvYXJkXCI7XG5pbXBvcnQgeyBhY3Rpb25SZW1vdmVBbGxFbGVtZW50c0Zyb21GcmFtZSwgYWN0aW9uU2VsZWN0QWxsRWxlbWVudHNJbkZyYW1lIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uRnJhbWVcIjtcbmltcG9ydCB7IGFjdGlvblRvZ2dsZUhhbmRUb29sLCB6b29tVG9GaXQgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25DYW52YXNcIjtcbmltcG9ydCB7IGpvdGFpU3RvcmUgfSBmcm9tIFwiLi4vam90YWlcIjtcbmltcG9ydCB7IGFjdGl2ZUNvbmZpcm1EaWFsb2dBdG9tIH0gZnJvbSBcIi4vQWN0aXZlQ29uZmlybURpYWxvZ1wiO1xuaW1wb3J0IHsgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkJvdW5kVGV4dFwiO1xuaW1wb3J0IEJyYXZlTWVhc3VyZVRleHRFcnJvciBmcm9tIFwiLi9CcmF2ZU1lYXN1cmVUZXh0RXJyb3JcIjtcbmltcG9ydCB7IGFjdGl2ZUV5ZURyb3BwZXJBdG9tIH0gZnJvbSBcIi4vRXllRHJvcHBlclwiO1xuaW1wb3J0IHsgY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzIH0gZnJvbSBcIi4uL2RhdGEvdHJhbnNmb3JtXCI7XG5pbXBvcnQgeyBpc1NpZGViYXJEb2NrZWRBdG9tIH0gZnJvbSBcIi4vU2lkZWJhci9TaWRlYmFyXCI7XG5pbXBvcnQgeyBTdGF0aWNDYW52YXMsIEludGVyYWN0aXZlQ2FudmFzIH0gZnJvbSBcIi4vY2FudmFzZXNcIjtcbmltcG9ydCB7IFJlbmRlcmVyIH0gZnJvbSBcIi4uL3NjZW5lL1JlbmRlcmVyXCI7XG5pbXBvcnQgeyBTaGFwZUNhY2hlIH0gZnJvbSBcIi4uL3NjZW5lL1NoYXBlQ2FjaGVcIjtcbmNvbnN0IEFwcENvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuY29uc3QgQXBwUHJvcHNDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChudWxsKTtcbmNvbnN0IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWUgPSB7XG4gIGlzU21TY3JlZW46IGZhbHNlLFxuICBpc01vYmlsZTogZmFsc2UsXG4gIGlzVG91Y2hTY3JlZW46IGZhbHNlLFxuICBjYW5EZXZpY2VGaXRTaWRlYmFyOiBmYWxzZSxcbiAgaXNMYW5kc2NhcGU6IGZhbHNlXG59O1xuY29uc3QgRGV2aWNlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoZGV2aWNlQ29udGV4dEluaXRpYWxWYWx1ZSk7XG5EZXZpY2VDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJEZXZpY2VDb250ZXh0XCI7XG5leHBvcnQgY29uc3QgRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KHtcbiAgY29udGFpbmVyOiBudWxsLFxuICBpZDogbnVsbFxufSk7XG5FeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdFbGVtZW50c0NvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KFtdKTtcbkV4Y2FsaWRyYXdFbGVtZW50c0NvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdFbGVtZW50c0NvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZ2V0RGVmYXVsdEFwcFN0YXRlKCkpLCB7XG4gIHdpZHRoOiAwLFxuICBoZWlnaHQ6IDAsXG4gIG9mZnNldExlZnQ6IDAsXG4gIG9mZnNldFRvcDogMFxufSkpO1xuRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoKCkgPT4ge1xuICBjb25zb2xlLndhcm4oXCJ1bml0aWFsaXplZCBFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0IGNvbnRleHQhXCIpO1xufSk7XG5FeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHRcIjtcbmV4cG9ydCBjb25zdCB1c2VBcHAgPSAoKSA9PiB1c2VDb250ZXh0KEFwcENvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUFwcFByb3BzID0gKCkgPT4gdXNlQ29udGV4dChBcHBQcm9wc0NvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZURldmljZSA9ICgpID0+IHVzZUNvbnRleHQoRGV2aWNlQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0NvbnRhaW5lciA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdFbGVtZW50cyA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0FwcFN0YXRlID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3U2V0QXBwU3RhdGUgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQpO1xubGV0IGRpZFRhcFR3aWNlID0gZmFsc2U7XG5sZXQgdGFwcGVkVHdpY2VUaW1lciA9IDA7XG5sZXQgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbmxldCBpc1Bhbm5pbmcgPSBmYWxzZTtcbmxldCBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gZmFsc2U7XG5sZXQgY3VycmVudFNjcm9sbEJhcnMgPSB7XG4gIGhvcml6b250YWw6IG51bGwsXG4gIHZlcnRpY2FsOiBudWxsXG59O1xubGV0IHRvdWNoVGltZW91dCA9IDA7XG5sZXQgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG4vKipcbiAqIE1hcCBvZiB5b3V0dWJlIGVtYmVkIHZpZGVvIHN0YXRlc1xuICovXG5cbmNvbnN0IFlPVVRVQkVfVklERU9fU1RBVEVTID0gbmV3IE1hcCgpO1xubGV0IElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG5sZXQgSVNfUExBSU5fUEFTVEVfVElNRVIgPSAwO1xubGV0IFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gZmFsc2U7XG5sZXQgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG5jb25zdCBnZXN0dXJlID0ge1xuICBwb2ludGVyczogbmV3IE1hcCgpLFxuICBsYXN0Q2VudGVyOiBudWxsLFxuICBpbml0aWFsRGlzdGFuY2U6IG51bGwsXG4gIGluaXRpYWxTY2FsZTogbnVsbFxufTtcblxuY2xhc3MgQXBwIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICB2YXIgX2E7XG5cbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyA9IG51bGw7XG4gICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICB0aGlzLmRldmljZSA9IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWU7XG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmID0gUmVhY3QuY3JlYXRlUmVmKCk7XG4gICAgdGhpcy5maWxlcyA9IHt9O1xuICAgIHRoaXMuaW1hZ2VDYWNoZSA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmlGcmFtZVJlZnMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5sYXN0UG9pbnRlckRvd24gPSBudWxsO1xuICAgIHRoaXMubGFzdFBvaW50ZXJVcCA9IG51bGw7XG4gICAgdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbiA9IHtcbiAgICAgIHg6IDAsXG4gICAgICB5OiAwXG4gICAgfTtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBlbWJlZGRhYmxlRWxlbWVudHMgPSBuZXcgTWFwKCk7XG4gICAgICBsZXQgdXBkYXRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgZW1iZWRkYWJsZUVsZW1lbnRzLnNldChlbGVtZW50LmlkLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50LnZhbGlkYXRlZCA9PSBudWxsKSB7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlZCA9IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IoZWxlbWVudC5saW5rLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSk7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgdmFsaWRhdGVkXG4gICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWQpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgfSAvLyBHQ1xuXG5cbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5mb3JFYWNoKChyZWYsIGlkKSA9PiB7XG4gICAgICAgIGlmICghZW1iZWRkYWJsZUVsZW1lbnRzLmhhcyhpZCkpIHtcbiAgICAgICAgICB0aGlzLmlGcmFtZVJlZnMuZGVsZXRlKGlkKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQgPSBmcmFtZUVsZW1lbnQgPT4ge1xuICAgICAgcmV0dXJuIGAke3RoaXMuaWR9LWZyYW1lLW5hbWUtJHtmcmFtZUVsZW1lbnQuaWR9YDtcbiAgICB9O1xuXG4gICAgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSA9IHtcbiAgICAgIGdldDogZnJhbWVFbGVtZW50ID0+IHtcbiAgICAgICAgbGV0IGJvdW5kcyA9IHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLmdldChmcmFtZUVsZW1lbnQuaWQpO1xuXG4gICAgICAgIGlmICghYm91bmRzIHx8IGJvdW5kcy56b29tICE9PSB0aGlzLnN0YXRlLnpvb20udmFsdWUgfHwgYm91bmRzLnZlcnNpb25Ob25jZSAhPT0gZnJhbWVFbGVtZW50LnZlcnNpb25Ob25jZSkge1xuICAgICAgICAgIGNvbnN0IGZyYW1lTmFtZURpdiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQoZnJhbWVFbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoZnJhbWVOYW1lRGl2KSB7XG4gICAgICAgICAgICBjb25zdCBib3ggPSBmcmFtZU5hbWVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBjb25zdCBib3hTY2VuZVRvcExlZnQgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgICBjbGllbnRYOiBib3gueCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LnlcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3QgYm94U2NlbmVCb3R0b21SaWdodCA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICAgIGNsaWVudFg6IGJveC5yaWdodCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LmJvdHRvbVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBib3VuZHMgPSB7XG4gICAgICAgICAgICAgIHg6IGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICB5OiBib3hTY2VuZVRvcExlZnQueSxcbiAgICAgICAgICAgICAgd2lkdGg6IGJveFNjZW5lQm90dG9tUmlnaHQueCAtIGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICBoZWlnaHQ6IGJveFNjZW5lQm90dG9tUmlnaHQueSAtIGJveFNjZW5lVG9wTGVmdC55LFxuICAgICAgICAgICAgICBhbmdsZTogMCxcbiAgICAgICAgICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLnZhbHVlLFxuICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IGZyYW1lRWxlbWVudC52ZXJzaW9uTm9uY2VcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLnNldChmcmFtZUVsZW1lbnQuaWQsIGJvdW5kcyk7XG5cbiAgICAgICAgICAgIHJldHVybiBib3VuZHM7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYm91bmRzO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICovXG4gICAgICBfY2FjaGU6IG5ldyBNYXAoKVxuICAgIH07XG5cbiAgICB0aGlzLnJlbmRlckZyYW1lTmFtZXMgPSAoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCB8fCAhdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc0RhcmtUaGVtZSA9IHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiO1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLm1hcCgoZiwgaW5kZXgpID0+IHtcbiAgICAgICAgaWYgKCFpc0VsZW1lbnRJblZpZXdwb3J0KGYsIHRoaXMuY2FudmFzLndpZHRoIC8gd2luZG93LmRldmljZVBpeGVsUmF0aW8sIHRoaXMuY2FudmFzLmhlaWdodCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLCB7XG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb21cbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAvLyBpZiBmcmFtZSBub3QgdmlzaWJsZSwgZG9uJ3QgcmVuZGVyIGl0cyBuYW1lXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogeDEsXG4gICAgICAgICAgeTogeTFcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBmLngsXG4gICAgICAgICAgc2NlbmVZOiBmLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB4MlxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IGYueCArIGYud2lkdGgsXG4gICAgICAgICAgc2NlbmVZOiBmLnkgKyBmLmhlaWdodFxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9HQVAgPSAyMDtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgPSA2O1xuXG4gICAgICAgIGNvbnN0IHJlc2V0ID0gKCkgPT4ge1xuICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgIGlmICgoKF9hID0gZi5uYW1lKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudHJpbSgpKSA9PT0gXCJcIikge1xuICAgICAgICAgICAgbXV0YXRlRWxlbWVudChmLCB7XG4gICAgICAgICAgICAgIG5hbWU6IG51bGxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0ZyYW1lOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbGV0IGZyYW1lTmFtZUpTWDtcblxuICAgICAgICBpZiAoZi5pZCA9PT0gdGhpcy5zdGF0ZS5lZGl0aW5nRnJhbWUpIHtcbiAgICAgICAgICBjb25zdCBmcmFtZU5hbWVJbkVkaXQgPSBmLm5hbWUgPT0gbnVsbCA/IGBGcmFtZSAke2luZGV4ICsgMX1gIDogZi5uYW1lO1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IF9qc3goXCJpbnB1dFwiLCB7XG4gICAgICAgICAgICBhdXRvRm9jdXM6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogZnJhbWVOYW1lSW5FZGl0LFxuICAgICAgICAgICAgb25DaGFuZ2U6IGUgPT4ge1xuICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGYsIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBlLnRhcmdldC52YWx1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkJsdXI6ICgpID0+IHJlc2V0KCksXG4gICAgICAgICAgICBvbktleURvd246IGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgLy8gZm9yIHNvbWUgaW5leHBsaWNhYmxlIHJlYXNvbiwgYG9uQmx1cmAgdHJpZ2dlcmVkIG9uIEVTQ1xuICAgICAgICAgICAgICAvLyBkb2VzIG5vdCByZXNldCBgc3RhdGUuZWRpdGluZ0ZyYW1lYCBkZXNwaXRlIGJlaW5nIGNhbGxlZCxcbiAgICAgICAgICAgICAgLy8gYW5kIHdlIG5lZWQgdG8gcmVzZXQgaXQgaGVyZSBhcyB3ZWxsXG4gICAgICAgICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuRVNDQVBFIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5FTlRFUikge1xuICAgICAgICAgICAgICAgIHJlc2V0KCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLnZpZXdCYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgICAgIGZpbHRlcjogaXNEYXJrVGhlbWUgPyBUSEVNRV9GSUxURVIgOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgekluZGV4OiAyLFxuICAgICAgICAgICAgICBib3JkZXI6IFwibm9uZVwiLFxuICAgICAgICAgICAgICBkaXNwbGF5OiBcImJsb2NrXCIsXG4gICAgICAgICAgICAgIHBhZGRpbmc6IGAke0ZSQU1FX05BTUVfRURJVF9QQURESU5HfXB4YCxcbiAgICAgICAgICAgICAgYm9yZGVyUmFkaXVzOiA0LFxuICAgICAgICAgICAgICBib3hTaGFkb3c6IFwiaW5zZXQgMCAwIDAgMXB4IHZhcigtLWNvbG9yLXByaW1hcnkpXCIsXG4gICAgICAgICAgICAgIGZvbnRGYW1pbHk6IFwiQXNzaXN0YW50XCIsXG4gICAgICAgICAgICAgIGZvbnRTaXplOiBcIjE0cHhcIixcbiAgICAgICAgICAgICAgdHJhbnNmb3JtOiBgdHJhbnNsYXRlWSgtJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weClgLFxuICAgICAgICAgICAgICBjb2xvcjogXCJ2YXIoLS1jb2xvci1ncmF5LTgwKVwiLFxuICAgICAgICAgICAgICBvdmVyZmxvdzogXCJoaWRkZW5cIixcbiAgICAgICAgICAgICAgbWF4V2lkdGg6IGAke01hdGgubWluKHgyIC0geDEgLSBGUkFNRV9OQU1FX0VESVRfUEFERElORywgZG9jdW1lbnQuYm9keS5jbGllbnRXaWR0aCAtIHgxIC0gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcpfXB4YFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNpemU6IGZyYW1lTmFtZUluRWRpdC5sZW5ndGggKyAxIHx8IDEsXG4gICAgICAgICAgICBkaXI6IFwiYXV0b1wiLFxuICAgICAgICAgICAgYXV0b0NvbXBsZXRlOiBcIm9mZlwiLFxuICAgICAgICAgICAgYXV0b0NhcGl0YWxpemU6IFwib2ZmXCIsXG4gICAgICAgICAgICBhdXRvQ29ycmVjdDogXCJvZmZcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IGYubmFtZSA9PSBudWxsIHx8IGYubmFtZS50cmltKCkgPT09IFwiXCIgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZS50cmltKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBpZDogdGhpcy5nZXRGcmFtZU5hbWVET01JZChmKSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgcG9zaXRpb246IFwiYWJzb2x1dGVcIixcbiAgICAgICAgICAgIHRvcDogYCR7eTEgLSBGUkFNRV9OQU1FX0dBUCAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wfXB4YCxcbiAgICAgICAgICAgIGxlZnQ6IGAke3gxIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0IC0gKHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID09PSBmLmlkID8gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgOiAwKX1weGAsXG4gICAgICAgICAgICB6SW5kZXg6IDIsXG4gICAgICAgICAgICBmb250U2l6ZTogXCIxNHB4XCIsXG4gICAgICAgICAgICBjb2xvcjogaXNEYXJrVGhlbWUgPyBcInZhcigtLWNvbG9yLWdyYXktNjApXCIgOiBcInZhcigtLWNvbG9yLWdyYXktNTApXCIsXG4gICAgICAgICAgICB3aWR0aDogXCJtYXgtY29udGVudFwiLFxuICAgICAgICAgICAgbWF4V2lkdGg6IGAke3gyIC0geDEgKyBGUkFNRV9OQU1FX0VESVRfUEFERElORyAqIDJ9cHhgLFxuICAgICAgICAgICAgb3ZlcmZsb3c6IGYuaWQgPT09IHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID8gXCJ2aXNpYmxlXCIgOiBcImhpZGRlblwiLFxuICAgICAgICAgICAgd2hpdGVTcGFjZTogXCJub3dyYXBcIixcbiAgICAgICAgICAgIHRleHRPdmVyZmxvdzogXCJlbGxpcHNpc1wiLFxuICAgICAgICAgICAgY3Vyc29yOiBDVVJTT1JfVFlQRS5NT1ZFLFxuICAgICAgICAgICAgcG9pbnRlckV2ZW50czogdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQgPyBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZCA6IFBPSU5URVJfRVZFTlRTLmluaGVyaXRGcm9tVUlcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uUG9pbnRlckRvd246IGV2ZW50ID0+IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24oZXZlbnQpLFxuICAgICAgICAgIG9uV2hlZWw6IGV2ZW50ID0+IHRoaXMuaGFuZGxlV2hlZWwoZXZlbnQpLFxuICAgICAgICAgIG9uQ29udGV4dE1lbnU6IHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUsXG4gICAgICAgICAgb25Eb3VibGVDbGljazogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogZi5pZFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IGZyYW1lTmFtZUpTWFxuICAgICAgICB9KSwgZi5pZCk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5mb2N1c0NvbnRhaW5lciA9ICgpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5mb2N1cygpO1xuICAgIH07XG5cbiAgICB0aGlzLmdldFNjZW5lRWxlbWVudHNJbmNsdWRpbmdEZWxldGVkID0gKCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0U2NlbmVFbGVtZW50cyA9ICgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgIH07XG5cbiAgICB0aGlzLm9uSW5zZXJ0RWxlbWVudHMgPSBlbGVtZW50cyA9PiB7XG4gICAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5KHtcbiAgICAgICAgZWxlbWVudHMsXG4gICAgICAgIHBvc2l0aW9uOiBcImNlbnRlclwiLFxuICAgICAgICBmaWxlczogbnVsbFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMub25FeHBvcnRJbWFnZSA9ICh0eXBlLCBlbGVtZW50cykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdHJhY2tFdmVudChcImV4cG9ydFwiLCB0eXBlLCBcInVpXCIpO1xuICAgICAgY29uc3QgZmlsZUhhbmRsZSA9IHlpZWxkIGV4cG9ydENhbnZhcyh0eXBlLCBlbGVtZW50cywgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcywge1xuICAgICAgICBleHBvcnRCYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLmV4cG9ydEJhY2tncm91bmQsXG4gICAgICAgIG5hbWU6IHRoaXMuc3RhdGUubmFtZSxcbiAgICAgICAgdmlld0JhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yXG4gICAgICB9KS5jYXRjaChtdXRlRlNBYm9ydEVycm9yKS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZXhwb3J0RW1iZWRTY2VuZSAmJiBmaWxlSGFuZGxlICYmIGlzSW1hZ2VGaWxlSGFuZGxlKGZpbGVIYW5kbGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGZpbGVIYW5kbGVcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLm9wZW5FeWVEcm9wcGVyID0gKHtcbiAgICAgIHR5cGVcbiAgICB9KSA9PiB7XG4gICAgICBqb3RhaVN0b3JlLnNldChhY3RpdmVFeWVEcm9wcGVyQXRvbSwge1xuICAgICAgICBzd2FwUHJldmlld09uQWx0OiB0cnVlLFxuICAgICAgICBjb2xvclBpY2tlclR5cGU6IHR5cGUgPT09IFwic3Ryb2tlXCIgPyBcImVsZW1lbnRTdHJva2VcIiA6IFwiZWxlbWVudEJhY2tncm91bmRcIixcbiAgICAgICAgb25TZWxlY3Q6IChjb2xvciwgZXZlbnQpID0+IHtcbiAgICAgICAgICBjb25zdCBzaG91bGRVcGRhdGVTdHJva2VDb2xvciA9IHR5cGUgPT09IFwiYmFja2dyb3VuZFwiICYmIGV2ZW50LmFsdEtleSB8fCB0eXBlID09PSBcInN0cm9rZVwiICYmICFldmVudC5hbHRLZXk7XG4gICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICAgIGlmICghc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICAgIGlmIChzaG91bGRVcGRhdGVTdHJva2VDb2xvcikge1xuICAgICAgICAgICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoe1xuICAgICAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgICBjdXJyZW50SXRlbVN0cm9rZUNvbG9yOiBjb2xvclxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCh7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yOiBjb2xvclxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVTY2VuZSh7XG4gICAgICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbCA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2VsLmlkXSkge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsLCB7XG4gICAgICAgICAgICAgICAgICAgIFtzaG91bGRVcGRhdGVTdHJva2VDb2xvciA/IFwic3Ryb2tlQ29sb3JcIiA6IFwiYmFja2dyb3VuZENvbG9yXCJdOiBjb2xvclxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGVsO1xuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBrZWVwT3Blbk9uQWx0OiBmYWxzZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhhY3Rpb25SZXN1bHQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaCwgX2o7XG5cbiAgICAgIGlmICh0aGlzLnVubW91bnRlZCB8fCBhY3Rpb25SZXN1bHQgPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgbGV0IGVkaXRpbmdFbGVtZW50ID0gbnVsbDtcblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5lbGVtZW50cykge1xuICAgICAgICBhY3Rpb25SZXN1bHQuZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pZCkgPT09IGVsZW1lbnQuaWQgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAhPT0gZWxlbWVudCAmJiBpc05vbkRlbGV0ZWRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoYWN0aW9uUmVzdWx0LmVsZW1lbnRzKTtcblxuICAgICAgICBpZiAoYWN0aW9uUmVzdWx0LmNvbW1pdFRvSGlzdG9yeSkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmZpbGVzKSB7XG4gICAgICAgIHRoaXMuZmlsZXMgPSBhY3Rpb25SZXN1bHQucmVwbGFjZUZpbGVzID8gYWN0aW9uUmVzdWx0LmZpbGVzIDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgYWN0aW9uUmVzdWx0LmZpbGVzKTtcbiAgICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5hcHBTdGF0ZSB8fCBlZGl0aW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIGlmIChhY3Rpb25SZXN1bHQuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHZpZXdNb2RlRW5hYmxlZCA9ICgoX2EgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS52aWV3TW9kZUVuYWJsZWQpIHx8IGZhbHNlO1xuICAgICAgICBsZXQgemVuTW9kZUVuYWJsZWQgPSAoKF9iID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuemVuTW9kZUVuYWJsZWQpIHx8IGZhbHNlO1xuICAgICAgICBsZXQgZ3JpZFNpemUgPSAoKF9jID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZ3JpZFNpemUpIHx8IG51bGw7XG4gICAgICAgIGNvbnN0IHRoZW1lID0gKChfZCA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnRoZW1lKSB8fCB0aGlzLnByb3BzLnRoZW1lIHx8IFRIRU1FLkxJR0hUO1xuICAgICAgICBsZXQgbmFtZSA9IChfZiA9IChfZSA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLm5hbWUpICE9PSBudWxsICYmIF9mICE9PSB2b2lkIDAgPyBfZiA6IHRoaXMuc3RhdGUubmFtZTtcbiAgICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gKF9oID0gKF9nID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2cuZXJyb3JNZXNzYWdlKSAhPT0gbnVsbCAmJiBfaCAhPT0gdm9pZCAwID8gX2ggOiB0aGlzLnN0YXRlLmVycm9yTWVzc2FnZTtcblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMudmlld01vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgdmlld01vZGVFbmFibGVkID0gdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICB6ZW5Nb2RlRW5hYmxlZCA9IHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgZ3JpZFNpemUgPSB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMubmFtZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIG5hbWUgPSB0aGlzLnByb3BzLm5hbWU7XG4gICAgICAgIH1cblxuICAgICAgICBlZGl0aW5nRWxlbWVudCA9IGVkaXRpbmdFbGVtZW50IHx8ICgoX2ogPSBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9qID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfai5lZGl0aW5nRWxlbWVudCkgfHwgbnVsbDtcblxuICAgICAgICBpZiAoZWRpdGluZ0VsZW1lbnQgPT09IG51bGwgfHwgZWRpdGluZ0VsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVkaXRpbmdFbGVtZW50LmlzRGVsZXRlZCkge1xuICAgICAgICAgIGVkaXRpbmdFbGVtZW50ID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIC8vIHVzaW5nIE9iamVjdC5hc3NpZ24gaW5zdGVhZCBvZiBzcHJlYWQgdG8gZm9vbCBUUyA0LjIuMisgaW50b1xuICAgICAgICAgIC8vIHJlZ2FyZGluZyB0aGUgcmVzdWx0aW5nIHR5cGUgYXMgbm90IGNvbnRhaW5pbmcgdW5kZWZpbmVkXG4gICAgICAgICAgLy8gKHdoaWNoIHRoZSBmb2xsb3dpbmcgZXhwcmVzc2lvbiB3aWxsIG5ldmVyIGNvbnRhaW4pXG4gICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oYWN0aW9uUmVzdWx0LmFwcFN0YXRlIHx8IHt9LCB7XG4gICAgICAgICAgICAvLyBOT1RFIHRoaXMgd2lsbCBwcmV2ZW50IG9wZW5pbmcgY29udGV4dCBtZW51IHVzaW5nIGFuIGFjdGlvblxuICAgICAgICAgICAgLy8gb3IgcHJvZ3JhbW1hdGljYWxseSBmcm9tIHRoZSBob3N0LCBzbyBpdCB3aWxsIG5lZWQgdG8gYmVcbiAgICAgICAgICAgIC8vIHJld3JpdHRlbiBsYXRlclxuICAgICAgICAgICAgY29udGV4dE1lbnU6IG51bGwsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudCxcbiAgICAgICAgICAgIHZpZXdNb2RlRW5hYmxlZCxcbiAgICAgICAgICAgIHplbk1vZGVFbmFibGVkLFxuICAgICAgICAgICAgZ3JpZFNpemUsXG4gICAgICAgICAgICB0aGVtZSxcbiAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2VcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIGlmIChhY3Rpb25SZXN1bHQuc3luY0hpc3RvcnkpIHtcbiAgICAgICAgICAgIHRoaXMuaGlzdG9yeS5zZXRDdXJyZW50U3RhdGUodGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTsgLy8gTGlmZWN5Y2xlXG5cbiAgICB0aGlzLm9uQmx1ciA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICBpc0hvbGRpbmdTcGFjZSA9IGZhbHNlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQ6IHRydWVcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGhpcy5vblVubG9hZCA9ICgpID0+IHtcbiAgICAgIHRoaXMub25CbHVyKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZGlzYWJsZUV2ZW50ID0gZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldEhpc3RvcnkgPSAoKSA9PiB7XG4gICAgICB0aGlzLmhpc3RvcnkuY2xlYXIoKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJlc2V0cyBzY2VuZSAmIGhpc3RvcnkuXG4gICAgICogISBEbyBub3QgdXNlIHRvIGNsZWFyIHNjZW5lIHVzZXIgYWN0aW9uICFcbiAgICAgKi9cblxuXG4gICAgdGhpcy5yZXNldFNjZW5lID0gd2l0aEJhdGNoZWRVcGRhdGVzKG9wdHMgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldERlZmF1bHRBcHBTdGF0ZSgpKSwge1xuICAgICAgICBpc0xvYWRpbmc6IChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucmVzZXRMb2FkaW5nU3RhdGUpID8gZmFsc2UgOiBzdGF0ZS5pc0xvYWRpbmcsXG4gICAgICAgIHRoZW1lOiB0aGlzLnN0YXRlLnRoZW1lXG4gICAgICB9KSk7XG4gICAgICB0aGlzLnJlc2V0SGlzdG9yeSgpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5pbml0aWFsaXplU2NlbmUgPSAoKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB2YXIgX2I7XG5cbiAgICAgIGlmIChcImxhdW5jaFF1ZXVlXCIgaW4gd2luZG93ICYmIFwiTGF1bmNoUGFyYW1zXCIgaW4gd2luZG93KSB7XG4gICAgICAgIHdpbmRvdy5sYXVuY2hRdWV1ZS5zZXRDb25zdW1lcihsYXVuY2hQYXJhbXMgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgICAgIGlmICghbGF1bmNoUGFyYW1zLmZpbGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGZpbGVIYW5kbGUgPSBsYXVuY2hQYXJhbXMuZmlsZXNbMF07XG4gICAgICAgICAgY29uc3QgYmxvYiA9IHlpZWxkIGZpbGVIYW5kbGUuZ2V0RmlsZSgpO1xuICAgICAgICAgIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhuZXcgRmlsZShbYmxvYl0sIGJsb2IubmFtZSB8fCBcIlwiLCB7XG4gICAgICAgICAgICB0eXBlOiBibG9iLnR5cGVcbiAgICAgICAgICB9KSwgZmlsZUhhbmRsZSk7XG4gICAgICAgIH0pKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMucHJvcHMudGhlbWUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5pc0xvYWRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBsZXQgaW5pdGlhbERhdGEgPSBudWxsO1xuXG4gICAgICB0cnkge1xuICAgICAgICBpbml0aWFsRGF0YSA9ICh5aWVsZCB0aGlzLnByb3BzLmluaXRpYWxEYXRhKSB8fCBudWxsO1xuXG4gICAgICAgIGlmIChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEubGlicmFyeUl0ZW1zKSB7XG4gICAgICAgICAgdGhpcy5saWJyYXJ5LnVwZGF0ZUxpYnJhcnkoe1xuICAgICAgICAgICAgbGlicmFyeUl0ZW1zOiBpbml0aWFsRGF0YS5saWJyYXJ5SXRlbXMsXG4gICAgICAgICAgICBtZXJnZTogdHJ1ZVxuICAgICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgaW5pdGlhbERhdGEgPSB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZSB8fCBcIkVuY291bnRlcmVkIGFuIGVycm9yIGR1cmluZyBpbXBvcnRpbmcgb3IgcmVzdG9yaW5nIHNjZW5lIGRhdGFcIlxuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2NlbmUgPSByZXN0b3JlKGluaXRpYWxEYXRhLCBudWxsLCBudWxsLCB7XG4gICAgICAgIHJlcGFpckJpbmRpbmdzOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIHNjZW5lLmFwcFN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIHtcbiAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWUgfHwgc2NlbmUuYXBwU3RhdGUudGhlbWUsXG4gICAgICAgIC8vIHdlJ3JlIGZhbGxpbmcgYmFjayB0byBjdXJyZW50IChwcmUtaW5pdCkgc3RhdGUgd2hlbiBkZWNpZGluZ1xuICAgICAgICAvLyB3aGV0aGVyIHRvIG9wZW4gdGhlIGxpYnJhcnksIHRvIGhhbmRsZSBhIGNhc2Ugd2hlcmUgd2VcbiAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZSBvdXRzaWRlIG9mIGluaXRpYWxEYXRhIChlLmcuIHdoZW4gbG9hZGluZyB0aGUgYXBwXG4gICAgICAgIC8vIHdpdGggYSBsaWJyYXJ5IGluc3RhbGwgbGluaywgd2hpY2ggc2hvdWxkIGF1dG8tb3BlbiB0aGUgbGlicmFyeSlcbiAgICAgICAgb3BlblNpZGViYXI6ICgoX2IgPSBzY2VuZS5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLm9wZW5TaWRlYmFyKSB8fCB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyLFxuICAgICAgICBhY3RpdmVUb29sOiBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbCksIHtcbiAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgIH0pIDogc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbCxcbiAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgdG9hc3Q6IHRoaXMuc3RhdGUudG9hc3RcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaW5pdGlhbERhdGEgPT09IG51bGwgfHwgaW5pdGlhbERhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGluaXRpYWxEYXRhLnNjcm9sbFRvQ29udGVudCkge1xuICAgICAgICBzY2VuZS5hcHBTdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCBjYWxjdWxhdGVTY3JvbGxDZW50ZXIoc2NlbmUuZWxlbWVudHMsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCB7XG4gICAgICAgICAgd2lkdGg6IHRoaXMuc3RhdGUud2lkdGgsXG4gICAgICAgICAgaGVpZ2h0OiB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgICAgICBvZmZzZXRUb3A6IHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnQ6IHRoaXMuc3RhdGUub2Zmc2V0TGVmdFxuICAgICAgICB9KSkpO1xuICAgICAgfSAvLyBGb250RmFjZVNldCBsb2FkaW5nZG9uZSBldmVudCB3ZSBsaXN0ZW4gb24gbWF5IG5vdCBhbHdheXMgZmlyZVxuICAgICAgLy8gKGxvb2tpbmcgYXQgeW91IFNhZmFyaSksIHNvIG9uIGluaXQgd2UgbWFudWFsbHkgbG9hZCBmb250cyBmb3IgY3VycmVudFxuICAgICAgLy8gdGV4dCBlbGVtZW50cyBvbiBjYW52YXMsIGFuZCByZXJlbmRlciB0aGVtIG9uY2UgZG9uZS4gVGhpcyBhbHNvXG4gICAgICAvLyBzZWVtcyBmYXN0ZXIgZXZlbiBpbiBicm93c2VycyB0aGF0IGRvIGZpcmUgdGhlIGxvYWRpbmdkb25lIGV2ZW50LlxuXG5cbiAgICAgIHRoaXMuZm9udHMubG9hZEZvbnRzRm9yRWxlbWVudHMoc2NlbmUuZWxlbWVudHMpO1xuICAgICAgdGhpcy5yZXNldEhpc3RvcnkoKTtcbiAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lKSwge1xuICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRoaXMucmVmcmVzaERldmljZVN0YXRlID0gY29udGFpbmVyID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgd2lkdGgsXG4gICAgICAgIGhlaWdodFxuICAgICAgfSA9IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGNvbnN0IHNpZGViYXJCcmVha3BvaW50ID0gdGhpcy5wcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT0gbnVsbCA/IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50IDogTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEg7XG4gICAgICB0aGlzLmRldmljZSA9IHVwZGF0ZU9iamVjdCh0aGlzLmRldmljZSwge1xuICAgICAgICBpc0xhbmRzY2FwZTogd2lkdGggPiBoZWlnaHQsXG4gICAgICAgIGlzU21TY3JlZW46IHdpZHRoIDwgTVFfU01fTUFYX1dJRFRILFxuICAgICAgICBpc01vYmlsZTogd2lkdGggPCBNUV9NQVhfV0lEVEhfUE9SVFJBSVQgfHwgaGVpZ2h0IDwgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUgJiYgd2lkdGggPCBNUV9NQVhfV0lEVEhfTEFORFNDQVBFLFxuICAgICAgICBjYW5EZXZpY2VGaXRTaWRlYmFyOiB3aWR0aCA+IHNpZGViYXJCcmVha3BvaW50XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5vblJlc2l6ZSA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZvckVhY2goZWxlbWVudCA9PiBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHt9KTtcbiAgICB9KTtcblxuICAgIHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrID0gKHtcbiAgICAgIGF0TGVhc3RPbmVWaXNpYmxlRWxlbWVudCxcbiAgICAgIHNjcm9sbEJhcnMsXG4gICAgICBlbGVtZW50c1xuICAgIH0pID0+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+IHtcbiAgICAgIC8vIHByZXZlbnQgYnJvd3NlciBwaW5jaCB6b29tIG9uIERPTSBlbGVtZW50c1xuICAgICAgaWYgKCEoZXZlbnQudGFyZ2V0IGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQpICYmIGV2ZW50LmN0cmxLZXkpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLm9uS2V5VXAgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5TUEFDRSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUuaXNCaW5kaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNBcnJvd0tleShldmVudC5rZXkpKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgPyBiaW5kT3JVbmJpbmRTZWxlY3RlZEVsZW1lbnRzKHNlbGVjdGVkRWxlbWVudHMpIDogdW5iaW5kTGluZWFyRWxlbWVudHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuc2V0QWN0aXZlVG9vbCA9IHRvb2wgPT4ge1xuICAgICAgY29uc3QgbmV4dEFjdGl2ZVRvb2wgPSB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHRvb2wpO1xuXG4gICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSA9PT0gXCJoYW5kXCIpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgfSBlbHNlIGlmICghaXNIb2xkaW5nU3BhY2UpIHtcbiAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc1Rvb2xJY29uKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpKSB7XG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc0xpbmVhckVsZW1lbnRUeXBlKG5leHRBY3RpdmVUb29sLnR5cGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICB0aGlzLm9uSW1hZ2VBY3Rpb24oKTtcbiAgICAgIH1cblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2wsXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IG5leHRBY3RpdmVUb29sLFxuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuc2V0Q3Vyc29yID0gY3Vyc29yID0+IHtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBjdXJzb3IpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0Q3Vyc29yID0gKCkgPT4ge1xuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiByZXR1cm5zIHdoZXRoZXIgdXNlciBpcyBtYWtpbmcgYSBnZXN0dXJlIHdpdGggPj0gMiBmaW5nZXJzIChwb2ludHMpXG4gICAgICogb24gbyB0b3VjaCBzY3JlZW4gKG5vdCBvbiBhIHRyYWNrcGFkKS4gQ3VycmVudGx5IG9ubHkgcmVsYXRlcyB0byBEYXJ3aW5cbiAgICAgKiAoaU9TL2lQYWRPUyxNYWNPUyksIGJ1dCBtYXkgd29yayBvbiBvdGhlciBkZXZpY2VzIGluIHRoZSBmdXR1cmUgaWZcbiAgICAgKiBHZXN0dXJlRXZlbnQgaXMgc3RhbmRhcmRpemVkLlxuICAgICAqL1xuXG5cbiAgICB0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSA9ICgpID0+IHtcbiAgICAgIC8vIHdlIGRvbid0IHdhbnQgdG8gZGVzZWxlY3Qgd2hlbiB1c2luZyB0cmFja3BhZCwgYW5kIG11bHRpLXBvaW50IGdlc3R1cmVzXG4gICAgICAvLyBvbmx5IHdvcmsgb24gdG91Y2ggc2NyZWVucywgc28gY2hlY2tpbmcgZm9yID49IHBvaW50ZXJzIG1lYW5zIHdlJ3JlIG9uIGFcbiAgICAgIC8vIHRvdWNoc2NyZWVuXG4gICAgICByZXR1cm4gZ2VzdHVyZS5wb2ludGVycy5zaXplID49IDI7XG4gICAgfTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuXG4gICAgdGhpcy5vbkdlc3R1cmVTdGFydCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyB3ZSBvbmx5IHdhbnQgdG8gZGVzZWxlY3Qgb24gdG91Y2ggc2NyZWVucyBiZWNhdXNlIHVzZXIgbWF5IGhhdmUgc2VsZWN0ZWRcbiAgICAgIC8vIGVsZW1lbnRzIGJ5IG1pc3Rha2Ugd2hpbGUgem9vbWluZ1xuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICB9KTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuICAgIHRoaXMub25HZXN0dXJlQ2hhbmdlID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIG9uR2VzdHVyZUNoYW5nZSBvbmx5IGhhcyB6b29tIGZhY3RvciBidXQgbm90IHRoZSBjZW50ZXIuXG4gICAgICAvLyBJZiB3ZSdyZSBvbiBpUGFkIG9yIGlQaG9uZSwgdGhlbiB3ZSByZWNvZ25pemUgbXVsdGktdG91Y2ggYW5kIHdpbGxcbiAgICAgIC8vIHpvb20gaW4gYXQgdGhlIHJpZ2h0IGxvY2F0aW9uIGluIHRoZSB0b3VjaG1vdmUgaGFuZGxlclxuICAgICAgLy8gKGhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlKS5cbiAgICAgIC8vXG4gICAgICAvLyBPbiBNYWNib29rIHRyYWNrcGFkLCB3ZSBkb24ndCBoYXZlIHRob3NlIGV2ZW50cyBzbyB3aWxsIHpvb20gaW4gYXQgdGhlXG4gICAgICAvLyBjdXJyZW50IGxvY2F0aW9uIGluc3RlYWQuXG4gICAgICAvL1xuICAgICAgLy8gQXMgc3VjaCwgYmFpbCBmcm9tIHRoaXMgaGFuZGxlciBvbiB0b3VjaCBkZXZpY2VzLlxuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGluaXRpYWxTY2FsZSA9IGdlc3R1cmUuaW5pdGlhbFNjYWxlO1xuXG4gICAgICBpZiAoaW5pdGlhbFNjYWxlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgICB2aWV3cG9ydFg6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCxcbiAgICAgICAgICB2aWV3cG9ydFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSxcbiAgICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20oaW5pdGlhbFNjYWxlICogZXZlbnQuc2NhbGUpXG4gICAgICAgIH0sIHN0YXRlKSkpO1xuICAgICAgfVxuICAgIH0pOyAvLyBmaXJlcyBvbmx5IG9uIFNhZmFyaVxuXG4gICAgdGhpcy5vbkdlc3R1cmVFbmQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gcmVzZWxlY3QgZWxlbWVudHMgb25seSBvbiB0b3VjaCBzY3JlZW5zIChzZWUgb25HZXN0dXJlU3RhcnQpXG5cbiAgICAgIGlmICh0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSgpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB7fSxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHRoaXMuc3RhdGUucHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHMsIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IG51bGw7XG4gICAgfSk7XG5cbiAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZLFxuICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXIgPSB0cnVlLFxuICAgICAgY29udGFpbmVyXG4gICAgfSkgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgbGV0IHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IGZhbHNlO1xuICAgICAgbGV0IHBhcmVudENlbnRlclBvc2l0aW9uID0gaW5zZXJ0QXRQYXJlbnRDZW50ZXIgJiYgdGhpcy5nZXRUZXh0V3lzaXd5Z1NuYXBwZWRUb0NlbnRlclBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZLCB0aGlzLnN0YXRlLCBjb250YWluZXIpO1xuXG4gICAgICBpZiAoY29udGFpbmVyICYmIHBhcmVudENlbnRlclBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lciA9IGdldEJvdW5kVGV4dEVsZW1lbnQoY29udGFpbmVyKTtcblxuICAgICAgICBpZiAoIWJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lcikge1xuICAgICAgICAgIHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgbGV0IGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBudWxsO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIGlmIChpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHNlbGVjdGVkRWxlbWVudHNbMF07XG4gICAgICAgIH0gZWxzZSBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IGdldEJvdW5kVGV4dEVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZm9udEZhbWlseSA9IChleGlzdGluZ1RleHRFbGVtZW50ID09PSBudWxsIHx8IGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nVGV4dEVsZW1lbnQuZm9udEZhbWlseSkgfHwgdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRGYW1pbHk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gKGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IG51bGwgfHwgZXhpc3RpbmdUZXh0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhpc3RpbmdUZXh0RWxlbWVudC5saW5lSGVpZ2h0KSB8fCBnZXREZWZhdWx0TGluZUhlaWdodChmb250RmFtaWx5KTtcbiAgICAgIGNvbnN0IGZvbnRTaXplID0gdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRTaXplO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyICYmIGNvbnRhaW5lciAmJiAhaXNBcnJvd0VsZW1lbnQoY29udGFpbmVyKSkge1xuICAgICAgICBjb25zdCBmb250U3RyaW5nID0ge1xuICAgICAgICAgIGZvbnRTaXplLFxuICAgICAgICAgIGZvbnRGYW1pbHlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgbWluV2lkdGggPSBnZXRBcHByb3hNaW5MaW5lV2lkdGgoZ2V0Rm9udFN0cmluZyhmb250U3RyaW5nKSwgbGluZUhlaWdodCk7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IGdldEFwcHJveE1pbkxpbmVIZWlnaHQoZm9udFNpemUsIGxpbmVIZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdIZWlnaHQgPSBNYXRoLm1heChjb250YWluZXIuaGVpZ2h0LCBtaW5IZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdXaWR0aCA9IE1hdGgubWF4KGNvbnRhaW5lci53aWR0aCwgbWluV2lkdGgpO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGNvbnRhaW5lciwge1xuICAgICAgICAgIGhlaWdodDogbmV3SGVpZ2h0LFxuICAgICAgICAgIHdpZHRoOiBuZXdXaWR0aFxuICAgICAgICB9KTtcbiAgICAgICAgc2NlbmVYID0gY29udGFpbmVyLnggKyBuZXdXaWR0aCAvIDI7XG4gICAgICAgIHNjZW5lWSA9IGNvbnRhaW5lci55ICsgbmV3SGVpZ2h0IC8gMjtcblxuICAgICAgICBpZiAocGFyZW50Q2VudGVyUG9zaXRpb24pIHtcbiAgICAgICAgICBwYXJlbnRDZW50ZXJQb3NpdGlvbiA9IHRoaXMuZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwgdGhpcy5zdGF0ZSwgY29udGFpbmVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBleGlzdGluZ1RleHRFbGVtZW50ID8gZXhpc3RpbmdUZXh0RWxlbWVudCA6IG5ld1RleHRFbGVtZW50KHtcbiAgICAgICAgeDogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWCA6IHNjZW5lWCxcbiAgICAgICAgeTogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWSA6IHNjZW5lWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIHRleHQ6IFwiXCIsXG4gICAgICAgIGZvbnRTaXplLFxuICAgICAgICBmb250RmFtaWx5LFxuICAgICAgICB0ZXh0QWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gXCJjZW50ZXJcIiA6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1UZXh0QWxpZ24sXG4gICAgICAgIHZlcnRpY2FsQWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gVkVSVElDQUxfQUxJR04uTUlERExFIDogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgICAgY29udGFpbmVySWQ6IHNob3VsZEJpbmRUb0NvbnRhaW5lciA/IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5pZCA6IHVuZGVmaW5lZCxcbiAgICAgICAgZ3JvdXBJZHM6IChfYSA9IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5ncm91cElkcykgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogW10sXG4gICAgICAgIGxpbmVIZWlnaHQsXG4gICAgICAgIGFuZ2xlOiAoX2IgPSBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuYW5nbGUpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDAsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfSk7XG5cbiAgICAgIGlmICghZXhpc3RpbmdUZXh0RWxlbWVudCAmJiBzaG91bGRCaW5kVG9Db250YWluZXIgJiYgY29udGFpbmVyKSB7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoY29udGFpbmVyLCB7XG4gICAgICAgICAgYm91bmRFbGVtZW50czogKGNvbnRhaW5lci5ib3VuZEVsZW1lbnRzIHx8IFtdKS5jb25jYXQoe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGNvbnRhaW5lciAmJiBzaG91bGRCaW5kVG9Db250YWluZXIpIHtcbiAgICAgICAgICBjb25zdCBjb250YWluZXJJbmRleCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudEluZGV4KGNvbnRhaW5lci5pZCk7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50QXRJbmRleChlbGVtZW50LCBjb250YWluZXJJbmRleCArIDEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuICAgICAgdGhpcy5oYW5kbGVUZXh0V3lzaXd5ZyhlbGVtZW50LCB7XG4gICAgICAgIGlzRXhpc3RpbmdFbGVtZW50OiAhIWV4aXN0aW5nVGV4dEVsZW1lbnRcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrID0gZXZlbnQgPT4ge1xuICAgICAgLy8gY2FzZTogZG91YmxlLWNsaWNraW5nIHdpdGggYXJyb3cvbGluZSB0b29sIHNlbGVjdGVkIHdvdWxkIGJvdGggY3JlYXRlXG4gICAgICAvLyB0ZXh0IGFuZCBlbnRlciBtdWx0aUVsZW1lbnQgbW9kZVxuICAgICAgaWYgKHRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gd2Ugc2hvdWxkIG9ubHkgYmUgYWJsZSB0byBkb3VibGUgY2xpY2sgd2hlbiBtb2RlIGlzIHNlbGVjdGlvblxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkpIHtcbiAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICghdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCAhPT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3Ioc2VsZWN0ZWRFbGVtZW50c1swXSwgdGhpcy5zY2VuZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCA9PT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgIGxldCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkR3JvdXBJZHMgPSBnZXRTZWxlY3RlZEdyb3VwSWRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRHcm91cElkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRHcm91cElkID0gaGl0RWxlbWVudCAmJiBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50KGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUuc2VsZWN0ZWRHcm91cElkcyk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkR3JvdXBJZCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogc2VsZWN0ZWRHcm91cElkLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICBlbGVtZW50OiBoaXRFbGVtZW50LFxuICAgICAgICAgICAgICBzdGF0ZTogXCJhY3RpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgc2NlbmVYLCBzY2VuZVkpO1xuXG4gICAgICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgICAgICBpZiAoaGFzQm91bmRUZXh0RWxlbWVudChjb250YWluZXIpIHx8ICFpc1RyYW5zcGFyZW50KGNvbnRhaW5lci5iYWNrZ3JvdW5kQ29sb3IpIHx8IGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94KGNvbnRhaW5lciwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgW3NjZW5lWCwgc2NlbmVZXSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG1pZFBvaW50ID0gZ2V0Q29udGFpbmVyQ2VudGVyKGNvbnRhaW5lciwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBzY2VuZVggPSBtaWRQb2ludC54O1xuICAgICAgICAgICAgc2NlbmVZID0gbWlkUG9pbnQueTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXI6ICFldmVudC5hbHRLZXksXG4gICAgICAgICAgY29udGFpbmVyXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbiA9IChzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpID0+IHtcbiAgICAgIC8vIFJldmVyc2luZyBzbyB3ZSB0cmF2ZXJzZSB0aGUgZWxlbWVudHMgaW4gZGVjcmVhc2luZyBvcmRlclxuICAgICAgLy8gb2Ygei1pbmRleFxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLnNsaWNlKCkucmV2ZXJzZSgpO1xuICAgICAgbGV0IGhpdEVsZW1lbnRJbmRleCA9IEluZmluaXR5O1xuICAgICAgcmV0dXJuIGVsZW1lbnRzLmZpbmQoKGVsZW1lbnQsIGluZGV4KSA9PiB7XG4gICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGVsZW1lbnQuaWQgPT09IGhpdEVsZW1lbnQuaWQpIHtcbiAgICAgICAgICBoaXRFbGVtZW50SW5kZXggPSBpbmRleDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGVtZW50LmxpbmsgJiYgaW5kZXggPD0gaGl0RWxlbWVudEluZGV4ICYmIGlzUG9pbnRIaXR0aW5nTGluayhlbGVtZW50LCB0aGlzLnN0YXRlLCBbc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55XSwgdGhpcy5kZXZpY2UuaXNNb2JpbGUpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVkaXJlY3RUb0xpbmsgPSAoZXZlbnQsIGlzVG91Y2hTY3JlZW4pID0+IHtcbiAgICAgIGNvbnN0IGRyYWdnZWREaXN0YW5jZSA9IGRpc3RhbmNlMmQodGhpcy5sYXN0UG9pbnRlckRvd24uY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlckRvd24uY2xpZW50WSwgdGhpcy5sYXN0UG9pbnRlclVwLmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJVcC5jbGllbnRZKTtcblxuICAgICAgaWYgKCF0aGlzLmhpdExpbmtFbGVtZW50IHx8IC8vIEZvciB0b3VjaCBzY3JlZW4gYWxsb3cgZHJhZ2dpbmcgdGhyZXNob2xkIGVsc2Ugc3RyaWN0IGNoZWNrXG4gICAgICBpc1RvdWNoU2NyZWVuICYmIGRyYWdnZWREaXN0YW5jZSA+IERSQUdHSU5HX1RIUkVTSE9MRCB8fCAhaXNUb3VjaFNjcmVlbiAmJiBkcmFnZ2VkRGlzdGFuY2UgIT09IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBsYXN0UG9pbnRlckRvd25Db29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHModGhpcy5sYXN0UG9pbnRlckRvd24sIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJEb3duSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlckRvd25Db29yZHMueCwgbGFzdFBvaW50ZXJEb3duQ29vcmRzLnldLCB0aGlzLmRldmljZS5pc01vYmlsZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHRoaXMubGFzdFBvaW50ZXJVcCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlclVwQ29vcmRzLngsIGxhc3RQb2ludGVyVXBDb29yZHMueV0sIHRoaXMuZGV2aWNlLmlzTW9iaWxlKTtcblxuICAgICAgaWYgKGxhc3RQb2ludGVyRG93bkhpdHRpbmdMaW5rSWNvbiAmJiBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uKSB7XG4gICAgICAgIGxldCB1cmwgPSB0aGlzLmhpdExpbmtFbGVtZW50Lmxpbms7XG5cbiAgICAgICAgaWYgKHVybCkge1xuICAgICAgICAgIHVybCA9IG5vcm1hbGl6ZUxpbmsodXJsKTtcbiAgICAgICAgICBsZXQgY3VzdG9tRXZlbnQ7XG5cbiAgICAgICAgICBpZiAodGhpcy5wcm9wcy5vbkxpbmtPcGVuKSB7XG4gICAgICAgICAgICBjdXN0b21FdmVudCA9IHdyYXBFdmVudChFVkVOVC5FWENBTElEUkFXX0xJTkssIGV2ZW50Lm5hdGl2ZUV2ZW50KTtcbiAgICAgICAgICAgIHRoaXMucHJvcHMub25MaW5rT3BlbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuaGl0TGlua0VsZW1lbnQpLCB7XG4gICAgICAgICAgICAgIGxpbms6IHVybFxuICAgICAgICAgICAgfSksIGN1c3RvbUV2ZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIShjdXN0b21FdmVudCA9PT0gbnVsbCB8fCBjdXN0b21FdmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogY3VzdG9tRXZlbnQuZGVmYXVsdFByZXZlbnRlZCkpIHtcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldCA9IGlzTG9jYWxMaW5rKHVybCkgPyBcIl9zZWxmXCIgOiBcIl9ibGFua1wiO1xuICAgICAgICAgICAgY29uc3QgbmV3V2luZG93ID0gd2luZG93Lm9wZW4odW5kZWZpbmVkLCB0YXJnZXQpOyAvLyBodHRwczovL21hdGhpYXNieW5lbnMuZ2l0aHViLmlvL3JlbC1ub29wZW5lci9cblxuICAgICAgICAgICAgaWYgKG5ld1dpbmRvdykge1xuICAgICAgICAgICAgICBuZXdXaW5kb3cub3BlbmVyID0gbnVsbDtcbiAgICAgICAgICAgICAgbmV3V2luZG93LmxvY2F0aW9uID0gdXJsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzID0gc2NlbmVDb29yZHMgPT4ge1xuICAgICAgY29uc3QgZnJhbWVzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRnJhbWVzKCkuZmlsdGVyKGZyYW1lID0+IGlzQ3Vyc29ySW5GcmFtZShzY2VuZUNvb3JkcywgZnJhbWUpKTtcbiAgICAgIHJldHVybiBmcmFtZXMubGVuZ3RoID8gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXSA6IG51bGw7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIHRoaXMuc3RhdGUuY3Vyc29yQnV0dG9uKTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuaGFzKGV2ZW50LnBvaW50ZXJJZCkpIHtcbiAgICAgICAgZ2VzdHVyZS5wb2ludGVycy5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICAgICAgeDogZXZlbnQuY2xpZW50WCxcbiAgICAgICAgICB5OiBldmVudC5jbGllbnRZXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbml0aWFsU2NhbGUgPSBnZXN0dXJlLmluaXRpYWxTY2FsZTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMiAmJiBnZXN0dXJlLmxhc3RDZW50ZXIgJiYgaW5pdGlhbFNjYWxlICYmIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlKSB7XG4gICAgICAgIGNvbnN0IGNlbnRlciA9IGdldENlbnRlcihnZXN0dXJlLnBvaW50ZXJzKTtcbiAgICAgICAgY29uc3QgZGVsdGFYID0gY2VudGVyLnggLSBnZXN0dXJlLmxhc3RDZW50ZXIueDtcbiAgICAgICAgY29uc3QgZGVsdGFZID0gY2VudGVyLnkgLSBnZXN0dXJlLmxhc3RDZW50ZXIueTtcbiAgICAgICAgZ2VzdHVyZS5sYXN0Q2VudGVyID0gY2VudGVyO1xuICAgICAgICBjb25zdCBkaXN0YW5jZSA9IGdldERpc3RhbmNlKEFycmF5LmZyb20oZ2VzdHVyZS5wb2ludGVycy52YWx1ZXMoKSkpO1xuICAgICAgICBjb25zdCBzY2FsZUZhY3RvciA9IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIgJiYgdGhpcy5zdGF0ZS5wZW5Nb2RlID8gMSA6IGRpc3RhbmNlIC8gZ2VzdHVyZS5pbml0aWFsRGlzdGFuY2U7XG4gICAgICAgIGNvbnN0IG5leHRab29tID0gc2NhbGVGYWN0b3IgPyBnZXROb3JtYWxpemVkWm9vbShpbml0aWFsU2NhbGUgKiBzY2FsZUZhY3RvcikgOiB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIGNvbnN0IHpvb21TdGF0ZSA9IGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgICB2aWV3cG9ydFg6IGNlbnRlci54LFxuICAgICAgICAgICAgdmlld3BvcnRZOiBjZW50ZXIueSxcbiAgICAgICAgICAgIG5leHRab29tXG4gICAgICAgICAgfSwgc3RhdGUpO1xuICAgICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgICAgIHpvb206IHpvb21TdGF0ZS56b29tLFxuICAgICAgICAgICAgc2Nyb2xsWDogem9vbVN0YXRlLnNjcm9sbFggKyBkZWx0YVggLyBuZXh0Wm9vbSxcbiAgICAgICAgICAgIHNjcm9sbFk6IHpvb21TdGF0ZS5zY3JvbGxZICsgZGVsdGFZIC8gbmV4dFpvb20sXG4gICAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlID0gZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNIb2xkaW5nU3BhY2UgfHwgaXNQYW5uaW5nIHx8IGlzRHJhZ2dpbmdTY3JvbGxCYXIgfHwgaXNIYW5kVG9vbEFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzID0gaXNPdmVyU2Nyb2xsQmFycyhjdXJyZW50U2Nyb2xsQmFycywgZXZlbnQuY2xpZW50WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgZXZlbnQuY2xpZW50WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wKTtcbiAgICAgIGNvbnN0IGlzT3ZlclNjcm9sbEJhciA9IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzLmlzT3ZlckVpdGhlcjtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lUG9pbnRlclgsXG4gICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgIH0gPSBzY2VuZVBvaW50ZXI7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgY29uc3QgZWRpdGluZ0xpbmVhckVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJNb3ZlKGV2ZW50LCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZWRpdGluZ0xpbmVhckVsZW1lbnQgIT09IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSBudWxsIHx8IGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlZGl0aW5nTGluZWFyRWxlbWVudC5sYXN0VW5jb21taXR0ZWRQb2ludCkgIT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0F0Q3Vyc29yKHNjZW5lUG9pbnRlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gY2F1c2VzIHN0YWNrIG92ZXJmbG93IGlmIG5vdCBzeW5jXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50VHlwZSh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgLy8gSG92ZXJpbmcgd2l0aCBhIHNlbGVjdGVkIHRvb2wgb3IgY3JlYXRpbmcgbmV3IGxpbmVhciBlbGVtZW50IHZpYSBjbGlja1xuICAgICAgICAvLyBhbmQgcG9pbnRcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBpZiAoaXNCaW5kaW5nRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ3NGb3JMaW5lYXJFbGVtZW50QXRDb29yZHMoZHJhZ2dpbmdFbGVtZW50LCBbc2NlbmVQb2ludGVyXSwgdGhpcy5zdGF0ZS5zdGFydEJvdW5kRWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3Ioc2NlbmVQb2ludGVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG11bHRpRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHJ4LFxuICAgICAgICAgIHk6IHJ5XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBwb2ludHMsXG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IGxhc3RQb2ludCA9IHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV07XG4gICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChsYXN0UG9pbnQgPT09IGxhc3RDb21taXR0ZWRQb2ludCkge1xuICAgICAgICAgIC8vIGlmIHdlIGhhdmVuJ3QgeWV0IGNyZWF0ZWQgYSB0ZW1wIHBvaW50IGFuZCB3ZSdyZSBiZXlvbmQgY29tbWl0LXpvbmVcbiAgICAgICAgICAvLyB0aHJlc2hvbGQsIGFkZCBhIHBvaW50XG4gICAgICAgICAgaWYgKGRpc3RhbmNlMmQoc2NlbmVQb2ludGVyWCAtIHJ4LCBzY2VuZVBvaW50ZXJZIC0gcnksIGxhc3RQb2ludFswXSwgbGFzdFBvaW50WzFdKSA+PSBMSU5FX0NPTkZJUk1fVEhSRVNIT0xEKSB7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeV1dXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpOyAvLyBpbiB0aGlzIGJyYW5jaCwgd2UncmUgaW5zaWRlIHRoZSBjb21taXQgem9uZSwgYW5kIG5vIHVuY29tbWl0dGVkXG4gICAgICAgICAgICAvLyBwb2ludCBleGlzdHMuIFRodXMgZG8gbm90aGluZyAoZG9uJ3QgYWRkL3JlbW92ZSBwb2ludHMpLlxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID4gMiAmJiBsYXN0Q29tbWl0dGVkUG9pbnQgJiYgZGlzdGFuY2UyZChzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeSwgbGFzdENvbW1pdHRlZFBvaW50WzBdLCBsYXN0Q29tbWl0dGVkUG9pbnRbMV0pIDwgTElORV9DT05GSVJNX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBwb2ludHMuc2xpY2UoMCwgLTEpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgICAgY29uc3QgW2xhc3RDb21taXR0ZWRYLCBsYXN0Q29tbWl0dGVkWV0gPSAoX2EgPSBtdWx0aUVsZW1lbnQgPT09IG51bGwgfHwgbXVsdGlFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBtdWx0aUVsZW1lbnQubGFzdENvbW1pdHRlZFBvaW50KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBbMCwgMF07XG4gICAgICAgICAgbGV0IGR4RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWCAtIHJ4IC0gbGFzdENvbW1pdHRlZFg7XG4gICAgICAgICAgbGV0IGR5RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWSAtIHJ5IC0gbGFzdENvbW1pdHRlZFk7XG5cbiAgICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpKSB7XG4gICAgICAgICAgICAoe1xuICAgICAgICAgICAgICB3aWR0aDogZHhGcm9tTGFzdENvbW1pdHRlZCxcbiAgICAgICAgICAgICAgaGVpZ2h0OiBkeUZyb21MYXN0Q29tbWl0dGVkXG4gICAgICAgICAgICB9ID0gZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplKCAvLyBhY3R1YWwgY29vcmRpbmF0ZSBvZiB0aGUgbGFzdCBjb21taXR0ZWQgcG9pbnRcbiAgICAgICAgICAgIGxhc3RDb21taXR0ZWRYICsgcngsIGxhc3RDb21taXR0ZWRZICsgcnksIC8vIGN1cnNvci1ncmlkIGNvb3JkaW5hdGVcbiAgICAgICAgICAgIGdyaWRYLCBncmlkWSkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChpc1BhdGhBTG9vcChwb2ludHMsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpIHtcbiAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICB9IC8vIHVwZGF0ZSBsYXN0IHVuY29tbWl0dGVkIHBvaW50XG5cblxuICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMuc2xpY2UoMCwgLTEpLCBbbGFzdENvbW1pdHRlZFggKyBkeEZyb21MYXN0Q29tbWl0dGVkLCBsYXN0Q29tbWl0dGVkWSArIGR5RnJvbUxhc3RDb21taXR0ZWRdXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNEZXNlbGVjdGVkQnV0dG9uID0gQm9vbGVhbihldmVudC5idXR0b25zKTtcblxuICAgICAgaWYgKGhhc0Rlc2VsZWN0ZWRCdXR0b24gfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwidGV4dFwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICFpc092ZXJTY3JvbGxCYXIgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlKGVsZW1lbnRzLCB0aGlzLnN0YXRlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICBpZiAoZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlICYmIGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS50cmFuc2Zvcm1IYW5kbGVUeXBlKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIGdldEN1cnNvckZvclJlc2l6aW5nRWxlbWVudChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiAxICYmICFpc092ZXJTY3JvbGxCYXIpIHtcbiAgICAgICAgY29uc3QgdHJhbnNmb3JtSGFuZGxlVHlwZSA9IGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzKGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG5cbiAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50KHtcbiAgICAgICAgICAgIHRyYW5zZm9ybUhhbmRsZVR5cGVcbiAgICAgICAgICB9KSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICB0aGlzLmhpdExpbmtFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KTtcblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGl0TGlua0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuaGl0TGlua0VsZW1lbnQuaWRdKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgc2hvd0h5cGVybGlua1Rvb2x0aXAodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoaWRlSHlwZXJsaW5rVG9vbGlwKCk7XG5cbiAgICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgKGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpKSAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSAmJiAhdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiAhdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXApIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogXCJpbmZvXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgaXNUZXh0RWxlbWVudChoaXRFbGVtZW50KSA/IENVUlNPUl9UWVBFLlRFWFQgOiBDVVJTT1JfVFlQRS5DUk9TU0hBSVIpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICB9IGVsc2UgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlSG92ZXJTZWxlY3RlZExpbmVhckVsZW1lbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpO1xuICAgICAgICB9IGVsc2UgaWYgKCAvLyBpZiB1c2luZyBjbWQvY3RybCwgd2UncmUgbm90IGRyYWdnaW5nXG4gICAgICAgICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICAgIGlmICgoaGl0RWxlbWVudCB8fCB0aGlzLmlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHNjZW5lUG9pbnRlciwgc2VsZWN0ZWRFbGVtZW50cykpICYmICEoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmxvY2tlZCkpIHtcbiAgICAgICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgZXZlbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICAgICAgZWxlbWVudDogaGl0RWxlbWVudCxcbiAgICAgICAgICAgICAgICAgIHN0YXRlOiBcImhvdmVyXCJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuXG4gICAgICAgICAgICAgIGlmICgoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImhvdmVyXCIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQVVUTyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVFcmFzZXIgPSAoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUsIHNjZW5lUG9pbnRlcikgPT4ge1xuICAgICAgY29uc3QgdXBkYXRlRWxlbWVudElkcyA9IGVsZW1lbnRzID0+IHtcbiAgICAgICAgZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoZWxlbWVudC5sb2NrZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZHNUb1VwZGF0ZS5wdXNoKGVsZW1lbnQuaWQpO1xuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSkge1xuICAgICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlbWVudC5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXS5lcmFzZSkge1xuICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdLmVyYXNlID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmICghcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSA9IHtcbiAgICAgICAgICAgICAgZXJhc2U6IHRydWUsXG4gICAgICAgICAgICAgIG9wYWNpdHk6IGVsZW1lbnQub3BhY2l0eVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfTtcblxuICAgICAgY29uc3QgaWRzVG9VcGRhdGUgPSBbXTtcbiAgICAgIGNvbnN0IGRpc3RhbmNlID0gZGlzdGFuY2UyZChwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnksIHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICBjb25zdCB0aHJlc2hvbGQgPSAxMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgIGNvbnN0IHBvaW50ID0gT2JqZWN0LmFzc2lnbih7fSwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzKTtcbiAgICAgIGxldCBzYW1wbGluZ0ludGVydmFsID0gMDtcblxuICAgICAgd2hpbGUgKHNhbXBsaW5nSW50ZXJ2YWwgPD0gZGlzdGFuY2UpIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbihwb2ludC54LCBwb2ludC55KTtcbiAgICAgICAgdXBkYXRlRWxlbWVudElkcyhoaXRFbGVtZW50cyk7IC8vIEV4aXQgc2luY2Ugd2UgcmVhY2hlZCBjdXJyZW50IHBvaW50XG5cbiAgICAgICAgaWYgKHNhbXBsaW5nSW50ZXJ2YWwgPT09IGRpc3RhbmNlKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gLy8gQ2FsY3VsYXRlIG5leHQgcG9pbnQgaW4gdGhlIGxpbmUgYXQgYSBkaXN0YW5jZSBvZiBzYW1wbGluZyBpbnRlcnZhbFxuXG5cbiAgICAgICAgc2FtcGxpbmdJbnRlcnZhbCA9IE1hdGgubWluKHNhbXBsaW5nSW50ZXJ2YWwgKyB0aHJlc2hvbGQsIGRpc3RhbmNlKTtcbiAgICAgICAgY29uc3QgZGlzdGFuY2VSYXRpbyA9IHNhbXBsaW5nSW50ZXJ2YWwgLyBkaXN0YW5jZTtcbiAgICAgICAgY29uc3QgbmV4dFggPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueCArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueDtcbiAgICAgICAgY29uc3QgbmV4dFkgPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueSArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueTtcbiAgICAgICAgcG9pbnQueCA9IG5leHRYO1xuICAgICAgICBwb2ludC55ID0gbmV4dFk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWxlID0+IHtcbiAgICAgICAgY29uc3QgaWQgPSBpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBpZHNUb1VwZGF0ZS5pbmNsdWRlcyhlbGUuY29udGFpbmVySWQpID8gZWxlLmNvbnRhaW5lcklkIDogZWxlLmlkO1xuXG4gICAgICAgIGlmIChpZHNUb1VwZGF0ZS5pbmNsdWRlcyhpZCkpIHtcbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0uZXJhc2UgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXS5vcGFjaXR5XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICAgIG9wYWNpdHk6IEVMRU1FTlRfUkVBRFlfVE9fRVJBU0VfT1BBQ0lUWVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBzY2VuZVBvaW50ZXIueDtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gc2NlbmVQb2ludGVyLnk7XG4gICAgfTsgLy8gc2V0IHRvdWNoIG1vdmluZyBmb3IgbW9iaWxlIGNvbnRleHQgbWVudVxuXG5cbiAgICB0aGlzLmhhbmRsZVRvdWNoTW92ZSA9IGV2ZW50ID0+IHtcbiAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IHRydWU7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24gPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBzaW5jZSBjb250ZXh0TWVudSBvcHRpb25zIGFyZSBwb3RlbnRpYWxseSBldmFsdWF0ZWQgb24gZWFjaCByZW5kZXIsXG4gICAgICAvLyBhbmQgYW4gY29udGV4dE1lbnUgYWN0aW9uIG1heSBkZXBlbmQgb24gc2VsZWN0aW9uIHN0YXRlLCB3ZSBtdXN0XG4gICAgICAvLyBjbG9zZSB0aGUgY29udGV4dE1lbnUgYmVmb3JlIHdlIHVwZGF0ZSB0aGUgc2VsZWN0aW9uIG9uIHBvaW50ZXJEb3duXG4gICAgICAvLyAoZS5nLiByZXNldHRpbmcgc2VsZWN0aW9uKVxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnVwZGF0ZUdlc3R1cmVPblBvaW50ZXJEb3duKGV2ZW50KTsgLy8gaWYgZHJhZ2dpbmcgZWxlbWVudCBpcyBmcmVlZHJhdyBhbmQgYW5vdGhlciBwb2ludGVyZG93biBldmVudCBvY2N1cnNcbiAgICAgIC8vIGEgc2Vjb25kIGZpbmdlciBpcyBvbiB0aGUgc2NyZWVuXG4gICAgICAvLyBkaXNjYXJkIHRoZSBmcmVlZHJhdyBlbGVtZW50IGlmIGl0IGlzIHZlcnkgc2hvcnQgYmVjYXVzZSBpdCBpcyBsaWtlbHlcbiAgICAgIC8vIGp1c3QgYSBzcGlrZSwgb3RoZXJ3aXNlIGZpbmFsaXplIHRoZSBmcmVlZHJhdyBlbGVtZW50IHdoZW4gdGhlIHNlY29uZFxuICAgICAgLy8gZmluZ2VyIGlzIGxpZnRlZFxuXG4gICAgICBpZiAoZXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIiAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50O1xuICAgICAgICB0aGlzLnVwZGF0ZVNjZW5lKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZWxlbWVudC5wb2ludHMubGVuZ3RoIDwgMTAgPyB7XG4gICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSBlbGVtZW50LmlkKVxuICAgICAgICB9IDoge30pLCB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5rZXlzKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5maWx0ZXIoa2V5ID0+IGtleSAhPT0gZWxlbWVudC5pZCkucmVkdWNlKChvYmosIGtleSkgPT4ge1xuICAgICAgICAgICAgICBvYmpba2V5XSA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2tleV07XG4gICAgICAgICAgICAgIHJldHVybiBvYmo7XG4gICAgICAgICAgICB9LCB7fSksIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gcmVtb3ZlIGFueSBhY3RpdmUgc2VsZWN0aW9uIHdoZW4gd2Ugc3RhcnQgdG8gaW50ZXJhY3Qgd2l0aCBjYW52YXNcbiAgICAgIC8vIChtYWlubHksIHdlIGNhcmUgYWJvdXQgcmVtb3Zpbmcgc2VsZWN0aW9uIG91dHNpZGUgdGhlIGNvbXBvbmVudCB3aGljaFxuICAgICAgLy8gIHdvdWxkIHByZXZlbnQgb3VyIGNvcHkgaGFuZGxpbmcgb3RoZXJ3aXNlKVxuXG5cbiAgICAgIGNvbnN0IHNlbGVjdGlvbiA9IGRvY3VtZW50LmdldFNlbGVjdGlvbigpO1xuXG4gICAgICBpZiAoc2VsZWN0aW9uID09PSBudWxsIHx8IHNlbGVjdGlvbiA9PT0gdm9pZCAwID8gdm9pZCAwIDogc2VsZWN0aW9uLmFuY2hvck5vZGUpIHtcbiAgICAgICAgc2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlT3BlbkNvbnRleHRNZW51QWZ0ZXJQb2ludGVyRG93bk9uVG91Y2hEZXZpY2VzKGV2ZW50KTtcbiAgICAgIHRoaXMubWF5YmVDbGVhbnVwQWZ0ZXJNaXNzaW5nUG9pbnRlclVwKGV2ZW50KTsgLy9maXJlcyBvbmx5IG9uY2UsIGlmIHBlbiBpcyBkZXRlY3RlZCwgcGVuTW9kZSBpcyBlbmFibGVkXG4gICAgICAvL3RoZSB1c2VyIGNhbiBkaXNhYmxlIHRoaXMgYnkgdG9nZ2xpbmcgdGhlIHBlbk1vZGUgYnV0dG9uXG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5wZW5EZXRlY3RlZCAmJiBldmVudC5wb2ludGVyVHlwZSA9PT0gXCJwZW5cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHBlbk1vZGU6IHRydWUsXG4gICAgICAgICAgICBwZW5EZXRlY3RlZDogdHJ1ZVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4gJiYgW1wicGVuXCIsIFwidG91Y2hcIl0uaW5jbHVkZXMoZXZlbnQucG9pbnRlclR5cGUpKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gdXBkYXRlT2JqZWN0KHRoaXMuZGV2aWNlLCB7XG4gICAgICAgICAgaXNUb3VjaFNjcmVlbjogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUGFubmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubGFzdFBvaW50ZXJEb3duID0gZXZlbnQ7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgbGFzdFBvaW50ZXJEb3duV2l0aDogZXZlbnQucG9pbnRlclR5cGUsXG4gICAgICAgIGN1cnNvckJ1dHRvbjogXCJkb3duXCJcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCBcImRvd25cIik7XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZUNhbnZhc1BhblVzaW5nV2hlZWxPclNwYWNlRHJhZyhldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBvbmx5IGhhbmRsZSBsZWZ0IG1vdXNlIGJ1dHRvbiBvciB0b3VjaFxuXG5cbiAgICAgIGlmIChldmVudC5idXR0b24gIT09IFBPSU5URVJfQlVUVE9OLk1BSU4gJiYgZXZlbnQuYnV0dG9uICE9PSBQT0lOVEVSX0JVVFRPTi5UT1VDSCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIGRvbid0IHNlbGVjdCB3aGlsZSBwYW5uaW5nXG5cblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA+IDEpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBTdGF0ZSBmb3IgdGhlIGR1cmF0aW9uIG9mIGEgcG9pbnRlciBpbnRlcmFjdGlvbiwgd2hpY2ggc3RhcnRzIHdpdGggYVxuICAgICAgLy8gcG9pbnRlckRvd24gZXZlbnQsIGVuZHMgd2l0aCBhIHBvaW50ZXJVcCBldmVudCAob3IgYW5vdGhlciBwb2ludGVyRG93bilcblxuXG4gICAgICBjb25zdCBwb2ludGVyRG93blN0YXRlID0gdGhpcy5pbml0aWFsUG9pbnRlckRvd25TdGF0ZShldmVudCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogZmFsc2VcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVEcmFnZ2luZ1Njcm9sbEJhcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmNsZWFyU2VsZWN0aW9uSWZOb3RVc2luZ1NlbGVjdGlvbigpO1xuICAgICAgdGhpcy51cGRhdGVCaW5kaW5nRW5hYmxlZE9uUG9pbnRlck1vdmUoZXZlbnQpO1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVTZWxlY3Rpb25PblBvaW50ZXJEb3duKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGFsbG93T25Qb2ludGVyRG93biA9ICF0aGlzLnN0YXRlLnBlbk1vZGUgfHwgZXZlbnQucG9pbnRlclR5cGUgIT09IFwidG91Y2hcIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIjtcblxuICAgICAgaWYgKCFhbGxvd09uUG9pbnRlckRvd24pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlVGV4dE9uUG9pbnRlckRvd24oZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImFycm93XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGluZVwiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlTGluZWFyRWxlbWVudE9uUG9pbnRlckRvd24oZXZlbnQsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlLCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICAvLyByZXNldCBpbWFnZSBwcmV2aWV3IG9uIHBvaW50ZXJkb3duXG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5DUk9TU0hBSVIpOyAvLyByZXRyaWV2ZSB0aGUgbGF0ZXN0IGVsZW1lbnQgYXMgdGhlIHN0YXRlIG1heSBiZSBzdGFsZVxuXG4gICAgICAgIGNvbnN0IHBlbmRpbmdJbWFnZUVsZW1lbnQgPSB0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCAmJiB0aGlzLnNjZW5lLmdldEVsZW1lbnQodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQpO1xuXG4gICAgICAgIGlmICghcGVuZGluZ0ltYWdlRWxlbWVudCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogcGVuZGluZ0ltYWdlRWxlbWVudCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogcGVuZGluZ0ltYWdlRWxlbWVudCxcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGwsXG4gICAgICAgICAgbXVsdGlFbGVtZW50OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBtdXRhdGVFbGVtZW50KHBlbmRpbmdJbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVGcmVlRHJhd0VsZW1lbnRPblBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImN1c3RvbVwiKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUZyYW1lRWxlbWVudE9uUG9pbnRlckRvd24ocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImhhbmRcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUdlbmVyaWNFbGVtZW50T25Qb2ludGVyRG93bih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vblBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB0aGlzLm9uUG9pbnRlck1vdmVGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgY29uc3Qgb25Qb2ludGVyVXAgPSB0aGlzLm9uUG9pbnRlclVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5RG93biA9IHRoaXMub25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5VXAgPSB0aGlzLm9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgbGFzdFBvaW50ZXJVcCA9IG9uUG9pbnRlclVwO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgb25LZXlEb3duKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIG9uS2V5VXApO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSA9IG9uUG9pbnRlck1vdmU7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25VcCA9IG9uUG9pbnRlclVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5VXAgPSBvbktleVVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5RG93biA9IG9uS2V5RG93bjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnJlbW92ZVBvaW50ZXIoZXZlbnQpO1xuICAgICAgdGhpcy5sYXN0UG9pbnRlclVwID0gZXZlbnQ7XG4gICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiBldmVudC5jbGllbnRYLFxuICAgICAgICBjbGllbnRZOiBldmVudC5jbGllbnRZXG4gICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGNsaWNrbGVuZ3RoID0gZXZlbnQudGltZVN0YW1wIC0gKChfYiA9IChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudGltZVN0YW1wKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwKTtcblxuICAgICAgaWYgKHRoaXMuZGV2aWNlLmlzTW9iaWxlICYmIGNsaWNrbGVuZ3RoIDwgMzAwKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG5cbiAgICAgICAgaWYgKGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgZXZlbnQsIHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSkpIHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayhoaXRFbGVtZW50KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4pIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgICAgdGhpcy5oaXRMaW5rRWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudExpbmtBdFBvc2l0aW9uKHNjZW5lUG9pbnRlciwgaGl0RWxlbWVudCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmhpdExpbmtFbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0aGlzLmhpdExpbmtFbGVtZW50LmlkXSkge1xuICAgICAgICBpZiAoY2xpY2tsZW5ndGggPCAzMDAgJiYgdGhpcy5oaXRMaW5rRWxlbWVudC50eXBlID09PSBcImVtYmVkZGFibGVcIiAmJiAhaXNQb2ludEhpdHRpbmdMaW5rSWNvbih0aGlzLmhpdExpbmtFbGVtZW50LCB0aGlzLnN0YXRlLCBbc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55XSkpIHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayh0aGlzLmhpdExpbmtFbGVtZW50KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnJlZGlyZWN0VG9MaW5rKGV2ZW50LCB0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsLFxuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge31cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVPcGVuQ29udGV4dE1lbnVBZnRlclBvaW50ZXJEb3duT25Ub3VjaERldmljZXMgPSBldmVudCA9PiB7XG4gICAgICAvLyBkZWFsIHdpdGggb3BlbmluZyBjb250ZXh0IG1lbnUgb24gdG91Y2ggZGV2aWNlc1xuICAgICAgaWYgKGV2ZW50LnBvaW50ZXJUeXBlID09PSBcInRvdWNoXCIpIHtcbiAgICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKHRvdWNoVGltZW91dCkge1xuICAgICAgICAgIC8vIElmIHRoZXJlJ3MgYWxyZWFkeSBhIHRvdWNoVGltZW91dCwgdGhpcyBtZWFucyB0aGF0IHRoZXJlJ3MgYW5vdGhlclxuICAgICAgICAgIC8vIHRvdWNoIGRvd24gYW5kIHdlIGFyZSBkb2luZyBhbm90aGVyIHRvdWNoLCBzbyB3ZSBzaG91bGRuJ3Qgb3BlbiB0aGVcbiAgICAgICAgICAvLyBjb250ZXh0IG1lbnUuXG4gICAgICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBvcGVuIHRoZSBjb250ZXh0IG1lbnUgd2l0aCB0aGUgZmlyc3QgdG91Y2gncyBjbGllbnRYIGFuZCBjbGllbnRZXG4gICAgICAgICAgLy8gaWYgdGhlIHRvdWNoIGlzIG5vdCBtb3ZpbmdcbiAgICAgICAgICB0b3VjaFRpbWVvdXQgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICB0b3VjaFRpbWVvdXQgPSAwO1xuXG4gICAgICAgICAgICBpZiAoIWludmFsaWRhdGVDb250ZXh0TWVudSkge1xuICAgICAgICAgICAgICB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51KGV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCBUT1VDSF9DVFhfTUVOVV9USU1FT1VUKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0Q29udGV4dE1lbnVUaW1lciA9ICgpID0+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/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIGVkaXRpbmdHcm91cElkOiB0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICBbZWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgfVxuICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogaXNMaW5lYXJFbGVtZW50KGVsZW1lbnQpID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZWxlbWVudCwgdGhpcy5zY2VuZSkgOiBudWxsXG4gICAgICB9KSA6IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZmFsc2VcbiAgICAgIH0pLCAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiB7XG4gICAgICAgICAgICB0b3AsXG4gICAgICAgICAgICBsZWZ0LFxuICAgICAgICAgICAgaXRlbXM6IHRoaXMuZ2V0Q29udGV4dE1lbnVJdGVtcyh0eXBlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudCA9IChwb2ludGVyRG93blN0YXRlLCBldmVudCkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBkcmFnZ2luZ0VsZW1lbnQgPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudDtcbiAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHM7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcInNlbGVjdGlvblwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyQ29vcmRzLngpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBwb2ludGVyQ29vcmRzLnkpLCBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCBpbWFnZSA9IGlzSW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSAmJiAoKF9hID0gdGhpcy5pbWFnZUNhY2hlLmdldChkcmFnZ2luZ0VsZW1lbnQuZmlsZUlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmltYWdlKTtcbiAgICAgICAgY29uc3QgYXNwZWN0UmF0aW8gPSBpbWFnZSAmJiAhKGltYWdlIGluc3RhbmNlb2YgUHJvbWlzZSkgPyBpbWFnZS53aWR0aCAvIGltYWdlLmhlaWdodCA6IG51bGw7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnksIGdyaWRYLCBncmlkWSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCwgZ3JpZFgpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55LCBncmlkWSksIGlzSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgPyAhc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCkgOiBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCksIGFzcGVjdFJhdGlvKTtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKFtkcmFnZ2luZ0VsZW1lbnRdKTsgLy8gaGlnaGxpZ2h0IGVsZW1lbnRzIHRoYXQgYXJlIHRvIGJlIGFkZGVkIHRvIGZyYW1lcyBvbiBmcmFtZXMgY3JlYXRpb25cblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWxlbWVudHNUb0hpZ2hsaWdodDogZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVIYW5kbGVSZXNpemUgPSAocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpID0+IHtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBzZWxlY3RlZEZyYW1lcyA9IHNlbGVjdGVkRWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuICAgICAgY29uc3QgdHJhbnNmb3JtSGFuZGxlVHlwZSA9IHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGU7XG5cbiAgICAgIGlmIChzZWxlY3RlZEZyYW1lcy5sZW5ndGggPiAwICYmIHRyYW5zZm9ybUhhbmRsZVR5cGUgPT09IFwicm90YXRpb25cIikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAvLyBUT0RPOiByZW5hbWUgdGhpcyBzdGF0ZSBmaWVsZCB0byBcImlzU2NhbGluZ1wiIHRvIGRpc3Rpbmd1aXNoXG4gICAgICAgIC8vIGl0IGZyb20gdGhlIGdlbmVyaWMgXCJpc1Jlc2l6aW5nXCIgd2hpY2ggaW5jbHVkZXMgc2NhbGluZyBhbmRcbiAgICAgICAgLy8gcm90YXRpbmdcbiAgICAgICAgaXNSZXNpemluZzogdHJhbnNmb3JtSGFuZGxlVHlwZSAmJiB0cmFuc2Zvcm1IYW5kbGVUeXBlICE9PSBcInJvdGF0aW9uXCIsXG4gICAgICAgIGlzUm90YXRpbmc6IHRyYW5zZm9ybUhhbmRsZVR5cGUgPT09IFwicm90YXRpb25cIixcbiAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzO1xuICAgICAgY29uc3QgW3Jlc2l6ZVgsIHJlc2l6ZVldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCAtIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldC54LCBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5vZmZzZXQueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcCA9IG5ldyBNYXAoKTtcbiAgICAgIHNlbGVjdGVkRnJhbWVzLmZvckVhY2goZnJhbWUgPT4ge1xuICAgICAgICBjb25zdCBlbGVtZW50c0luRnJhbWUgPSBnZXRGcmFtZUVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLmlkKTtcbiAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgZnJhbWVFbGVtZW50c09mZnNldHNNYXAuc2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCwge1xuICAgICAgICAgICAgeDogZWxlbWVudC54IC0gZnJhbWUueCxcbiAgICAgICAgICAgIHk6IGVsZW1lbnQueSAtIGZyYW1lLnlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHRyYW5zZm9ybUVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUsIHRyYW5zZm9ybUhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHMsIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmFycm93RGlyZWN0aW9uLCBzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZShldmVudCksIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIoZXZlbnQpLCBzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0ltYWdlRWxlbWVudChzZWxlY3RlZEVsZW1lbnRzWzBdKSA/ICFzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSA6IHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpLCByZXNpemVYLCByZXNpemVZLCBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5jZW50ZXIueCwgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuY2VudGVyLnkpKSB7XG4gICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgY29uc3QgZWxlbWVudHNUb0hpZ2hsaWdodCA9IG5ldyBTZXQoKTtcbiAgICAgICAgc2VsZWN0ZWRGcmFtZXMuZm9yRWFjaChmcmFtZSA9PiB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudHNJbkZyYW1lID0gZ2V0RnJhbWVFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBmcmFtZS5pZCk7IC8vIGtlZXAgZWxlbWVudHMnIHBvc2l0aW9ucyByZWxhdGl2ZSB0byB0aGVpciBmcmFtZXMgb24gZnJhbWVzIHJlc2l6aW5nXG5cbiAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZSkge1xuICAgICAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUuaW5jbHVkZXMoXCJ3XCIpKSB7XG4gICAgICAgICAgICAgIGVsZW1lbnRzSW5GcmFtZS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgIHg6IGZyYW1lLnggKyAoKChfYSA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EueCkgfHwgMCksXG4gICAgICAgICAgICAgICAgICB5OiBmcmFtZS55ICsgKCgoX2IgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnkpIHx8IDApXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZS5pbmNsdWRlcyhcIm5cIikpIHtcbiAgICAgICAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgeDogZnJhbWUueCArICgoKF9hID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS54KSB8fCAwKSxcbiAgICAgICAgICAgICAgICAgIHk6IGZyYW1lLnkgKyAoKChfYiA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IueSkgfHwgMClcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZnJhbWUsIHRoaXMuc3RhdGUpLmZvckVhY2goZWxlbWVudCA9PiBlbGVtZW50c1RvSGlnaGxpZ2h0LmFkZChlbGVtZW50KSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBbLi4uZWxlbWVudHNUb0hpZ2hsaWdodF1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0Q29udGV4dE1lbnVJdGVtcyA9IHR5cGUgPT4ge1xuICAgICAgY29uc3Qgb3B0aW9ucyA9IFtdO1xuICAgICAgb3B0aW9ucy5wdXNoKGFjdGlvbkNvcHlBc1BuZywgYWN0aW9uQ29weUFzU3ZnKTsgLy8gY2FudmFzIGNvbnRleHRNZW51XG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICAgIGlmICh0eXBlID09PSBcImNhbnZhc1wiKSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICAgIHJldHVybiBbLi4ub3B0aW9ucywgYWN0aW9uVG9nZ2xlR3JpZE1vZGUsIGFjdGlvblRvZ2dsZVplbk1vZGUsIGFjdGlvblRvZ2dsZVZpZXdNb2RlLCBhY3Rpb25Ub2dnbGVTdGF0c107XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gW2FjdGlvblBhc3RlLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Db3B5QXNQbmcsIGFjdGlvbkNvcHlBc1N2ZywgY29weVRleHQsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvblNlbGVjdEFsbCwgYWN0aW9uVW5sb2NrQWxsRWxlbWVudHMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvblRvZ2dsZUdyaWRNb2RlLCBhY3Rpb25Ub2dnbGVaZW5Nb2RlLCBhY3Rpb25Ub2dnbGVWaWV3TW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHNdO1xuICAgICAgfSAvLyBlbGVtZW50IGNvbnRleHRNZW51XG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuICAgICAgb3B0aW9ucy5wdXNoKGNvcHlUZXh0KTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHJldHVybiBbYWN0aW9uQ29weSwgLi4ub3B0aW9uc107XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBbYWN0aW9uQ3V0LCBhY3Rpb25Db3B5LCBhY3Rpb25QYXN0ZSwgYWN0aW9uU2VsZWN0QWxsRWxlbWVudHNJbkZyYW1lLCBhY3Rpb25SZW1vdmVBbGxFbGVtZW50c0Zyb21GcmFtZSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgLi4ub3B0aW9ucywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQ29weVN0eWxlcywgYWN0aW9uUGFzdGVTdHlsZXMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkdyb3VwLCBhY3Rpb25VbmJpbmRUZXh0LCBhY3Rpb25CaW5kVGV4dCwgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciwgYWN0aW9uVW5ncm91cCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQWRkVG9MaWJyYXJ5LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25TZW5kQmFja3dhcmQsIGFjdGlvbkJyaW5nRm9yd2FyZCwgYWN0aW9uU2VuZFRvQmFjaywgYWN0aW9uQnJpbmdUb0Zyb250LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25GbGlwSG9yaXpvbnRhbCwgYWN0aW9uRmxpcFZlcnRpY2FsLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Ub2dnbGVMaW5lYXJFZGl0b3IsIGFjdGlvbkxpbmssIGFjdGlvbkR1cGxpY2F0ZVNlbGVjdGlvbiwgYWN0aW9uVG9nZ2xlRWxlbWVudExvY2ssIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkRlbGV0ZVNlbGVjdGVkXTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVXaGVlbCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAoaXNQYW5uaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICBkZWx0YVgsXG4gICAgICAgIGRlbHRhWVxuICAgICAgfSA9IGV2ZW50OyAvLyBub3RlIHRoYXQgZXZlbnQuY3RybEtleSBpcyBuZWNlc3NhcnkgdG8gaGFuZGxlIHBpbmNoIHpvb21pbmdcblxuICAgICAgaWYgKGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuY3RybEtleSkge1xuICAgICAgICBjb25zdCBzaWduID0gTWF0aC5zaWduKGRlbHRhWSk7XG4gICAgICAgIGNvbnN0IE1BWF9TVEVQID0gWk9PTV9TVEVQICogMTAwO1xuICAgICAgICBjb25zdCBhYnNEZWx0YSA9IE1hdGguYWJzKGRlbHRhWSk7XG4gICAgICAgIGxldCBkZWx0YSA9IGRlbHRhWTtcblxuICAgICAgICBpZiAoYWJzRGVsdGEgPiBNQVhfU1RFUCkge1xuICAgICAgICAgIGRlbHRhID0gTUFYX1NURVAgKiBzaWduO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG5ld1pvb20gPSB0aGlzLnN0YXRlLnpvb20udmFsdWUgLSBkZWx0YSAvIDEwMDsgLy8gaW5jcmVhc2Ugem9vbSBzdGVwcyB0aGUgbW9yZSB6b29tZWQtaW4gd2UgYXJlIChhcHBsaWVzIHRvID4xMDAlIG9ubHkpXG5cbiAgICAgICAgbmV3Wm9vbSArPSBNYXRoLmxvZzEwKE1hdGgubWF4KDEsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpICogLXNpZ24gKiAvLyByZWR1Y2VkIGFtcGxpZmljYXRpb24gZm9yIHNtYWxsIGRlbHRhcyAoc21hbGwgbW92ZW1lbnRzIG9uIGEgdHJhY2twYWQpXG4gICAgICAgIE1hdGgubWluKDEsIGFic0RlbHRhIC8gMjApO1xuICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgdmlld3BvcnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgICAgdmlld3BvcnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnksXG4gICAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKG5ld1pvb20pXG4gICAgICAgIH0sIHN0YXRlKSksIHtcbiAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgfSkpO1xuICAgICAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gc2Nyb2xsIGhvcml6b250YWxseSB3aGVuIHNoaWZ0IHByZXNzZWRcblxuXG4gICAgICBpZiAoZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoKHtcbiAgICAgICAgICB6b29tLFxuICAgICAgICAgIHNjcm9sbFhcbiAgICAgICAgfSkgPT4gKHtcbiAgICAgICAgICAvLyBvbiBNYWMsIHNoaWZ0K3doZWVsIHRlbmRzIHRvIHJlc3VsdCBpbiBkZWx0YVhcbiAgICAgICAgICBzY3JvbGxYOiBzY3JvbGxYIC0gKGRlbHRhWSB8fCBkZWx0YVgpIC8gem9vbS52YWx1ZVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoKHtcbiAgICAgICAgem9vbSxcbiAgICAgICAgc2Nyb2xsWCxcbiAgICAgICAgc2Nyb2xsWVxuICAgICAgfSkgPT4gKHtcbiAgICAgICAgc2Nyb2xsWDogc2Nyb2xsWCAtIGRlbHRhWCAvIHpvb20udmFsdWUsXG4gICAgICAgIHNjcm9sbFk6IHNjcm9sbFkgLSBkZWx0YVkgLyB6b29tLnZhbHVlXG4gICAgICB9KSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnNhdmVQb2ludGVyID0gKHgsIHksIGJ1dHRvbikgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgaWYgKCF4IHx8ICF5KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgIGNsaWVudFg6IHgsXG4gICAgICAgIGNsaWVudFk6IHlcbiAgICAgIH0sIHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoaXNOYU4ocG9pbnRlci54KSB8fCBpc05hTihwb2ludGVyLnkpKSB7Ly8gc29tZXRpbWVzIHRoZSBwb2ludGVyIGdvZXMgb2ZmIHNjcmVlblxuICAgICAgfVxuXG4gICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKS5vblBvaW50ZXJVcGRhdGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5jYWxsKF9hLCB7XG4gICAgICAgIHBvaW50ZXIsXG4gICAgICAgIGJ1dHRvbixcbiAgICAgICAgcG9pbnRlcnNNYXA6IGdlc3R1cmUucG9pbnRlcnNcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkID0gZGVib3VuY2UoKCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLnVubW91bnRlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IGZhbHNlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0sIDMwMCk7XG5cbiAgICB0aGlzLnVwZGF0ZURPTVJlY3QgPSBjYiA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGlmICgoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jdXJyZW50KSB7XG4gICAgICAgIGNvbnN0IGV4Y2FsaWRyYXdDb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHdpZHRoLFxuICAgICAgICAgIGhlaWdodCxcbiAgICAgICAgICBsZWZ0OiBvZmZzZXRMZWZ0LFxuICAgICAgICAgIHRvcDogb2Zmc2V0VG9wXG4gICAgICAgIH0gPSBleGNhbGlkcmF3Q29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgd2lkdGg6IGN1cnJlbnRXaWR0aCxcbiAgICAgICAgICBoZWlnaHQ6IGN1cnJlbnRIZWlnaHQsXG4gICAgICAgICAgb2Zmc2V0VG9wOiBjdXJyZW50T2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnQ6IGN1cnJlbnRPZmZzZXRMZWZ0XG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuXG4gICAgICAgIGlmICh3aWR0aCA9PT0gY3VycmVudFdpZHRoICYmIGhlaWdodCA9PT0gY3VycmVudEhlaWdodCAmJiBvZmZzZXRMZWZ0ID09PSBjdXJyZW50T2Zmc2V0TGVmdCAmJiBvZmZzZXRUb3AgPT09IGN1cnJlbnRPZmZzZXRUb3ApIHtcbiAgICAgICAgICBpZiAoY2IpIHtcbiAgICAgICAgICAgIGNiKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgIG9mZnNldExlZnQsXG4gICAgICAgICAgb2Zmc2V0VG9wXG4gICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICBjYiAmJiBjYigpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5yZWZyZXNoID0gKCkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKHt9LCB0aGlzLmdldENhbnZhc09mZnNldHMoKSkpO1xuICAgIH07XG5cbiAgICBjb25zdCBkZWZhdWx0QXBwU3RhdGUgPSBnZXREZWZhdWx0QXBwU3RhdGUoKTtcbiAgICBjb25zdCB7XG4gICAgICBleGNhbGlkcmF3UmVmLFxuICAgICAgdmlld01vZGVFbmFibGVkID0gZmFsc2UsXG4gICAgICB6ZW5Nb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgZ3JpZE1vZGVFbmFibGVkID0gZmFsc2UsXG4gICAgICB0aGVtZSA9IGRlZmF1bHRBcHBTdGF0ZS50aGVtZSxcbiAgICAgIG5hbWUgPSBkZWZhdWx0QXBwU3RhdGUubmFtZVxuICAgIH0gPSBwcm9wcztcbiAgICB0aGlzLnN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZGVmYXVsdEFwcFN0YXRlKSwge1xuICAgICAgdGhlbWUsXG4gICAgICBpc0xvYWRpbmc6IHRydWVcbiAgICB9KSwgdGhpcy5nZXRDYW52YXNPZmZzZXRzKCkpLCB7XG4gICAgICB2aWV3TW9kZUVuYWJsZWQsXG4gICAgICB6ZW5Nb2RlRW5hYmxlZCxcbiAgICAgIGdyaWRTaXplOiBncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsLFxuICAgICAgbmFtZSxcbiAgICAgIHdpZHRoOiB3aW5kb3cuaW5uZXJXaWR0aCxcbiAgICAgIGhlaWdodDogd2luZG93LmlubmVySGVpZ2h0XG4gICAgfSk7XG4gICAgdGhpcy5pZCA9IG5hbm9pZCgpO1xuICAgIHRoaXMubGlicmFyeSA9IG5ldyBMaWJyYXJ5KHRoaXMpO1xuICAgIHRoaXMuc2NlbmUgPSBuZXcgU2NlbmUoKTtcbiAgICB0aGlzLmNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgdGhpcy5yYyA9IHJvdWdoLmNhbnZhcyh0aGlzLmNhbnZhcyk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcblxuICAgIGlmIChleGNhbGlkcmF3UmVmKSB7XG4gICAgICBjb25zdCByZWFkeVByb21pc2UgPSBcImN1cnJlbnRcIiBpbiBleGNhbGlkcmF3UmVmICYmICgoX2EgPSBleGNhbGlkcmF3UmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZWFkeVByb21pc2UpIHx8IHJlc29sdmFibGVQcm9taXNlKCk7XG4gICAgICBjb25zdCBhcGkgPSB7XG4gICAgICAgIHJlYWR5OiB0cnVlLFxuICAgICAgICByZWFkeVByb21pc2UsXG4gICAgICAgIHVwZGF0ZVNjZW5lOiB0aGlzLnVwZGF0ZVNjZW5lLFxuICAgICAgICB1cGRhdGVMaWJyYXJ5OiB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSxcbiAgICAgICAgYWRkRmlsZXM6IHRoaXMuYWRkRmlsZXMsXG4gICAgICAgIHJlc2V0U2NlbmU6IHRoaXMucmVzZXRTY2VuZSxcbiAgICAgICAgZ2V0U2NlbmVFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQ6IHRoaXMuZ2V0U2NlbmVFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQsXG4gICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICBjbGVhcjogdGhpcy5yZXNldEhpc3RvcnlcbiAgICAgICAgfSxcbiAgICAgICAgc2Nyb2xsVG9Db250ZW50OiB0aGlzLnNjcm9sbFRvQ29udGVudCxcbiAgICAgICAgZ2V0U2NlbmVFbGVtZW50czogdGhpcy5nZXRTY2VuZUVsZW1lbnRzLFxuICAgICAgICBnZXRBcHBTdGF0ZTogKCkgPT4gdGhpcy5zdGF0ZSxcbiAgICAgICAgZ2V0RmlsZXM6ICgpID0+IHRoaXMuZmlsZXMsXG4gICAgICAgIHJlZnJlc2g6IHRoaXMucmVmcmVzaCxcbiAgICAgICAgc2V0VG9hc3Q6IHRoaXMuc2V0VG9hc3QsXG4gICAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgICBzZXRBY3RpdmVUb29sOiB0aGlzLnNldEFjdGl2ZVRvb2wsXG4gICAgICAgIHNldEN1cnNvcjogdGhpcy5zZXRDdXJzb3IsXG4gICAgICAgIHJlc2V0Q3Vyc29yOiB0aGlzLnJlc2V0Q3Vyc29yLFxuICAgICAgICB1cGRhdGVGcmFtZVJlbmRlcmluZzogdGhpcy51cGRhdGVGcmFtZVJlbmRlcmluZyxcbiAgICAgICAgdG9nZ2xlU2lkZWJhcjogdGhpcy50b2dnbGVTaWRlYmFyXG4gICAgICB9O1xuXG4gICAgICBpZiAodHlwZW9mIGV4Y2FsaWRyYXdSZWYgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBleGNhbGlkcmF3UmVmKGFwaSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBleGNhbGlkcmF3UmVmLmN1cnJlbnQgPSBhcGk7XG4gICAgICB9XG5cbiAgICAgIHJlYWR5UHJvbWlzZS5yZXNvbHZlKGFwaSk7XG4gICAgfVxuXG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWUgPSB7XG4gICAgICBjb250YWluZXI6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LFxuICAgICAgaWQ6IHRoaXMuaWRcbiAgICB9O1xuICAgIHRoaXMuZm9udHMgPSBuZXcgRm9udHMoe1xuICAgICAgc2NlbmU6IHRoaXMuc2NlbmUsXG4gICAgICBvblNjZW5lVXBkYXRlZDogdGhpcy5vblNjZW5lVXBkYXRlZFxuICAgIH0pO1xuICAgIHRoaXMuaGlzdG9yeSA9IG5ldyBIaXN0b3J5KCk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyID0gbmV3IEFjdGlvbk1hbmFnZXIodGhpcy5zeW5jQWN0aW9uUmVzdWx0LCAoKSA9PiB0aGlzLnN0YXRlLCAoKSA9PiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBbGwoYWN0aW9ucyk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVVuZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVJlZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gIH1cblxuICBvbldpbmRvd01lc3NhZ2UoZXZlbnQpIHtcbiAgICBpZiAoZXZlbnQub3JpZ2luICE9PSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiICYmIGV2ZW50Lm9yaWdpbiAhPT0gXCJodHRwczovL3d3dy55b3V0dWJlLmNvbVwiKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IGRhdGEgPSBudWxsO1xuXG4gICAgdHJ5IHtcbiAgICAgIGRhdGEgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG5cbiAgICBpZiAoIWRhdGEpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKGV2ZW50Lm9yaWdpbikge1xuICAgICAgY2FzZSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiOlxuICAgICAgICAvL0FsbG93aW5nIGZvciBtdWx0aXBsZSBpbnN0YW5jZXMgb2YgRXhjYWxpZHJhdyBydW5uaW5nIGluIHRoZSB3aW5kb3dcbiAgICAgICAgaWYgKGRhdGEubWV0aG9kID09PSBcInBhdXNlZFwiKSB7XG4gICAgICAgICAgbGV0IHNvdXJjZSA9IG51bGw7XG4gICAgICAgICAgY29uc3QgaWZyYW1lcyA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvckFsbChcImlmcmFtZS5leGNhbGlkcmF3X19lbWJlZGRhYmxlXCIpO1xuXG4gICAgICAgICAgaWYgKCFpZnJhbWVzKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBmb3IgKGNvbnN0IGlmcmFtZSBvZiBpZnJhbWVzKSB7XG4gICAgICAgICAgICBpZiAoaWZyYW1lLmNvbnRlbnRXaW5kb3cgPT09IGV2ZW50LnNvdXJjZSkge1xuICAgICAgICAgICAgICBzb3VyY2UgPSBpZnJhbWUuY29udGVudFdpbmRvdztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzb3VyY2UgPT09IG51bGwgfHwgc291cmNlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBzb3VyY2UucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgbWV0aG9kOiBkYXRhLnZhbHVlID8gXCJwbGF5XCIgOiBcInBhdXNlXCIsXG4gICAgICAgICAgICB2YWx1ZTogdHJ1ZVxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBcImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tXCI6XG4gICAgICAgIGlmIChkYXRhLmV2ZW50ID09PSBcImluZm9EZWxpdmVyeVwiICYmIGRhdGEuaW5mbyAmJiBkYXRhLmlkICYmIHR5cGVvZiBkYXRhLmluZm8ucGxheWVyU3RhdGUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICBjb25zdCBpZCA9IGRhdGEuaWQ7XG4gICAgICAgICAgY29uc3QgcGxheWVyU3RhdGUgPSBkYXRhLmluZm8ucGxheWVyU3RhdGU7XG5cbiAgICAgICAgICBpZiAoT2JqZWN0LnZhbHVlcyhZT1VUVUJFX1NUQVRFUykuaW5jbHVkZXMocGxheWVyU3RhdGUpKSB7XG4gICAgICAgICAgICBZT1VUVUJFX1ZJREVPX1NUQVRFUy5zZXQoaWQsIHBsYXllclN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICB1cGRhdGVFbWJlZGRhYmxlUmVmKGlkLCByZWYpIHtcbiAgICBpZiAocmVmKSB7XG4gICAgICB0aGlzLmlGcmFtZVJlZnMuc2V0KGlkLCByZWYpO1xuICAgIH1cbiAgfVxuXG4gIGdldEhUTUxJRnJhbWVFbGVtZW50KGlkKSB7XG4gICAgcmV0dXJuIHRoaXMuaUZyYW1lUmVmcy5nZXQoaWQpO1xuICB9XG5cbiAgaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKGVsZW1lbnQpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG5cbiAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpID09PSBlbGVtZW50ICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiYWN0aXZlXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9IC8vIFRoZSBkZWxheSBzZXJ2ZXMgdHdvIHB1cnBvc2VzXG4gICAgLy8gMS4gVG8gcHJldmVudCBmaXJzdCBjbGljayBwcm9wYWdhdGluZyB0byBpZnJhbWUgb24gbW9iaWxlLFxuICAgIC8vICAgIGVsc2UgdGhlIGNsaWNrIHdpbGwgaW1tZWRpYXRlbHkgc3RhcnQgYW5kIHN0b3AgdGhlIHZpZGVvXG4gICAgLy8gMi4gSWYgdGhlIHVzZXIgZG91YmxlIGNsaWNrcyB0aGUgZnJhbWUgY2VudGVyIHRvIGFjdGl2YXRlIGl0XG4gICAgLy8gICAgd2l0aG91dCB0aGUgZGVsYXkgeW91dHViZSB3aWxsIGltbWVkaWF0ZWx5IG9wZW4gdGhlIHZpZGVvXG4gICAgLy8gICAgaW4gZnVsbHNjcmVlbiBtb2RlXG5cblxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IHtcbiAgICAgICAgICBlbGVtZW50LFxuICAgICAgICAgIHN0YXRlOiBcImFjdGl2ZVwiXG4gICAgICAgIH0sXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgIFtlbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGlvbkVsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH0sIDEwMCk7XG4gICAgY29uc3QgaWZyYW1lID0gdGhpcy5nZXRIVE1MSUZyYW1lRWxlbWVudChlbGVtZW50LmlkKTtcblxuICAgIGlmICghKGlmcmFtZSA9PT0gbnVsbCB8fCBpZnJhbWUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGlmcmFtZS5jb250ZW50V2luZG93KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpZnJhbWUuc3JjLmluY2x1ZGVzKFwieW91dHViZVwiKSkge1xuICAgICAgY29uc3Qgc3RhdGUgPSBZT1VUVUJFX1ZJREVPX1NUQVRFUy5nZXQoZWxlbWVudC5pZCk7XG5cbiAgICAgIGlmICghc3RhdGUpIHtcbiAgICAgICAgWU9VVFVCRV9WSURFT19TVEFURVMuc2V0KGVsZW1lbnQuaWQsIFlPVVRVQkVfU1RBVEVTLlVOU1RBUlRFRCk7XG4gICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBldmVudDogXCJsaXN0ZW5pbmdcIixcbiAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgfVxuXG4gICAgICBzd2l0Y2ggKHN0YXRlKSB7XG4gICAgICAgIGNhc2UgWU9VVFVCRV9TVEFURVMuUExBWUlORzpcbiAgICAgICAgY2FzZSBZT1VUVUJFX1NUQVRFUy5CVUZGRVJJTkc6XG4gICAgICAgICAgKF9jID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBhdXNlVmlkZW9cIixcbiAgICAgICAgICAgIGFyZ3M6IFwiXCJcbiAgICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgKF9kID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBsYXlWaWRlb1wiLFxuICAgICAgICAgICAgYXJnczogXCJcIlxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGlmcmFtZS5zcmMuaW5jbHVkZXMoXCJwbGF5ZXIudmltZW8uY29tXCIpKSB7XG4gICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIG1ldGhvZDogXCJwYXVzZWRcIiAvL3ZpZGVvIHBsYXkvcGF1c2UgaW4gb25XaW5kb3dNZXNzYWdlIGhhbmRsZXJcblxuICAgICAgfSksIFwiKlwiKTtcbiAgICB9XG4gIH1cblxuICBpc0VtYmVkZGFibGVDZW50ZXIoZWwsIGV2ZW50LCBzY2VuZVgsIHNjZW5lWSkge1xuICAgIHZhciBfYSwgX2I7XG5cbiAgICByZXR1cm4gZWwgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQuc2hpZnRLZXkgJiYgIWV2ZW50Lm1ldGFLZXkgJiYgIWV2ZW50LmN0cmxLZXkgJiYgKCgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSAhPT0gZWwgfHwgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJob3ZlclwiIHx8ICF0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpICYmIHNjZW5lWCA+PSBlbC54ICsgZWwud2lkdGggLyAzICYmIHNjZW5lWCA8PSBlbC54ICsgMiAqIGVsLndpZHRoIC8gMyAmJiBzY2VuZVkgPj0gZWwueSArIGVsLmhlaWdodCAvIDMgJiYgc2NlbmVZIDw9IGVsLnkgKyAyICogZWwuaGVpZ2h0IC8gMztcbiAgfVxuXG4gIHJlbmRlckVtYmVkZGFibGVzKCkge1xuICAgIGNvbnN0IHNjYWxlID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRXaWR0aCA9IHRoaXMuc3RhdGUud2lkdGg7XG4gICAgY29uc3Qgbm9ybWFsaXplZEhlaWdodCA9IHRoaXMuc3RhdGUuaGVpZ2h0O1xuICAgIGNvbnN0IGVtYmVkZGFibGVFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsID0+IGlzRW1iZWRkYWJsZUVsZW1lbnQoZWwpICYmICEhZWwudmFsaWRhdGVkKTtcbiAgICByZXR1cm4gX2pzeChfRnJhZ21lbnQsIHtcbiAgICAgIGNoaWxkcmVuOiBlbWJlZGRhYmxlRWxlbWVudHMubWFwKGVsID0+IHtcbiAgICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaDtcblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogZWwueCxcbiAgICAgICAgICBzY2VuZVk6IGVsLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGVtYmVkTGluayA9IGdldEVtYmVkTGluayh0b1ZhbGlkVVJMKGVsLmxpbmsgfHwgXCJcIikpO1xuICAgICAgICBjb25zdCBpc1Zpc2libGUgPSBpc0VsZW1lbnRJblZpZXdwb3J0KGVsLCBub3JtYWxpemVkV2lkdGgsIG5vcm1hbGl6ZWRIZWlnaHQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBpc0FjdGl2ZSA9ICgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSA9PT0gZWwgJiYgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJhY3RpdmVcIjtcbiAgICAgICAgY29uc3QgaXNIb3ZlcmVkID0gKChfYyA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmVsZW1lbnQpID09PSBlbCAmJiAoKF9kID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Quc3RhdGUpID09PSBcImhvdmVyXCI7XG4gICAgICAgIHJldHVybiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgIGNsYXNzTmFtZTogY2xzeChcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtY29udGFpbmVyXCIsIHtcbiAgICAgICAgICAgIFwiaXMtaG92ZXJlZFwiOiBpc0hvdmVyZWRcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgdHJhbnNmb3JtOiBpc1Zpc2libGUgPyBgdHJhbnNsYXRlKCR7eCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdH1weCwgJHt5IC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3B9cHgpIHNjYWxlKCR7c2NhbGV9KWAgOiBcIm5vbmVcIixcbiAgICAgICAgICAgIGRpc3BsYXk6IGlzVmlzaWJsZSA/IFwiYmxvY2tcIiA6IFwibm9uZVwiLFxuICAgICAgICAgICAgb3BhY2l0eTogZWwub3BhY2l0eSAvIDEwMCxcbiAgICAgICAgICAgIFtcIi0tZW1iZWRkYWJsZS1yYWRpdXNcIl06IGAke2dldENvcm5lclJhZGl1cyhNYXRoLm1pbihlbC53aWR0aCwgZWwuaGVpZ2h0KSwgZWwpfXB4YFxuICAgICAgICAgIH1cbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBfanN4cyhcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgIC8vdGhpcyBpcyBhIGhhY2sgdGhhdCBhZGRyZXNzZXMgaXNzZSB3aXRoIGVtYmVkZGVkIGV4Y2FsaWRyYXcuY29tIGVtYmVkZGFibGVcbiAgICAgICAgICAgIC8vaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzY2OTEjaXNzdWVjb21tZW50LTE2MDczODM5MzhcblxuICAgICAgICAgICAgLypyZWY9eyhyZWYpID0+IHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgICAgICAgICAgY29uc3Qgc2ggPSBjb250YWluZXIuc2Nyb2xsSGVpZ2h0O1xuICAgICAgICAgICAgICBjb25zdCBjaCA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQ7XG4gICAgICAgICAgICAgIGlmIChzaCAhPT0gY2gpIHtcbiAgICAgICAgICAgICAgICBjb250YWluZXIuc3R5bGUuaGVpZ2h0ID0gYCR7c2h9cHhgO1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgY29udGFpbmVyLnN0eWxlLmhlaWdodCA9IGAxMDAlYDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfX0qL1xuICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtY29udGFpbmVyX19pbm5lclwiLFxuICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgd2lkdGg6IGlzVmlzaWJsZSA/IGAke2VsLndpZHRofXB4YCA6IDAsXG4gICAgICAgICAgICAgIGhlaWdodDogaXNWaXNpYmxlID8gYCR7ZWwuaGVpZ2h0fXB4YCA6IDAsXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogaXNWaXNpYmxlID8gYHJvdGF0ZSgke2VsLmFuZ2xlfXJhZClgIDogXCJub25lXCIsXG4gICAgICAgICAgICAgIHBvaW50ZXJFdmVudHM6IGlzQWN0aXZlID8gUE9JTlRFUl9FVkVOVFMuZW5hYmxlZCA6IFBPSU5URVJfRVZFTlRTLmRpc2FibGVkXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgY2hpbGRyZW46IFtpc0hvdmVyZWQgJiYgX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtaGludFwiXG4gICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgIGNoaWxkcmVuOiB0KFwiYnV0dG9ucy5lbWJlZGRhYmxlSW50ZXJhY3Rpb25CdXR0b25cIilcbiAgICAgICAgICAgIH0pKSwgX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGVfX291dGVyXCIsXG4gICAgICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgcGFkZGluZzogYCR7ZWwuc3Ryb2tlV2lkdGh9cHhgXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IChfZyA9IChfZiA9IChfZSA9IHRoaXMucHJvcHMpLnJlbmRlckVtYmVkZGFibGUpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5jYWxsKF9lLCBlbCwgdGhpcy5zdGF0ZSkpICE9PSBudWxsICYmIF9nICE9PSB2b2lkIDAgPyBfZyA6IF9qc3goXCJpZnJhbWVcIiwge1xuICAgICAgICAgICAgICAgIHJlZjogcmVmID0+IHRoaXMudXBkYXRlRW1iZWRkYWJsZVJlZihlbC5pZCwgcmVmKSxcbiAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZVwiLFxuICAgICAgICAgICAgICAgIHNyY0RvYzogKGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay50eXBlKSA9PT0gXCJkb2N1bWVudFwiID8gZW1iZWRMaW5rLnNyY2RvYyh0aGlzLnN0YXRlLnRoZW1lKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBzcmM6IChlbWJlZExpbmsgPT09IG51bGwgfHwgZW1iZWRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbWJlZExpbmsudHlwZSkgIT09IFwiZG9jdW1lbnRcIiA/IChfaCA9IGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay5saW5rKSAhPT0gbnVsbCAmJiBfaCAhPT0gdm9pZCAwID8gX2ggOiBcIlwiIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcS8xODQ3MDAxNVxuICAgICAgICAgICAgICAgIHNjcm9sbGluZzogXCJub1wiLFxuICAgICAgICAgICAgICAgIHJlZmVycmVyUG9saWN5OiBcIm5vLXJlZmVycmVyLXdoZW4tZG93bmdyYWRlXCIsXG4gICAgICAgICAgICAgICAgdGl0bGU6IFwiRXhjYWxpZHJhdyBFbWJlZGRlZCBDb250ZW50XCIsXG4gICAgICAgICAgICAgICAgYWxsb3c6IFwiYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZVwiLFxuICAgICAgICAgICAgICAgIGFsbG93RnVsbFNjcmVlbjogdHJ1ZSxcbiAgICAgICAgICAgICAgICBzYW5kYm94OiBcImFsbG93LXNhbWUtb3JpZ2luIGFsbG93LXNjcmlwdHMgYWxsb3ctZm9ybXMgYWxsb3ctcG9wdXBzIGFsbG93LXBvcHVwcy10by1lc2NhcGUtc2FuZGJveCBhbGxvdy1wcmVzZW50YXRpb24gYWxsb3ctZG93bmxvYWRzXCJcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pKV1cbiAgICAgICAgICB9KSlcbiAgICAgICAgfSksIGVsLmlkKTtcbiAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICByZW5kZXIoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2M7XG5cbiAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHtcbiAgICAgIHJlbmRlclRvcFJpZ2h0VUksXG4gICAgICByZW5kZXJDdXN0b21TdGF0c1xuICAgIH0gPSB0aGlzLnByb3BzO1xuICAgIGNvbnN0IHZlcnNpb25Ob25jZSA9IHRoaXMuc2NlbmUuZ2V0VmVyc2lvbk5vbmNlKCk7XG4gICAgY29uc3Qge1xuICAgICAgY2FudmFzRWxlbWVudHMsXG4gICAgICB2aXNpYmxlRWxlbWVudHNcbiAgICB9ID0gdGhpcy5yZW5kZXJlci5nZXRSZW5kZXJhYmxlRWxlbWVudHMoe1xuICAgICAgdmVyc2lvbk5vbmNlLFxuICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLFxuICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgb2Zmc2V0VG9wOiB0aGlzLnN0YXRlLm9mZnNldFRvcCxcbiAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCxcbiAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgIGhlaWdodDogdGhpcy5zdGF0ZS5oZWlnaHQsXG4gICAgICB3aWR0aDogdGhpcy5zdGF0ZS53aWR0aCxcbiAgICAgIGVkaXRpbmdFbGVtZW50OiB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50LFxuICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiB0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZFxuICAgIH0pO1xuICAgIHJldHVybiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgY2xhc3NOYW1lOiBjbHN4KFwiZXhjYWxpZHJhdyBleGNhbGlkcmF3LWNvbnRhaW5lclwiLCB7XG4gICAgICAgIFwiZXhjYWxpZHJhdy0tdmlldy1tb2RlXCI6IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkLFxuICAgICAgICBcImV4Y2FsaWRyYXctLW1vYmlsZVwiOiB0aGlzLmRldmljZS5pc01vYmlsZVxuICAgICAgfSksXG4gICAgICBzdHlsZToge1xuICAgICAgICBbXCItLXVpLXBvaW50ZXJFdmVudHNcIl06IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCB8fCB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLnJlc2l6aW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICYmICFpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID8gUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5lbmFibGVkXG4gICAgICB9LFxuICAgICAgcmVmOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYsXG4gICAgICBvbkRyb3A6IHRoaXMuaGFuZGxlQXBwT25Ecm9wLFxuICAgICAgdGFiSW5kZXg6IDAsXG4gICAgICBvbktleURvd246IHRoaXMucHJvcHMuaGFuZGxlS2V5Ym9hcmRHbG9iYWxseSA/IHVuZGVmaW5lZCA6IHRoaXMub25LZXlEb3duXG4gICAgfSwge1xuICAgICAgY2hpbGRyZW46IF9qc3goQXBwQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgIHZhbHVlOiB0aGlzXG4gICAgICB9LCB7XG4gICAgICAgIGNoaWxkcmVuOiBfanN4KEFwcFByb3BzQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdmFsdWU6IHRoaXMucHJvcHNcbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJWYWx1ZVxuICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KERldmljZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5kZXZpY2VcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc2V0QXBwU3RhdGVcbiAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc3RhdGVcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICBjaGlsZHJlbjogX2pzeHMoRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpXG4gICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbX2pzeHMoRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5hY3Rpb25NYW5hZ2VyXG4gICAgICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW19qc3goTGF5ZXJVSSwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmVDYW52YXM6IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVzOiB0aGlzLmZpbGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0QXBwU3RhdGU6IHRoaXMuc2V0QXBwU3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25NYW5hZ2VyOiB0aGlzLmFjdGlvbk1hbmFnZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uTG9ja1RvZ2dsZTogdGhpcy50b2dnbGVMb2NrLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25QZW5Nb2RlVG9nZ2xlOiB0aGlzLnRvZ2dsZVBlbk1vZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkhhbmRUb29sVG9nZ2xlOiB0aGlzLm9uSGFuZFRvb2xUb2dnbGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBsYW5nQ29kZTogZ2V0TGFuZ3VhZ2UoKS5jb2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyVG9wUmlnaHRVSTogcmVuZGVyVG9wUmlnaHRVSSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlckN1c3RvbVN0YXRzOiByZW5kZXJDdXN0b21TdGF0cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dFeGl0WmVuTW9kZUJ0bjogdHlwZW9mICgoX2EgPSB0aGlzLnByb3BzKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuemVuTW9kZUVuYWJsZWQpID09PSBcInVuZGVmaW5lZFwiICYmIHRoaXMuc3RhdGUuemVuTW9kZUVuYWJsZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBVSU9wdGlvbnM6IHRoaXMucHJvcHMuVUlPcHRpb25zLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25JbWFnZUFjdGlvbjogdGhpcy5vbkltYWdlQWN0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25FeHBvcnRJbWFnZTogdGhpcy5vbkV4cG9ydEltYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyV2VsY29tZVNjcmVlbjogIXRoaXMuc3RhdGUuaXNMb2FkaW5nICYmIHRoaXMuc3RhdGUuc2hvd1dlbGNvbWVTY3JlZW4gJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgIXRoaXMuc3RhdGUuemVuTW9kZUVuYWJsZWQgJiYgIXRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubGVuZ3RoLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwOiB0aGlzXG4gICAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IHRoaXMucHJvcHMuY2hpbGRyZW5cbiAgICAgICAgICAgICAgICAgICAgICB9KSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctdGV4dEVkaXRvckNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctY29udGV4dE1lbnVDb250YWluZXJcIlxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KFwiZGl2XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3LWV5ZS1kcm9wcGVyLWNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICF0aGlzLnN0YXRlLmNvbnRleHRNZW51ICYmIHRoaXMuc3RhdGUuc2hvd0h5cGVybGlua1BvcHVwICYmIF9qc3goSHlwZXJsaW5rLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50OiBzZWxlY3RlZEVsZW1lbnRzWzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0QXBwU3RhdGU6IHRoaXMuc2V0QXBwU3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkxpbmtPcGVuOiB0aGlzLnByb3BzLm9uTGlua09wZW4sXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRUb2FzdDogdGhpcy5zZXRUb2FzdFxuICAgICAgICAgICAgICAgICAgICAgIH0sIHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpLCB0aGlzLnN0YXRlLnRvYXN0ICE9PSBudWxsICYmIF9qc3goVG9hc3QsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IHRoaXMuc3RhdGUudG9hc3QubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xvc2U6ICgpID0+IHRoaXMuc2V0VG9hc3QobnVsbCksXG4gICAgICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogdGhpcy5zdGF0ZS50b2FzdC5kdXJhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsb3NhYmxlOiB0aGlzLnN0YXRlLnRvYXN0LmNsb3NhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHRoaXMuc3RhdGUuY29udGV4dE1lbnUgJiYgX2pzeChDb250ZXh0TWVudSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbXM6IHRoaXMuc3RhdGUuY29udGV4dE1lbnUuaXRlbXMsXG4gICAgICAgICAgICAgICAgICAgICAgICB0b3A6IHRoaXMuc3RhdGUuY29udGV4dE1lbnUudG9wLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGVmdDogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS5sZWZ0LFxuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uTWFuYWdlcjogdGhpcy5hY3Rpb25NYW5hZ2VyXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goU3RhdGljQ2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmM6IHRoaXMucmMsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogY2FudmFzRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB2aXNpYmxlRWxlbWVudHM6IHZpc2libGVFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb25Ob25jZTogdmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uTm9uY2U6IChfYiA9IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyQ29uZmlnOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlQ2FjaGU6IHRoaXMuaW1hZ2VDYWNoZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaXNFeHBvcnRpbmc6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJHcmlkOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goSW50ZXJhY3RpdmVDYW52YXMsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lclJlZjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmludGVyYWN0aXZlQ2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IGNhbnZhc0VsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZUVsZW1lbnRzOiB2aXNpYmxlRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzOiBzZWxlY3RlZEVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmVyc2lvbk5vbmNlOiB2ZXJzaW9uTm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25Ob25jZTogKF9jID0gdGhpcy5zdGF0ZS5zZWxlY3Rpb25FbGVtZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MudmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGU6IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJJbnRlcmFjdGl2ZVNjZW5lQ2FsbGJhY2s6IHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlQ2FudmFzUmVmOiB0aGlzLmhhbmRsZUludGVyYWN0aXZlQ2FudmFzUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Db250ZXh0TWVudTogdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlck1vdmU6IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJVcDogdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJDYW5jZWw6IHRoaXMucmVtb3ZlUG9pbnRlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uVG91Y2hNb3ZlOiB0aGlzLmhhbmRsZVRvdWNoTW92ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlckRvd246IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24sXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkRvdWJsZUNsaWNrOiB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHRoaXMucmVuZGVyRnJhbWVOYW1lcygpXVxuICAgICAgICAgICAgICAgICAgICB9KSksIHRoaXMucmVuZGVyRW1iZWRkYWJsZXMoKV1cbiAgICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgIH0pKVxuICAgICAgICB9KSlcbiAgICAgIH0pKVxuICAgIH0pKTtcbiAgfVxuXG4gIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgIHZhciBfYSwgX2I7XG5cbiAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlLmNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IEVOVi5URVNUIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICAgICAgICBjb25zdCBzZXRTdGF0ZSA9IHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMod2luZG93LmgsIHtcbiAgICAgICAgICBzdGF0ZToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZ2V0OiAoKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2V0U3RhdGU6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiAoLi4uYXJncykgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSguLi5hcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIGFwcDoge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHRoaXNcbiAgICAgICAgICB9LFxuICAgICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmhpc3RvcnlcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNjZW5lLmFkZENhbGxiYWNrKHRoaXMub25TY2VuZVVwZGF0ZWQpO1xuICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVycygpO1xuXG4gICAgICBpZiAodGhpcy5wcm9wcy5hdXRvRm9jdXMgJiYgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQgJiYgLy8gYm91bmRpbmcgcmVjdHMgZG9uJ3Qgd29yayBpbiB0ZXN0cyBzbyB1cGRhdGluZ1xuICAgICAgLy8gdGhlIHN0YXRlIG9uIGluaXQgd291bGQgcmVzdWx0IGluIG1ha2luZyB0aGUgdGVzdCBlbnZpcm8gcnVuXG4gICAgICAvLyBpbiBtb2JpbGUgYnJlYWtwb2ludCAoMCB3aWR0aC9oZWlnaHQpLCBtYWtpbmcgZXZlcnl0aGluZyBmYWlsXG4gICAgICAhaXNUZXN0RW52KCkpIHtcbiAgICAgICAgdGhpcy5yZWZyZXNoRGV2aWNlU3RhdGUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAoXCJSZXNpemVPYnNlcnZlclwiIGluIHdpbmRvdyAmJiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkpIHtcbiAgICAgICAgdGhpcy5yZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcigoKSA9PiB7XG4gICAgICAgICAgLy8gcmVjb21wdXRlIGRldmljZSBkaW1lbnNpb25zIHN0YXRlXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgICAgdGhpcy5yZWZyZXNoRGV2aWNlU3RhdGUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpOyAvLyByZWZyZXNoIG9mZnNldHNcbiAgICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAgICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgKF9iID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLm9ic2VydmUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgfSBlbHNlIGlmICh3aW5kb3cubWF0Y2hNZWRpYSkge1xuICAgICAgICBjb25zdCBtZFNjcmVlblF1ZXJ5ID0gd2luZG93Lm1hdGNoTWVkaWEoYChtYXgtd2lkdGg6ICR7TVFfTUFYX1dJRFRIX1BPUlRSQUlUfXB4KSwgKG1heC1oZWlnaHQ6ICR7TVFfTUFYX0hFSUdIVF9MQU5EU0NBUEV9cHgpIGFuZCAobWF4LXdpZHRoOiAke01RX01BWF9XSURUSF9MQU5EU0NBUEV9cHgpYCk7XG4gICAgICAgIGNvbnN0IHNtU2NyZWVuUXVlcnkgPSB3aW5kb3cubWF0Y2hNZWRpYShgKG1heC13aWR0aDogJHtNUV9TTV9NQVhfV0lEVEh9cHgpYCk7XG4gICAgICAgIGNvbnN0IGNhbkRldmljZUZpdFNpZGViYXJNZWRpYVF1ZXJ5ID0gd2luZG93Lm1hdGNoTWVkaWEoYChtaW4td2lkdGg6ICR7Ly8gTk9URSB0aGlzIHdvbid0IHVwZGF0ZSBpZiBhIGRpZmZlcmVudCBicmVha3BvaW50IGlzIHN1cHBsaWVkXG4gICAgICAgIC8vIGFmdGVyIG1vdW50XG4gICAgICAgIHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50ICE9IG51bGwgPyB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCA6IE1RX1JJR0hUX1NJREVCQVJfTUlOX1dJRFRIfXB4KWApO1xuXG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgdGhpcy5kZXZpY2UgPSB1cGRhdGVPYmplY3QodGhpcy5kZXZpY2UsIHtcbiAgICAgICAgICAgIGlzU21TY3JlZW46IHNtU2NyZWVuUXVlcnkubWF0Y2hlcyxcbiAgICAgICAgICAgIGlzTW9iaWxlOiBtZFNjcmVlblF1ZXJ5Lm1hdGNoZXMsXG4gICAgICAgICAgICBjYW5EZXZpY2VGaXRTaWRlYmFyOiBjYW5EZXZpY2VGaXRTaWRlYmFyTWVkaWFRdWVyeS5tYXRjaGVzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbWRTY3JlZW5RdWVyeS5hZGRMaXN0ZW5lcihoYW5kbGVyKTtcblxuICAgICAgICB0aGlzLmRldGFjaElzTW9iaWxlTXFIYW5kbGVyID0gKCkgPT4gbWRTY3JlZW5RdWVyeS5yZW1vdmVMaXN0ZW5lcihoYW5kbGVyKTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VhcmNoUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoLnNsaWNlKDEpKTtcblxuICAgICAgaWYgKHNlYXJjaFBhcmFtcy5oYXMoXCJ3ZWItc2hhcmUtdGFyZ2V0XCIpKSB7XG4gICAgICAgIC8vIE9idGFpbiBhIGZpbGUgdGhhdCB3YXMgc2hhcmVkIHZpYSB0aGUgV2ViIFNoYXJlIFRhcmdldCBBUEkuXG4gICAgICAgIHRoaXMucmVzdG9yZUZpbGVGcm9tU2hhcmUoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCh0aGlzLmluaXRpYWxpemVTY2VuZSk7XG4gICAgICB9IC8vIG5vdGUgdGhhdCB0aGlzIGNoZWNrIHNlZW1zIHRvIGFsd2F5cyBwYXNzIGluIGxvY2FsaG9zdFxuXG5cbiAgICAgIGlmIChpc0JyYXZlKCkgJiYgIWlzTWVhc3VyZVRleHRTdXBwb3J0ZWQoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IF9qc3goQnJhdmVNZWFzdXJlVGV4dEVycm9yLCB7fSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICB2YXIgX2E7XG5cbiAgICB0aGlzLnJlbmRlcmVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLnNjZW5lID0gbmV3IFNjZW5lKCk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcbiAgICB0aGlzLmZpbGVzID0ge307XG4gICAgdGhpcy5pbWFnZUNhY2hlLmNsZWFyKCk7XG4gICAgKF9hID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmRpc2Nvbm5lY3QoKTtcbiAgICB0aGlzLnVubW91bnRlZCA9IHRydWU7XG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHRoaXMuc2NlbmUuZGVzdHJveSgpO1xuICAgIHRoaXMubGlicmFyeS5kZXN0cm95KCk7XG4gICAgU2hhcGVDYWNoZS5kZXN0cm95KCk7XG4gICAgY2xlYXJUaW1lb3V0KHRvdWNoVGltZW91dCk7XG4gICAgaXNTb21lRWxlbWVudFNlbGVjdGVkLmNsZWFyQ2FjaGUoKTtcbiAgICBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzLmNsZWFyQ2FjaGUoKTtcbiAgICB0b3VjaFRpbWVvdXQgPSAwO1xuICB9XG5cbiAgcmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZTtcblxuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGhpcy5yZW1vdmVQb2ludGVyKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkNPUFksIHRoaXMub25Db3B5KTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5DVVQsIHRoaXMub25DdXQpO1xuICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5XSEVFTCwgdGhpcy5vbldoZWVsKTtcbiAgICAoX2IgPSB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5TQ1JPTEwsIHRoaXMub25TY3JvbGwpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgdGhpcy5vbktleURvd24sIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1PVVNFX01PVkUsIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfYyA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9kID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX1NUQVJULCB0aGlzLm9uR2VzdHVyZVN0YXJ0LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0NIQU5HRSwgdGhpcy5vbkdlc3R1cmVDaGFuZ2UsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfRU5ELCB0aGlzLm9uR2VzdHVyZUVuZCwgZmFsc2UpO1xuICAgIChfZSA9IHRoaXMuZGV0YWNoSXNNb2JpbGVNcUhhbmRsZXIpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5jYWxsKHRoaXMpO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gIH1cblxuICBhZGRFdmVudExpc3RlbmVycygpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lO1xuXG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0aGlzLnJlbW92ZVBvaW50ZXIpOyAvLyAjMzU1M1xuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5DT1BZLCB0aGlzLm9uQ29weSk7XG4gICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLm9uV2hlZWwsIHtcbiAgICAgIHBhc3NpdmU6IGZhbHNlXG4gICAgfSk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5oYW5kbGVLZXlib2FyZEdsb2JhbGx5KSB7XG4gICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHRoaXMub25LZXlEb3duLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwLCB7XG4gICAgICBwYXNzaXZlOiB0cnVlXG4gICAgfSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5NT1VTRV9NT1ZFLCB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbik7IC8vIHJlcmVuZGVyIHRleHQgZWxlbWVudHMgb24gZm9udCBsb2FkIHRvIGZpeCAjNjM3ICYmICMxNTUzXG5cbiAgICAoX2MgPSAoX2IgPSBkb2N1bWVudC5mb250cykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmFkZEV2ZW50TGlzdGVuZXIpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5jYWxsKF9iLCBcImxvYWRpbmdkb25lXCIsIGV2ZW50ID0+IHtcbiAgICAgIGNvbnN0IGxvYWRlZEZvbnRGYWNlcyA9IGV2ZW50LmZvbnRmYWNlcztcbiAgICAgIHRoaXMuZm9udHMub25Gb250c0xvYWRlZChsb2FkZWRGb250RmFjZXMpO1xuICAgIH0pOyAvLyBTYWZhcmktb25seSBkZXNrdG9wIHBpbmNoIHpvb21cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9TVEFSVCwgdGhpcy5vbkdlc3R1cmVTdGFydCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9DSEFOR0UsIHRoaXMub25HZXN0dXJlQ2hhbmdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0VORCwgdGhpcy5vbkdlc3R1cmVFbmQsIGZhbHNlKTtcblxuICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHRoaXMucGFzdGVGcm9tQ2xpcGJvYXJkKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkNVVCwgdGhpcy5vbkN1dCk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5kZXRlY3RTY3JvbGwpIHtcbiAgICAgIHRoaXMubmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIgPSBnZXROZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lcih0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCk7XG4gICAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuU0NST0xMLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICB9XG5cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfZCA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9lID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gIH1cblxuICBjb21wb25lbnREaWRVcGRhdGUocHJldlByb3BzLCBwcmV2U3RhdGUpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZjtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMoKTtcblxuICAgIGlmICghdGhpcy5zdGF0ZS5zaG93V2VsY29tZVNjcmVlbiAmJiAhdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5sZW5ndGgpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzaG93V2VsY29tZVNjcmVlbjogdHJ1ZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50ICYmIHByZXZQcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT09IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50KSB7XG4gICAgICB0aGlzLnJlZnJlc2hEZXZpY2VTdGF0ZSh0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZTdGF0ZS5zY3JvbGxYICE9PSB0aGlzLnN0YXRlLnNjcm9sbFggfHwgcHJldlN0YXRlLnNjcm9sbFkgIT09IHRoaXMuc3RhdGUuc2Nyb2xsWSkge1xuICAgICAgKF9iID0gKF9hID0gdGhpcy5wcm9wcykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm9uU2Nyb2xsQ2hhbmdlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwgdGhpcy5zdGF0ZS5zY3JvbGxYLCB0aGlzLnN0YXRlLnNjcm9sbFkpO1xuICAgIH1cblxuICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcykubGVuZ3RoICYmIGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICB9KVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImVyYXNlclwiICYmIHByZXZTdGF0ZS50aGVtZSAhPT0gdGhpcy5zdGF0ZS50aGVtZSkge1xuICAgICAgc2V0RXJhc2VyQ3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUudGhlbWUpO1xuICAgIH0gLy8gSGlkZSBoeXBlcmxpbmsgcG9wdXAgaWYgc2hvd24gd2hlbiBlbGVtZW50IHR5cGUgaXMgbm90IHNlbGVjdGlvblxuXG5cbiAgICBpZiAocHJldlN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZmFsc2VcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMubGFuZ0NvZGUgIT09IHRoaXMucHJvcHMubGFuZ0NvZGUpIHtcbiAgICAgIHRoaXMudXBkYXRlTGFuZ3VhZ2UoKTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLnZpZXdNb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB2aWV3TW9kZUVuYWJsZWQ6ICEhdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWRcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2U3RhdGUudmlld01vZGVFbmFibGVkICE9PSB0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVycygpO1xuICAgICAgdGhpcy5kZXNlbGVjdEVsZW1lbnRzKCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy56ZW5Nb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHplbk1vZGVFbmFibGVkOiAhIXRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWRcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMudGhlbWUgIT09IHRoaXMucHJvcHMudGhlbWUgJiYgdGhpcy5wcm9wcy50aGVtZSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHRoZW1lOiB0aGlzLnByb3BzLnRoZW1lXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLmdyaWRNb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBncmlkU2l6ZTogdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5wcm9wcy5uYW1lICYmIHByZXZQcm9wcy5uYW1lICE9PSB0aGlzLnByb3BzLm5hbWUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBuYW1lOiB0aGlzLnByb3BzLm5hbWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIChfYyA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuY2xhc3NMaXN0LnRvZ2dsZShcInRoZW1lLS1kYXJrXCIsIHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiKTtcblxuICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZF0pIHtcbiAgICAgIC8vIGRlZmVyIHNvIHRoYXQgdGhlIGNvbW1pdFRvSGlzdG9yeSBmbGFnIGlzbid0IHJlc2V0IHZpYSBjdXJyZW50IHVwZGF0ZVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIC8vIGV4ZWN1dGUgb25seSBpZiB0aGUgY29uZGl0aW9uIHN0aWxsIGhvbGRzIHdoZW4gdGhlIGRlZmVycmVkIGNhbGxiYWNrXG4gICAgICAgIC8vIGV4ZWN1dGVzIChpdCBjYW4gYmUgc2NoZWR1bGVkIG11bHRpcGxlIHRpbWVzIGRlcGVuZGluZyBvbiBob3dcbiAgICAgICAgLy8gbWFueSB0aW1lcyB0aGUgY29tcG9uZW50IHJlbmRlcnMpXG4gICAgICAgIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgfSk7XG4gICAgfSAvLyBmYWlsc2FmZSBpbiBjYXNlIHRoZSBzdGF0ZSBpcyBiZWluZyB1cGRhdGVkIGluIGluY29ycmVjdCBvcmRlciByZXN1bHRpbmdcbiAgICAvLyBpbiB0aGUgZWRpdGluZ0VsZW1lbnQgYmVpbmcgbm93IGEgZGVsZXRlZCBlbGVtZW50XG5cblxuICAgIGlmICgoX2QgPSB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuaXNEZWxldGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuZWxlbWVudElkXSkge1xuICAgICAgLy8gVG8gbWFrZSBzdXJlIGBzZWxlY3RlZExpbmVhckVsZW1lbnRgIGlzIGluIHN5bmMgd2l0aCBgc2VsZWN0ZWRFbGVtZW50SWRzYCwgaG93ZXZlciB0aGlzIHNob3VsZG4ndCBiZSBuZWVkZWQgb25jZVxuICAgICAgLy8gd2UgaGF2ZSBhIHNpbmdsZSBBUEkgdG8gdXBkYXRlIGBzZWxlY3RlZEVsZW1lbnRJZHNgXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBjb25zdCB7XG4gICAgICBtdWx0aUVsZW1lbnRcbiAgICB9ID0gcHJldlN0YXRlO1xuXG4gICAgaWYgKHByZXZTdGF0ZS5hY3RpdmVUb29sICE9PSB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wgJiYgbXVsdGlFbGVtZW50ICE9IG51bGwgJiYgaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSAmJiBpc0JpbmRpbmdFbGVtZW50KG11bHRpRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICBtYXliZUJpbmRMaW5lYXJFbGVtZW50KG11bHRpRWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZSwgdHVwbGVUb0Nvb3JzKExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0UG9pbnRBdEluZGV4R2xvYmFsQ29vcmRpbmF0ZXMobXVsdGlFbGVtZW50LCAtMSkpKTtcbiAgICB9XG5cbiAgICB0aGlzLmhpc3RvcnkucmVjb3JkKHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkpOyAvLyBEbyBub3Qgbm90aWZ5IGNvbnN1bWVycyBpZiB3ZSdyZSBzdGlsbCBsb2FkaW5nIHRoZSBzY2VuZS4gQW1vbmcgb3RoZXJcbiAgICAvLyBwb3RlbnRpYWwgaXNzdWVzLCB0aGlzIGZpeGVzIGEgY2FzZSB3aGVyZSB0aGUgdGFiIGlzbid0IGZvY3VzZWQgZHVyaW5nXG4gICAgLy8gaW5pdCwgd2hpY2ggd291bGQgdHJpZ2dlciBvbkNoYW5nZSB3aXRoIGVtcHR5IGVsZW1lbnRzLCB3aGljaCB3b3VsZCB0aGVuXG4gICAgLy8gb3ZlcnJpZGUgd2hhdGV2ZXIgaXMgaW4gbG9jYWxTdG9yYWdlIGN1cnJlbnRseS5cblxuICAgIGlmICghdGhpcy5zdGF0ZS5pc0xvYWRpbmcpIHtcbiAgICAgIChfZiA9IChfZSA9IHRoaXMucHJvcHMpLm9uQ2hhbmdlKSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuY2FsbChfZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcyk7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIHJlc2V0VGFwVHdpY2UoKSB7XG4gICAgZGlkVGFwVHdpY2UgPSBmYWxzZTtcbiAgfVxuXG4gIGFkZFRleHRGcm9tUGFzdGUodGV4dCwgaXNQbGFpblBhc3RlID0gZmFsc2UpIHtcbiAgICBjb25zdCB7XG4gICAgICB4LFxuICAgICAgeVxuICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgY2xpZW50WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgY2xpZW50WTogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55XG4gICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgY29uc3QgdGV4dEVsZW1lbnRQcm9wcyA9IHtcbiAgICAgIHgsXG4gICAgICB5LFxuICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICB0ZXh0LFxuICAgICAgZm9udFNpemU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250U2l6ZSxcbiAgICAgIGZvbnRGYW1pbHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250RmFtaWx5LFxuICAgICAgdGV4dEFsaWduOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtVGV4dEFsaWduLFxuICAgICAgdmVydGljYWxBbGlnbjogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgIGxvY2tlZDogZmFsc2VcbiAgICB9O1xuICAgIGNvbnN0IExJTkVfR0FQID0gMTA7XG4gICAgbGV0IGN1cnJlbnRZID0geTtcbiAgICBjb25zdCBsaW5lcyA9IGlzUGxhaW5QYXN0ZSA/IFt0ZXh0XSA6IHRleHQuc3BsaXQoXCJcXG5cIik7XG4gICAgY29uc3QgdGV4dEVsZW1lbnRzID0gbGluZXMucmVkdWNlKChhY2MsIGxpbmUsIGlkeCkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCB0ZXh0ID0gbGluZS50cmltKCk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gZ2V0RGVmYXVsdExpbmVIZWlnaHQodGV4dEVsZW1lbnRQcm9wcy5mb250RmFtaWx5KTtcblxuICAgICAgaWYgKHRleHQubGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHk6IGN1cnJlbnRZXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBlbGVtZW50ID0gbmV3VGV4dEVsZW1lbnQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0ZXh0RWxlbWVudFByb3BzKSwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeTogY3VycmVudFksXG4gICAgICAgICAgdGV4dCxcbiAgICAgICAgICBsaW5lSGVpZ2h0LFxuICAgICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgICB9KSk7XG4gICAgICAgIGFjYy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICBjdXJyZW50WSArPSBlbGVtZW50LmhlaWdodCArIExJTkVfR0FQO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcHJldkxpbmUgPSAoX2EgPSBsaW5lc1tpZHggLSAxXSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRyaW0oKTsgLy8gYWRkIHBhcmFncmFwaCBvbmx5IGlmIHByZXZpb3VzIGxpbmUgd2FzIG5vdCBlbXB0eSwgSU9XIGRvbid0IGFkZFxuICAgICAgICAvLyBtb3JlIHRoYW4gb25lIGVtcHR5IGxpbmVcblxuICAgICAgICBpZiAocHJldkxpbmUpIHtcbiAgICAgICAgICBjdXJyZW50WSArPSBnZXRMaW5lSGVpZ2h0SW5QeCh0ZXh0RWxlbWVudFByb3BzLmZvbnRTaXplLCBsaW5lSGVpZ2h0KSArIExJTkVfR0FQO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwgW10pO1xuXG4gICAgaWYgKHRleHRFbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBmcmFtZUlkID0gdGV4dEVsZW1lbnRzWzBdLmZyYW1lSWQ7XG5cbiAgICBpZiAoZnJhbWVJZCkge1xuICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50c0F0SW5kZXgodGV4dEVsZW1lbnRzLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRJbmRleChmcmFtZUlkKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCAuLi50ZXh0RWxlbWVudHNdKTtcbiAgICB9XG5cbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmZyb21FbnRyaWVzKHRleHRFbGVtZW50cy5tYXAoZWwgPT4gW2VsLmlkLCB0cnVlXSkpLCB0aGlzLnN0YXRlKVxuICAgIH0pO1xuXG4gICAgaWYgKCFpc1BsYWluUGFzdGUgJiYgdGV4dEVsZW1lbnRzLmxlbmd0aCA+IDEgJiYgUExBSU5fUEFTVEVfVE9BU1RfU0hPV04gPT09IGZhbHNlICYmICF0aGlzLmRldmljZS5pc01vYmlsZSkge1xuICAgICAgdGhpcy5zZXRUb2FzdCh7XG4gICAgICAgIG1lc3NhZ2U6IHQoXCJ0b2FzdC5wYXN0ZUFzU2luZ2xlRWxlbWVudFwiLCB7XG4gICAgICAgICAgc2hvcnRjdXQ6IGdldFNob3J0Y3V0S2V5KFwiQ3RybE9yQ21kK1NoaWZ0K1ZcIilcbiAgICAgICAgfSksXG4gICAgICAgIGR1cmF0aW9uOiA1MDAwXG4gICAgICB9KTtcbiAgICAgIFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gIH1cblxuICBoYW5kbGVUZXh0V3lzaXd5ZyhlbGVtZW50LCB7XG4gICAgaXNFeGlzdGluZ0VsZW1lbnQgPSBmYWxzZVxuICB9KSB7XG4gICAgY29uc3QgdXBkYXRlRWxlbWVudCA9ICh0ZXh0LCBvcmlnaW5hbFRleHQsIGlzRGVsZXRlZCkgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoWy4uLnRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKF9lbGVtZW50ID0+IHtcbiAgICAgICAgaWYgKF9lbGVtZW50LmlkID09PSBlbGVtZW50LmlkICYmIGlzVGV4dEVsZW1lbnQoX2VsZW1lbnQpKSB7XG4gICAgICAgICAgcmV0dXJuIHVwZGF0ZVRleHRFbGVtZW50KF9lbGVtZW50LCB7XG4gICAgICAgICAgICB0ZXh0LFxuICAgICAgICAgICAgaXNEZWxldGVkLFxuICAgICAgICAgICAgb3JpZ2luYWxUZXh0XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2VsZW1lbnQ7XG4gICAgICB9KV0pO1xuICAgIH07XG5cbiAgICB0ZXh0V3lzaXd5Zyh7XG4gICAgICBpZDogZWxlbWVudC5pZCxcbiAgICAgIGNhbnZhczogdGhpcy5jYW52YXMsXG4gICAgICBnZXRWaWV3cG9ydENvb3JkczogKHgsIHkpID0+IHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHZpZXdwb3J0WCxcbiAgICAgICAgICB5OiB2aWV3cG9ydFlcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiB4LFxuICAgICAgICAgIHNjZW5lWTogeVxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgcmV0dXJuIFt2aWV3cG9ydFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIHZpZXdwb3J0WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wXTtcbiAgICAgIH0sXG4gICAgICBvbkNoYW5nZTogd2l0aEJhdGNoZWRVcGRhdGVzKHRleHQgPT4ge1xuICAgICAgICB1cGRhdGVFbGVtZW50KHRleHQsIHRleHQsIGZhbHNlKTtcblxuICAgICAgICBpZiAoaXNOb25EZWxldGVkRWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICAgIHVwZGF0ZUJvdW5kRWxlbWVudHMoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0pLFxuICAgICAgb25TdWJtaXQ6IHdpdGhCYXRjaGVkVXBkYXRlcygoe1xuICAgICAgICB0ZXh0LFxuICAgICAgICB2aWFLZXlib2FyZCxcbiAgICAgICAgb3JpZ2luYWxUZXh0XG4gICAgICB9KSA9PiB7XG4gICAgICAgIGNvbnN0IGlzRGVsZXRlZCA9ICF0ZXh0LnRyaW0oKTtcbiAgICAgICAgdXBkYXRlRWxlbWVudCh0ZXh0LCBvcmlnaW5hbFRleHQsIGlzRGVsZXRlZCk7IC8vIHNlbGVjdCB0aGUgY3JlYXRlZCB0ZXh0IGVsZW1lbnQgb25seSBpZiBzdWJtaXR0aW5nIHZpYSBrZXlib2FyZFxuICAgICAgICAvLyAod2hlbiBzdWJtaXR0aW5nIHZpYSBjbGljayBpdCBzaG91bGQgYWN0IGFzIHNpZ25hbCB0byBkZXNlbGVjdClcblxuICAgICAgICBpZiAoIWlzRGVsZXRlZCAmJiB2aWFLZXlib2FyZCkge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRJZFRvU2VsZWN0ID0gZWxlbWVudC5jb250YWluZXJJZCA/IGVsZW1lbnQuY29udGFpbmVySWQgOiBlbGVtZW50LmlkO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgW2VsZW1lbnRJZFRvU2VsZWN0XTogdHJ1ZVxuICAgICAgICAgICAgfSksIHByZXZTdGF0ZSlcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNEZWxldGVkKSB7XG4gICAgICAgICAgZml4QmluZGluZ3NBZnRlckRlbGV0aW9uKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIFtlbGVtZW50XSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWlzRGVsZXRlZCB8fCBpc0V4aXN0aW5nRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogbnVsbFxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLmxvY2tlZCkge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfSksXG4gICAgICBlbGVtZW50LFxuICAgICAgZXhjYWxpZHJhd0NvbnRhaW5lcjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQsXG4gICAgICBhcHA6IHRoaXNcbiAgICB9KTsgLy8gZGVzZWxlY3QgYWxsIG90aGVyIGVsZW1lbnRzIHdoZW4gaW5zZXJ0aW5nIHRleHRcblxuICAgIHRoaXMuZGVzZWxlY3RFbGVtZW50cygpOyAvLyBkbyBhbiBpbml0aWFsIHVwZGF0ZSB0byByZS1pbml0aWFsaXplIGVsZW1lbnQgcG9zaXRpb24gc2luY2Ugd2Ugd2VyZVxuICAgIC8vIG1vZGlmeWluZyBlbGVtZW50J3MgeC95IGZvciBzYWtlIG9mIGVkaXRvciAoY2FzZTogc3luY2luZyB0byByZW1vdGUpXG5cbiAgICB1cGRhdGVFbGVtZW50KGVsZW1lbnQudGV4dCwgZWxlbWVudC5vcmlnaW5hbFRleHQsIGZhbHNlKTtcbiAgfVxuXG4gIGRlc2VsZWN0RWxlbWVudHMoKSB7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgfSk7XG4gIH1cblxuICBnZXRUZXh0RWxlbWVudEF0UG9zaXRpb24oeCwgeSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHgsIHksIHtcbiAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlXG4gICAgfSk7XG5cbiAgICBpZiAoZWxlbWVudCAmJiBpc1RleHRFbGVtZW50KGVsZW1lbnQpICYmICFlbGVtZW50LmlzRGVsZXRlZCkge1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBnZXRFbGVtZW50QXRQb3NpdGlvbih4LCB5LCBvcHRzKSB7XG4gICAgY29uc3QgYWxsSGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbih4LCB5LCBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQsIG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5pbmNsdWRlTG9ja2VkRWxlbWVudHMpO1xuXG4gICAgaWYgKGFsbEhpdEVsZW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIGlmIChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucHJlZmVyU2VsZWN0ZWQpIHtcbiAgICAgICAgZm9yIChsZXQgaW5kZXggPSBhbGxIaXRFbGVtZW50cy5sZW5ndGggLSAxOyBpbmRleCA+IC0xOyBpbmRleC0tKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2FsbEhpdEVsZW1lbnRzW2luZGV4XS5pZF0pIHtcbiAgICAgICAgICAgIHJldHVybiBhbGxIaXRFbGVtZW50c1tpbmRleF07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleCA9IGFsbEhpdEVsZW1lbnRzW2FsbEhpdEVsZW1lbnRzLmxlbmd0aCAtIDFdOyAvLyBJZiB3ZSdyZSBoaXR0aW5nIGVsZW1lbnQgd2l0aCBoaWdoZXN0IHotaW5kZXggb25seSBvbiBpdHMgYm91bmRpbmcgYm94XG4gICAgICAvLyB3aGlsZSBhbHNvIGhpdHRpbmcgb3RoZXIgZWxlbWVudCBmaWd1cmUsIHRoZSBsYXR0ZXIgc2hvdWxkIGJlIGNvbnNpZGVyZWQuXG5cbiAgICAgIHJldHVybiBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQoZWxlbWVudFdpdGhIaWdoZXN0WkluZGV4LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCB4LCB5KSA/IGFsbEhpdEVsZW1lbnRzW2FsbEhpdEVsZW1lbnRzLmxlbmd0aCAtIDJdIDogZWxlbWVudFdpdGhIaWdoZXN0WkluZGV4O1xuICAgIH1cblxuICAgIGlmIChhbGxIaXRFbGVtZW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHJldHVybiBhbGxIaXRFbGVtZW50c1swXTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGdldEVsZW1lbnRzQXRQb3NpdGlvbih4LCB5LCBpbmNsdWRlQm91bmRUZXh0RWxlbWVudCA9IGZhbHNlLCBpbmNsdWRlTG9ja2VkRWxlbWVudHMgPSBmYWxzZSkge1xuICAgIGNvbnN0IGVsZW1lbnRzID0gaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgJiYgaW5jbHVkZUxvY2tlZEVsZW1lbnRzID8gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSA6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsZW1lbnQgPT4gKGluY2x1ZGVMb2NrZWRFbGVtZW50cyB8fCAhZWxlbWVudC5sb2NrZWQpICYmIChpbmNsdWRlQm91bmRUZXh0RWxlbWVudCB8fCAhKGlzVGV4dEVsZW1lbnQoZWxlbWVudCkgJiYgZWxlbWVudC5jb250YWluZXJJZCkpKTtcbiAgICByZXR1cm4gZ2V0RWxlbWVudHNBdFBvc2l0aW9uKGVsZW1lbnRzLCBlbGVtZW50ID0+IGhpdFRlc3QoZWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgeCwgeSkpLmZpbHRlcihlbGVtZW50ID0+IHtcbiAgICAgIC8vIGhpdHRpbmcgYSBmcmFtZSdzIGVsZW1lbnQgZnJvbSBvdXRzaWRlIHRoZSBmcmFtZSBpcyBub3QgY29uc2lkZXJlZCBhIGhpdFxuICAgICAgY29uc3QgY29udGFpbmluZ0ZyYW1lID0gZ2V0Q29udGFpbmluZ0ZyYW1lKGVsZW1lbnQpO1xuICAgICAgcmV0dXJuIGNvbnRhaW5pbmdGcmFtZSAmJiB0aGlzLnN0YXRlLmZyYW1lUmVuZGVyaW5nLmVuYWJsZWQgJiYgdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5jbGlwID8gaXNDdXJzb3JJbkZyYW1lKHtcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfSwgY29udGFpbmluZ0ZyYW1lKSA6IHRydWU7XG4gICAgfSk7XG4gIH1cblxuICBoYW5kbGVIb3ZlclNlbGVjdGVkTGluZWFyRWxlbWVudChsaW5lYXJFbGVtZW50RWRpdG9yLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSB7XG4gICAgY29uc3QgZWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0RWxlbWVudChsaW5lYXJFbGVtZW50RWRpdG9yLmVsZW1lbnRJZCk7XG4gICAgY29uc3QgYm91bmRUZXh0RWxlbWVudCA9IGdldEJvdW5kVGV4dEVsZW1lbnQoZWxlbWVudCk7XG5cbiAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgIGxldCBob3ZlclBvaW50SW5kZXggPSAtMTtcbiAgICAgIGxldCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzID0gbnVsbDtcblxuICAgICAgaWYgKGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94KGVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIFtzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZXSkpIHtcbiAgICAgICAgaG92ZXJQb2ludEluZGV4ID0gTGluZWFyRWxlbWVudEVkaXRvci5nZXRQb2ludEluZGV4VW5kZXJDdXJzb3IoZWxlbWVudCwgdGhpcy5zdGF0ZS56b29tLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKTtcbiAgICAgICAgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3JkcyA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0U2VnbWVudE1pZHBvaW50SGl0Q29vcmRzKGxpbmVhckVsZW1lbnRFZGl0b3IsIHtcbiAgICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKGhvdmVyUG9pbnRJbmRleCA+PSAwIHx8IHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuUE9JTlRFUik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHNob3VsZFNob3dCb3VuZGluZ0JveChbZWxlbWVudF0sIHRoaXMuc3RhdGUpICYmIGlzSGl0dGluZ0VsZW1lbnRCb3VuZGluZ0JveFdpdGhvdXRIaXR0aW5nRWxlbWVudChlbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSkge1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG4gICAgICB9IGVsc2UgaWYgKGJvdW5kVGV4dEVsZW1lbnQgJiYgaGl0VGVzdChib3VuZFRleHRFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSkge1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5ob3ZlclBvaW50SW5kZXggIT09IGhvdmVyUG9pbnRJbmRleCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICBob3ZlclBvaW50SW5kZXhcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFMaW5lYXJFbGVtZW50RWRpdG9yLmFyZVBvaW50c0VxdWFsKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LnNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMsIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHNcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkFVVE8pO1xuICAgIH1cbiAgfVxuXG4gIG1heWJlQ2xlYW51cEFmdGVyTWlzc2luZ1BvaW50ZXJVcChldmVudCkge1xuICAgIGlmIChsYXN0UG9pbnRlclVwICE9PSBudWxsKSB7XG4gICAgICAvLyBVbmZvcnR1bmF0ZWx5LCBzb21ldGltZXMgd2UgZG9uJ3QgZ2V0IGEgcG9pbnRlcnVwIGFmdGVyIGEgcG9pbnRlcmRvd24sXG4gICAgICAvLyB0aGlzIGNhbiBoYXBwZW4gd2hlbiBhIGNvbnRleHR1YWwgbWVudSBvciBhbGVydCBpcyB0cmlnZ2VyZWQuIEluIG9yZGVyIHRvIGF2b2lkXG4gICAgICAvLyBiZWluZyBpbiBhIHdlaXJkIHN0YXRlLCB3ZSBjbGVhbiB1cCBvbiB0aGUgbmV4dCBwb2ludGVyZG93blxuICAgICAgbGFzdFBvaW50ZXJVcChldmVudCk7XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlR2VzdHVyZU9uUG9pbnRlckRvd24oZXZlbnQpIHtcbiAgICBnZXN0dXJlLnBvaW50ZXJzLnNldChldmVudC5wb2ludGVySWQsIHtcbiAgICAgIHg6IGV2ZW50LmNsaWVudFgsXG4gICAgICB5OiBldmVudC5jbGllbnRZXG4gICAgfSk7XG5cbiAgICBpZiAoZ2VzdHVyZS5wb2ludGVycy5zaXplID09PSAyKSB7XG4gICAgICBnZXN0dXJlLmxhc3RDZW50ZXIgPSBnZXRDZW50ZXIoZ2VzdHVyZS5wb2ludGVycyk7XG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlID0gZ2V0RGlzdGFuY2UoQXJyYXkuZnJvbShnZXN0dXJlLnBvaW50ZXJzLnZhbHVlcygpKSk7XG4gICAgfVxuICB9XG5cbiAgaW5pdGlhbFBvaW50ZXJEb3duU3RhdGUoZXZlbnQpIHtcbiAgICBjb25zdCBvcmlnaW4gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgY29uc3QgW21pblgsIG1pblksIG1heFgsIG1heFldID0gZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgIHJldHVybiB7XG4gICAgICBvcmlnaW4sXG4gICAgICB3aXRoQ21kT3JDdHJsOiBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSxcbiAgICAgIG9yaWdpbkluR3JpZDogdHVwbGVUb0Nvb3JzKGdldEdyaWRQb2ludChvcmlnaW4ueCwgb3JpZ2luLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpKSxcbiAgICAgIHNjcm9sbGJhcnM6IGlzT3ZlclNjcm9sbEJhcnMoY3VycmVudFNjcm9sbEJhcnMsIGV2ZW50LmNsaWVudFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIGV2ZW50LmNsaWVudFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcCksXG4gICAgICAvLyB3ZSBuZWVkIHRvIGR1cGxpY2F0ZSBiZWNhdXNlIHdlJ2xsIGJlIHVwZGF0aW5nIHRoaXMgc3RhdGVcbiAgICAgIGxhc3RDb29yZHM6IE9iamVjdC5hc3NpZ24oe30sIG9yaWdpbiksXG4gICAgICBvcmlnaW5hbEVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgIGFjYy5zZXQoZWxlbWVudC5pZCwgZGVlcENvcHlFbGVtZW50KGVsZW1lbnQpKTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIG5ldyBNYXAoKSksXG4gICAgICByZXNpemU6IHtcbiAgICAgICAgaGFuZGxlVHlwZTogZmFsc2UsXG4gICAgICAgIGlzUmVzaXppbmc6IGZhbHNlLFxuICAgICAgICBvZmZzZXQ6IHtcbiAgICAgICAgICB4OiAwLFxuICAgICAgICAgIHk6IDBcbiAgICAgICAgfSxcbiAgICAgICAgYXJyb3dEaXJlY3Rpb246IFwib3JpZ2luXCIsXG4gICAgICAgIGNlbnRlcjoge1xuICAgICAgICAgIHg6IChtYXhYICsgbWluWCkgLyAyLFxuICAgICAgICAgIHk6IChtYXhZICsgbWluWSkgLyAyXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBoaXQ6IHtcbiAgICAgICAgZWxlbWVudDogbnVsbCxcbiAgICAgICAgYWxsSGl0RWxlbWVudHM6IFtdLFxuICAgICAgICB3YXNBZGRlZFRvU2VsZWN0aW9uOiBmYWxzZSxcbiAgICAgICAgaGFzQmVlbkR1cGxpY2F0ZWQ6IGZhbHNlLFxuICAgICAgICBoYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50czogdGhpcy5pc0hpdHRpbmdDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cyhvcmlnaW4sIHNlbGVjdGVkRWxlbWVudHMpXG4gICAgICB9LFxuICAgICAgZHJhZzoge1xuICAgICAgICBoYXNPY2N1cnJlZDogZmFsc2UsXG4gICAgICAgIG9mZnNldDogbnVsbFxuICAgICAgfSxcbiAgICAgIGV2ZW50TGlzdGVuZXJzOiB7XG4gICAgICAgIG9uTW92ZTogbnVsbCxcbiAgICAgICAgb25VcDogbnVsbCxcbiAgICAgICAgb25LZXlVcDogbnVsbCxcbiAgICAgICAgb25LZXlEb3duOiBudWxsXG4gICAgICB9LFxuICAgICAgYm94U2VsZWN0aW9uOiB7XG4gICAgICAgIGhhc09jY3VycmVkOiBmYWxzZVxuICAgICAgfSxcbiAgICAgIGVsZW1lbnRJZHNUb0VyYXNlOiB7fVxuICAgIH07XG4gIH0gLy8gUmV0dXJucyB3aGV0aGVyIHRoZSBldmVudCBpcyBhIGRyYWdnaW5nIGEgc2Nyb2xsYmFyXG5cblxuICBoYW5kbGVEcmFnZ2luZ1Njcm9sbEJhcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkge1xuICAgIGlmICghKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJFaXRoZXIgJiYgIXRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlzRHJhZ2dpbmdTY3JvbGxCYXIgPSB0cnVlO1xuICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gZXZlbnQuY2xpZW50WDtcbiAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IGV2ZW50LmNsaWVudFk7XG4gICAgY29uc3Qgb25Qb2ludGVyTW92ZSA9IHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZChldmVudCA9PiB7XG4gICAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQ7XG5cbiAgICAgIGlmICghKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgfSk7XG4gICAgY29uc3Qgb25Qb2ludGVyVXAgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoKCkgPT4ge1xuICAgICAgaXNEcmFnZ2luZ1Njcm9sbEJhciA9IGZhbHNlO1xuICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICBsYXN0UG9pbnRlclVwID0gbnVsbDtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIlxuICAgICAgfSk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgb25Qb2ludGVyVXApO1xuICAgICAgb25Qb2ludGVyTW92ZS5mbHVzaCgpO1xuICAgIH0pO1xuICAgIGxhc3RQb2ludGVyVXAgPSBvblBvaW50ZXJVcDtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGlzQVNlbGVjdGVkRWxlbWVudChoaXRFbGVtZW50KSB7XG4gICAgcmV0dXJuIGhpdEVsZW1lbnQgIT0gbnVsbCAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXTtcbiAgfVxuXG4gIGlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHBvaW50LCBzZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoIDwgMikge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gLy8gSG93IG1hbnkgcGl4ZWxzIG9mZiB0aGUgc2hhcGUgYm91bmRhcnkgd2Ugc3RpbGwgY29uc2lkZXIgYSBoaXRcblxuXG4gICAgY29uc3QgdGhyZXNob2xkID0gMTAgLyB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgY29uc3QgW3gxLCB5MSwgeDIsIHkyXSA9IGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICByZXR1cm4gcG9pbnQueCA+IHgxIC0gdGhyZXNob2xkICYmIHBvaW50LnggPCB4MiArIHRocmVzaG9sZCAmJiBwb2ludC55ID4geTEgLSB0aHJlc2hvbGQgJiYgcG9pbnQueSA8IHkyICsgdGhyZXNob2xkO1xuICB9XG5cbiAgZ2V0Q3VycmVudEl0ZW1Sb3VuZG5lc3MoZWxlbWVudFR5cGUpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdW5kbmVzcyA9PT0gXCJyb3VuZFwiID8ge1xuICAgICAgdHlwZTogaXNVc2luZ0FkYXB0aXZlUmFkaXVzKGVsZW1lbnRUeXBlKSA/IFJPVU5ETkVTUy5BREFQVElWRV9SQURJVVMgOiBST1VORE5FU1MuUFJPUE9SVElPTkFMX1JBRElVU1xuICAgIH0gOiBudWxsO1xuICB9XG5cbiAgb25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIFByZXZlbnRzIGZvY3VzIGZyb20gZXNjYXBpbmcgZXhjYWxpZHJhdyB0YWJcbiAgICAgIGV2ZW50LmtleSA9PT0gS0VZUy5BTFQgJiYgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKHRoaXMubWF5YmVIYW5kbGVSZXNpemUocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudChwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgfSk7XG4gIH1cblxuICBvblBvaW50ZXJNb3ZlRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZChldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBXZSBuZWVkIHRvIGluaXRpYWxpemUgZHJhZ09mZnNldFhZIG9ubHkgYWZ0ZXIgd2UndmUgdXBkYXRlZFxuICAgICAgLy8gYHN0YXRlLnNlbGVjdGVkRWxlbWVudElkc2Agb24gcG9pbnRlckRvd24uIERvaW5nIGl0IGhlcmUgaW4gcG9pbnRlck1vdmVcbiAgICAgIC8vIGV2ZW50IGhhbmRsZXIgc2hvdWxkIGhvcGVmdWxseSBlbnN1cmUgd2UncmUgYWxyZWFkeSB3b3JraW5nIHdpdGhcbiAgICAgIC8vIHRoZSB1cGRhdGVkIHN0YXRlLlxuXG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0ID09PSBudWxsKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5vZmZzZXQgPSB0dXBsZVRvQ29vcnMoZ2V0RHJhZ09mZnNldFhZKHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQ7XG5cbiAgICAgIGlmICghKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICB0aGlzLmhhbmRsZUVyYXNlcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSwgcG9pbnRlckNvb3Jkcyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpOyAvLyBmb3IgYXJyb3dzL2xpbmVzLCBkb24ndCBzdGFydCBkcmFnZ2luZyB1bnRpbCBhIGdpdmVuIHRocmVzaG9sZFxuICAgICAgLy8gdG8gZW5zdXJlIHdlIGRvbid0IGNyZWF0ZSBhIDItcG9pbnQgYXJyb3cgYnkgbWlzdGFrZSB3aGVuXG4gICAgICAvLyB1c2VyIGNsaWNrcyBtb3VzZSBpbiBhIHdheSB0aGF0IGl0IG1vdmVzIGEgdGlueSBiaXQgKHRodXNcbiAgICAgIC8vIHRyaWdnZXJpbmcgcG9pbnRlcm1vdmUpXG5cbiAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJhcnJvd1wiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxpbmVcIikpIHtcbiAgICAgICAgaWYgKGRpc3RhbmNlMmQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpIDwgRFJBR0dJTkdfVEhSRVNIT0xEKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5pc1Jlc2l6aW5nKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gcG9pbnRlckNvb3Jkcy54O1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcblxuICAgICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudEVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQ7XG5cbiAgICAgICAgaWYgKExpbmVhckVsZW1lbnRFZGl0b3Iuc2hvdWxkQWRkTWlkcG9pbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHBvaW50ZXJDb29yZHMsIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgICAgY29uc3QgcmV0ID0gTGluZWFyRWxlbWVudEVkaXRvci5hZGRNaWRwb2ludCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgcG9pbnRlckNvb3JkcywgdGhpcy5zdGF0ZSwgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKTtcblxuICAgICAgICAgIGlmICghcmV0KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG5cblxuICAgICAgICAgIGZsdXNoU3luYygoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZTogcmV0LnBvaW50ZXJEb3duU3RhdGUsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IHJldC5zZWxlY3RlZFBvaW50c0luZGljZXNcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGU6IHJldC5wb2ludGVyRG93blN0YXRlLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRQb2ludHNJbmRpY2VzOiByZXQuc2VsZWN0ZWRQb2ludHNJbmRpY2VzXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2UgaWYgKGxpbmVhckVsZW1lbnRFZGl0b3IucG9pbnRlckRvd25TdGF0ZS5zZWdtZW50TWlkcG9pbnQudmFsdWUgIT09IG51bGwgJiYgIWxpbmVhckVsZW1lbnRFZGl0b3IucG9pbnRlckRvd25TdGF0ZS5zZWdtZW50TWlkcG9pbnQuYWRkZWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBkaWREcmFnID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludERyYWdnaW5nKGV2ZW50LCB0aGlzLnN0YXRlLCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgKGVsZW1lbnQsIHBvaW50c1NjZW5lQ29vcmRzKSA9PiB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhlbGVtZW50LCBwb2ludHNTY2VuZUNvb3Jkcyk7XG4gICAgICAgIH0sIGxpbmVhckVsZW1lbnRFZGl0b3IpO1xuXG4gICAgICAgIGlmIChkaWREcmFnKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBwb2ludGVyQ29vcmRzLnk7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgIGlzRHJhZ2dpbmc6IHRydWVcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICBpc0RyYWdnaW5nOiB0cnVlXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgaGFzSGl0QVNlbGVjdGVkRWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiB0aGlzLmlzQVNlbGVjdGVkRWxlbWVudChlbGVtZW50KSk7XG4gICAgICBjb25zdCBpc1NlbGVjdGluZ1BvaW50c0luTGluZUVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZXZlbnQuc2hpZnRLZXkgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgPT09ICgoX2EgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaWQpO1xuXG4gICAgICBpZiAoKGhhc0hpdEFTZWxlY3RlZEVsZW1lbnQgfHwgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpICYmICFpc1NlbGVjdGluZ1BvaW50c0luTGluZUVkaXRvcikge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmV2ZXJ5KGVsZW1lbnQgPT4gZWxlbWVudC5sb2NrZWQpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50c0hhc0FGcmFtZSA9IHNlbGVjdGVkRWxlbWVudHMuZmluZChlID0+IGlzRnJhbWVFbGVtZW50KGUpKTtcbiAgICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMocG9pbnRlckNvb3Jkcyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGZyYW1lVG9IaWdobGlnaHQ6IHRvcExheWVyRnJhbWUgJiYgIXNlbGVjdGVkRWxlbWVudHNIYXNBRnJhbWUgPyB0b3BMYXllckZyYW1lIDogbnVsbFxuICAgICAgICB9KTsgLy8gTWFya2luZyB0aGF0IGNsaWNrIHdhcyB1c2VkIGZvciBkcmFnZ2luZyB0byBjaGVja1xuICAgICAgICAvLyBpZiBlbGVtZW50cyBzaG91bGQgYmUgZGVzZWxlY3RlZCBvbiBwb2ludGVydXBcblxuICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkOiB0cnVlXG4gICAgICAgIH0pOyAvLyBwcmV2ZW50IGRyYWdnaW5nIGV2ZW4gaWYgd2UncmUgbm8gbG9uZ2VyIGhvbGRpbmcgY21kL2N0cmwgb3RoZXJ3aXNlXG4gICAgICAgIC8vIGl0IHdvdWxkIGhhdmUgd2VpcmQgcmVzdWx0cyAoc3R1ZmYganVtcGluZyBhbGwgb3ZlciB0aGUgc2NyZWVuKVxuICAgICAgICAvLyBDaGVja2luZyBmb3IgZWRpdGluZ0VsZW1lbnQgdG8gYXZvaWQganVtcCB3aGlsZSBlZGl0aW5nIG9uIG1vYmlsZSAjNjUwM1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDAgJiYgIXBvaW50ZXJEb3duU3RhdGUud2l0aENtZE9yQ3RybCAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAmJiAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpICE9PSBcImFjdGl2ZVwiKSB7XG4gICAgICAgICAgY29uc3QgW2RyYWdYLCBkcmFnWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54IC0gcG9pbnRlckRvd25TdGF0ZS5kcmFnLm9mZnNldC54LCBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0LnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICAgIGNvbnN0IFtkcmFnRGlzdGFuY2VYLCBkcmFnRGlzdGFuY2VZXSA9IFtNYXRoLmFicyhwb2ludGVyQ29vcmRzLnggLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54KSwgTWF0aC5hYnMocG9pbnRlckNvb3Jkcy55IC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSldOyAvLyBXZSBvbmx5IGRyYWcgaW4gb25lIGRpcmVjdGlvbiBpZiBzaGlmdCBpcyBwcmVzc2VkXG5cbiAgICAgICAgICBjb25zdCBsb2NrRGlyZWN0aW9uID0gZXZlbnQuc2hpZnRLZXk7IC8vIHdoZW4gd2UncmUgZWRpdGluZyB0aGUgbmFtZSBvZiBhIGZyYW1lLCB3ZSB3YW50IHRoZSB1c2VyIHRvIGJlXG4gICAgICAgICAgLy8gYWJsZSB0byBzZWxlY3QgYW5kIGludGVyYWN0IHdpdGggdGhlIHRleHQgaW5wdXRcblxuICAgICAgICAgICF0aGlzLnN0YXRlLmVkaXRpbmdGcmFtZSAmJiBkcmFnU2VsZWN0ZWRFbGVtZW50cyhwb2ludGVyRG93blN0YXRlLCBzZWxlY3RlZEVsZW1lbnRzLCBkcmFnWCwgZHJhZ1ksIGxvY2tEaXJlY3Rpb24sIGRyYWdEaXN0YW5jZVgsIGRyYWdEaXN0YW5jZVksIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUpO1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKTsgLy8gV2UgZHVwbGljYXRlIHRoZSBzZWxlY3RlZCBlbGVtZW50IGlmIGFsdCBpcyBwcmVzc2VkIG9uIHBvaW50ZXIgbW92ZVxuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQpIHtcbiAgICAgICAgICAgIC8vIE1vdmUgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBlbGVtZW50cyB0byB0aGUgdG9wIG9mIHRoZSB6IGluZGV4IHN0YWNrLCBhbmRcbiAgICAgICAgICAgIC8vIHB1dCB0aGUgZHVwbGljYXRlcyB3aGVyZSB0aGUgc2VsZWN0ZWQgZWxlbWVudHMgdXNlZCB0byBiZS5cbiAgICAgICAgICAgIC8vICh0aGUgb3JpZ2luIHBvaW50IHdoZXJlIHRoZSBkcmFnZ2luZyBzdGFydGVkKVxuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29uc3QgbmV4dEVsZW1lbnRzID0gW107XG4gICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvQXBwZW5kID0gW107XG4gICAgICAgICAgICBjb25zdCBncm91cElkTWFwID0gbmV3IE1hcCgpO1xuICAgICAgICAgICAgY29uc3Qgb2xkSWRUb0R1cGxpY2F0ZWRJZCA9IG5ldyBNYXAoKTtcbiAgICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuICAgICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50SWRzID0gbmV3IFNldCh0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzLFxuICAgICAgICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZSxcbiAgICAgICAgICAgICAgaW5jbHVkZUVsZW1lbnRzSW5GcmFtZXM6IHRydWVcbiAgICAgICAgICAgIH0pLm1hcChlbGVtZW50ID0+IGVsZW1lbnQuaWQpKTtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRJZHMuaGFzKGVsZW1lbnQuaWQpIHx8IC8vIGNhc2U6IHRoZSBzdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMgbWlnaHQgbm90IGhhdmUgYmVlblxuICAgICAgICAgICAgICAvLyB1cGRhdGVkIHlldCBieSB0aGUgdGltZSB0aGlzIG1vdXNlbW92ZSBldmVudCBpcyBmaXJlZFxuICAgICAgICAgICAgICBlbGVtZW50LmlkID09PSAoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmlkKSAmJiBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZHVwbGljYXRlZEVsZW1lbnQgPSBkdXBsaWNhdGVFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQsIGdyb3VwSWRNYXAsIGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IFtvcmlnaW5EcmFnWCwgb3JpZ2luRHJhZ1ldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnggLSBwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0LngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkgLSBwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0LnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHVwbGljYXRlZEVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgIHg6IGR1cGxpY2F0ZWRFbGVtZW50LnggKyAob3JpZ2luRHJhZ1ggLSBkcmFnWCksXG4gICAgICAgICAgICAgICAgICB5OiBkdXBsaWNhdGVkRWxlbWVudC55ICsgKG9yaWdpbkRyYWdZIC0gZHJhZ1kpXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzLnB1c2goZHVwbGljYXRlZEVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIGVsZW1lbnRzVG9BcHBlbmQucHVzaChlbGVtZW50KTtcbiAgICAgICAgICAgICAgICBvbGRJZFRvRHVwbGljYXRlZElkLnNldChlbGVtZW50LmlkLCBkdXBsaWNhdGVkRWxlbWVudC5pZCk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzLnB1c2goZWxlbWVudCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbmV4dFNjZW5lRWxlbWVudHMgPSBbLi4ubmV4dEVsZW1lbnRzLCAuLi5lbGVtZW50c1RvQXBwZW5kXTtcbiAgICAgICAgICAgIGJpbmRUZXh0VG9TaGFwZUFmdGVyRHVwbGljYXRpb24obmV4dEVsZW1lbnRzLCBlbGVtZW50c1RvQXBwZW5kLCBvbGRJZFRvRHVwbGljYXRlZElkKTtcbiAgICAgICAgICAgIGZpeEJpbmRpbmdzQWZ0ZXJEdXBsaWNhdGlvbihuZXh0U2NlbmVFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCwgXCJkdXBsaWNhdGVzU2VydmVBc09sZFwiKTtcbiAgICAgICAgICAgIGJpbmRFbGVtZW50c1RvRnJhbWVzQWZ0ZXJEdXBsaWNhdGlvbihuZXh0U2NlbmVFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCk7XG4gICAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0U2NlbmVFbGVtZW50cyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IC8vIEl0IGlzIHZlcnkgaW1wb3J0YW50IHRvIHJlYWQgdGhpcy5zdGF0ZSB3aXRoaW4gZWFjaCBtb3ZlIGV2ZW50LFxuICAgICAgLy8gb3RoZXJ3aXNlIHdlIHdvdWxkIHJlYWQgYSBzdGFsZSBvbmUhXG5cblxuICAgICAgY29uc3QgZHJhZ2dpbmdFbGVtZW50ID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQ7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgY29uc3QgZHggPSBwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgY29uc3QgZHkgPSBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcbiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9pbnRzLmxlbmd0aCA+IDAgJiYgcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXTtcbiAgICAgICAgY29uc3QgZGlzY2FyZFBvaW50ID0gbGFzdFBvaW50ICYmIGxhc3RQb2ludFswXSA9PT0gZHggJiYgbGFzdFBvaW50WzFdID09PSBkeTtcblxuICAgICAgICBpZiAoIWRpc2NhcmRQb2ludCkge1xuICAgICAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGRyYWdnaW5nRWxlbWVudC5zaW11bGF0ZVByZXNzdXJlID8gZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcyA6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucHJlc3N1cmVzLCBldmVudC5wcmVzc3VyZV07XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dLFxuICAgICAgICAgICAgcHJlc3N1cmVzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoaXNMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgbGV0IGR4ID0gZ3JpZFggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgbGV0IGR5ID0gZ3JpZFkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcblxuICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpICYmIHBvaW50cy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICAoe1xuICAgICAgICAgICAgd2lkdGg6IGR4LFxuICAgICAgICAgICAgaGVpZ2h0OiBkeVxuICAgICAgICAgIH0gPSBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUoZHJhZ2dpbmdFbGVtZW50LngsIGRyYWdnaW5nRWxlbWVudC55LCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBvaW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLCBbZHgsIGR5XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cy5zbGljZSgwLCAtMSksIFtkeCwgZHldXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgICAgICAvLyBXaGVuIGNyZWF0aW5nIGEgbGluZWFyIGVsZW1lbnQgYnkgZHJhZ2dpbmdcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdzRm9yTGluZWFyRWxlbWVudEF0Q29vcmRzKGRyYWdnaW5nRWxlbWVudCwgW3BvaW50ZXJDb29yZHNdLCB0aGlzLnN0YXRlLnN0YXJ0Qm91bmRFbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuICAgICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuYm94U2VsZWN0aW9uLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpOyAvLyBib3gtc2VsZWN0IGxpbmUgZWRpdG9yIHBvaW50c1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVCb3hTZWxlY3Rpb24oZXZlbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKSk7IC8vIHJlZ3VsYXIgYm94LXNlbGVjdFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxldCBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IHRydWU7XG5cbiAgICAgICAgICBpZiAoIWV2ZW50LnNoaWZ0S2V5ICYmIGlzU29tZUVsZW1lbnRTZWxlY3RlZChlbGVtZW50cywgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLndpdGhDbWRPckN0cmwgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgICAgW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uID0gZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24oZWxlbWVudHMsIGRyYWdnaW5nRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2hvdWxkUmV1c2VTZWxlY3Rpb24gJiYgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgIGFjY1tlbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgICAgIHJldHVybiBhY2M7XG4gICAgICAgICAgICB9LCB7fSkpO1xuXG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICAvLyBpZiB1c2luZyBjdHJsL2NtZCwgc2VsZWN0IHRoZSBoaXRFbGVtZW50IG9ubHkgaWYgd2VcbiAgICAgICAgICAgICAgLy8gaGF2ZW4ndCBib3gtc2VsZWN0ZWQgYW55dGhpbmcgZWxzZVxuICAgICAgICAgICAgICBpZiAoIWVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudC5pZF0gPSB0cnVlO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXZTdGF0ZSA9ICFzaG91bGRSZXVzZVNlbGVjdGlvbiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGxcbiAgICAgICAgICAgIH0pIDogcHJldlN0YXRlO1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dFNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgLy8gc2VsZWN0IGxpbmVhciBlbGVtZW50IG9ubHkgd2hlbiB3ZSBoYXZlbid0IGJveC1zZWxlY3RlZCBhbnl0aGluZyBlbHNlXG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24ubGVuZ3RoID09PSAxICYmIGlzTGluZWFyRWxlbWVudChlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSwgdGhpcy5zY2VuZSkgOiBudWxsLFxuICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCA9PT0gMSAmJiAoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0ubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdKSkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9IC8vIFJldHVybnMgd2hldGhlciB0aGUgcG9pbnRlciBtb3ZlIGhhcHBlbmVkIG92ZXIgZWl0aGVyIHNjcm9sbGJhclxuXG5cbiAgaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSkge1xuICAgIGlmIChwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVySG9yaXpvbnRhbCkge1xuICAgICAgY29uc3QgeCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICBjb25zdCBkeCA9IHggLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueDtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYIC0gZHggLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSB4O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJWZXJ0aWNhbCkge1xuICAgICAgY29uc3QgeSA9IGV2ZW50LmNsaWVudFk7XG4gICAgICBjb25zdCBkeSA9IHkgLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueTtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZIC0gZHkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSB5O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgb25Qb2ludGVyVXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGNoaWxkRXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2Y7XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSkge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZS5mbHVzaCgpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIGRyYWdnaW5nRWxlbWVudCxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50LFxuICAgICAgICBtdWx0aUVsZW1lbnQsXG4gICAgICAgIGFjdGl2ZVRvb2wsXG4gICAgICAgIGlzUmVzaXppbmcsXG4gICAgICAgIGlzUm90YXRpbmdcbiAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzUmVzaXppbmc6IGZhbHNlLFxuICAgICAgICBpc1JvdGF0aW5nOiBmYWxzZSxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50OiBudWxsLFxuICAgICAgICBzZWxlY3Rpb25FbGVtZW50OiBudWxsLFxuICAgICAgICBmcmFtZVRvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIixcbiAgICAgICAgLy8gdGV4dCBlbGVtZW50cyBhcmUgcmVzZXQgb24gZmluYWxpemUsIGFuZCByZXNldHRpbmcgb24gcG9pbnRlcnVwXG4gICAgICAgIC8vIG1heSBjYXVzZSBpc3N1ZXMgd2l0aCBkb3VibGUgdGFwc1xuICAgICAgICBlZGl0aW5nRWxlbWVudDogbXVsdGlFbGVtZW50IHx8IGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPyB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50IDogbnVsbFxuICAgICAgfSk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGNoaWxkRXZlbnQuY2xpZW50WCwgY2hpbGRFdmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IGZhbHNlXG4gICAgICB9KTsgLy8gSGFuZGxlIGVuZCBvZiBkcmFnZ2luZyBhIHBvaW50IG9mIGEgbGluZWFyIGVsZW1lbnQsIG1pZ2h0IGNsb3NlIGEgbG9vcFxuICAgICAgLy8gYW5kIHNldHMgYmluZGluZyBlbGVtZW50XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5ib3hTZWxlY3Rpb24uaGFzT2NjdXJyZWQgJiYgKChfYiA9IChfYSA9IHBvaW50ZXJEb3duU3RhdGUuaGl0KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/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");
2466
+ 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_65__ = __webpack_require__(/*! nanoid */ \"../../../node_modules/nanoid/index.browser.js\");\n/* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../actions */ \"../../actions/index.ts\");\n/* harmony import */ var _actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../actions/actionHistory */ \"../../actions/actionHistory.tsx\");\n/* harmony import */ var _actions_manager__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../actions/manager */ \"../../actions/manager.tsx\");\n/* harmony import */ var _actions_register__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../actions/register */ \"../../actions/register.ts\");\n/* harmony import */ var _analytics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../analytics */ \"../../analytics.ts\");\n/* harmony import */ var _appState__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../appState */ \"../../appState.ts\");\n/* harmony import */ var _clipboard__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../clipboard */ \"../../clipboard.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../constants */ \"../../constants.ts\");\n/* harmony import */ var _data__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../data */ \"../../data/index.ts\");\n/* harmony import */ var _data_library__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../data/library */ \"../../data/library.ts\");\n/* harmony import */ var _data_restore__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../data/restore */ \"../../data/restore.ts\");\n/* harmony import */ var _element__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../element */ \"../../element/index.ts\");\n/* harmony import */ var _element_binding__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../element/binding */ \"../../element/binding.ts\");\n/* harmony import */ var _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../element/linearElementEditor */ \"../../element/linearElementEditor.ts\");\n/* harmony import */ var _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../element/mutateElement */ \"../../element/mutateElement.ts\");\n/* harmony import */ var _element_newElement__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../element/newElement */ \"../../element/newElement.ts\");\n/* harmony import */ var _element_typeChecks__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../element/typeChecks */ \"../../element/typeChecks.ts\");\n/* harmony import */ var _gesture__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../gesture */ \"../../gesture.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../groups */ \"../../groups.ts\");\n/* harmony import */ var _history__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../history */ \"../../history.ts\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../i18n */ \"../../i18n.ts\");\n/* harmony import */ var _keys__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ../keys */ \"../../keys.ts\");\n/* harmony import */ var _element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ../element/sizeHelpers */ \"../../element/sizeHelpers.ts\");\n/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ../math */ \"../../math.ts\");\n/* harmony import */ var _scene__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ../scene */ \"../../scene/index.ts\");\n/* harmony import */ var _scene_Scene__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ../scene/Scene */ \"../../scene/Scene.ts\");\n/* harmony import */ var _scene_zoom__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ../scene/zoom */ \"../../scene/zoom.ts\");\n/* harmony import */ var _shapes__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ../shapes */ \"../../shapes.tsx\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ../utils */ \"../../utils.ts\");\n/* harmony import */ var _element_embeddable__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ../element/embeddable */ \"../../element/embeddable.ts\");\n/* harmony import */ var _ContextMenu__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ./ContextMenu */ \"../../components/ContextMenu.tsx\");\n/* harmony import */ var _LayerUI__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./LayerUI */ \"../../components/LayerUI.tsx\");\n/* harmony import */ var _Toast__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./Toast */ \"../../components/Toast.tsx\");\n/* harmony import */ var _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ../actions/actionToggleViewMode */ \"../../actions/actionToggleViewMode.tsx\");\n/* harmony import */ var _data_blob__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ../data/blob */ \"../../data/blob.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ../element/image */ \"../../element/image.ts\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! lodash.throttle */ \"../../../node_modules/lodash.throttle/index.js\");\n/* harmony import */ var lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default = /*#__PURE__*/__webpack_require__.n(lodash_throttle__WEBPACK_IMPORTED_MODULE_41__);\n/* harmony import */ var _data_filesystem__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! ../data/filesystem */ \"../../data/filesystem.ts\");\n/* harmony import */ var _element_textElement__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ../element/textElement */ \"../../element/textElement.ts\");\n/* harmony import */ var _element_collision__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ../element/collision */ \"../../element/collision.ts\");\n/* harmony import */ var _element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! ../element/Hyperlink */ \"../../element/Hyperlink.tsx\");\n/* harmony import */ var _data_url__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! ../data/url */ \"../../data/url.ts\");\n/* harmony import */ var _element_transformHandles__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! ../element/transformHandles */ \"../../element/transformHandles.ts\");\n/* harmony import */ var _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! ../actions/actionElementLock */ \"../../actions/actionElementLock.ts\");\n/* harmony import */ var _scene_Fonts__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! ../scene/Fonts */ \"../../scene/Fonts.ts\");\n/* harmony import */ var _frame__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! ../frame */ \"../../frame.ts\");\n/* harmony import */ var _scene_selection__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! ../scene/selection */ \"../../scene/selection.ts\");\n/* harmony import */ var _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! ../actions/actionClipboard */ \"../../actions/actionClipboard.tsx\");\n/* harmony import */ var _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! ../actions/actionFrame */ \"../../actions/actionFrame.ts\");\n/* harmony import */ var _actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ../actions/actionCanvas */ \"../../actions/actionCanvas.tsx\");\n/* harmony import */ var _jotai__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ../jotai */ \"../../jotai.ts\");\n/* harmony import */ var _ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! ./ActiveConfirmDialog */ \"../../components/ActiveConfirmDialog.tsx\");\n/* harmony import */ var _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ../actions/actionBoundText */ \"../../actions/actionBoundText.tsx\");\n/* harmony import */ var _BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(/*! ./BraveMeasureTextError */ \"../../components/BraveMeasureTextError.tsx\");\n/* harmony import */ var _EyeDropper__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(/*! ./EyeDropper */ \"../../components/EyeDropper.tsx\");\n/* harmony import */ var _data_transform__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(/*! ../data/transform */ \"../../data/transform.ts\");\n/* harmony import */ var _Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(/*! ./Sidebar/Sidebar */ \"../../components/Sidebar/Sidebar.tsx\");\n/* harmony import */ var _canvases__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(/*! ./canvases */ \"../../components/canvases/index.tsx\");\n/* harmony import */ var _scene_Renderer__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(/*! ../scene/Renderer */ \"../../scene/Renderer.ts\");\n/* harmony import */ var _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(/*! ../scene/ShapeCache */ \"../../scene/ShapeCache.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\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\n this.updateEmbeddables = () => {\n const embeddableElements = new Map();\n let updated = false;\n this.scene.getNonDeletedElements().filter(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(element)) {\n embeddableElements.set(element.id, true);\n\n if (element.validated == null) {\n updated = true;\n const validated = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(element.link, this.props.validateEmbeddable);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n validated\n }, false);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__.ShapeCache[\"delete\"](element);\n }\n }\n\n return false;\n });\n\n if (updated) {\n this.scene.informMutation();\n } // GC\n\n\n this.iFrameRefs.forEach((ref, id) => {\n if (!embeddableElements.has(id)) {\n this.iFrameRefs.delete(id);\n }\n });\n };\n\n this.getFrameNameDOMId = frameElement => {\n return `${this.id}-frame-name-${frameElement.id}`;\n };\n\n this.frameNameBoundsCache = {\n get: frameElement => {\n let bounds = this.frameNameBoundsCache._cache.get(frameElement.id);\n\n if (!bounds || bounds.zoom !== this.state.zoom.value || bounds.versionNonce !== frameElement.versionNonce) {\n const frameNameDiv = document.getElementById(this.getFrameNameDOMId(frameElement));\n\n if (frameNameDiv) {\n const box = frameNameDiv.getBoundingClientRect();\n const boxSceneTopLeft = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: box.x,\n clientY: box.y\n }, this.state);\n const boxSceneBottomRight = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: box.right,\n clientY: box.bottom\n }, this.state);\n bounds = {\n x: boxSceneTopLeft.x,\n y: boxSceneTopLeft.y,\n width: boxSceneBottomRight.x - boxSceneTopLeft.x,\n height: boxSceneBottomRight.y - boxSceneTopLeft.y,\n angle: 0,\n zoom: this.state.zoom.value,\n versionNonce: frameElement.versionNonce\n };\n\n this.frameNameBoundsCache._cache.set(frameElement.id, bounds);\n\n return bounds;\n }\n\n return null;\n }\n\n return bounds;\n },\n\n /**\n * @private\n */\n _cache: new Map()\n };\n\n this.renderFrameNames = () => {\n if (!this.state.frameRendering.enabled || !this.state.frameRendering.name) {\n return null;\n }\n\n const isDarkTheme = this.state.theme === \"dark\";\n return this.scene.getNonDeletedFrames().map((f, index) => {\n if (!(0,_element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__.isElementInViewport)(f, this.canvas.width / window.devicePixelRatio, this.canvas.height / window.devicePixelRatio, {\n offsetLeft: this.state.offsetLeft,\n offsetTop: this.state.offsetTop,\n scrollX: this.state.scrollX,\n scrollY: this.state.scrollY,\n zoom: this.state.zoom\n })) {\n // if frame not visible, don't render its name\n return null;\n }\n\n const {\n x: x1,\n y: y1\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: f.x,\n sceneY: f.y\n }, this.state);\n const {\n x: x2\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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__.exportCanvas)(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_33__.muteFSAbortError).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: error.message\n });\n });\n\n if (this.state.exportEmbedScene && fileHandle && (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isImageFileHandle)(fileHandle)) {\n this.setState({\n fileHandle\n });\n }\n });\n\n this.openEyeDropper = ({\n type\n }) => {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_EyeDropper__WEBPACK_IMPORTED_MODULE_59__.activeEyeDropperAtom, {\n swapPreviewOnAlt: true,\n colorPickerType: type === \"stroke\" ? \"elementStroke\" : \"elementBackground\",\n onSelect: (color, event) => {\n const shouldUpdateStrokeColor = type === \"background\" && event.altKey || type === \"stroke\" && !event.altKey;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (!selectedElements.length || this.state.activeTool.type !== \"selection\") {\n if (shouldUpdateStrokeColor) {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemStrokeColor: color\n }),\n commitToHistory: true\n });\n } else {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemBackgroundColor: color\n }),\n commitToHistory: true\n });\n }\n } else {\n this.updateScene({\n elements: this.scene.getElementsIncludingDeleted().map(el => {\n if (this.state.selectedElementIds[el.id]) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(el, {\n [shouldUpdateStrokeColor ? \"strokeColor\" : \"backgroundColor\"]: color\n });\n }\n\n return el;\n })\n });\n }\n },\n keepOpenOnAlt: false\n });\n };\n\n this.syncActionResult = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(actionResult => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n\n if (this.unmounted || actionResult === false) {\n return;\n }\n\n let editingElement = null;\n\n if (actionResult.elements) {\n actionResult.elements.forEach(element => {\n var _a;\n\n if (((_a = this.state.editingElement) === null || _a === void 0 ? void 0 : _a.id) === element.id && this.state.editingElement !== element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n editingElement = element;\n }\n });\n this.scene.replaceAllElements(actionResult.elements);\n\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n }\n\n if (actionResult.files) {\n this.files = actionResult.replaceFiles ? actionResult.files : Object.assign(Object.assign({}, this.files), actionResult.files);\n this.addNewImagesToImageCache();\n }\n\n if (actionResult.appState || editingElement || this.state.contextMenu) {\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n\n let viewModeEnabled = ((_a = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _a === void 0 ? void 0 : _a.viewModeEnabled) || false;\n let zenModeEnabled = ((_b = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _b === void 0 ? void 0 : _b.zenModeEnabled) || false;\n let gridSize = ((_c = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _c === void 0 ? void 0 : _c.gridSize) || null;\n const theme = ((_d = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _d === void 0 ? void 0 : _d.theme) || this.props.theme || _constants__WEBPACK_IMPORTED_MODULE_12__.THEME.LIGHT;\n let name = (_f = (_e = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : this.state.name;\n const errorMessage = (_h = (_g = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _g === void 0 ? void 0 : _g.errorMessage) !== null && _h !== void 0 ? _h : this.state.errorMessage;\n\n if (typeof this.props.viewModeEnabled !== \"undefined\") {\n viewModeEnabled = this.props.viewModeEnabled;\n }\n\n if (typeof this.props.zenModeEnabled !== \"undefined\") {\n zenModeEnabled = this.props.zenModeEnabled;\n }\n\n if (typeof this.props.gridModeEnabled !== \"undefined\") {\n gridSize = this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null;\n }\n\n if (typeof this.props.name !== \"undefined\") {\n name = this.props.name;\n }\n\n editingElement = editingElement || ((_j = actionResult.appState) === null || _j === void 0 ? void 0 : _j.editingElement) || null;\n\n if (editingElement === null || editingElement === void 0 ? void 0 : editingElement.isDeleted) {\n editingElement = null;\n }\n\n this.setState(state => {\n // using Object.assign instead of spread to fool TS 4.2.2+ into\n // regarding the resulting type as not containing undefined\n // (which the following expression will never contain)\n return Object.assign(actionResult.appState || {}, {\n // NOTE this will prevent opening context menu using an action\n // or programmatically from the host, so it will need to be\n // rewritten later\n contextMenu: null,\n editingElement,\n viewModeEnabled,\n zenModeEnabled,\n gridSize,\n theme,\n name,\n errorMessage\n });\n }, () => {\n if (actionResult.syncHistory) {\n this.history.setCurrentState(this.state, this.scene.getElementsIncludingDeleted());\n }\n });\n }\n }); // Lifecycle\n\n this.onBlur = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isHoldingSpace = false;\n this.setState({\n isBindingEnabled: true\n });\n });\n\n this.onUnload = () => {\n this.onBlur();\n };\n\n this.disableEvent = event => {\n event.preventDefault();\n };\n\n this.resetHistory = () => {\n this.history.clear();\n };\n /**\n * Resets scene & history.\n * ! Do not use to clear scene user action !\n */\n\n\n this.resetScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(opts => {\n this.scene.replaceAllElements([]);\n this.setState(state => Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n isLoading: (opts === null || opts === void 0 ? void 0 : opts.resetLoadingState) ? false : state.isLoading,\n theme: this.state.theme\n }));\n this.resetHistory();\n });\n\n this.initializeScene = () => __awaiter(this, void 0, void 0, function* () {\n var _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_29__.calculateScrollCenter)(scene.elements, Object.assign(Object.assign({}, scene.appState), {\n width: this.state.width,\n height: this.state.height,\n offsetTop: this.state.offsetTop,\n offsetLeft: this.state.offsetLeft\n })));\n } // FontFaceSet loadingdone event we listen on may not always fire\n // (looking at you Safari), so on init we manually load fonts for current\n // text elements on canvas, and rerender them once done. This also\n // seems faster even in browsers that do fire the loadingdone event.\n\n\n this.fonts.loadFontsForElements(scene.elements);\n this.resetHistory();\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n commitToHistory: true\n }));\n });\n\n this.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_33__.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_33__.withBatchedUpdates)(() => {\n this.scene.getElementsIncludingDeleted().forEach(element => _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__.ShapeCache[\"delete\"](element));\n this.setState({});\n });\n\n this.renderInteractiveSceneCallback = ({\n atLeastOneVisibleElement,\n scrollBars,\n elements\n }) => {\n if (scrollBars) {\n currentScrollBars = scrollBars;\n }\n\n const scrolledOutside = // hide when editing text\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? false : !atLeastOneVisibleElement && elements.length > 0;\n\n if (this.state.scrolledOutside !== scrolledOutside) {\n this.setState({\n scrolledOutside\n });\n }\n\n this.scheduleImageRefresh();\n };\n\n this.onScroll = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n const {\n offsetTop,\n offsetLeft\n } = this.getCanvasOffsets();\n this.setState(state => {\n if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {\n return null;\n }\n\n return {\n offsetTop,\n offsetLeft\n };\n });\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.SCROLL_TIMEOUT); // Copy/paste\n\n this.onCut = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.cutAll();\n event.preventDefault();\n event.stopPropagation();\n });\n this.onCopy = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.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_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n };\n\n this.onTouchEnd = event => {\n this.resetContextMenuTimer();\n\n if (event.touches.length > 0) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n } else {\n gesture.pointers.clear();\n }\n };\n\n this.pasteFromClipboard = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => __awaiter(this, void 0, void 0, function* () {\n var _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_33__.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_39__.SVGStringToFile)(string);\n }\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state); // prefer spreadsheet data over image file (MS Office/Libre Office)\n\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.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_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n });\n return;\n }\n\n if (this.props.onPaste) {\n try {\n if ((yield this.props.onPaste(data, event)) === false) {\n return;\n }\n } catch (error) {\n console.error(error);\n }\n }\n\n if (data.errorMessage) {\n this.setState({\n errorMessage: data.errorMessage\n });\n } else if (data.spreadsheet && !isPlainPaste) {\n this.setState({\n pasteDialog: {\n data: data.spreadsheet,\n shown: true\n }\n });\n } else if (data.elements) {\n const elements = data.programmaticAPI ? (0,_data_transform__WEBPACK_IMPORTED_MODULE_60__.convertToExcalidrawElements)(data.elements) : data.elements; // TODO remove formatting from elements if isPlainPaste\n\n this.addElementsFromPasteOrLibrary({\n elements,\n files: data.files || null,\n position: \"cursor\",\n retainSeed: isPlainPaste\n });\n } else if (data.text) {\n const maybeUrl = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.extractSrc)(data.text);\n\n if (!isPlainPaste && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(maybeUrl, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(maybeUrl) || ((_e = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.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_46__.normalizeLink)(maybeUrl)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n\n return;\n }\n\n this.addTextFromPaste(data.text, isPlainPaste);\n }\n\n this.setActiveTool({\n type: \"selection\"\n });\n event === null || event === void 0 ? void 0 : event.preventDefault();\n }));\n\n this.addElementsFromPasteOrLibrary = opts => {\n const elements = (0,_data_restore__WEBPACK_IMPORTED_MODULE_15__.restoreElements)(opts.elements, null, undefined);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(elements);\n const elementsCenterX = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minX, maxX) / 2;\n const elementsCenterY = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minY, maxY) / 2;\n const clientX = typeof opts.position === \"object\" ? opts.position.clientX : opts.position === \"cursor\" ? this.lastViewportPosition.x : this.state.width / 2 + this.state.offsetLeft;\n const clientY = typeof opts.position === \"object\" ? opts.position.clientY : opts.position === \"cursor\" ? this.lastViewportPosition.y : this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const dx = x - elementsCenterX;\n const dy = y - elementsCenterY;\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(dx, dy, this.state.gridSize);\n const newElements = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.duplicateElements)(elements.map(element => {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n x: element.x + gridX - minX,\n y: element.y + gridY - minY\n });\n }), {\n randomizeSeed: !opts.retainSeed\n });\n const nextElements = [...this.scene.getElementsIncludingDeleted(), ...newElements];\n this.scene.replaceAllElements(nextElements);\n newElements.forEach(newElement => {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(newElement) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(newElement)) {\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerElement)(newElement);\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.redrawTextBoundingBox)(newElement, container);\n }\n });\n\n if (opts.files) {\n this.files = Object.assign(Object.assign({}, this.files), opts.files);\n }\n\n this.history.resumeRecording();\n const nextElementsToSelect = (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.excludeElementsInFramesFromSelection)(newElements);\n this.setState(Object.assign(Object.assign(Object.assign({}, this.state), {\n // keep sidebar (presumably the library) open if it's docked and\n // can fit.\n //\n // Note, we should close the sidebar only if we're dropping items\n // from library, not when pasting from clipboard. Alas.\n openSidebar: this.state.openSidebar && this.device.canDeviceFitSidebar && _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.get(_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_61__.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_33__.updateActiveTool)(this.state, prevState.activeTool.locked ? {\n type: \"selection\"\n } : prevState.activeTool)), {\n locked: !prevState.activeTool.locked\n })\n };\n });\n };\n\n this.updateFrameRendering = opts => {\n this.setState(prevState => {\n var _a, _b, _c, _d;\n\n const next = typeof opts === \"function\" ? opts(prevState.frameRendering) : opts;\n return {\n frameRendering: {\n enabled: (_a = next === null || next === void 0 ? void 0 : next.enabled) !== null && _a !== void 0 ? _a : prevState.frameRendering.enabled,\n clip: (_b = next === null || next === void 0 ? void 0 : next.clip) !== null && _b !== void 0 ? _b : prevState.frameRendering.clip,\n name: (_c = next === null || next === void 0 ? void 0 : next.name) !== null && _c !== void 0 ? _c : prevState.frameRendering.name,\n outline: (_d = next === null || next === void 0 ? void 0 : next.outline) !== null && _d !== void 0 ? _d : prevState.frameRendering.outline\n }\n };\n });\n };\n\n this.togglePenMode = () => {\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_54__.actionToggleHandTool);\n };\n /**\n * Zooms on canvas viewport center\n */\n\n\n this.zoomCanvas = (\n /** decimal fraction between 0.1 (10% zoom) and 30 (3000% zoom) */\n value) => {\n this.setState(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.state.width / 2 + this.state.offsetLeft,\n viewportY: this.state.height / 2 + this.state.offsetTop,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(value)\n }, this.state)));\n };\n\n this.cancelInProgresAnimation = null;\n\n this.scrollToContent = (target = this.scene.getNonDeletedElements(), opts) => {\n var _a, _b;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this); // convert provided target into ExcalidrawElement[] if necessary\n\n const targetElements = Array.isArray(target) ? target : [target];\n let zoom = this.state.zoom;\n let scrollX = this.state.scrollX;\n let scrollY = this.state.scrollY;\n\n if ((opts === null || opts === void 0 ? void 0 : opts.fitToContent) || (opts === null || opts === void 0 ? void 0 : opts.fitToViewport)) {\n const {\n appState\n } = (0,_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.zoomToFit)({\n targetElements,\n appState: this.state,\n fitToViewport: !!(opts === null || opts === void 0 ? void 0 : opts.fitToViewport),\n viewportZoomFactor: opts === null || opts === void 0 ? void 0 : opts.viewportZoomFactor\n });\n zoom = appState.zoom;\n scrollX = appState.scrollX;\n scrollY = appState.scrollY;\n } else {\n // compute only the viewport location, without any zoom adjustment\n const scroll = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(targetElements, this.state);\n scrollX = scroll.scrollX;\n scrollY = scroll.scrollY;\n } // when animating, we use RequestAnimationFrame to prevent the animation\n // from slowing down other processes\n\n\n if (opts === null || opts === void 0 ? void 0 : opts.animate) {\n const origScrollX = this.state.scrollX;\n const origScrollY = this.state.scrollY;\n const origZoom = this.state.zoom.value;\n const cancel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeToValuesRAF)({\n fromValues: {\n scrollX: origScrollX,\n scrollY: origScrollY,\n zoom: origZoom\n },\n toValues: {\n scrollX,\n scrollY,\n zoom: zoom.value\n },\n interpolateValue: (from, to, progress, key) => {\n // for zoom, use different easing\n if (key === \"zoom\") {\n return from * Math.pow(to / from, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeOut)(progress));\n } // handle using default\n\n\n return undefined;\n },\n onStep: ({\n scrollX,\n scrollY,\n zoom\n }) => {\n this.setState({\n scrollX,\n scrollY,\n zoom: {\n value: zoom\n }\n });\n },\n onStart: () => {\n this.setState({\n shouldCacheIgnoreZoom: true\n });\n },\n onEnd: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n onCancel: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n duration: (_b = opts === null || opts === void 0 ? void 0 : opts.duration) !== null && _b !== void 0 ? _b : 500\n });\n\n this.cancelInProgresAnimation = () => {\n cancel();\n this.cancelInProgresAnimation = null;\n };\n } else {\n this.setState({\n scrollX,\n scrollY,\n zoom\n });\n }\n };\n /** use when changing scrollX/scrollY/zoom based on user interaction */\n\n\n this.translateCanvas = state => {\n var _a;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this);\n this.setState(state);\n };\n\n this.setToast = toast => {\n this.setState({\n toast\n });\n };\n\n this.restoreFileFromShare = () => __awaiter(this, void 0, void 0, function* () {\n try {\n const webShareTargetCache = yield caches.open(\"web-share-target\");\n const response = yield webShareTargetCache.match(\"shared-file\");\n\n if (response) {\n const blob = yield response.blob();\n const file = new File([blob], blob.name || \"\", {\n type: blob.type\n });\n this.loadFileToCanvas(file, null);\n yield webShareTargetCache.delete(\"shared-file\");\n window.history.replaceState(null, _constants__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, window.location.pathname);\n }\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n });\n /** adds supplied files to existing files in the appState */\n\n\n this.addFiles = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(files => {\n const filesMap = files.reduce((acc, fileData) => {\n acc.set(fileData.id, fileData);\n return acc;\n }, new Map());\n this.files = Object.assign(Object.assign({}, this.files), Object.fromEntries(filesMap));\n this.scene.getNonDeletedElements().forEach(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && filesMap.has(element.fileId)) {\n this.imageCache.delete(element.fileId);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__.ShapeCache[\"delete\"](element);\n }\n });\n this.scene.informMutation();\n this.addNewImagesToImageCache();\n });\n this.updateScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(sceneData => {\n if (sceneData.commitToHistory) {\n this.history.resumeRecording();\n }\n\n if (sceneData.appState) {\n this.setState(sceneData.appState);\n }\n\n if (sceneData.elements) {\n this.scene.replaceAllElements(sceneData.elements);\n }\n\n if (sceneData.collaborators) {\n this.setState({\n collaborators: sceneData.collaborators\n });\n }\n });\n\n this.onSceneUpdated = () => {\n this.setState({});\n };\n /**\n * @returns whether the menu was toggled on or off\n */\n\n\n this.toggleSidebar = ({\n name,\n tab,\n force\n }) => {\n var _a;\n\n let nextName;\n\n if (force === undefined) {\n nextName = ((_a = this.state.openSidebar) === null || _a === void 0 ? void 0 : _a.name) === name ? null : name;\n } else {\n nextName = force ? name : null;\n }\n\n this.setState({\n openSidebar: nextName ? {\n name: nextName,\n tab\n } : null\n });\n return !!nextName;\n };\n\n this.updateCurrentCursorPosition = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n this.lastViewportPosition.x = event.clientX;\n this.lastViewportPosition.y = event.clientY;\n }); // Input handling\n\n this.onKeyDown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // normalize `event.key` when CapsLock is pressed #2372\n if (\"Proxy\" in window && (!event.shiftKey && /^[A-Z]$/.test(event.key) || event.shiftKey && /^[a-z]$/.test(event.key))) {\n event = new Proxy(event, {\n get(ev, prop) {\n const value = ev[prop];\n\n if (typeof value === \"function\") {\n // fix for Proxies hijacking `this`\n return value.bind(ev);\n }\n\n return prop === \"key\" ? // CapsLock inverts capitalization based on ShiftKey, so invert\n // it back\n event.shiftKey ? ev.key.toUpperCase() : ev.key.toLowerCase() : value;\n }\n\n });\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.V) {\n IS_PLAIN_PASTE = event.shiftKey;\n clearTimeout(IS_PLAIN_PASTE_TIMER); // reset (100ms to be safe that we it runs after the ensuing\n // paste event). Though, technically unnecessary to reset since we\n // (re)set the flag before each paste event.\n\n IS_PLAIN_PASTE_TIMER = window.setTimeout(() => {\n IS_PLAIN_PASTE = false;\n }, 100);\n } // prevent browser zoom in input fields\n\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n if (event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.MINUS || event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.EQUAL) {\n event.preventDefault();\n return;\n }\n } // bail if\n\n\n if ( // inside an input\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target) && // unless pressing escape (finalize action)\n event.key !== _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ESCAPE || // or unless using arrows (to move between buttons)\n (0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key) && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isInputLike)(event.target)) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.QUESTION_MARK) {\n this.setState({\n openDialog: \"help\"\n });\n return;\n } else if (event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.E && event.shiftKey && event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n event.preventDefault();\n this.setState({\n openDialog: \"imageExport\"\n });\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_UP || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n let offset = (event.shiftKey ? this.state.width : this.state.height) / this.state.zoom.value;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n offset = -offset;\n }\n\n if (event.shiftKey) {\n this.translateCanvas(state => ({\n scrollX: state.scrollX + offset\n }));\n } else {\n this.translateCanvas(state => ({\n scrollY: state.scrollY + offset\n }));\n }\n }\n\n if (this.actionManager.handleKeyDown(event)) {\n return;\n }\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: false\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const step = this.state.gridSize && (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize) || (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_SHIFT_TRANSLATE_AMOUNT : _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT);\n let offsetX = 0;\n let offsetY = 0;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_LEFT) {\n offsetX = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_RIGHT) {\n offsetX = step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_UP) {\n offsetY = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_DOWN) {\n offsetY = step;\n }\n\n const selectedElements = this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n });\n selectedElements.forEach(element => {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: element.x + offsetX,\n y: element.y + offsetY\n });\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element, {\n simultaneouslyUpdated: selectedElements\n });\n });\n this.maybeSuggestBindingForAll(selectedElements);\n event.preventDefault();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ENTER) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n const selectedElement = selectedElements[0];\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElement)) {\n if (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElement, this.scene)\n });\n }\n }\n } else if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isValidTextContainer)(selectedElement)) {\n let container;\n\n if (!(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement)) {\n container = selectedElement;\n }\n\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(selectedElement, this.state);\n const sceneX = midPoint.x;\n const sceneY = midPoint.y;\n this.startTextEditing({\n sceneX,\n sceneY,\n container\n });\n event.preventDefault();\n return;\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(selectedElement)) {\n this.setState({\n editingFrame: selectedElement.id\n });\n }\n }\n } else if (!event.ctrlKey && !event.altKey && !event.metaKey && this.state.draggingElement === null) {\n const shape = (0,_shapes__WEBPACK_IMPORTED_MODULE_32__.findShapeByKey)(event.key);\n\n if (shape) {\n if (this.state.activeTool.type !== shape) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", shape, `keyboard (${this.device.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n event.preventDefault();\n }\n\n if ((event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (this.state.activeTool.type === \"selection\" && !selectedElements.length) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && ((0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(this.state.activeTool.type) || selectedElements.some(element => (0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(element.type)))) {\n this.setState({\n openPopup: \"elementBackground\"\n });\n event.stopPropagation();\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) {\n this.setState({\n openPopup: \"elementStroke\"\n });\n event.stopPropagation();\n }\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.BACKSPACE || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.DELETE)) {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__.activeConfirmDialogAtom, \"clearCanvas\");\n } // eye dropper\n // -----------------------------------------------------------------------\n\n\n const lowerCased = event.key.toLocaleLowerCase();\n const isPickingStroke = lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S && event.shiftKey;\n const isPickingBackground = event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.I || lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && event.shiftKey;\n\n if (isPickingStroke || isPickingBackground) {\n this.openEyeDropper({\n type: isPickingStroke ? \"stroke\" : \"background\"\n });\n } // -----------------------------------------------------------------------\n\n });\n this.onWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // prevent browser pinch zoom on DOM elements\n if (!(event.target instanceof HTMLCanvasElement) && event.ctrlKey) {\n event.preventDefault();\n }\n });\n this.onKeyUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE) {\n if (this.state.viewModeEnabled) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n isHoldingSpace = false;\n }\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: true\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements)(selectedElements) : (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(selectedElements);\n this.setState({\n suggestedBindings: []\n });\n }\n });\n\n this.setActiveTool = tool => {\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, tool);\n\n if (nextActiveTool.type === \"hand\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (!isHoldingSpace) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_33__.isToolIcon)(document.activeElement)) {\n this.focusContainer();\n }\n\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElementType)(nextActiveTool.type)) {\n this.setState({\n suggestedBindings: []\n });\n }\n\n if (nextActiveTool.type === \"image\") {\n this.onImageAction();\n }\n\n if (nextActiveTool.type !== \"selection\") {\n this.setState({\n activeTool: nextActiveTool,\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n } else {\n this.setState({\n activeTool: nextActiveTool,\n activeEmbeddable: null\n });\n }\n };\n\n this.setCursor = cursor => {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, cursor);\n };\n\n this.resetCursor = () => {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n };\n /**\n * returns whether user is making a gesture with >= 2 fingers (points)\n * on o touch screen (not on a trackpad). Currently only relates to Darwin\n * (iOS/iPadOS,MacOS), but may work on other devices in the future if\n * GestureEvent is standardized.\n */\n\n\n this.isTouchScreenMultiTouchGesture = () => {\n // we don't want to deselect when using trackpad, and multi-point gestures\n // only work on touch screens, so checking for >= pointers means we're on a\n // touchscreen\n return gesture.pointers.size >= 2;\n }; // fires only on Safari\n\n\n this.onGestureStart = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // we only want to deselect on touch screens because user may have selected\n // elements by mistake while zooming\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n\n gesture.initialScale = this.state.zoom.value;\n }); // fires only on Safari\n\n this.onGestureChange = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // onGestureChange only has zoom factor but not the center.\n // If we're on iPad or iPhone, then we recognize multi-touch and will\n // zoom in at the right location in the touchmove handler\n // (handleCanvasPointerMove).\n //\n // On Macbook trackpad, we don't have those events so will zoom in at the\n // current location instead.\n //\n // As such, bail from this handler on touch devices.\n\n if (this.isTouchScreenMultiTouchGesture()) {\n return;\n }\n\n const initialScale = gesture.initialScale;\n\n if (initialScale) {\n this.setState(state => Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * event.scale)\n }, state)));\n }\n }); // fires only on Safari\n\n this.onGestureEnd = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // reselect elements only on touch screens (see onGestureStart)\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n }\n\n gesture.initialScale = null;\n });\n\n this.startTextEditing = ({\n sceneX,\n sceneY,\n insertAtParentCenter = true,\n container\n }) => {\n var _a, _b;\n\n let shouldBindToContainer = false;\n let parentCenterPosition = insertAtParentCenter && this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n\n if (container && parentCenterPosition) {\n const boundTextElementToContainer = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(container);\n\n if (!boundTextElementToContainer) {\n shouldBindToContainer = true;\n }\n }\n\n let existingTextElement = null;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElements[0])) {\n existingTextElement = selectedElements[0];\n } else if (container) {\n existingTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(selectedElements[0]);\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n\n const fontFamily = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.fontFamily) || this.state.currentItemFontFamily;\n const lineHeight = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.lineHeight) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(fontFamily);\n const fontSize = this.state.currentItemFontSize;\n\n if (!existingTextElement && shouldBindToContainer && container && !(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isArrowElement)(container)) {\n const fontString = {\n fontSize,\n fontFamily\n };\n const minWidth = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineWidth)((0,_utils__WEBPACK_IMPORTED_MODULE_33__.getFontString)(fontString), lineHeight);\n const minHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineHeight)(fontSize, lineHeight);\n const newHeight = Math.max(container.height, minHeight);\n const newWidth = Math.max(container.width, minWidth);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n height: newHeight,\n width: newWidth\n });\n sceneX = container.x + newWidth / 2;\n sceneY = container.y + newHeight / 2;\n\n if (parentCenterPosition) {\n parentCenterPosition = this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n }\n }\n\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: sceneX,\n y: sceneY\n });\n const element = existingTextElement ? existingTextElement : (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)({\n x: parentCenterPosition ? parentCenterPosition.elementCenterX : sceneX,\n y: parentCenterPosition ? parentCenterPosition.elementCenterY : sceneY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text: \"\",\n fontSize,\n fontFamily,\n textAlign: parentCenterPosition ? \"center\" : this.state.currentItemTextAlign,\n verticalAlign: parentCenterPosition ? _constants__WEBPACK_IMPORTED_MODULE_12__.VERTICAL_ALIGN.MIDDLE : _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n containerId: shouldBindToContainer ? container === null || container === void 0 ? void 0 : container.id : undefined,\n groupIds: (_a = container === null || container === void 0 ? void 0 : container.groupIds) !== null && _a !== void 0 ? _a : [],\n lineHeight,\n angle: (_b = container === null || container === void 0 ? void 0 : container.angle) !== null && _b !== void 0 ? _b : 0,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n\n if (!existingTextElement && shouldBindToContainer && container) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n boundElements: (container.boundElements || []).concat({\n type: \"text\",\n id: element.id\n })\n });\n }\n\n this.setState({\n editingElement: element\n });\n\n if (!existingTextElement) {\n if (container && shouldBindToContainer) {\n const containerIndex = this.scene.getElementIndex(container.id);\n this.scene.insertElementAtIndex(element, containerIndex + 1);\n } else {\n this.scene.addNewElement(element);\n }\n }\n\n this.setState({\n editingElement: element\n });\n this.handleTextWysiwyg(element, {\n isExistingElement: !!existingTextElement\n });\n };\n\n this.handleCanvasDoubleClick = event => {\n // case: double-clicking with arrow/line tool selected would both create\n // text and enter multiElement mode\n if (this.state.multiElement) {\n return;\n } // we should only be able to double click when mode is selection\n\n\n if (this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0])) {\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id)) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElements[0], this.scene)\n });\n return;\n } else if (this.state.editingLinearElement && this.state.editingLinearElement.elementId === selectedElements[0].id) {\n return;\n }\n }\n\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n let {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedGroupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIds)(this.state);\n\n if (selectedGroupIds.length > 0) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n const selectedGroupId = hitElement && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIdForElement)(hitElement, this.state.selectedGroupIds);\n\n if (selectedGroupId) {\n this.setState(prevState => Object.assign(Object.assign({}, prevState), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: selectedGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)));\n return;\n }\n }\n\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.viewModeEnabled) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) {\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"active\"\n }\n });\n return;\n }\n\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if (container) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(container) || !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTransparent)(container.backgroundColor) || (0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY])) {\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, this.state);\n sceneX = midPoint.x;\n sceneY = midPoint.y;\n }\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n }\n };\n\n this.getElementLinkAtPosition = (scenePointer, hitElement) => {\n // Reversing so we traverse the elements in decreasing order\n // of z-index\n const elements = this.scene.getNonDeletedElements().slice().reverse();\n let hitElementIndex = Infinity;\n return elements.find((element, index) => {\n if (hitElement && element.id === hitElement.id) {\n hitElementIndex = index;\n }\n\n return element.link && index <= hitElementIndex && (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(element, this.state, [scenePointer.x, scenePointer.y], this.device.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_33__.viewportCoordsToSceneCoords)(this.lastPointerDown, this.state);\n const lastPointerDownHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerDownCoords.x, lastPointerDownCoords.y], this.device.isMobile);\n const lastPointerUpCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerUp, this.state);\n const lastPointerUpHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.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_46__.normalizeLink)(url);\n let customEvent;\n\n if (this.props.onLinkOpen) {\n customEvent = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.wrapEvent)(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.EXCALIDRAW_LINK, event.nativeEvent);\n this.props.onLinkOpen(Object.assign(Object.assign({}, this.hitLinkElement), {\n link: url\n }), customEvent);\n }\n\n if (!(customEvent === null || customEvent === void 0 ? void 0 : customEvent.defaultPrevented)) {\n const target = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.isLocalLink)(url) ? \"_self\" : \"_blank\";\n const newWindow = window.open(undefined, target); // https://mathiasbynens.github.io/rel-noopener/\n\n if (newWindow) {\n newWindow.opener = null;\n newWindow.location = url;\n }\n }\n }\n }\n };\n\n this.getTopLayerFrameAtSceneCoords = sceneCoords => {\n const frames = this.scene.getNonDeletedFrames().filter(frame => (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)(sceneCoords, frame));\n return frames.length ? frames[frames.length - 1] : null;\n };\n\n this.handleCanvasPointerMove = event => {\n var _a, _b;\n\n this.savePointer(event.clientX, event.clientY, this.state.cursorButton);\n\n if (gesture.pointers.has(event.pointerId)) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n }\n\n const initialScale = gesture.initialScale;\n\n if (gesture.pointers.size === 2 && gesture.lastCenter && initialScale && gesture.initialDistance) {\n const center = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n const deltaX = center.x - gesture.lastCenter.x;\n const deltaY = center.y - gesture.lastCenter.y;\n gesture.lastCenter = center;\n const distance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n const scaleFactor = this.state.activeTool.type === \"freedraw\" && this.state.penMode ? 1 : distance / gesture.initialDistance;\n const nextZoom = scaleFactor ? (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * scaleFactor) : this.state.zoom.value;\n this.setState(state => {\n const zoomState = (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: center.x,\n viewportY: center.y,\n nextZoom\n }, state);\n this.translateCanvas({\n zoom: zoomState.zoom,\n scrollX: zoomState.scrollX + deltaX / nextZoom,\n scrollY: zoomState.scrollY + deltaY / nextZoom,\n shouldCacheIgnoreZoom: true\n });\n });\n this.resetShouldCacheIgnoreZoomDebounced();\n } else {\n gesture.lastCenter = gesture.initialDistance = gesture.initialScale = null;\n }\n\n if (isHoldingSpace || isPanning || isDraggingScrollBar || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state)) {\n return;\n }\n\n const isPointerOverScrollBars = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop);\n const isOverScrollBar = isPointerOverScrollBars.isOverEither;\n\n if (!this.state.draggingElement && !this.state.multiElement) {\n if (isOverScrollBar) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const {\n x: scenePointerX,\n y: scenePointerY\n } = scenePointer;\n\n if (this.state.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_33__.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_33__.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_33__.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_33__.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_33__.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_33__.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.showHyperlinkTooltip)(this.hitLinkElement, this.state);\n } else {\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.hideHyperlinkToolip)();\n\n if (hitElement && (hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) && this.state.selectedElementIds[hitElement.id] && !this.state.contextMenu && !this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: \"info\"\n });\n } else if (this.state.activeTool.type === \"text\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (isOverScrollBar) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.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_33__.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_33__.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 this.updateGestureOnPointerDown(event); // if dragging element is freedraw and another pointerdown event occurs\n // a second finger is on the screen\n // discard the freedraw element if it is very short because it is likely\n // just a spike, otherwise finalize the freedraw element when the second\n // finger is lifted\n\n if (event.pointerType === \"touch\" && this.state.draggingElement && this.state.draggingElement.type === \"freedraw\") {\n const element = this.state.draggingElement;\n this.updateScene(Object.assign(Object.assign({}, element.points.length < 10 ? {\n elements: this.scene.getElementsIncludingDeleted().filter(el => el.id !== element.id)\n } : {}), {\n appState: {\n draggingElement: null,\n editingElement: null,\n startBoundElement: null,\n suggestedBindings: [],\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.keys(this.state.selectedElementIds).filter(key => key !== element.id).reduce((obj, key) => {\n obj[key] = this.state.selectedElementIds[key];\n return obj;\n }, {}), this.state)\n }\n }));\n return;\n } // remove any active selection when we start to interact with canvas\n // (mainly, we care about removing selection outside the component which\n // would prevent our copy handling otherwise)\n\n\n const selection = document.getSelection();\n\n if (selection === null || selection === void 0 ? void 0 : selection.anchorNode) {\n selection.removeAllRanges();\n }\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices(event);\n this.maybeCleanupAfterMissingPointerUp(event); //fires only once, if pen is detected, penMode is enabled\n //the user can disable this by toggling the penMode button\n\n if (!this.state.penDetected && event.pointerType === \"pen\") {\n this.setState(prevState => {\n return {\n penMode: true,\n penDetected: true\n };\n });\n }\n\n if (!this.device.isTouchScreen && [\"pen\", \"touch\"].includes(event.pointerType)) {\n this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(this.device, {\n isTouchScreen: true\n });\n }\n\n if (isPanning) {\n return;\n }\n\n this.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.CROSSHAIR); // retrieve the latest element as the state may be stale\n\n const pendingImageElement = this.state.pendingImageElementId && this.scene.getElement(this.state.pendingImageElementId);\n\n if (!pendingImageElement) {\n return;\n }\n\n this.setState({\n draggingElement: pendingImageElement,\n editingElement: pendingImageElement,\n pendingImageElementId: null,\n multiElement: null\n });\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n (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 (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\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 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_33__.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_45__.isPointHittingLinkIcon)(this.hitLinkElement, this.state, [scenePointer.x, scenePointer.y])) {\n this.handleEmbeddableCenterClick(this.hitLinkElement);\n } else {\n this.redirectToLink(event, this.device.isTouchScreen);\n }\n } else if (this.state.viewModeEnabled) {\n this.setState({\n activeEmbeddable: null,\n selectedElementIds: {}\n });\n }\n };\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices = event => {\n // deal with opening context menu on touch devices\n if (event.pointerType === \"touch\") {\n invalidateContextMenu = false;\n\n if (touchTimeout) {\n // If there's already a touchTimeout, this means that there's another\n // touch down and we are doing another touch, so we shouldn't open the\n // context menu.\n invalidateContextMenu = true;\n } else {\n // open the context menu with the first touch's clientX and clientY\n // if the touch is not moving\n touchTimeout = window.setTimeout(() => {\n touchTimeout = 0;\n\n if (!invalidateContextMenu) {\n this.handleCanvasContextMenu(event);\n }\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.TOUCH_CTX_MENU_TIMEOUT);\n }\n }\n };\n\n this.resetContextMenuTimer = () => {\n clearTimeout(touchTimeout);\n touchTimeout = 0;\n invalidateContextMenu = false;\n }; // Returns whether the event is a panning\n\n\n this.handleCanvasPanUsingWheelOrSpaceDrag = event => {\n if (!(gesture.pointers.size <= 1 && (event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.WHEEL || event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && isHoldingSpace || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state) || this.state.viewModeEnabled)) || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement)) {\n return false;\n }\n\n isPanning = true;\n event.preventDefault();\n let nextPastePrevented = false;\n const isLinux = /Linux/.test(window.navigator.platform);\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRABBING);\n let {\n clientX: lastX,\n clientY: lastY\n } = event;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const deltaX = lastX - event.clientX;\n const deltaY = lastY - event.clientY;\n lastX = event.clientX;\n lastY = event.clientY;\n /*\n * Prevent paste event if we move while middle clicking on Linux.\n * See issue #1383.\n */\n\n if (isLinux && !nextPastePrevented && (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1)) {\n nextPastePrevented = true;\n /* Prevent the next paste event */\n\n const preventNextPaste = event => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n event.stopPropagation();\n };\n /*\n * Reenable next paste in case of disabled middle click paste for\n * any reason:\n * - right click paste\n * - empty clipboard\n */\n\n\n const enableNextPaste = () => {\n setTimeout(() => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }, 100);\n };\n\n document.body.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }\n\n this.translateCanvas({\n scrollX: this.state.scrollX - deltaX / this.state.zoom.value,\n scrollY: this.state.scrollY - deltaY / this.state.zoom.value\n });\n });\n const teardown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(lastPointerUp = () => {\n lastPointerUp = null;\n isPanning = false;\n\n if (!isHoldingSpace) {\n if (this.state.viewModeEnabled) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n this.setState({\n cursorButton: \"up\"\n });\n this.savePointer(event.clientX, event.clientY, \"up\");\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, teardown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, teardown);\n onPointerMove.flush();\n });\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, teardown);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove, {\n passive: true\n });\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, teardown);\n return true;\n };\n\n this.clearSelectionIfNotUsingSelection = () => {\n if (this.state.activeTool.type !== \"selection\") {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n };\n /**\n * @returns whether the pointer event has been completely handled\n */\n\n\n this.handleSelectionOnPointerDown = (event, pointerDownState) => {\n var _a;\n\n if (this.state.activeTool.type === \"selection\") {\n const elements = this.scene.getNonDeletedElements();\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && !this.state.editingLinearElement) {\n const elementWithTransformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getElementWithTransformHandleType)(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);\n\n if (elementWithTransformHandleType != null) {\n this.setState({\n resizingElement: elementWithTransformHandleType.element\n });\n pointerDownState.resize.handleType = elementWithTransformHandleType.transformHandleType;\n }\n } else if (selectedElements.length > 1) {\n pointerDownState.resize.handleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getTransformHandleTypeFromCoords)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);\n }\n\n if (pointerDownState.resize.handleType) {\n pointerDownState.resize.isResizing = true;\n pointerDownState.resize.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getResizeOffsetXY)(pointerDownState.resize.handleType, selectedElements, pointerDownState.origin.x, pointerDownState.origin.y));\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0]) && selectedElements[0].points.length === 2) {\n pointerDownState.resize.arrowDirection = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getResizeArrowDirection)(pointerDownState.resize.handleType, selectedElements[0]);\n }\n } else {\n if (this.state.selectedLinearElement) {\n const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;\n const ret = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerDown(event, this.state, this.history, pointerDownState.origin, linearElementEditor);\n\n if (ret.hitElement) {\n pointerDownState.hit.element = ret.hitElement;\n }\n\n if (ret.linearElementEditor) {\n this.setState({\n selectedLinearElement: ret.linearElementEditor\n });\n\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: ret.linearElementEditor\n });\n }\n }\n\n if (ret.didAddPoint) {\n return true;\n }\n } // hitElement may already be set above, so check first\n\n\n pointerDownState.hit.element = (_a = pointerDownState.hit.element) !== null && _a !== void 0 ? _a : this.getElementAtPosition(pointerDownState.origin.x, pointerDownState.origin.y);\n\n if (pointerDownState.hit.element) {\n // Early return if pointer is hitting link icon\n const hitLinkElement = this.getElementLinkAtPosition({\n x: pointerDownState.origin.x,\n y: pointerDownState.origin.y\n }, pointerDownState.hit.element);\n\n if (hitLinkElement) {\n return false;\n }\n } // For overlapped elements one position may hit\n // multiple elements\n\n\n pointerDownState.hit.allHitElements = this.getElementsAtPosition(pointerDownState.origin.x, pointerDownState.origin.y);\n const hitElement = pointerDownState.hit.element;\n const someHitElementIsSelected = pointerDownState.hit.allHitElements.some(element => this.isASelectedElement(element));\n\n if ((hitElement === null || !someHitElementIsSelected) && !event.shiftKey && !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) {\n this.clearSelection(hitElement);\n }\n\n if (this.state.editingLinearElement) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [this.state.editingLinearElement.elementId]: true\n }, this.state)\n }); // If we click on something\n } else if (hitElement != null) {\n // on CMD/CTRL, drill down to hit element regardless of groups etc.\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if (!this.state.selectedElementIds[hitElement.id]) {\n pointerDownState.hit.wasAddedToSelection = true;\n }\n\n this.setState(prevState => Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.editGroupForSelectedElement)(prevState, hitElement)), {\n previousSelectedElementIds: this.state.selectedElementIds\n })); // mark as not completely handled so as to allow dragging etc.\n\n return false;\n } // deselect if item is selected\n // if shift is not clicked, this will always return true\n // otherwise, it will trigger selection based on current\n // state of the box\n\n\n if (!this.state.selectedElementIds[hitElement.id]) {\n // if we are currently editing a group, exiting editing mode and deselect the group.\n if (this.state.editingGroupId && !(0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, this.state.editingGroupId)) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n } // Add hit element to selection. At this point if we're not holding\n // SHIFT the previously selected element(s) were deselected above\n // (make sure you use setState updater to use latest state)\n // With shift-selection, we want to make sure that frames and their containing\n // elements are not selected at the same time.\n\n\n if (!someHitElementIsSelected && !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) {\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n });\n const previouslySelectedElements = [];\n Object.keys(prevState.selectedElementIds).forEach(id => {\n const element = this.scene.getElement(id);\n element && previouslySelectedElements.push(element);\n }); // if hitElement is frame, deselect all of its elements if they are selected\n\n if (hitElement.type === \"frame\") {\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.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_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(element)) {\n container = element;\n sceneX = element.x + element.width / 2;\n sceneY = element.y + element.height / 2;\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n\n if (!this.state.activeTool.locked) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n };\n\n this.handleFreeDrawElementOnPointerDown = (event, elementType, pointerDownState) => {\n // Begin a mark capture. This does not have to update state yet.\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, null);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFreeDrawElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: null,\n simulatePressure: event.pressure === 0.5,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n const pressures = element.simulatePressure ? element.pressures : [...element.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [[0, 0]],\n pressures\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }; //create rectangle element with youtube top left on nearest grid point width / hight 640/360\n\n\n this.insertEmbeddableElement = ({\n sceneX,\n sceneY,\n link\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.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_34__.getEmbedLink)(link);\n\n if (!embedLink) {\n return;\n }\n\n if (embedLink.warning) {\n this.setToast({\n message: embedLink.warning,\n closable: true\n });\n }\n\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)({\n type: \"embeddable\",\n x: gridX,\n y: gridY,\n strokeColor: \"transparent\",\n backgroundColor: \"transparent\",\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n roundness: this.getCurrentItemRoundness(\"embeddable\"),\n opacity: this.state.currentItemOpacity,\n locked: false,\n width: embedLink.aspectRatio.w,\n height: embedLink.aspectRatio.h,\n link,\n validated: null\n });\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), element]);\n return element;\n };\n\n this.createImageElement = ({\n sceneX,\n sceneY\n }) => {\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_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [multiElement.id]: true\n }), prevState)\n })); // clicking outside commit zone → update reference for last committed\n // point\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n lastCommittedPoint: multiElement.points[multiElement.points.length - 1]\n });\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.\n If so, we want it to be null for start and \"arrow\" for end. If the linear item is not\n an arrow, we want it to be null for both. Otherwise, we want it to use the\n values from appState. */\n\n const {\n currentItemStartArrowhead,\n currentItemEndArrowhead\n } = this.state;\n const [startArrowhead, endArrowhead] = elementType === \"arrow\" ? [currentItemStartArrowhead, currentItemEndArrowhead] : [null, null];\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newLinearElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.state.currentItemRoundness === \"round\" ? {\n type: _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null,\n startArrowhead,\n endArrowhead,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [...element.points, [0, 0]]\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }\n };\n\n this.createGenericElementOnPointerDown = (elementType, pointerDownState) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.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_39__.isSupportedImageFile)(imageFile)) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.unsupportedFileType\"));\n }\n\n const mimeType = imageFile.type;\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, \"wait\");\n\n if (mimeType === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n try {\n imageFile = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.normalizeSVG)(yield imageFile.text()), imageFile.name);\n } catch (error) {\n console.warn(error);\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.svgImageInsertError\"));\n }\n } // generate image id (by default the file digest) before any\n // resizing/compression takes place to keep it more portable\n\n\n const fileId = yield ((_g = (_f = this.props).generateIdForFile) === null || _g === void 0 ? void 0 : _g.call(_f, imageFile)) || (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.generateIdFromFile)(imageFile);\n\n if (!fileId) {\n console.warn(\"Couldn't generate file id or the supplied `generateIdForFile` didn't resolve to one.\");\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\"));\n }\n\n const existingFileData = this.files[fileId];\n\n if (!(existingFileData === null || existingFileData === void 0 ? void 0 : existingFileData.dataURL)) {\n try {\n imageFile = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT\n });\n } catch (error) {\n console.error(\"error trying to resing image file on insertion\", error);\n }\n\n if (imageFile.size > _constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.fileTooBig\", {\n maxSize: `${Math.trunc(_constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES / 1024 / 1024)}MB`\n }));\n }\n }\n\n if (showCursorImagePreview) {\n const dataURL = (_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_39__.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_39__.getDataURL)(imageFile));\n const imageElement = (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(_imageElement, {\n fileId\n }, false);\n return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {\n var _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_33__.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_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: cursorImageSizePx\n });\n let previewDataURL = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imagePreview); // SVG cannot be resized via `resizeImageFile` so we resize by rendering to\n // a small canvas\n\n if (imageFile.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n const img = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.loadHTMLImageElement)(previewDataURL);\n let height = Math.min(img.height, cursorImageSizePx);\n let width = height * (img.width / img.height);\n\n if (width > cursorImageSizePx) {\n width = cursorImageSizePx;\n height = width * (img.height / img.width);\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.height = height;\n canvas.width = width;\n const context = canvas.getContext(\"2d\");\n context.drawImage(img, 0, 0, width, height);\n previewDataURL = canvas.toDataURL(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg);\n }\n\n if (this.state.pendingImageElementId) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const imageFile = yield (0,_data_filesystem__WEBPACK_IMPORTED_MODULE_42__.fileOpen)({\n description: \"Image\",\n extensions: Object.keys(_constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_MIME_TYPES)\n });\n const imageElement = this.createImageElement({\n sceneX: x,\n sceneY: y\n });\n\n if (insertOnCanvasDirectly) {\n this.insertImageElement(imageElement, imageFile);\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } else {\n this.setState({\n pendingImageElementId: imageElement.id\n }, () => {\n this.insertImageElement(imageElement, imageFile,\n /* showCursorImagePreview */\n true);\n });\n }\n } catch (error) {\n if (error.name !== \"AbortError\") {\n console.error(error);\n } else {\n console.warn(error);\n }\n\n this.setState({\n pendingImageElementId: null,\n editingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n }\n });\n\n this.initializeImageDimensions = (imageElement, forceNaturalSize = false) => {\n var _a;\n\n const image = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(imageElement) && ((_a = this.imageCache.get(imageElement.fileId)) === null || _a === void 0 ? void 0 : _a.image);\n\n if (!image || image instanceof Promise) {\n if (imageElement.width < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value && imageElement.height < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value) {\n const placeholderSize = 100 / this.state.zoom.value;\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n x: imageElement.x - placeholderSize / 2,\n y: imageElement.y - placeholderSize / 2,\n width: placeholderSize,\n height: placeholderSize\n });\n }\n\n return;\n }\n\n if (forceNaturalSize || // if user-created bounding box is below threshold, assume the\n // intention was to click instead of drag, and use the image's\n // intrinsic size\n imageElement.width < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value && imageElement.height < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD / this.state.zoom.value) {\n const minHeight = Math.max(this.state.height - 120, 160); // max 65% of canvas height, clamped to <300px, vh - 120px>\n\n const maxHeight = Math.min(minHeight, Math.floor(this.state.height * 0.5) / this.state.zoom.value);\n const height = Math.min(image.naturalHeight, maxHeight);\n const width = height * (image.naturalWidth / image.naturalHeight); // add current imageElement width/height to account for previous centering\n // of the placeholder image\n\n const x = imageElement.x + imageElement.width / 2 - width / 2;\n const y = imageElement.y + imageElement.height / 2 - height / 2;\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n x,\n y,\n width,\n height\n });\n }\n };\n /** updates image cache, refreshing updated elements and/or setting status\n to error for images that fail during <img> element creation */\n\n\n this.updateImageCache = (elements, files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const {\n updatedFiles,\n erroredFiles\n } = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.updateImageCache)({\n imageCache: this.imageCache,\n fileIds: elements.map(element => element.fileId),\n files\n });\n\n if (updatedFiles.size || erroredFiles.size) {\n for (const element of elements) {\n if (updatedFiles.has(element.fileId)) {\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_64__.ShapeCache[\"delete\"](element);\n }\n }\n }\n\n if (erroredFiles.size) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().map(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && erroredFiles.has(element.fileId)) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n status: \"error\"\n });\n }\n\n return element;\n }));\n }\n\n return {\n updatedFiles,\n erroredFiles\n };\n });\n /** adds new images to imageCache and re-renders if needed */\n\n\n this.addNewImagesToImageCache = (imageElements = (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.getInitializedImageElements)(this.scene.getNonDeletedElements()), files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const uncachedImageElements = imageElements.filter(element => !element.isDeleted && !this.imageCache.has(element.fileId));\n\n if (uncachedImageElements.length) {\n const {\n updatedFiles\n } = yield this.updateImageCache(uncachedImageElements, files);\n\n if (updatedFiles.size) {\n this.scene.informMutation();\n }\n }\n });\n /** generally you should use `addNewImagesToImageCache()` directly if you need\n * to render new images. This is just a failsafe */\n\n\n this.scheduleImageRefresh = lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default()(() => {\n this.addNewImagesToImageCache();\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_RENDER_TIMEOUT);\n\n this.updateBindingEnabledOnPointerMove = event => {\n const shouldEnableBinding = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.shouldEnableBindingForPointerEvent)(event);\n\n if (this.state.isBindingEnabled !== shouldEnableBinding) {\n this.setState({\n isBindingEnabled: shouldEnableBinding\n });\n }\n };\n\n this.maybeSuggestBindingAtCursor = pointerCoords => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerCoords, this.scene);\n this.setState({\n suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : []\n });\n };\n\n this.maybeSuggestBindingsForLinearElementAtCoords = (linearElement,\n /** scene coords */\n pointerCoords, // During line creation the start binding hasn't been written yet\n // into `linearElement`\n oppositeBindingBoundElement) => {\n if (!pointerCoords.length) {\n return;\n }\n\n const suggestedBindings = pointerCoords.reduce((acc, coords) => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(coords, this.scene);\n\n if (hoveredBindableElement != null && !(0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isLinearElementSimpleAndAlreadyBound)(linearElement, oppositeBindingBoundElement === null || oppositeBindingBoundElement === void 0 ? void 0 : oppositeBindingBoundElement.id, hoveredBindableElement)) {\n acc.push(hoveredBindableElement);\n }\n\n return acc;\n }, []);\n this.setState({\n suggestedBindings\n });\n };\n\n this.handleInteractiveCanvasRef = canvas => {\n var _a, _b, _c; // canvas is null when unmounting\n\n\n if (canvas !== null) {\n this.interactiveCanvas = canvas; // -----------------------------------------------------------------------\n // NOTE wheel, touchstart, touchend events must be registered outside\n // of react because react binds them them passively (so we can't prevent\n // default on them)\n\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd); // -----------------------------------------------------------------------\n } else {\n (_a = this.interactiveCanvas) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n (_b = this.interactiveCanvas) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n (_c = this.interactiveCanvas) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd);\n }\n };\n\n this.handleAppOnDrop = event => __awaiter(this, void 0, void 0, function* () {\n var _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_39__.getFileFromEvent)(event);\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n try {\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.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_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n });\n return;\n }\n } catch (error) {\n return this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n\n const libraryJSON = event.dataTransfer.getData(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib);\n\n if (libraryJSON && typeof libraryJSON === \"string\") {\n try {\n const libraryItems = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.parseLibraryJSON)(libraryJSON);\n this.addElementsFromPasteOrLibrary({\n elements: (0,_data_library__WEBPACK_IMPORTED_MODULE_14__.distributeLibraryItemsOnSquareGrid)(libraryItems),\n position: event,\n files: null\n });\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n\n return;\n }\n\n if (file) {\n // atetmpt to parse an excalidraw/excalidrawlib file\n yield this.loadFileToCanvas(file, fileHandle);\n }\n\n if ((_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_34__.embeddableURLValidator)(text, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(text) || ((_p = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.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_46__.normalizeLink)(text)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n }\n }\n });\n\n this.loadFileToCanvas = (file, fileHandle) => __awaiter(this, void 0, void 0, function* () {\n file = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.normalizeFile)(file);\n\n try {\n const ret = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.loadSceneOrLibraryFromBlob)(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);\n\n if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidraw) {\n this.setState({\n isLoading: true\n });\n this.syncActionResult(Object.assign(Object.assign({}, ret.data), {\n appState: Object.assign(Object.assign({}, ret.data.appState || this.state), {\n isLoading: false\n }),\n replaceFiles: true,\n commitToHistory: true\n }));\n } else if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib) {\n yield this.library.updateLibrary({\n libraryItems: file,\n merge: true,\n openLibraryMenu: true\n }).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.importLibraryError\")\n });\n });\n }\n } catch (error) {\n this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n });\n\n this.handleCanvasContextMenu = event => {\n event.preventDefault();\n\n if ((\"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"touch\" || \"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"pen\" && // always allow if user uses a pen secondary button\n event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.SECONDARY) && this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const element = this.getElementAtPosition(x, y, {\n preferSelected: true,\n includeLockedElements: true\n });\n const selectedElements = this.scene.getSelectedElements(this.state);\n const isHittignCommonBoundBox = this.isHittingCommonBoundingBoxOfSelectedElements({\n x,\n y\n }, selectedElements);\n const type = element || isHittignCommonBoundBox ? \"element\" : \"canvas\";\n const container = this.excalidrawContainerRef.current;\n const {\n top: offsetTop,\n left: offsetLeft\n } = container.getBoundingClientRect();\n const left = event.clientX - offsetLeft;\n const top = event.clientY - offsetTop;\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"contextMenu\", \"openContextMenu\", type);\n this.setState(Object.assign(Object.assign({}, element && !this.state.selectedElementIds[element.id] ? Object.assign(Object.assign(Object.assign({}, this.state), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: this.state.editingGroupId,\n selectedElementIds: {\n [element.id]: true\n }\n }, this.scene.getNonDeletedElements(), this.state, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(element) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(element, this.scene) : null\n }) : this.state), {\n showHyperlinkPopup: false\n }), () => {\n this.setState({\n contextMenu: {\n top,\n left,\n items: this.getContextMenuItems(type)\n }\n });\n });\n };\n\n this.maybeDragNewGenericElement = (pointerDownState, event) => {\n var _a;\n\n const draggingElement = this.state.draggingElement;\n const pointerCoords = pointerDownState.lastCoords;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"selection\" && this.state.activeTool.type !== \"eraser\") {\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.origin.x, pointerDownState.origin.y, pointerCoords.x, pointerCoords.y, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.x, pointerCoords.x), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.y, pointerCoords.y), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event));\n } else {\n 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 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 (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.originInGrid.x, pointerDownState.originInGrid.y, gridX, gridY, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.x, gridX), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.y, gridY), (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), aspectRatio);\n this.maybeSuggestBindingForAll([draggingElement]); // highlight elements that are to be added to frames on frames creation\n\n if (this.state.activeTool.type === \"frame\") {\n this.setState({\n elementsToHighlight: (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), draggingElement, this.state)\n });\n }\n }\n };\n\n this.maybeHandleResize = (pointerDownState, event) => {\n const selectedElements = this.scene.getSelectedElements(this.state);\n const selectedFrames = selectedElements.filter(element => element.type === \"frame\");\n const transformHandleType = pointerDownState.resize.handleType;\n\n if (selectedFrames.length > 0 && transformHandleType === \"rotation\") {\n return false;\n }\n\n this.setState({\n // TODO: rename this state field to \"isScaling\" to distinguish\n // it from the generic \"isResizing\" which includes scaling and\n // rotating\n isResizing: transformHandleType && transformHandleType !== \"rotation\",\n isRotating: transformHandleType === \"rotation\",\n activeEmbeddable: null\n });\n const pointerCoords = pointerDownState.lastCoords;\n const [resizeX, resizeY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x - pointerDownState.resize.offset.x, pointerCoords.y - pointerDownState.resize.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const frameElementsOffsetsMap = new Map();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.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 });\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)) {\n this.maybeSuggestBindingForAll(selectedElements);\n const elementsToHighlight = new Set();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.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_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), frame, this.state).forEach(element => elementsToHighlight.add(element));\n });\n this.setState({\n elementsToHighlight: [...elementsToHighlight]\n });\n return true;\n }\n\n return false;\n };\n\n this.getContextMenuItems = type => {\n const options = [];\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsPng, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsSvg); // canvas contextMenu\n // -------------------------------------------------------------------------\n\n if (type === \"canvas\") {\n if (this.state.viewModeEnabled) {\n return [...options, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleGridMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n }\n\n return [_actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsPng, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyAsSvg, _actions__WEBPACK_IMPORTED_MODULE_5__.copyText, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSelectAll, _actions_actionElementLock__WEBPACK_IMPORTED_MODULE_48__.actionUnlockAllElements, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleGridMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n } // element contextMenu\n // -------------------------------------------------------------------------\n\n\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.copyText);\n\n if (this.state.viewModeEnabled) {\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, ...options];\n }\n\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionSelectAllElementsInFrame, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionRemoveAllElementsFromFrame, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, ...options, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyStyles, _actions__WEBPACK_IMPORTED_MODULE_5__.actionPasteStyles, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionGroup, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUnbindText, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBindText, _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_57__.actionWrapTextInContainer, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUngroup, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionAddToLibrary, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendBackward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringForward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendToBack, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringToFront, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipHorizontal, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipVertical, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleLinearEditor, _actions__WEBPACK_IMPORTED_MODULE_5__.actionLink, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDuplicateSelection, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleElementLock, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDeleteSelected];\n };\n\n this.handleWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault();\n\n if (isPanning) {\n return;\n }\n\n const {\n deltaX,\n deltaY\n } = event; // note that event.ctrlKey is necessary to handle pinch zooming\n\n if (event.metaKey || event.ctrlKey) {\n const sign = Math.sign(deltaY);\n const MAX_STEP = _constants__WEBPACK_IMPORTED_MODULE_12__.ZOOM_STEP * 100;\n const absDelta = Math.abs(deltaY);\n let delta = deltaY;\n\n if (absDelta > MAX_STEP) {\n delta = MAX_STEP * sign;\n }\n\n let newZoom = this.state.zoom.value - delta / 100; // increase zoom steps the more zoomed-in we are (applies to >100% only)\n\n newZoom += Math.log10(Math.max(1, this.state.zoom.value)) * -sign * // reduced amplification for small deltas (small movements on a trackpad)\n Math.min(1, absDelta / 20);\n this.translateCanvas(state => Object.assign(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(newZoom)\n }, state)), {\n shouldCacheIgnoreZoom: true\n }));\n this.resetShouldCacheIgnoreZoomDebounced();\n return;\n } // scroll horizontally when shift pressed\n\n\n if (event.shiftKey) {\n this.translateCanvas(({\n zoom,\n scrollX\n }) => ({\n // on Mac, shift+wheel tends to result in deltaX\n scrollX: scrollX - (deltaY || deltaX) / zoom.value\n }));\n return;\n }\n\n this.translateCanvas(({\n zoom,\n scrollX,\n scrollY\n }) => ({\n scrollX: scrollX - deltaX / zoom.value,\n scrollY: scrollY - deltaY / zoom.value\n }));\n });\n\n this.savePointer = (x, y, button) => {\n var _a, _b;\n\n if (!x || !y) {\n return;\n }\n\n const pointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.debounce)(() => {\n if (!this.unmounted) {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n }\n }, 300);\n\n this.updateDOMRect = cb => {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n width,\n height,\n left: offsetLeft,\n top: offsetTop\n } = excalidrawContainer.getBoundingClientRect();\n const {\n width: currentWidth,\n height: currentHeight,\n offsetTop: currentOffsetTop,\n offsetLeft: currentOffsetLeft\n } = this.state;\n\n if (width === currentWidth && height === currentHeight && offsetLeft === currentOffsetLeft && offsetTop === currentOffsetTop) {\n if (cb) {\n cb();\n }\n\n return;\n }\n\n this.setState({\n width,\n height,\n offsetLeft,\n offsetTop\n }, () => {\n cb && cb();\n });\n }\n };\n\n this.refresh = () => {\n this.setState(Object.assign({}, this.getCanvasOffsets()));\n };\n\n const defaultAppState = (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)();\n const {\n excalidrawRef,\n viewModeEnabled = false,\n zenModeEnabled = false,\n gridModeEnabled = 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 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_65__.nanoid)();\n this.library = new _data_library__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this);\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_30__[\"default\"]();\n this.canvas = document.createElement(\"canvas\");\n this.rc = roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_3__[\"default\"].canvas(this.canvas);\n this.renderer = new _scene_Renderer__WEBPACK_IMPORTED_MODULE_63__.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_33__.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 };\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_49__.Fonts({\n scene: this.scene,\n onSceneUpdated: this.onSceneUpdated\n });\n this.history = new _history__WEBPACK_IMPORTED_MODULE_24__[\"default\"]();\n this.actionManager = new _actions_manager__WEBPACK_IMPORTED_MODULE_7__.ActionManager(this.syncActionResult, () => this.state, () => this.scene.getElementsIncludingDeleted(), this);\n this.actionManager.registerAll(_actions_register__WEBPACK_IMPORTED_MODULE_8__.actions);\n this.actionManager.registerAction((0,_actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__.createUndoAction)(this.history));\n this.actionManager.registerAction((0,_actions_actionHistory__WEBPACK_IMPORTED_MODULE_6__.createRedoAction)(this.history));\n }\n\n onWindowMessage(event) {\n if (event.origin !== \"https://player.vimeo.com\" && event.origin !== \"https://www.youtube.com\") {\n return;\n }\n\n let data = null;\n\n try {\n data = JSON.parse(event.data);\n } catch (e) {}\n\n if (!data) {\n return;\n }\n\n switch (event.origin) {\n case \"https://player.vimeo.com\":\n //Allowing for multiple instances of Excalidraw running in the window\n if (data.method === \"paused\") {\n let source = null;\n const iframes = document.body.querySelectorAll(\"iframe.excalidraw__embeddable\");\n\n if (!iframes) {\n break;\n }\n\n for (const iframe of iframes) {\n if (iframe.contentWindow === event.source) {\n source = iframe.contentWindow;\n }\n }\n\n source === null || source === void 0 ? void 0 : source.postMessage(JSON.stringify({\n method: data.value ? \"play\" : \"pause\",\n value: true\n }), \"*\");\n }\n\n break;\n\n case \"https://www.youtube.com\":\n if (data.event === \"infoDelivery\" && data.info && data.id && typeof data.info.playerState === \"number\") {\n const id = data.id;\n const playerState = data.info.playerState;\n\n if (Object.values(_constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES).includes(playerState)) {\n YOUTUBE_VIDEO_STATES.set(id, playerState);\n }\n }\n\n break;\n }\n }\n\n updateEmbeddableRef(id, ref) {\n if (ref) {\n this.iFrameRefs.set(id, ref);\n }\n }\n\n getHTMLIFrameElement(id) {\n return this.iFrameRefs.get(id);\n }\n\n handleEmbeddableCenterClick(element) {\n var _a, _b, _c, _d;\n\n if (((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) === element && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"active\") {\n return;\n } // The delay serves two purposes\n // 1. To prevent first click propagating to iframe on mobile,\n // else the click will immediately start and stop the video\n // 2. If the user double clicks the frame center to activate it\n // without the delay youtube will immediately open the video\n // in fullscreen mode\n\n\n setTimeout(() => {\n this.setState({\n activeEmbeddable: {\n element,\n state: \"active\"\n },\n selectedElementIds: {\n [element.id]: true\n },\n draggingElement: null,\n selectionElement: null\n });\n }, 100);\n const iframe = this.getHTMLIFrameElement(element.id);\n\n if (!(iframe === null || iframe === void 0 ? void 0 : iframe.contentWindow)) {\n return;\n }\n\n if (iframe.src.includes(\"youtube\")) {\n const state = YOUTUBE_VIDEO_STATES.get(element.id);\n\n if (!state) {\n YOUTUBE_VIDEO_STATES.set(element.id, _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.UNSTARTED);\n iframe.contentWindow.postMessage(JSON.stringify({\n event: \"listening\",\n id: element.id\n }), \"*\");\n }\n\n switch (state) {\n case _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.PLAYING:\n case _constants__WEBPACK_IMPORTED_MODULE_12__.YOUTUBE_STATES.BUFFERING:\n (_c = iframe.contentWindow) === null || _c === void 0 ? void 0 : _c.postMessage(JSON.stringify({\n event: \"command\",\n func: \"pauseVideo\",\n args: \"\"\n }), \"*\");\n break;\n\n default:\n (_d = iframe.contentWindow) === null || _d === void 0 ? void 0 : _d.postMessage(JSON.stringify({\n event: \"command\",\n func: \"playVideo\",\n args: \"\"\n }), \"*\");\n }\n }\n\n if (iframe.src.includes(\"player.vimeo.com\")) {\n iframe.contentWindow.postMessage(JSON.stringify({\n method: \"paused\" //video play/pause in onWindowMessage handler\n\n }), \"*\");\n }\n }\n\n isEmbeddableCenter(el, event, sceneX, sceneY) {\n var _a, _b;\n\n return el && !event.altKey && !event.shiftKey && !event.metaKey && !event.ctrlKey && (((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) !== el || ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"hover\" || !this.state.activeEmbeddable) && sceneX >= el.x + el.width / 3 && sceneX <= el.x + 2 * el.width / 3 && sceneY >= el.y + el.height / 3 && sceneY <= el.y + 2 * el.height / 3;\n }\n\n renderEmbeddables() {\n const scale = this.state.zoom.value;\n const normalizedWidth = this.state.width;\n const normalizedHeight = this.state.height;\n const embeddableElements = this.scene.getNonDeletedElements().filter(el => (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(el) && !!el.validated);\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {\n children: embeddableElements.map(el => {\n var _a, _b, _c, _d, _e, _f, _g, _h;\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: el.x,\n sceneY: el.y\n }, this.state);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)((0,_data_url__WEBPACK_IMPORTED_MODULE_46__.toValidURL)(el.link || \"\"));\n const isVisible = (0,_element_sizeHelpers__WEBPACK_IMPORTED_MODULE_27__.isElementInViewport)(el, normalizedWidth, normalizedHeight, this.state);\n const isActive = ((_a = this.state.activeEmbeddable) === null || _a === void 0 ? void 0 : _a.element) === el && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"active\";\n const isHovered = ((_c = this.state.activeEmbeddable) === null || _c === void 0 ? void 0 : _c.element) === el && ((_d = this.state.activeEmbeddable) === null || _d === void 0 ? void 0 : _d.state) === \"hover\";\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: (0,clsx__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\"excalidraw__embeddable-container\", {\n \"is-hovered\": isHovered\n }),\n style: {\n transform: isVisible ? `translate(${x - this.state.offsetLeft}px, ${y - this.state.offsetTop}px) scale(${scale})` : \"none\",\n display: isVisible ? \"block\" : \"none\",\n opacity: el.opacity / 100,\n [\"--embeddable-radius\"]: `${(0,_math__WEBPACK_IMPORTED_MODULE_28__.getCornerRadius)(Math.min(el.width, el.height), el)}px`\n }\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(\"div\", Object.assign({\n //this is a hack that addresses isse with embedded excalidraw.com embeddable\n //https://github.com/excalidraw/excalidraw/pull/6691#issuecomment-1607383938\n\n /*ref={(ref) => {\n if (!this.excalidrawContainerRef.current) {\n return;\n }\n const container = this.excalidrawContainerRef.current;\n const sh = container.scrollHeight;\n const ch = container.clientHeight;\n if (sh !== ch) {\n container.style.height = `${sh}px`;\n setTimeout(() => {\n container.style.height = `100%`;\n });\n }\n }}*/\n className: \"excalidraw__embeddable-container__inner\",\n style: {\n width: isVisible ? `${el.width}px` : 0,\n height: isVisible ? `${el.height}px` : 0,\n transform: isVisible ? `rotate(${el.angle}rad)` : \"none\",\n pointerEvents: isActive ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled\n }\n }, {\n children: [isHovered && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: \"excalidraw__embeddable-hint\"\n }, {\n children: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"buttons.embeddableInteractionButton\")\n })), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: \"excalidraw__embeddable__outer\",\n style: {\n padding: `${el.strokeWidth}px`\n }\n }, {\n children: (_g = (_f = (_e = this.props).renderEmbeddable) === null || _f === void 0 ? void 0 : _f.call(_e, el, this.state)) !== null && _g !== void 0 ? _g : (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"iframe\", {\n ref: ref => this.updateEmbeddableRef(el.id, ref),\n className: \"excalidraw__embeddable\",\n srcDoc: (embedLink === null || embedLink === void 0 ? void 0 : embedLink.type) === \"document\" ? embedLink.srcdoc(this.state.theme) : undefined,\n src: (embedLink === null || embedLink === void 0 ? void 0 : embedLink.type) !== \"document\" ? (_h = embedLink === null || embedLink === void 0 ? void 0 : embedLink.link) !== null && _h !== void 0 ? _h : \"\" : undefined,\n // https://stackoverflow.com/q/18470015\n scrolling: \"no\",\n referrerPolicy: \"no-referrer-when-downgrade\",\n title: \"Excalidraw Embedded Content\",\n allow: \"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\",\n allowFullScreen: true,\n sandbox: \"allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads\"\n })\n }))]\n }))\n }), el.id);\n })\n });\n }\n\n render() {\n var _a, _b, _c;\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n const {\n renderTopRightUI,\n renderCustomStats\n } = this.props;\n const versionNonce = this.scene.getVersionNonce();\n const {\n canvasElements,\n visibleElements\n } = this.renderer.getRenderableElements({\n versionNonce,\n zoom: this.state.zoom,\n offsetLeft: this.state.offsetLeft,\n offsetTop: this.state.offsetTop,\n scrollX: this.state.scrollX,\n scrollY: this.state.scrollY,\n height: this.state.height,\n width: this.state.width,\n editingElement: this.state.editingElement,\n pendingImageElementId: this.state.pendingImageElementId\n });\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", Object.assign({\n className: (0,clsx__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\"excalidraw excalidraw-container\", {\n \"excalidraw--view-mode\": this.state.viewModeEnabled,\n \"excalidraw--mobile\": this.device.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_36__[\"default\"], Object.assign({\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 renderTopRightUI: renderTopRightUI,\n renderCustomStats: renderCustomStats,\n showExitZenModeBtn: typeof ((_a = this.props) === null || _a === void 0 ? void 0 : _a.zenModeEnabled) === \"undefined\" && this.state.zenModeEnabled,\n UIOptions: this.props.UIOptions,\n onImageAction: this.onImageAction,\n onExportImage: this.onExportImage,\n renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === \"selection\" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,\n app: this\n }, {\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_45__.Hyperlink, {\n element: selectedElements[0],\n setAppState: this.setAppState,\n onLinkOpen: this.props.onLinkOpen,\n setToast: this.setToast\n }, selectedElements[0].id), this.state.toast !== null && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_Toast__WEBPACK_IMPORTED_MODULE_37__.Toast, {\n message: this.state.toast.message,\n onClose: () => this.setToast(null),\n duration: this.state.toast.duration,\n closable: this.state.toast.closable\n }), this.state.contextMenu && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_ContextMenu__WEBPACK_IMPORTED_MODULE_35__.ContextMenu, {\n items: this.state.contextMenu.items,\n top: this.state.contextMenu.top,\n left: this.state.contextMenu.left,\n actionManager: this.actionManager\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_62__.StaticCanvas, {\n canvas: this.canvas,\n rc: this.rc,\n elements: canvasElements,\n visibleElements: visibleElements,\n versionNonce: versionNonce,\n selectionNonce: (_b = this.state.selectionElement) === null || _b === void 0 ? void 0 : _b.versionNonce,\n scale: window.devicePixelRatio,\n appState: this.state,\n renderConfig: {\n imageCache: this.imageCache,\n isExporting: false,\n renderGrid: true\n }\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_62__.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_33__.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_33__.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_43__.isMeasureTextSupported)()) {\n this.setState({\n errorMessage: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_58__[\"default\"], {})\n });\n }\n });\n }\n\n componentWillUnmount() {\n var _a;\n\n this.renderer.destroy();\n this.scene = new _scene_Scene__WEBPACK_IMPORTED_MODULE_30__[\"default\"]();\n this.renderer = new _scene_Renderer__WEBPACK_IMPORTED_MODULE_63__.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_64__.ShapeCache.destroy();\n clearTimeout(touchTimeout);\n _scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected.clearCache();\n _groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements.clearCache();\n touchTimeout = 0;\n }\n\n removeEventListeners() {\n var _a, _b, _c, _d, _e;\n\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel);\n (_b = this.nearestScrollableContainer) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n (_e = this.detachIsMobileMqHandler) === null || _e === void 0 ? void 0 : _e.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\", event => {\n const loadedFontFaces = event.fontfaces;\n this.fonts.onFontsLoaded(loadedFontFaces);\n }); // Safari-only desktop pinch zoom\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n\n if (this.props.detectScroll) {\n this.nearestScrollableContainer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getNearestScrollableContainer)(this.excalidrawContainerRef.current);\n this.nearestScrollableContainer.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n }\n\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_e = this.excalidrawContainerRef.current) === null || _e === void 0 ? void 0 : _e.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n }\n\n componentDidUpdate(prevProps, prevState) {\n var _a, _b, _c, _d, _e, _f;\n\n this.updateEmbeddables();\n\n if (!this.state.showWelcomeScreen && !this.scene.getElementsIncludingDeleted().length) {\n this.setState({\n showWelcomeScreen: true\n });\n }\n\n if (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_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n\n if (this.state.activeTool.type === \"eraser\" && prevState.theme !== this.state.theme) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setEraserCursor)(this.interactiveCanvas, this.state.theme);\n } // Hide hyperlink popup if shown when element type is not selection\n\n\n if (prevState.activeTool.type === \"selection\" && this.state.activeTool.type !== \"selection\" && this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: false\n });\n }\n\n if (prevProps.langCode !== this.props.langCode) {\n this.updateLanguage();\n }\n\n if (prevProps.viewModeEnabled !== this.props.viewModeEnabled) {\n this.setState({\n viewModeEnabled: !!this.props.viewModeEnabled\n });\n }\n\n if (prevState.viewModeEnabled !== this.state.viewModeEnabled) {\n this.addEventListeners();\n this.deselectElements();\n }\n\n if (prevProps.zenModeEnabled !== this.props.zenModeEnabled) {\n this.setState({\n zenModeEnabled: !!this.props.zenModeEnabled\n });\n }\n\n if (prevProps.theme !== this.props.theme && this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {\n this.setState({\n gridSize: this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null\n });\n }\n\n if (this.props.name && prevProps.name !== this.props.name) {\n this.setState({\n name: this.props.name\n });\n }\n\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.classList.toggle(\"theme--dark\", this.state.theme === \"dark\");\n\n if (this.state.editingLinearElement && !this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {\n // defer so that the commitToHistory flag isn't reset via current update\n setTimeout(() => {\n // execute only if the condition still holds when the deferred callback\n // executes (it can be scheduled multiple times depending on how\n // many times the component renders)\n this.state.editingLinearElement && this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } // failsafe in case the state is being updated in incorrect order resulting\n // in the editingElement being now a deleted element\n\n\n if ((_d = this.state.editingElement) === null || _d === void 0 ? void 0 : _d.isDeleted) {\n this.setState({\n editingElement: null\n });\n }\n\n if (this.state.selectedLinearElement && !this.state.selectedElementIds[this.state.selectedLinearElement.elementId]) {\n // To make sure `selectedLinearElement` is in sync with `selectedElementIds`, however this shouldn't be needed once\n // we have a single API to update `selectedElementIds`\n this.setState({\n selectedLinearElement: null\n });\n }\n\n const {\n multiElement\n } = prevState;\n\n if (prevState.activeTool !== this.state.activeTool && multiElement != null && (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(multiElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(multiElement, this.state, this.scene, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)(_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1)));\n }\n\n this.history.record(this.state, this.scene.getElementsIncludingDeleted()); // Do not notify consumers if we're still loading the scene. Among other\n // potential issues, this fixes a case where the tab isn't focused during\n // init, which would trigger onChange with empty elements, which would then\n // override whatever is in localStorage currently.\n\n if (!this.state.isLoading) {\n (_f = (_e = this.props).onChange) === null || _f === void 0 ? void 0 : _f.call(_e, this.scene.getElementsIncludingDeleted(), this.state, this.files);\n }\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_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state);\n const textElementProps = {\n x,\n y,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roundness: null,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text,\n fontSize: this.state.currentItemFontSize,\n fontFamily: this.state.currentItemFontFamily,\n textAlign: this.state.currentItemTextAlign,\n verticalAlign: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n locked: false\n };\n const LINE_GAP = 10;\n let currentY = y;\n const lines = isPlainPaste ? [text] : text.split(\"\\n\");\n const textElements = lines.reduce((acc, line, idx) => {\n var _a;\n\n const text = line.trim();\n const lineHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(textElementProps.fontFamily);\n\n if (text.length) {\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x,\n y: currentY\n });\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)(Object.assign(Object.assign({}, textElementProps), {\n x,\n y: currentY,\n text,\n lineHeight,\n frameId: topLayerFrame ? topLayerFrame.id : null\n }));\n acc.push(element);\n currentY += element.height + LINE_GAP;\n } else {\n const prevLine = (_a = lines[idx - 1]) === null || _a === void 0 ? void 0 : _a.trim(); // add paragraph only if previous line was not empty, IOW don't add\n // more than one empty line\n\n if (prevLine) {\n currentY += (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getLineHeightInPx)(textElementProps.fontSize, lineHeight) + LINE_GAP;\n }\n }\n\n return acc;\n }, []);\n\n if (textElements.length === 0) {\n return;\n }\n\n const frameId = textElements[0].frameId;\n\n if (frameId) {\n this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));\n } else {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), ...textElements]);\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.fromEntries(textElements.map(el => [el.id, true])), this.state)\n });\n\n if (!isPlainPaste && textElements.length > 1 && PLAIN_PASTE_TOAST_SHOWN === false && !this.device.isMobile) {\n this.setToast({\n message: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"toast.pasteAsSingleElement\", {\n shortcut: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getShortcutKey)(\"CtrlOrCmd+Shift+V\")\n }),\n duration: 5000\n });\n PLAIN_PASTE_TOAST_SHOWN = true;\n }\n\n this.history.resumeRecording();\n }\n\n handleTextWysiwyg(element, {\n isExistingElement = false\n }) {\n const updateElement = (text, originalText, isDeleted) => {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted().map(_element => {\n if (_element.id === element.id && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(_element)) {\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.updateTextElement)(_element, {\n text,\n isDeleted,\n originalText\n });\n }\n\n return _element;\n })]);\n };\n\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.textWysiwyg)({\n id: element.id,\n canvas: this.canvas,\n getViewportCoords: (x, y) => {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: x,\n sceneY: y\n }, this.state);\n return [viewportX - this.state.offsetLeft, viewportY - this.state.offsetTop];\n },\n onChange: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(text => {\n updateElement(text, text, false);\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element);\n }\n }),\n onSubmit: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(({\n text,\n viaKeyboard,\n originalText\n }) => {\n const isDeleted = !text.trim();\n updateElement(text, originalText, isDeleted); // select the created text element only if submitting via keyboard\n // (when submitting via click it should act as signal to deselect)\n\n if (!isDeleted && viaKeyboard) {\n const elementIdToSelect = element.containerId ? element.containerId : element.id;\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [elementIdToSelect]: true\n }), prevState)\n }));\n }\n\n if (isDeleted) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDeletion)(this.scene.getNonDeletedElements(), [element]);\n }\n\n if (!isDeleted || isExistingElement) {\n this.history.resumeRecording();\n }\n\n this.setState({\n draggingElement: null,\n editingElement: null\n });\n\n if (this.state.activeTool.locked) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n this.focusContainer();\n }),\n element,\n excalidrawContainer: this.excalidrawContainerRef.current,\n app: this\n }); // deselect all other elements when inserting text\n\n this.deselectElements(); // do an initial update to re-initialize element position since we were\n // modifying element's x/y for sake of editor (case: syncing to remote)\n\n updateElement(element.text, element.originalText, false);\n }\n\n deselectElements() {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n getTextElementAtPosition(x, y) {\n const element = this.getElementAtPosition(x, y, {\n includeBoundTextElement: true\n });\n\n if (element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && !element.isDeleted) {\n return element;\n }\n\n return null;\n }\n\n getElementAtPosition(x, y, opts) {\n const allHitElements = this.getElementsAtPosition(x, y, opts === null || opts === void 0 ? void 0 : opts.includeBoundTextElement, opts === null || opts === void 0 ? void 0 : opts.includeLockedElements);\n\n if (allHitElements.length > 1) {\n if (opts === null || opts === void 0 ? void 0 : opts.preferSelected) {\n for (let index = allHitElements.length - 1; index > -1; index--) {\n if (this.state.selectedElementIds[allHitElements[index].id]) {\n return allHitElements[index];\n }\n }\n }\n\n const elementWithHighestZIndex = allHitElements[allHitElements.length - 1]; // If we're hitting element with highest z-index only on its bounding box\n // while also hitting other element figure, the latter should be considered.\n\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(elementWithHighestZIndex, this.state, this.frameNameBoundsCache, x, y) ? allHitElements[allHitElements.length - 2] : elementWithHighestZIndex;\n }\n\n if (allHitElements.length === 1) {\n return allHitElements[0];\n }\n\n return null;\n }\n\n getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {\n const elements = includeBoundTextElement && includeLockedElements ? this.scene.getNonDeletedElements() : this.scene.getNonDeletedElements().filter(element => (includeLockedElements || !element.locked) && (includeBoundTextElement || !((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && element.containerId)));\n return (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsAtPosition)(elements, element => (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(element, this.state, this.frameNameBoundsCache, x, y)).filter(element => {\n // hitting a frame's element from outside the frame is not considered a hit\n const containingFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(element);\n return containingFrame && this.state.frameRendering.enabled && this.state.frameRendering.clip ? (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)({\n x,\n y\n }, containingFrame) : true;\n });\n }\n\n handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {\n const element = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getElement(linearElementEditor.elementId);\n const boundTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(element);\n\n if (!element) {\n return;\n }\n\n if (this.state.selectedLinearElement) {\n let hoverPointIndex = -1;\n let segmentMidPointHoveredCoords = null;\n\n if ((0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(element, this.state, this.frameNameBoundsCache, [scenePointerX, scenePointerY])) {\n hoverPointIndex = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointIndexUnderCursor(element, this.state.zoom, scenePointerX, scenePointerY);\n segmentMidPointHoveredCoords = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, {\n x: scenePointerX,\n y: scenePointerY\n }, this.state);\n\n if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n } else if ((0,_element_transformHandles__WEBPACK_IMPORTED_MODULE_47__.shouldShowBoundingBox)([element], this.state) && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_33__.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_33__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n\n maybeCleanupAfterMissingPointerUp(event) {\n if (lastPointerUp !== null) {\n // Unfortunately, sometimes we don't get a pointerup after a pointerdown,\n // this can happen when a contextual menu or alert is triggered. In order to avoid\n // being in a weird state, we clean up on the next pointerdown\n lastPointerUp(event);\n }\n }\n\n updateGestureOnPointerDown(event) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n\n if (gesture.pointers.size === 2) {\n gesture.lastCenter = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n gesture.initialScale = this.state.zoom.value;\n gesture.initialDistance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n }\n }\n\n initialPointerDownState(event) {\n const origin = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedElements = this.scene.getSelectedElements(this.state);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return {\n origin,\n withCmdOrCtrl: event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD],\n originInGrid: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(origin.x, origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize)),\n scrollbars: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop),\n // we need to duplicate because we'll be updating this state\n lastCoords: Object.assign({}, origin),\n originalElements: this.scene.getNonDeletedElements().reduce((acc, element) => {\n acc.set(element.id, (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.deepCopyElement)(element));\n return acc;\n }, new Map()),\n resize: {\n handleType: false,\n isResizing: false,\n offset: {\n x: 0,\n y: 0\n },\n arrowDirection: \"origin\",\n center: {\n x: (maxX + minX) / 2,\n y: (maxY + minY) / 2\n }\n },\n hit: {\n element: null,\n allHitElements: [],\n wasAddedToSelection: false,\n hasBeenDuplicated: false,\n hasHitCommonBoundingBoxOfSelectedElements: this.isHittingCommonBoundingBoxOfSelectedElements(origin, selectedElements)\n },\n drag: {\n hasOccurred: false,\n offset: null\n },\n eventListeners: {\n onMove: null,\n onUp: null,\n onKeyUp: null,\n onKeyDown: null\n },\n boxSelection: {\n hasOccurred: false\n },\n elementIdsToErase: {}\n };\n } // Returns whether the event is a dragging a scrollbar\n\n\n handleDraggingScrollBar(event, pointerDownState) {\n if (!(pointerDownState.scrollbars.isOverEither && !this.state.multiElement)) {\n return false;\n }\n\n isDraggingScrollBar = true;\n pointerDownState.lastCoords.x = event.clientX;\n pointerDownState.lastCoords.y = event.clientY;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n this.handlePointerMoveOverScrollbars(event, pointerDownState);\n });\n const onPointerUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isDraggingScrollBar = false;\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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 onKeyDownFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onKeyUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // Prevents focus from escaping excalidraw tab\n event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ALT && event.preventDefault();\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onPointerMoveFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n var _a, _b; // We need to initialize dragOffsetXY only after we've updated\n // `state.selectedElementIds` on pointerDown. Doing it here in pointerMove\n // event handler should hopefully ensure we're already working with\n // the updated state.\n\n\n if (pointerDownState.drag.offset === null) {\n pointerDownState.drag.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getDragOffsetXY)(this.scene.getSelectedElements(this.state), pointerDownState.origin.x, pointerDownState.origin.y));\n }\n\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n if (this.handlePointerMoveOverScrollbars(event, pointerDownState)) {\n return;\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.handleEraser(event, pointerDownState, pointerCoords);\n return;\n }\n\n 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 [dragX, dragY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x - pointerDownState.drag.offset.x, pointerCoords.y - pointerDownState.drag.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const [dragDistanceX, dragDistanceY] = [Math.abs(pointerCoords.x - pointerDownState.origin.x), Math.abs(pointerCoords.y - pointerDownState.origin.y)]; // We only drag in one direction if shift is pressed\n\n const lockDirection = event.shiftKey; // 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, dragX, dragY, lockDirection, dragDistanceX, dragDistanceY, this.state, this.scene);\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 [originDragX, originDragY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x - pointerDownState.drag.offset.x, pointerDownState.origin.y - pointerDownState.drag.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(duplicatedElement, {\n x: duplicatedElement.x + (originDragX - dragX),\n y: duplicatedElement.y + (originDragY - dragY)\n });\n nextElements.push(duplicatedElement);\n elementsToAppend.push(element);\n oldIdToDuplicatedId.set(element.id, duplicatedElement.id);\n } else {\n nextElements.push(element);\n }\n }\n\n const nextSceneElements = [...nextElements, ...elementsToAppend];\n (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.bindTextToShapeAfterDuplication)(nextElements, elementsToAppend, oldIdToDuplicatedId);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, \"duplicatesServeAsOld\");\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.bindElementsToFramesAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);\n this.scene.replaceAllElements(nextSceneElements);\n }\n\n return;\n }\n } // It is very important to read this.state within each move event,\n // otherwise we would read a stale one!\n\n\n const draggingElement = this.state.draggingElement;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"freedraw\") {\n const points = draggingElement.points;\n const dx = pointerCoords.x - draggingElement.x;\n const dy = pointerCoords.y - draggingElement.y;\n const lastPoint = points.length > 0 && points[points.length - 1];\n const discardPoint = lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;\n\n if (!discardPoint) {\n const pressures = draggingElement.simulatePressure ? draggingElement.pressures : [...draggingElement.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures\n });\n }\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n });\n const points = draggingElement.points;\n let dx = gridX - draggingElement.x;\n let dy = gridY - draggingElement.y;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event) && points.length === 2) {\n ({\n width: dx,\n height: dy\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)(draggingElement.x, draggingElement.y, pointerCoords.x, pointerCoords.y));\n }\n\n if (points.length === 1) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]]\n });\n } else if (points.length === 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points.slice(0, -1), [dx, dy]]\n });\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n // When creating a linear element by dragging\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [pointerCoords], this.state.startBoundElement);\n }\n } else {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n this.maybeDragNewGenericElement(pointerDownState, event);\n }\n\n if (this.state.activeTool.type === \"selection\") {\n pointerDownState.boxSelection.hasOccurred = true;\n const elements = this.scene.getNonDeletedElements(); // box-select line editor points\n\n if (this.state.editingLinearElement) {\n _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handleBoxSelection(event, this.state, this.setState.bind(this)); // regular box-select\n } else {\n let shouldReuseSelection = true;\n\n if (!event.shiftKey && (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(elements, this.state)) {\n if (pointerDownState.withCmdOrCtrl && pointerDownState.hit.element) {\n this.setState(prevState => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)(Object.assign(Object.assign({}, prevState), {\n selectedElementIds: {\n [pointerDownState.hit.element.id]: true\n }\n }), this.scene.getNonDeletedElements(), prevState, this));\n } else {\n shouldReuseSelection = false;\n }\n }\n\n const elementsWithinSelection = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsWithinSelection)(elements, draggingElement);\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, shouldReuseSelection && prevState.selectedElementIds), elementsWithinSelection.reduce((acc, element) => {\n acc[element.id] = true;\n return acc;\n }, {}));\n\n if (pointerDownState.hit.element) {\n // if using ctrl/cmd, select the hitElement only if we\n // haven't box-selected anything else\n if (!elementsWithinSelection.length) {\n nextSelectedElementIds[pointerDownState.hit.element.id] = true;\n } else {\n delete nextSelectedElementIds[pointerDownState.hit.element.id];\n }\n }\n\n prevState = !shouldReuseSelection ? Object.assign(Object.assign({}, prevState), {\n selectedGroupIds: {},\n editingGroupId: null\n }) : prevState;\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // select linear element only when we haven't box-selected anything else\n selectedLinearElement: elementsWithinSelection.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(elementsWithinSelection[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(elementsWithinSelection[0], this.scene) : null,\n showHyperlinkPopup: elementsWithinSelection.length === 1 && (elementsWithinSelection[0].link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(elementsWithinSelection[0])) ? \"info\" : false\n });\n });\n }\n }\n });\n } // Returns whether the pointer move happened over either scrollbar\n\n\n handlePointerMoveOverScrollbars(event, pointerDownState) {\n if (pointerDownState.scrollbars.isOverHorizontal) {\n const x = event.clientX;\n const dx = x - pointerDownState.lastCoords.x;\n this.translateCanvas({\n scrollX: this.state.scrollX - dx / this.state.zoom.value\n });\n pointerDownState.lastCoords.x = x;\n return true;\n }\n\n if (pointerDownState.scrollbars.isOverVertical) {\n const y = event.clientY;\n const dy = y - pointerDownState.lastCoords.y;\n this.translateCanvas({\n scrollY: this.state.scrollY - dy / this.state.zoom.value\n });\n pointerDownState.lastCoords.y = y;\n return true;\n }\n\n return false;\n }\n\n onPointerUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(childEvent => {\n var _a, _b, _c, _d, _e, _f;\n\n if (pointerDownState.eventListeners.onMove) {\n pointerDownState.eventListeners.onMove.flush();\n }\n\n const {\n draggingElement,\n resizingElement,\n multiElement,\n activeTool,\n isResizing,\n isRotating\n } = this.state;\n this.setState({\n isResizing: false,\n isRotating: false,\n resizingElement: null,\n selectionElement: null,\n frameToHighlight: null,\n elementsToHighlight: null,\n cursorButton: \"up\",\n // text elements are reset on finalize, and resetting on pointerup\n // may cause issues with double taps\n editingElement: multiElement || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? this.state.editingElement : null\n });\n this.savePointer(childEvent.clientX, childEvent.clientY, \"up\");\n this.setState({\n selectedElementsAreBeingDragged: false\n }); // Handle end of dragging a point of a linear element, might close a loop\n // and sets binding element\n\n if (this.state.editingLinearElement) {\n if (!pointerDownState.boxSelection.hasOccurred && ((_b = (_a = pointerDownState.hit) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.id) !== this.state.editingLinearElement.elementId) {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n } else {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state);\n\n if (editingLinearElement !== this.state.editingLinearElement) {\n this.setState({\n editingLinearElement,\n suggestedBindings: []\n });\n }\n }\n } else if (this.state.selectedLinearElement) {\n if (((_d = (_c = pointerDownState.hit) === null || _c === void 0 ? void 0 : _c.element) === null || _d === void 0 ? void 0 : _d.id) !== this.state.selectedLinearElement.elementId) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement to null if there is more than one element selected since we don't want to show linear element handles\n\n if (selectedELements.length > 1) {\n this.setState({\n selectedLinearElement: null\n });\n }\n } else {\n const linearElementEditor = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state);\n const {\n startBindingElement,\n endBindingElement\n } = linearElementEditor;\n const element = this.scene.getElement(linearElementEditor.elementId);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindLinearElement)(element, startBindingElement, endBindingElement);\n }\n\n if (linearElementEditor !== this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, linearElementEditor), {\n selectedPointsIndices: null\n }),\n suggestedBindings: []\n });\n }\n }\n }\n\n lastPointerUp = null;\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, pointerDownState.eventListeners.onMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, pointerDownState.eventListeners.onUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, pointerDownState.eventListeners.onKeyDown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, pointerDownState.eventListeners.onKeyUp);\n\n if (this.state.pendingImageElementId) {\n this.setState({\n pendingImageElementId: null\n });\n }\n\n if ((draggingElement === null || draggingElement === void 0 ? void 0 : draggingElement.type) === \"freedraw\") {\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n const points = draggingElement.points;\n let dx = pointerCoords.x - draggingElement.x;\n let dy = pointerCoords.y - draggingElement.y; // Allows dots to avoid being flagged as infinitely small\n\n if (dx === points[0][0] && dy === points[0][1]) {\n dy += 0.0001;\n dx += 0.0001;\n }\n\n const pressures = draggingElement.simulatePressure ? [] : [...draggingElement.pressures, childEvent.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures,\n lastCommittedPoint: [dx, dy]\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement)) {\n const imageElement = draggingElement;\n\n try {\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } catch (error) {\n console.error(error);\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== imageElement.id));\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n }\n\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n if (draggingElement.points.length > 1) {\n this.history.resumeRecording();\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n\n if (!pointerDownState.drag.hasOccurred && draggingElement && !multiElement) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...draggingElement.points, [pointerCoords.x - draggingElement.x, pointerCoords.y - draggingElement.y]]\n });\n this.setState({\n multiElement: draggingElement,\n editingElement: this.state.draggingElement\n });\n } else if (pointerDownState.drag.hasOccurred && !multiElement) {\n if ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(draggingElement, this.state, this.scene, pointerCoords);\n }\n\n this.setState({\n suggestedBindings: [],\n startBoundElement: null\n });\n\n if (!activeTool.locked) {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n this.setState(prevState => ({\n draggingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n }),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(draggingElement, this.scene)\n }));\n } else {\n this.setState(prevState => ({\n draggingElement: null\n }));\n }\n }\n\n return;\n }\n\n if (activeTool.type !== \"selection\" && draggingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(draggingElement)) {\n // remove invisible element which was added in onPointerDown\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().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_33__.viewportCoordsToSceneCoords)(childEvent, this.state); // when editing the points of a linear element, we check if the\n // linear element still is in the frame afterwards\n // if not, the linear element will be removed from its frame (if any)\n\n if (this.state.selectedLinearElement && this.state.selectedLinearElement.isDragging) {\n const linearElement = this.scene.getElement(this.state.selectedLinearElement.elementId);\n\n if (linearElement === null || linearElement === void 0 ? void 0 : linearElement.frameId) {\n const frame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(linearElement);\n\n if (frame && linearElement) {\n if (!(0,_frame__WEBPACK_IMPORTED_MODULE_50__.elementOverlapsWithFrame)(linearElement, frame)) {\n // remove the linear element from all groups\n // before removing it from the frame as well\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(linearElement, {\n groupIds: []\n });\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.removeElementsFromFrame)(this.scene.getElementsIncludingDeleted(), [linearElement], this.state));\n }\n }\n }\n } else {\n // update the relationships between selected elements and frames\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(sceneCoords);\n const selectedElements = this.scene.getSelectedElements(this.state);\n let nextElements = this.scene.getElementsIncludingDeleted();\n\n const updateGroupIdsAfterEditingGroup = elements => {\n if (elements.length > 0) {\n for (const element of elements) {\n const index = element.groupIds.indexOf(this.state.editingGroupId);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: element.groupIds.slice(0, index)\n }, false);\n }\n\n nextElements.forEach(element => {\n if (element.groupIds.length && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(nextElements, element.groupIds[element.groupIds.length - 1]).length < 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: []\n }, false);\n }\n });\n this.setState({\n editingGroupId: null\n });\n }\n };\n\n if (topLayerFrame && !this.state.selectedElementIds[topLayerFrame.id]) {\n const elementsToAdd = selectedElements.filter(element => element.frameId !== topLayerFrame.id && (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n\n if (this.state.editingGroupId) {\n updateGroupIdsAfterEditingGroup(elementsToAdd);\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(nextElements, elementsToAdd, topLayerFrame);\n } else if (!topLayerFrame) {\n if (this.state.editingGroupId) {\n const elementsToRemove = selectedElements.filter(element => element.frameId && !(0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n updateGroupIdsAfterEditingGroup(elementsToRemove);\n }\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(nextElements, this.state, this);\n this.scene.replaceAllElements(nextElements);\n }\n }\n\n if (draggingElement.type === \"frame\") {\n const elementsInsideFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInNewFrame)(this.scene.getElementsIncludingDeleted(), draggingElement);\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(this.scene.getElementsIncludingDeleted(), elementsInsideFrame, draggingElement));\n }\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getNormalizedDimensions)(draggingElement));\n }\n\n if (resizingElement) {\n this.history.resumeRecording();\n }\n\n if (resizingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(resizingElement)) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== resizingElement.id));\n } // handle frame membership for resizing frames and/or selected elements\n\n\n if (pointerDownState.resize.isResizing) {\n let nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(this.scene.getElementsIncludingDeleted(), this.state, this);\n const selectedFrames = this.scene.getSelectedElements(this.state).filter(element => element.type === \"frame\");\n\n for (const frame of selectedFrames) {\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.replaceAllElementsInFrame)(nextElements, (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getElementsIncludingDeleted(), frame, this.state), frame, this.state);\n }\n\n this.scene.replaceAllElements(nextElements);\n } // Code below handles selection when element(s) weren't\n // drag or added to selection on pointer down phase.\n\n\n const hitElement = pointerDownState.hit.element;\n\n if (((_e = this.state.selectedLinearElement) === null || _e === void 0 ? void 0 : _e.elementId) !== (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement)) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement when no other element selected except\n // the one we've hit\n\n if (selectedELements.length === 1) {\n this.setState({\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene)\n });\n }\n }\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDown.clientX, this.lastPointerDown.clientY, this.lastPointerUp.clientX, this.lastPointerUp.clientY);\n\n if (draggedDistance === 0) {\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.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_51__.makeNextSelectedElementIds)(nextSelectedElementIds, _prevState)\n };\n }); // if not gragging a linear element point (outside editor)\n } else if (!((_f = this.state.selectedLinearElement) === null || _f === void 0 ? void 0 : _f.isDragging)) {\n // remove element from selection while\n // keeping prev elements selected\n this.setState(prevState => {\n const newSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete newSelectedElementIds[hitElement.id];\n const newSelectedElements = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(this.scene.getNonDeletedElements(), {\n selectedElementIds: newSelectedElementIds\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: newSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // set selectedLinearElement only if thats the only element selected\n selectedLinearElement: newSelectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(newSelectedElements[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(newSelectedElements[0], this.scene) : prevState.selectedLinearElement\n });\n });\n }\n } else if (hitElement.frameId && this.state.selectedElementIds[hitElement.frameId]) {\n // when hitElement is part of a selected frame, deselect the frame\n // to avoid frame and containing elements selected simultaneously\n this.setState(prevState => {\n var _a, _b;\n\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n }); // deselect the frame\n\n delete nextSelectedElementIds[hitElement.frameId]; // deselect groups containing the frame\n\n ((_b = (_a = this.scene.getElement(hitElement.frameId)) === null || _a === void 0 ? void 0 : _a.groupIds) !== null && _b !== void 0 ? _b : []).flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n showHyperlinkPopup: hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) ? \"info\" : false\n });\n });\n } else {\n // add element to selection while keeping prev elements selected\n this.setState(_prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, _prevState.selectedElementIds), {\n [hitElement.id]: true\n }), _prevState)\n }));\n }\n } else {\n this.setState(prevState => {\n var _a;\n\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement) && // Don't set `selectedLinearElement` if its same as the hitElement, this is mainly to prevent resetting the `hoverPointIndex` to -1.\n // Future we should update the API to take care of setting the correct `hoverPointIndex` when initialized\n ((_a = prevState.selectedLinearElement) === null || _a === void 0 ? void 0 : _a.elementId) !== hitElement.id ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene) : prevState.selectedLinearElement\n });\n });\n }\n }\n\n if (!pointerDownState.drag.hasOccurred && !this.state.isResizing && (hitElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(hitElement, this.state, this.frameNameBoundsCache, pointerDownState.origin.x, pointerDownState.origin.y) || !hitElement && pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements)) {\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: null\n });\n } else {\n // Deselect selected elements\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\" && draggingElement && draggingElement.type !== \"selection\") {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n showHyperlinkPopup: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(draggingElement) && !draggingElement.link ? \"editor\" : prevState.showHyperlinkPopup\n }));\n }\n\n if (activeTool.type !== \"selection\" || (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(this.scene.getNonDeletedElements(), this.state)) {\n this.history.resumeRecording();\n }\n\n if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {\n ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? _element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements : _element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(this.scene.getSelectedElements(this.state));\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\") {\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.resetCursor)(this.interactiveCanvas);\n this.setState({\n draggingElement: null,\n suggestedBindings: [],\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n } else {\n this.setState({\n draggingElement: null,\n suggestedBindings: []\n });\n }\n\n if (hitElement && this.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_51__.makeNextSelectedElementIds)({}, prevState),\n activeEmbeddable: null,\n selectedGroupIds: {},\n // Continue editing the same group if the user selected a different\n // element from it\n editingGroupId: prevState.editingGroupId && hitElement != null && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, prevState.editingGroupId) ? prevState.editingGroupId : null\n }));\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null,\n previousSelectedElementIds: this.state.selectedElementIds\n });\n }\n\n getTextWysiwygSnappedToCenterPosition(x, y, appState, container) {\n if (container) {\n let elementCenterX = container.x + container.width / 2;\n let elementCenterY = container.y + container.height / 2;\n const elementCenter = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, appState);\n\n if (elementCenter) {\n elementCenterX = elementCenter.x;\n elementCenterY = elementCenter.y;\n }\n\n const distanceToCenter = Math.hypot(x - elementCenterX, y - elementCenterY);\n const isSnappedToCenter = distanceToCenter < _constants__WEBPACK_IMPORTED_MODULE_12__.TEXT_TO_CENTER_SNAP_THRESHOLD;\n\n if (isSnappedToCenter) {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: elementCenterX,\n sceneY: elementCenterY\n }, appState);\n return {\n viewportX,\n viewportY,\n elementCenterX,\n elementCenterY\n };\n }\n }\n }\n\n getCanvasOffsets() {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n left,\n top\n } = excalidrawContainer.getBoundingClientRect();\n return {\n offsetLeft: left,\n offsetTop: top\n };\n }\n\n return {\n offsetLeft: 0,\n offsetTop: 0\n };\n }\n\n updateLanguage() {\n return __awaiter(this, void 0, void 0, function* () {\n const currentLang = _i18n__WEBPACK_IMPORTED_MODULE_25__.languages.find(lang => lang.code === this.props.langCode) || _i18n__WEBPACK_IMPORTED_MODULE_25__.defaultLang;\n yield (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.setLanguage)(currentLang);\n this.setAppState({});\n });\n }\n\n}\n\nApp.defaultProps = {\n // needed for tests to pass since we directly render App in many tests\n UIOptions: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_UI_OPTIONS\n};\n\nif (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n window.h = window.h || {};\n Object.defineProperties(window.h, {\n elements: {\n configurable: true,\n\n get() {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.getElementsIncludingDeleted();\n },\n\n set(elements) {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.replaceAllElements(elements);\n }\n\n }\n });\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIseUVBQWtCOztBQUU5QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG1EQUFtRCxzRUFBNkI7O0FBRWhGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLG9FQUEyQjtBQUN2QztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSwwQkFBMEIsa0RBQWMsK0NBQStDLCtDQUFXO0FBQ2xHLFlBQVksbURBQVc7QUFDdkIseUJBQXlCO0FBQ3pCLEtBQUs7QUFDTDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsYUFBYSwyREFBa0I7QUFDL0I7O0FBRUEsSUFBSSxhQUFvQixLQUFLLGlEQUFRLElBQUksYUFBb0I7QUFDN0Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsR0FBRztBQUNIOztBQUVBLGlFQUFlLEdBQUciLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vY29tcG9uZW50cy9BcHAudHN4PzA2MjQiXSwic291cmNlc0NvbnRlbnQiOlsidmFyIF9fYXdhaXRlciA9IHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xuICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7XG4gICAgICByZXNvbHZlKHZhbHVlKTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZWplY3QoZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7XG4gICAgICByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTtcbiAgICB9XG5cbiAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XG4gIH0pO1xufTtcblxuaW1wb3J0IHsganN4IGFzIF9qc3gsIGpzeHMgYXMgX2pzeHMsIEZyYWdtZW50IGFzIF9GcmFnbWVudCB9IGZyb20gXCJyZWFjdC9qc3gtcnVudGltZVwiO1xuaW1wb3J0IFJlYWN0LCB7IHVzZUNvbnRleHQgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCB7IGZsdXNoU3luYyB9IGZyb20gXCJyZWFjdC1kb21cIjtcbmltcG9ydCByb3VnaCBmcm9tIFwicm91Z2hqcy9iaW4vcm91Z2hcIjtcbmltcG9ydCBjbHN4IGZyb20gXCJjbHN4XCI7XG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tIFwibmFub2lkXCI7XG5pbXBvcnQgeyBhY3Rpb25BZGRUb0xpYnJhcnksIGFjdGlvbkJyaW5nRm9yd2FyZCwgYWN0aW9uQnJpbmdUb0Zyb250LCBhY3Rpb25Db3B5LCBhY3Rpb25Db3B5QXNQbmcsIGFjdGlvbkNvcHlBc1N2ZywgY29weVRleHQsIGFjdGlvbkNvcHlTdHlsZXMsIGFjdGlvbkN1dCwgYWN0aW9uRGVsZXRlU2VsZWN0ZWQsIGFjdGlvbkR1cGxpY2F0ZVNlbGVjdGlvbiwgYWN0aW9uRmluYWxpemUsIGFjdGlvbkZsaXBIb3Jpem9udGFsLCBhY3Rpb25GbGlwVmVydGljYWwsIGFjdGlvbkdyb3VwLCBhY3Rpb25QYXN0ZVN0eWxlcywgYWN0aW9uU2VsZWN0QWxsLCBhY3Rpb25TZW5kQmFja3dhcmQsIGFjdGlvblNlbmRUb0JhY2ssIGFjdGlvblRvZ2dsZUdyaWRNb2RlLCBhY3Rpb25Ub2dnbGVTdGF0cywgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVW5iaW5kVGV4dCwgYWN0aW9uQmluZFRleHQsIGFjdGlvblVuZ3JvdXAsIGFjdGlvbkxpbmssIGFjdGlvblRvZ2dsZUVsZW1lbnRMb2NrLCBhY3Rpb25Ub2dnbGVMaW5lYXJFZGl0b3IgfSBmcm9tIFwiLi4vYWN0aW9uc1wiO1xuaW1wb3J0IHsgY3JlYXRlUmVkb0FjdGlvbiwgY3JlYXRlVW5kb0FjdGlvbiB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkhpc3RvcnlcIjtcbmltcG9ydCB7IEFjdGlvbk1hbmFnZXIgfSBmcm9tIFwiLi4vYWN0aW9ucy9tYW5hZ2VyXCI7XG5pbXBvcnQgeyBhY3Rpb25zIH0gZnJvbSBcIi4uL2FjdGlvbnMvcmVnaXN0ZXJcIjtcbmltcG9ydCB7IHRyYWNrRXZlbnQgfSBmcm9tIFwiLi4vYW5hbHl0aWNzXCI7XG5pbXBvcnQgeyBnZXREZWZhdWx0QXBwU3RhdGUsIGlzRXJhc2VyQWN0aXZlLCBpc0hhbmRUb29sQWN0aXZlIH0gZnJvbSBcIi4uL2FwcFN0YXRlXCI7XG5pbXBvcnQgeyBwYXJzZUNsaXBib2FyZCB9IGZyb20gXCIuLi9jbGlwYm9hcmRcIjtcbmltcG9ydCB7IEFQUF9OQU1FLCBDVVJTT1JfVFlQRSwgREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hULCBERUZBVUxUX1VJX09QVElPTlMsIERFRkFVTFRfVkVSVElDQUxfQUxJR04sIERSQUdHSU5HX1RIUkVTSE9MRCwgRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZLCBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQsIEVMRU1FTlRfVFJBTlNMQVRFX0FNT1VOVCwgRU5WLCBFVkVOVCwgRlJBTUVfU1RZTEUsIEdSSURfU0laRSwgSU1BR0VfTUlNRV9UWVBFUywgSU1BR0VfUkVOREVSX1RJTUVPVVQsIGlzQW5kcm9pZCwgaXNCcmF2ZSwgTElORV9DT05GSVJNX1RIUkVTSE9MRCwgTUFYX0FMTE9XRURfRklMRV9CWVRFUywgTUlNRV9UWVBFUywgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9QT1JUUkFJVCwgTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEgsIE1RX1NNX01BWF9XSURUSCwgUE9JTlRFUl9CVVRUT04sIFJPVU5ETkVTUywgU0NST0xMX1RJTUVPVVQsIFRBUF9UV0lDRV9USU1FT1VULCBURVhUX1RPX0NFTlRFUl9TTkFQX1RIUkVTSE9MRCwgVEhFTUUsIFRIRU1FX0ZJTFRFUiwgVE9VQ0hfQ1RYX01FTlVfVElNRU9VVCwgVkVSVElDQUxfQUxJR04sIFlPVVRVQkVfU1RBVEVTLCBaT09NX1NURVAsIFBPSU5URVJfRVZFTlRTIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgZXhwb3J0Q2FudmFzLCBsb2FkRnJvbUJsb2IgfSBmcm9tIFwiLi4vZGF0YVwiO1xuaW1wb3J0IExpYnJhcnksIHsgZGlzdHJpYnV0ZUxpYnJhcnlJdGVtc09uU3F1YXJlR3JpZCB9IGZyb20gXCIuLi9kYXRhL2xpYnJhcnlcIjtcbmltcG9ydCB7IHJlc3RvcmUsIHJlc3RvcmVFbGVtZW50cyB9IGZyb20gXCIuLi9kYXRhL3Jlc3RvcmVcIjtcbmltcG9ydCB7IGRyYWdOZXdFbGVtZW50LCBkcmFnU2VsZWN0ZWRFbGVtZW50cywgZHVwbGljYXRlRWxlbWVudCwgZ2V0Q29tbW9uQm91bmRzLCBnZXRDdXJzb3JGb3JSZXNpemluZ0VsZW1lbnQsIGdldERyYWdPZmZzZXRYWSwgZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLCBnZXROb3JtYWxpemVkRGltZW5zaW9ucywgZ2V0UmVzaXplQXJyb3dEaXJlY3Rpb24sIGdldFJlc2l6ZU9mZnNldFhZLCBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUsIGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzLCBoaXRUZXN0LCBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQsIGlzSW52aXNpYmx5U21hbGxFbGVtZW50LCBpc05vbkRlbGV0ZWRFbGVtZW50LCBpc1RleHRFbGVtZW50LCBuZXdFbGVtZW50LCBuZXdMaW5lYXJFbGVtZW50LCBuZXdUZXh0RWxlbWVudCwgbmV3SW1hZ2VFbGVtZW50LCB0ZXh0V3lzaXd5ZywgdHJhbnNmb3JtRWxlbWVudHMsIHVwZGF0ZVRleHRFbGVtZW50LCByZWRyYXdUZXh0Qm91bmRpbmdCb3ggfSBmcm9tIFwiLi4vZWxlbWVudFwiO1xuaW1wb3J0IHsgYmluZE9yVW5iaW5kTGluZWFyRWxlbWVudCwgYmluZE9yVW5iaW5kU2VsZWN0ZWRFbGVtZW50cywgZml4QmluZGluZ3NBZnRlckRlbGV0aW9uLCBmaXhCaW5kaW5nc0FmdGVyRHVwbGljYXRpb24sIGdldEVsaWdpYmxlRWxlbWVudHNGb3JCaW5kaW5nLCBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcsIGlzQmluZGluZ0VuYWJsZWQsIGlzTGluZWFyRWxlbWVudFNpbXBsZUFuZEFscmVhZHlCb3VuZCwgbWF5YmVCaW5kTGluZWFyRWxlbWVudCwgc2hvdWxkRW5hYmxlQmluZGluZ0ZvclBvaW50ZXJFdmVudCwgdW5iaW5kTGluZWFyRWxlbWVudHMsIHVwZGF0ZUJvdW5kRWxlbWVudHMgfSBmcm9tIFwiLi4vZWxlbWVudC9iaW5kaW5nXCI7XG5pbXBvcnQgeyBMaW5lYXJFbGVtZW50RWRpdG9yIH0gZnJvbSBcIi4uL2VsZW1lbnQvbGluZWFyRWxlbWVudEVkaXRvclwiO1xuaW1wb3J0IHsgbXV0YXRlRWxlbWVudCwgbmV3RWxlbWVudFdpdGggfSBmcm9tIFwiLi4vZWxlbWVudC9tdXRhdGVFbGVtZW50XCI7XG5pbXBvcnQgeyBkZWVwQ29weUVsZW1lbnQsIGR1cGxpY2F0ZUVsZW1lbnRzLCBuZXdGcmFtZUVsZW1lbnQsIG5ld0ZyZWVEcmF3RWxlbWVudCwgbmV3RW1iZWRkYWJsZUVsZW1lbnQgfSBmcm9tIFwiLi4vZWxlbWVudC9uZXdFbGVtZW50XCI7XG5pbXBvcnQgeyBoYXNCb3VuZFRleHRFbGVtZW50LCBpc0Fycm93RWxlbWVudCwgaXNCaW5kaW5nRWxlbWVudCwgaXNCaW5kaW5nRWxlbWVudFR5cGUsIGlzQm91bmRUb0NvbnRhaW5lciwgaXNGcmFtZUVsZW1lbnQsIGlzSW1hZ2VFbGVtZW50LCBpc0VtYmVkZGFibGVFbGVtZW50LCBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50LCBpc0xpbmVhckVsZW1lbnQsIGlzTGluZWFyRWxlbWVudFR5cGUsIGlzVXNpbmdBZGFwdGl2ZVJhZGl1cyB9IGZyb20gXCIuLi9lbGVtZW50L3R5cGVDaGVja3NcIjtcbmltcG9ydCB7IGdldENlbnRlciwgZ2V0RGlzdGFuY2UgfSBmcm9tIFwiLi4vZ2VzdHVyZVwiO1xuaW1wb3J0IHsgZWRpdEdyb3VwRm9yU2VsZWN0ZWRFbGVtZW50LCBnZXRFbGVtZW50c0luR3JvdXAsIGdldFNlbGVjdGVkR3JvdXBJZEZvckVsZW1lbnQsIGdldFNlbGVjdGVkR3JvdXBJZHMsIGlzRWxlbWVudEluR3JvdXAsIGlzU2VsZWN0ZWRWaWFHcm91cCwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyB9IGZyb20gXCIuLi9ncm91cHNcIjtcbmltcG9ydCBIaXN0b3J5IGZyb20gXCIuLi9oaXN0b3J5XCI7XG5pbXBvcnQgeyBkZWZhdWx0TGFuZywgZ2V0TGFuZ3VhZ2UsIGxhbmd1YWdlcywgc2V0TGFuZ3VhZ2UsIHQgfSBmcm9tIFwiLi4vaTE4blwiO1xuaW1wb3J0IHsgQ09ERVMsIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIsIHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8sIHNob3VsZFJvdGF0ZVdpdGhEaXNjcmV0ZUFuZ2xlLCBpc0Fycm93S2V5LCBLRVlTIH0gZnJvbSBcIi4uL2tleXNcIjtcbmltcG9ydCB7IGlzRWxlbWVudEluVmlld3BvcnQgfSBmcm9tIFwiLi4vZWxlbWVudC9zaXplSGVscGVyc1wiO1xuaW1wb3J0IHsgZGlzdGFuY2UyZCwgZ2V0Q29ybmVyUmFkaXVzLCBnZXRHcmlkUG9pbnQsIGlzUGF0aEFMb29wIH0gZnJvbSBcIi4uL21hdGhcIjtcbmltcG9ydCB7IGNhbGN1bGF0ZVNjcm9sbENlbnRlciwgZ2V0RWxlbWVudHNBdFBvc2l0aW9uLCBnZXRFbGVtZW50c1dpdGhpblNlbGVjdGlvbiwgZ2V0Tm9ybWFsaXplZFpvb20sIGdldFNlbGVjdGVkRWxlbWVudHMsIGhhc0JhY2tncm91bmQsIGlzT3ZlclNjcm9sbEJhcnMsIGlzU29tZUVsZW1lbnRTZWxlY3RlZCB9IGZyb20gXCIuLi9zY2VuZVwiO1xuaW1wb3J0IFNjZW5lIGZyb20gXCIuLi9zY2VuZS9TY2VuZVwiO1xuaW1wb3J0IHsgZ2V0U3RhdGVGb3Jab29tIH0gZnJvbSBcIi4uL3NjZW5lL3pvb21cIjtcbmltcG9ydCB7IGZpbmRTaGFwZUJ5S2V5IH0gZnJvbSBcIi4uL3NoYXBlc1wiO1xuaW1wb3J0IHsgZGVib3VuY2UsIGRpc3RhbmNlLCBnZXRGb250U3RyaW5nLCBnZXROZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lciwgaXNJbnB1dExpa2UsIGlzVG9vbEljb24sIGlzV3JpdGFibGVFbGVtZW50LCByZXNldEN1cnNvciwgcmVzb2x2YWJsZVByb21pc2UsIHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcywgc2V0Q3Vyc29yLCBzZXRDdXJzb3JGb3JTaGFwZSwgdHVwbGVUb0Nvb3JzLCB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMsIHdpdGhCYXRjaGVkVXBkYXRlcywgd3JhcEV2ZW50LCB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQsIHVwZGF0ZU9iamVjdCwgc2V0RXJhc2VyQ3Vyc29yLCB1cGRhdGVBY3RpdmVUb29sLCBnZXRTaG9ydGN1dEtleSwgaXNUcmFuc3BhcmVudCwgZWFzZVRvVmFsdWVzUkFGLCBtdXRlRlNBYm9ydEVycm9yLCBpc1Rlc3RFbnYsIGVhc2VPdXQgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IsIGV4dHJhY3RTcmMsIGdldEVtYmVkTGluayB9IGZyb20gXCIuLi9lbGVtZW50L2VtYmVkZGFibGVcIjtcbmltcG9ydCB7IENvbnRleHRNZW51LCBDT05URVhUX01FTlVfU0VQQVJBVE9SIH0gZnJvbSBcIi4vQ29udGV4dE1lbnVcIjtcbmltcG9ydCBMYXllclVJIGZyb20gXCIuL0xheWVyVUlcIjtcbmltcG9ydCB7IFRvYXN0IH0gZnJvbSBcIi4vVG9hc3RcIjtcbmltcG9ydCB7IGFjdGlvblRvZ2dsZVZpZXdNb2RlIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uVG9nZ2xlVmlld01vZGVcIjtcbmltcG9ydCB7IGRhdGFVUkxUb0ZpbGUsIGdlbmVyYXRlSWRGcm9tRmlsZSwgZ2V0RGF0YVVSTCwgZ2V0RmlsZUZyb21FdmVudCwgaXNJbWFnZUZpbGVIYW5kbGUsIGlzU3VwcG9ydGVkSW1hZ2VGaWxlLCBsb2FkU2NlbmVPckxpYnJhcnlGcm9tQmxvYiwgbm9ybWFsaXplRmlsZSwgcGFyc2VMaWJyYXJ5SlNPTiwgcmVzaXplSW1hZ2VGaWxlLCBTVkdTdHJpbmdUb0ZpbGUgfSBmcm9tIFwiLi4vZGF0YS9ibG9iXCI7XG5pbXBvcnQgeyBnZXRJbml0aWFsaXplZEltYWdlRWxlbWVudHMsIGxvYWRIVE1MSW1hZ2VFbGVtZW50LCBub3JtYWxpemVTVkcsIHVwZGF0ZUltYWdlQ2FjaGUgYXMgX3VwZGF0ZUltYWdlQ2FjaGUgfSBmcm9tIFwiLi4vZWxlbWVudC9pbWFnZVwiO1xuaW1wb3J0IHRocm90dGxlIGZyb20gXCJsb2Rhc2gudGhyb3R0bGVcIjtcbmltcG9ydCB7IGZpbGVPcGVuIH0gZnJvbSBcIi4uL2RhdGEvZmlsZXN5c3RlbVwiO1xuaW1wb3J0IHsgYmluZFRleHRUb1NoYXBlQWZ0ZXJEdXBsaWNhdGlvbiwgZ2V0QXBwcm94TWluTGluZUhlaWdodCwgZ2V0QXBwcm94TWluTGluZVdpZHRoLCBnZXRCb3VuZFRleHRFbGVtZW50LCBnZXRDb250YWluZXJDZW50ZXIsIGdldENvbnRhaW5lckVsZW1lbnQsIGdldERlZmF1bHRMaW5lSGVpZ2h0LCBnZXRMaW5lSGVpZ2h0SW5QeCwgZ2V0VGV4dEJpbmRhYmxlQ29udGFpbmVyQXRQb3NpdGlvbiwgaXNNZWFzdXJlVGV4dFN1cHBvcnRlZCwgaXNWYWxpZFRleHRDb250YWluZXIgfSBmcm9tIFwiLi4vZWxlbWVudC90ZXh0RWxlbWVudFwiO1xuaW1wb3J0IHsgaXNIaXR0aW5nRWxlbWVudE5vdENvbnNpZGVyaW5nQm91bmRpbmdCb3ggfSBmcm9tIFwiLi4vZWxlbWVudC9jb2xsaXNpb25cIjtcbmltcG9ydCB7IHNob3dIeXBlcmxpbmtUb29sdGlwLCBoaWRlSHlwZXJsaW5rVG9vbGlwLCBIeXBlcmxpbmssIGlzUG9pbnRIaXR0aW5nTGluaywgaXNQb2ludEhpdHRpbmdMaW5rSWNvbiB9IGZyb20gXCIuLi9lbGVtZW50L0h5cGVybGlua1wiO1xuaW1wb3J0IHsgaXNMb2NhbExpbmssIG5vcm1hbGl6ZUxpbmssIHRvVmFsaWRVUkwgfSBmcm9tIFwiLi4vZGF0YS91cmxcIjtcbmltcG9ydCB7IHNob3VsZFNob3dCb3VuZGluZ0JveCB9IGZyb20gXCIuLi9lbGVtZW50L3RyYW5zZm9ybUhhbmRsZXNcIjtcbmltcG9ydCB7IGFjdGlvblVubG9ja0FsbEVsZW1lbnRzIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uRWxlbWVudExvY2tcIjtcbmltcG9ydCB7IEZvbnRzIH0gZnJvbSBcIi4uL3NjZW5lL0ZvbnRzXCI7XG5pbXBvcnQgeyBnZXRGcmFtZUVsZW1lbnRzLCBpc0N1cnNvckluRnJhbWUsIGJpbmRFbGVtZW50c1RvRnJhbWVzQWZ0ZXJEdXBsaWNhdGlvbiwgYWRkRWxlbWVudHNUb0ZyYW1lLCByZXBsYWNlQWxsRWxlbWVudHNJbkZyYW1lLCByZW1vdmVFbGVtZW50c0Zyb21GcmFtZSwgZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUsIGdldEVsZW1lbnRzSW5OZXdGcmFtZSwgZ2V0Q29udGFpbmluZ0ZyYW1lLCBlbGVtZW50T3ZlcmxhcHNXaXRoRnJhbWUsIHVwZGF0ZUZyYW1lTWVtYmVyc2hpcE9mU2VsZWN0ZWRFbGVtZW50cywgaXNFbGVtZW50SW5GcmFtZSB9IGZyb20gXCIuLi9mcmFtZVwiO1xuaW1wb3J0IHsgZXhjbHVkZUVsZW1lbnRzSW5GcmFtZXNGcm9tU2VsZWN0aW9uLCBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyB9IGZyb20gXCIuLi9zY2VuZS9zZWxlY3Rpb25cIjtcbmltcG9ydCB7IGFjdGlvblBhc3RlIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uQ2xpcGJvYXJkXCI7XG5pbXBvcnQgeyBhY3Rpb25SZW1vdmVBbGxFbGVtZW50c0Zyb21GcmFtZSwgYWN0aW9uU2VsZWN0QWxsRWxlbWVudHNJbkZyYW1lIH0gZnJvbSBcIi4uL2FjdGlvbnMvYWN0aW9uRnJhbWVcIjtcbmltcG9ydCB7IGFjdGlvblRvZ2dsZUhhbmRUb29sLCB6b29tVG9GaXQgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25DYW52YXNcIjtcbmltcG9ydCB7IGpvdGFpU3RvcmUgfSBmcm9tIFwiLi4vam90YWlcIjtcbmltcG9ydCB7IGFjdGl2ZUNvbmZpcm1EaWFsb2dBdG9tIH0gZnJvbSBcIi4vQWN0aXZlQ29uZmlybURpYWxvZ1wiO1xuaW1wb3J0IHsgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkJvdW5kVGV4dFwiO1xuaW1wb3J0IEJyYXZlTWVhc3VyZVRleHRFcnJvciBmcm9tIFwiLi9CcmF2ZU1lYXN1cmVUZXh0RXJyb3JcIjtcbmltcG9ydCB7IGFjdGl2ZUV5ZURyb3BwZXJBdG9tIH0gZnJvbSBcIi4vRXllRHJvcHBlclwiO1xuaW1wb3J0IHsgY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzIH0gZnJvbSBcIi4uL2RhdGEvdHJhbnNmb3JtXCI7XG5pbXBvcnQgeyBpc1NpZGViYXJEb2NrZWRBdG9tIH0gZnJvbSBcIi4vU2lkZWJhci9TaWRlYmFyXCI7XG5pbXBvcnQgeyBTdGF0aWNDYW52YXMsIEludGVyYWN0aXZlQ2FudmFzIH0gZnJvbSBcIi4vY2FudmFzZXNcIjtcbmltcG9ydCB7IFJlbmRlcmVyIH0gZnJvbSBcIi4uL3NjZW5lL1JlbmRlcmVyXCI7XG5pbXBvcnQgeyBTaGFwZUNhY2hlIH0gZnJvbSBcIi4uL3NjZW5lL1NoYXBlQ2FjaGVcIjtcbmNvbnN0IEFwcENvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuY29uc3QgQXBwUHJvcHNDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChudWxsKTtcbmNvbnN0IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWUgPSB7XG4gIGlzU21TY3JlZW46IGZhbHNlLFxuICBpc01vYmlsZTogZmFsc2UsXG4gIGlzVG91Y2hTY3JlZW46IGZhbHNlLFxuICBjYW5EZXZpY2VGaXRTaWRlYmFyOiBmYWxzZSxcbiAgaXNMYW5kc2NhcGU6IGZhbHNlXG59O1xuY29uc3QgRGV2aWNlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoZGV2aWNlQ29udGV4dEluaXRpYWxWYWx1ZSk7XG5EZXZpY2VDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJEZXZpY2VDb250ZXh0XCI7XG5leHBvcnQgY29uc3QgRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KHtcbiAgY29udGFpbmVyOiBudWxsLFxuICBpZDogbnVsbFxufSk7XG5FeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdFbGVtZW50c0NvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KFtdKTtcbkV4Y2FsaWRyYXdFbGVtZW50c0NvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdFbGVtZW50c0NvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZ2V0RGVmYXVsdEFwcFN0YXRlKCkpLCB7XG4gIHdpZHRoOiAwLFxuICBoZWlnaHQ6IDAsXG4gIG9mZnNldExlZnQ6IDAsXG4gIG9mZnNldFRvcDogMFxufSkpO1xuRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoKCkgPT4ge1xuICBjb25zb2xlLndhcm4oXCJ1bml0aWFsaXplZCBFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0IGNvbnRleHQhXCIpO1xufSk7XG5FeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHRcIjtcbmV4cG9ydCBjb25zdCB1c2VBcHAgPSAoKSA9PiB1c2VDb250ZXh0KEFwcENvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUFwcFByb3BzID0gKCkgPT4gdXNlQ29udGV4dChBcHBQcm9wc0NvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZURldmljZSA9ICgpID0+IHVzZUNvbnRleHQoRGV2aWNlQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0NvbnRhaW5lciA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdFbGVtZW50cyA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0FwcFN0YXRlID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3U2V0QXBwU3RhdGUgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQpO1xubGV0IGRpZFRhcFR3aWNlID0gZmFsc2U7XG5sZXQgdGFwcGVkVHdpY2VUaW1lciA9IDA7XG5sZXQgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbmxldCBpc1Bhbm5pbmcgPSBmYWxzZTtcbmxldCBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gZmFsc2U7XG5sZXQgY3VycmVudFNjcm9sbEJhcnMgPSB7XG4gIGhvcml6b250YWw6IG51bGwsXG4gIHZlcnRpY2FsOiBudWxsXG59O1xubGV0IHRvdWNoVGltZW91dCA9IDA7XG5sZXQgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG4vKipcbiAqIE1hcCBvZiB5b3V0dWJlIGVtYmVkIHZpZGVvIHN0YXRlc1xuICovXG5cbmNvbnN0IFlPVVRVQkVfVklERU9fU1RBVEVTID0gbmV3IE1hcCgpO1xubGV0IElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG5sZXQgSVNfUExBSU5fUEFTVEVfVElNRVIgPSAwO1xubGV0IFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gZmFsc2U7XG5sZXQgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG5jb25zdCBnZXN0dXJlID0ge1xuICBwb2ludGVyczogbmV3IE1hcCgpLFxuICBsYXN0Q2VudGVyOiBudWxsLFxuICBpbml0aWFsRGlzdGFuY2U6IG51bGwsXG4gIGluaXRpYWxTY2FsZTogbnVsbFxufTtcblxuY2xhc3MgQXBwIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICB2YXIgX2E7XG5cbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyA9IG51bGw7XG4gICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICB0aGlzLmRldmljZSA9IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWU7XG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmID0gUmVhY3QuY3JlYXRlUmVmKCk7XG4gICAgdGhpcy5maWxlcyA9IHt9O1xuICAgIHRoaXMuaW1hZ2VDYWNoZSA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmlGcmFtZVJlZnMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5sYXN0UG9pbnRlckRvd24gPSBudWxsO1xuICAgIHRoaXMubGFzdFBvaW50ZXJVcCA9IG51bGw7XG4gICAgdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbiA9IHtcbiAgICAgIHg6IDAsXG4gICAgICB5OiAwXG4gICAgfTtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBlbWJlZGRhYmxlRWxlbWVudHMgPSBuZXcgTWFwKCk7XG4gICAgICBsZXQgdXBkYXRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgZW1iZWRkYWJsZUVsZW1lbnRzLnNldChlbGVtZW50LmlkLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50LnZhbGlkYXRlZCA9PSBudWxsKSB7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlZCA9IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IoZWxlbWVudC5saW5rLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSk7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgdmFsaWRhdGVkXG4gICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWQpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgfSAvLyBHQ1xuXG5cbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5mb3JFYWNoKChyZWYsIGlkKSA9PiB7XG4gICAgICAgIGlmICghZW1iZWRkYWJsZUVsZW1lbnRzLmhhcyhpZCkpIHtcbiAgICAgICAgICB0aGlzLmlGcmFtZVJlZnMuZGVsZXRlKGlkKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQgPSBmcmFtZUVsZW1lbnQgPT4ge1xuICAgICAgcmV0dXJuIGAke3RoaXMuaWR9LWZyYW1lLW5hbWUtJHtmcmFtZUVsZW1lbnQuaWR9YDtcbiAgICB9O1xuXG4gICAgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSA9IHtcbiAgICAgIGdldDogZnJhbWVFbGVtZW50ID0+IHtcbiAgICAgICAgbGV0IGJvdW5kcyA9IHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLmdldChmcmFtZUVsZW1lbnQuaWQpO1xuXG4gICAgICAgIGlmICghYm91bmRzIHx8IGJvdW5kcy56b29tICE9PSB0aGlzLnN0YXRlLnpvb20udmFsdWUgfHwgYm91bmRzLnZlcnNpb25Ob25jZSAhPT0gZnJhbWVFbGVtZW50LnZlcnNpb25Ob25jZSkge1xuICAgICAgICAgIGNvbnN0IGZyYW1lTmFtZURpdiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQoZnJhbWVFbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoZnJhbWVOYW1lRGl2KSB7XG4gICAgICAgICAgICBjb25zdCBib3ggPSBmcmFtZU5hbWVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBjb25zdCBib3hTY2VuZVRvcExlZnQgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgICBjbGllbnRYOiBib3gueCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LnlcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3QgYm94U2NlbmVCb3R0b21SaWdodCA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICAgIGNsaWVudFg6IGJveC5yaWdodCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LmJvdHRvbVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBib3VuZHMgPSB7XG4gICAgICAgICAgICAgIHg6IGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICB5OiBib3hTY2VuZVRvcExlZnQueSxcbiAgICAgICAgICAgICAgd2lkdGg6IGJveFNjZW5lQm90dG9tUmlnaHQueCAtIGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICBoZWlnaHQ6IGJveFNjZW5lQm90dG9tUmlnaHQueSAtIGJveFNjZW5lVG9wTGVmdC55LFxuICAgICAgICAgICAgICBhbmdsZTogMCxcbiAgICAgICAgICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLnZhbHVlLFxuICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IGZyYW1lRWxlbWVudC52ZXJzaW9uTm9uY2VcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLnNldChmcmFtZUVsZW1lbnQuaWQsIGJvdW5kcyk7XG5cbiAgICAgICAgICAgIHJldHVybiBib3VuZHM7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYm91bmRzO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICovXG4gICAgICBfY2FjaGU6IG5ldyBNYXAoKVxuICAgIH07XG5cbiAgICB0aGlzLnJlbmRlckZyYW1lTmFtZXMgPSAoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCB8fCAhdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc0RhcmtUaGVtZSA9IHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiO1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLm1hcCgoZiwgaW5kZXgpID0+IHtcbiAgICAgICAgaWYgKCFpc0VsZW1lbnRJblZpZXdwb3J0KGYsIHRoaXMuY2FudmFzLndpZHRoIC8gd2luZG93LmRldmljZVBpeGVsUmF0aW8sIHRoaXMuY2FudmFzLmhlaWdodCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLCB7XG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb21cbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAvLyBpZiBmcmFtZSBub3QgdmlzaWJsZSwgZG9uJ3QgcmVuZGVyIGl0cyBuYW1lXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogeDEsXG4gICAgICAgICAgeTogeTFcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBmLngsXG4gICAgICAgICAgc2NlbmVZOiBmLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB4MlxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IGYueCArIGYud2lkdGgsXG4gICAgICAgICAgc2NlbmVZOiBmLnkgKyBmLmhlaWdodFxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9HQVAgPSAyMDtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgPSA2O1xuXG4gICAgICAgIGNvbnN0IHJlc2V0ID0gKCkgPT4ge1xuICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgIGlmICgoKF9hID0gZi5uYW1lKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudHJpbSgpKSA9PT0gXCJcIikge1xuICAgICAgICAgICAgbXV0YXRlRWxlbWVudChmLCB7XG4gICAgICAgICAgICAgIG5hbWU6IG51bGxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0ZyYW1lOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbGV0IGZyYW1lTmFtZUpTWDtcblxuICAgICAgICBpZiAoZi5pZCA9PT0gdGhpcy5zdGF0ZS5lZGl0aW5nRnJhbWUpIHtcbiAgICAgICAgICBjb25zdCBmcmFtZU5hbWVJbkVkaXQgPSBmLm5hbWUgPT0gbnVsbCA/IGBGcmFtZSAke2luZGV4ICsgMX1gIDogZi5uYW1lO1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IF9qc3goXCJpbnB1dFwiLCB7XG4gICAgICAgICAgICBhdXRvRm9jdXM6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogZnJhbWVOYW1lSW5FZGl0LFxuICAgICAgICAgICAgb25DaGFuZ2U6IGUgPT4ge1xuICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGYsIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBlLnRhcmdldC52YWx1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkJsdXI6ICgpID0+IHJlc2V0KCksXG4gICAgICAgICAgICBvbktleURvd246IGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgLy8gZm9yIHNvbWUgaW5leHBsaWNhYmxlIHJlYXNvbiwgYG9uQmx1cmAgdHJpZ2dlcmVkIG9uIEVTQ1xuICAgICAgICAgICAgICAvLyBkb2VzIG5vdCByZXNldCBgc3RhdGUuZWRpdGluZ0ZyYW1lYCBkZXNwaXRlIGJlaW5nIGNhbGxlZCxcbiAgICAgICAgICAgICAgLy8gYW5kIHdlIG5lZWQgdG8gcmVzZXQgaXQgaGVyZSBhcyB3ZWxsXG4gICAgICAgICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuRVNDQVBFIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5FTlRFUikge1xuICAgICAgICAgICAgICAgIHJlc2V0KCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLnZpZXdCYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgICAgIGZpbHRlcjogaXNEYXJrVGhlbWUgPyBUSEVNRV9GSUxURVIgOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgekluZGV4OiAyLFxuICAgICAgICAgICAgICBib3JkZXI6IFwibm9uZVwiLFxuICAgICAgICAgICAgICBkaXNwbGF5OiBcImJsb2NrXCIsXG4gICAgICAgICAgICAgIHBhZGRpbmc6IGAke0ZSQU1FX05BTUVfRURJVF9QQURESU5HfXB4YCxcbiAgICAgICAgICAgICAgYm9yZGVyUmFkaXVzOiA0LFxuICAgICAgICAgICAgICBib3hTaGFkb3c6IFwiaW5zZXQgMCAwIDAgMXB4IHZhcigtLWNvbG9yLXByaW1hcnkpXCIsXG4gICAgICAgICAgICAgIGZvbnRGYW1pbHk6IFwiQXNzaXN0YW50XCIsXG4gICAgICAgICAgICAgIGZvbnRTaXplOiBcIjE0cHhcIixcbiAgICAgICAgICAgICAgdHJhbnNmb3JtOiBgdHJhbnNsYXRlWSgtJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weClgLFxuICAgICAgICAgICAgICBjb2xvcjogXCJ2YXIoLS1jb2xvci1ncmF5LTgwKVwiLFxuICAgICAgICAgICAgICBvdmVyZmxvdzogXCJoaWRkZW5cIixcbiAgICAgICAgICAgICAgbWF4V2lkdGg6IGAke01hdGgubWluKHgyIC0geDEgLSBGUkFNRV9OQU1FX0VESVRfUEFERElORywgZG9jdW1lbnQuYm9keS5jbGllbnRXaWR0aCAtIHgxIC0gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcpfXB4YFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNpemU6IGZyYW1lTmFtZUluRWRpdC5sZW5ndGggKyAxIHx8IDEsXG4gICAgICAgICAgICBkaXI6IFwiYXV0b1wiLFxuICAgICAgICAgICAgYXV0b0NvbXBsZXRlOiBcIm9mZlwiLFxuICAgICAgICAgICAgYXV0b0NhcGl0YWxpemU6IFwib2ZmXCIsXG4gICAgICAgICAgICBhdXRvQ29ycmVjdDogXCJvZmZcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IGYubmFtZSA9PSBudWxsIHx8IGYubmFtZS50cmltKCkgPT09IFwiXCIgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZS50cmltKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBpZDogdGhpcy5nZXRGcmFtZU5hbWVET01JZChmKSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgcG9zaXRpb246IFwiYWJzb2x1dGVcIixcbiAgICAgICAgICAgIHRvcDogYCR7eTEgLSBGUkFNRV9OQU1FX0dBUCAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wfXB4YCxcbiAgICAgICAgICAgIGxlZnQ6IGAke3gxIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0IC0gKHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID09PSBmLmlkID8gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgOiAwKX1weGAsXG4gICAgICAgICAgICB6SW5kZXg6IDIsXG4gICAgICAgICAgICBmb250U2l6ZTogXCIxNHB4XCIsXG4gICAgICAgICAgICBjb2xvcjogaXNEYXJrVGhlbWUgPyBcInZhcigtLWNvbG9yLWdyYXktNjApXCIgOiBcInZhcigtLWNvbG9yLWdyYXktNTApXCIsXG4gICAgICAgICAgICB3aWR0aDogXCJtYXgtY29udGVudFwiLFxuICAgICAgICAgICAgbWF4V2lkdGg6IGAke3gyIC0geDEgKyBGUkFNRV9OQU1FX0VESVRfUEFERElORyAqIDJ9cHhgLFxuICAgICAgICAgICAgb3ZlcmZsb3c6IGYuaWQgPT09IHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID8gXCJ2aXNpYmxlXCIgOiBcImhpZGRlblwiLFxuICAgICAgICAgICAgd2hpdGVTcGFjZTogXCJub3dyYXBcIixcbiAgICAgICAgICAgIHRleHRPdmVyZmxvdzogXCJlbGxpcHNpc1wiLFxuICAgICAgICAgICAgY3Vyc29yOiBDVVJTT1JfVFlQRS5NT1ZFLFxuICAgICAgICAgICAgcG9pbnRlckV2ZW50czogdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQgPyBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZCA6IFBPSU5URVJfRVZFTlRTLmVuYWJsZWRcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uUG9pbnRlckRvd246IGV2ZW50ID0+IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24oZXZlbnQpLFxuICAgICAgICAgIG9uV2hlZWw6IGV2ZW50ID0+IHRoaXMuaGFuZGxlV2hlZWwoZXZlbnQpLFxuICAgICAgICAgIG9uQ29udGV4dE1lbnU6IHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUsXG4gICAgICAgICAgb25Eb3VibGVDbGljazogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogZi5pZFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IGZyYW1lTmFtZUpTWFxuICAgICAgICB9KSwgZi5pZCk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5mb2N1c0NvbnRhaW5lciA9ICgpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5mb2N1cygpO1xuICAgIH07XG5cbiAgICB0aGlzLmdldFNjZW5lRWxlbWVudHNJbmNsdWRpbmdEZWxldGVkID0gKCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0U2NlbmVFbGVtZW50cyA9ICgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgIH07XG5cbiAgICB0aGlzLm9uSW5zZXJ0RWxlbWVudHMgPSBlbGVtZW50cyA9PiB7XG4gICAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5KHtcbiAgICAgICAgZWxlbWVudHMsXG4gICAgICAgIHBvc2l0aW9uOiBcImNlbnRlclwiLFxuICAgICAgICBmaWxlczogbnVsbFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMub25FeHBvcnRJbWFnZSA9ICh0eXBlLCBlbGVtZW50cykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdHJhY2tFdmVudChcImV4cG9ydFwiLCB0eXBlLCBcInVpXCIpO1xuICAgICAgY29uc3QgZmlsZUhhbmRsZSA9IHlpZWxkIGV4cG9ydENhbnZhcyh0eXBlLCBlbGVtZW50cywgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcywge1xuICAgICAgICBleHBvcnRCYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLmV4cG9ydEJhY2tncm91bmQsXG4gICAgICAgIG5hbWU6IHRoaXMuc3RhdGUubmFtZSxcbiAgICAgICAgdmlld0JhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yXG4gICAgICB9KS5jYXRjaChtdXRlRlNBYm9ydEVycm9yKS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZXhwb3J0RW1iZWRTY2VuZSAmJiBmaWxlSGFuZGxlICYmIGlzSW1hZ2VGaWxlSGFuZGxlKGZpbGVIYW5kbGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGZpbGVIYW5kbGVcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLm9wZW5FeWVEcm9wcGVyID0gKHtcbiAgICAgIHR5cGVcbiAgICB9KSA9PiB7XG4gICAgICBqb3RhaVN0b3JlLnNldChhY3RpdmVFeWVEcm9wcGVyQXRvbSwge1xuICAgICAgICBzd2FwUHJldmlld09uQWx0OiB0cnVlLFxuICAgICAgICBjb2xvclBpY2tlclR5cGU6IHR5cGUgPT09IFwic3Ryb2tlXCIgPyBcImVsZW1lbnRTdHJva2VcIiA6IFwiZWxlbWVudEJhY2tncm91bmRcIixcbiAgICAgICAgb25TZWxlY3Q6IChjb2xvciwgZXZlbnQpID0+IHtcbiAgICAgICAgICBjb25zdCBzaG91bGRVcGRhdGVTdHJva2VDb2xvciA9IHR5cGUgPT09IFwiYmFja2dyb3VuZFwiICYmIGV2ZW50LmFsdEtleSB8fCB0eXBlID09PSBcInN0cm9rZVwiICYmICFldmVudC5hbHRLZXk7XG4gICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICAgIGlmICghc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICAgIGlmIChzaG91bGRVcGRhdGVTdHJva2VDb2xvcikge1xuICAgICAgICAgICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoe1xuICAgICAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgICBjdXJyZW50SXRlbVN0cm9rZUNvbG9yOiBjb2xvclxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCh7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yOiBjb2xvclxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVTY2VuZSh7XG4gICAgICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbCA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2VsLmlkXSkge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsLCB7XG4gICAgICAgICAgICAgICAgICAgIFtzaG91bGRVcGRhdGVTdHJva2VDb2xvciA/IFwic3Ryb2tlQ29sb3JcIiA6IFwiYmFja2dyb3VuZENvbG9yXCJdOiBjb2xvclxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGVsO1xuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBrZWVwT3Blbk9uQWx0OiBmYWxzZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhhY3Rpb25SZXN1bHQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaCwgX2o7XG5cbiAgICAgIGlmICh0aGlzLnVubW91bnRlZCB8fCBhY3Rpb25SZXN1bHQgPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgbGV0IGVkaXRpbmdFbGVtZW50ID0gbnVsbDtcblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5lbGVtZW50cykge1xuICAgICAgICBhY3Rpb25SZXN1bHQuZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pZCkgPT09IGVsZW1lbnQuaWQgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAhPT0gZWxlbWVudCAmJiBpc05vbkRlbGV0ZWRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoYWN0aW9uUmVzdWx0LmVsZW1lbnRzKTtcblxuICAgICAgICBpZiAoYWN0aW9uUmVzdWx0LmNvbW1pdFRvSGlzdG9yeSkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmZpbGVzKSB7XG4gICAgICAgIHRoaXMuZmlsZXMgPSBhY3Rpb25SZXN1bHQucmVwbGFjZUZpbGVzID8gYWN0aW9uUmVzdWx0LmZpbGVzIDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgYWN0aW9uUmVzdWx0LmZpbGVzKTtcbiAgICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5hcHBTdGF0ZSB8fCBlZGl0aW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIGlmIChhY3Rpb25SZXN1bHQuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHZpZXdNb2RlRW5hYmxlZCA9ICgoX2EgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS52aWV3TW9kZUVuYWJsZWQpIHx8IGZhbHNlO1xuICAgICAgICBsZXQgemVuTW9kZUVuYWJsZWQgPSAoKF9iID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuemVuTW9kZUVuYWJsZWQpIHx8IGZhbHNlO1xuICAgICAgICBsZXQgZ3JpZFNpemUgPSAoKF9jID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZ3JpZFNpemUpIHx8IG51bGw7XG4gICAgICAgIGNvbnN0IHRoZW1lID0gKChfZCA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnRoZW1lKSB8fCB0aGlzLnByb3BzLnRoZW1lIHx8IFRIRU1FLkxJR0hUO1xuICAgICAgICBsZXQgbmFtZSA9IChfZiA9IChfZSA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLm5hbWUpICE9PSBudWxsICYmIF9mICE9PSB2b2lkIDAgPyBfZiA6IHRoaXMuc3RhdGUubmFtZTtcbiAgICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gKF9oID0gKF9nID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2cuZXJyb3JNZXNzYWdlKSAhPT0gbnVsbCAmJiBfaCAhPT0gdm9pZCAwID8gX2ggOiB0aGlzLnN0YXRlLmVycm9yTWVzc2FnZTtcblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMudmlld01vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgdmlld01vZGVFbmFibGVkID0gdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICB6ZW5Nb2RlRW5hYmxlZCA9IHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgZ3JpZFNpemUgPSB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMubmFtZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIG5hbWUgPSB0aGlzLnByb3BzLm5hbWU7XG4gICAgICAgIH1cblxuICAgICAgICBlZGl0aW5nRWxlbWVudCA9IGVkaXRpbmdFbGVtZW50IHx8ICgoX2ogPSBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9qID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfai5lZGl0aW5nRWxlbWVudCkgfHwgbnVsbDtcblxuICAgICAgICBpZiAoZWRpdGluZ0VsZW1lbnQgPT09IG51bGwgfHwgZWRpdGluZ0VsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVkaXRpbmdFbGVtZW50LmlzRGVsZXRlZCkge1xuICAgICAgICAgIGVkaXRpbmdFbGVtZW50ID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIC8vIHVzaW5nIE9iamVjdC5hc3NpZ24gaW5zdGVhZCBvZiBzcHJlYWQgdG8gZm9vbCBUUyA0LjIuMisgaW50b1xuICAgICAgICAgIC8vIHJlZ2FyZGluZyB0aGUgcmVzdWx0aW5nIHR5cGUgYXMgbm90IGNvbnRhaW5pbmcgdW5kZWZpbmVkXG4gICAgICAgICAgLy8gKHdoaWNoIHRoZSBmb2xsb3dpbmcgZXhwcmVzc2lvbiB3aWxsIG5ldmVyIGNvbnRhaW4pXG4gICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oYWN0aW9uUmVzdWx0LmFwcFN0YXRlIHx8IHt9LCB7XG4gICAgICAgICAgICAvLyBOT1RFIHRoaXMgd2lsbCBwcmV2ZW50IG9wZW5pbmcgY29udGV4dCBtZW51IHVzaW5nIGFuIGFjdGlvblxuICAgICAgICAgICAgLy8gb3IgcHJvZ3JhbW1hdGljYWxseSBmcm9tIHRoZSBob3N0LCBzbyBpdCB3aWxsIG5lZWQgdG8gYmVcbiAgICAgICAgICAgIC8vIHJld3JpdHRlbiBsYXRlclxuICAgICAgICAgICAgY29udGV4dE1lbnU6IG51bGwsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudCxcbiAgICAgICAgICAgIHZpZXdNb2RlRW5hYmxlZCxcbiAgICAgICAgICAgIHplbk1vZGVFbmFibGVkLFxuICAgICAgICAgICAgZ3JpZFNpemUsXG4gICAgICAgICAgICB0aGVtZSxcbiAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2VcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIGlmIChhY3Rpb25SZXN1bHQuc3luY0hpc3RvcnkpIHtcbiAgICAgICAgICAgIHRoaXMuaGlzdG9yeS5zZXRDdXJyZW50U3RhdGUodGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTsgLy8gTGlmZWN5Y2xlXG5cbiAgICB0aGlzLm9uQmx1ciA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICBpc0hvbGRpbmdTcGFjZSA9IGZhbHNlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQ6IHRydWVcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGhpcy5vblVubG9hZCA9ICgpID0+IHtcbiAgICAgIHRoaXMub25CbHVyKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZGlzYWJsZUV2ZW50ID0gZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldEhpc3RvcnkgPSAoKSA9PiB7XG4gICAgICB0aGlzLmhpc3RvcnkuY2xlYXIoKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJlc2V0cyBzY2VuZSAmIGhpc3RvcnkuXG4gICAgICogISBEbyBub3QgdXNlIHRvIGNsZWFyIHNjZW5lIHVzZXIgYWN0aW9uICFcbiAgICAgKi9cblxuXG4gICAgdGhpcy5yZXNldFNjZW5lID0gd2l0aEJhdGNoZWRVcGRhdGVzKG9wdHMgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldERlZmF1bHRBcHBTdGF0ZSgpKSwge1xuICAgICAgICBpc0xvYWRpbmc6IChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucmVzZXRMb2FkaW5nU3RhdGUpID8gZmFsc2UgOiBzdGF0ZS5pc0xvYWRpbmcsXG4gICAgICAgIHRoZW1lOiB0aGlzLnN0YXRlLnRoZW1lXG4gICAgICB9KSk7XG4gICAgICB0aGlzLnJlc2V0SGlzdG9yeSgpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5pbml0aWFsaXplU2NlbmUgPSAoKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB2YXIgX2I7XG5cbiAgICAgIGlmIChcImxhdW5jaFF1ZXVlXCIgaW4gd2luZG93ICYmIFwiTGF1bmNoUGFyYW1zXCIgaW4gd2luZG93KSB7XG4gICAgICAgIHdpbmRvdy5sYXVuY2hRdWV1ZS5zZXRDb25zdW1lcihsYXVuY2hQYXJhbXMgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgICAgIGlmICghbGF1bmNoUGFyYW1zLmZpbGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGZpbGVIYW5kbGUgPSBsYXVuY2hQYXJhbXMuZmlsZXNbMF07XG4gICAgICAgICAgY29uc3QgYmxvYiA9IHlpZWxkIGZpbGVIYW5kbGUuZ2V0RmlsZSgpO1xuICAgICAgICAgIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhuZXcgRmlsZShbYmxvYl0sIGJsb2IubmFtZSB8fCBcIlwiLCB7XG4gICAgICAgICAgICB0eXBlOiBibG9iLnR5cGVcbiAgICAgICAgICB9KSwgZmlsZUhhbmRsZSk7XG4gICAgICAgIH0pKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMucHJvcHMudGhlbWUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5pc0xvYWRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBsZXQgaW5pdGlhbERhdGEgPSBudWxsO1xuXG4gICAgICB0cnkge1xuICAgICAgICBpbml0aWFsRGF0YSA9ICh5aWVsZCB0aGlzLnByb3BzLmluaXRpYWxEYXRhKSB8fCBudWxsO1xuXG4gICAgICAgIGlmIChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEubGlicmFyeUl0ZW1zKSB7XG4gICAgICAgICAgdGhpcy5saWJyYXJ5LnVwZGF0ZUxpYnJhcnkoe1xuICAgICAgICAgICAgbGlicmFyeUl0ZW1zOiBpbml0aWFsRGF0YS5saWJyYXJ5SXRlbXMsXG4gICAgICAgICAgICBtZXJnZTogdHJ1ZVxuICAgICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgaW5pdGlhbERhdGEgPSB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZSB8fCBcIkVuY291bnRlcmVkIGFuIGVycm9yIGR1cmluZyBpbXBvcnRpbmcgb3IgcmVzdG9yaW5nIHNjZW5lIGRhdGFcIlxuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2NlbmUgPSByZXN0b3JlKGluaXRpYWxEYXRhLCBudWxsLCBudWxsLCB7XG4gICAgICAgIHJlcGFpckJpbmRpbmdzOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIHNjZW5lLmFwcFN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIHtcbiAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWUgfHwgc2NlbmUuYXBwU3RhdGUudGhlbWUsXG4gICAgICAgIC8vIHdlJ3JlIGZhbGxpbmcgYmFjayB0byBjdXJyZW50IChwcmUtaW5pdCkgc3RhdGUgd2hlbiBkZWNpZGluZ1xuICAgICAgICAvLyB3aGV0aGVyIHRvIG9wZW4gdGhlIGxpYnJhcnksIHRvIGhhbmRsZSBhIGNhc2Ugd2hlcmUgd2VcbiAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZSBvdXRzaWRlIG9mIGluaXRpYWxEYXRhIChlLmcuIHdoZW4gbG9hZGluZyB0aGUgYXBwXG4gICAgICAgIC8vIHdpdGggYSBsaWJyYXJ5IGluc3RhbGwgbGluaywgd2hpY2ggc2hvdWxkIGF1dG8tb3BlbiB0aGUgbGlicmFyeSlcbiAgICAgICAgb3BlblNpZGViYXI6ICgoX2IgPSBzY2VuZS5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLm9wZW5TaWRlYmFyKSB8fCB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyLFxuICAgICAgICBhY3RpdmVUb29sOiBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbCksIHtcbiAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgIH0pIDogc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbCxcbiAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgdG9hc3Q6IHRoaXMuc3RhdGUudG9hc3RcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaW5pdGlhbERhdGEgPT09IG51bGwgfHwgaW5pdGlhbERhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGluaXRpYWxEYXRhLnNjcm9sbFRvQ29udGVudCkge1xuICAgICAgICBzY2VuZS5hcHBTdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCBjYWxjdWxhdGVTY3JvbGxDZW50ZXIoc2NlbmUuZWxlbWVudHMsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCB7XG4gICAgICAgICAgd2lkdGg6IHRoaXMuc3RhdGUud2lkdGgsXG4gICAgICAgICAgaGVpZ2h0OiB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgICAgICBvZmZzZXRUb3A6IHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnQ6IHRoaXMuc3RhdGUub2Zmc2V0TGVmdFxuICAgICAgICB9KSkpO1xuICAgICAgfSAvLyBGb250RmFjZVNldCBsb2FkaW5nZG9uZSBldmVudCB3ZSBsaXN0ZW4gb24gbWF5IG5vdCBhbHdheXMgZmlyZVxuICAgICAgLy8gKGxvb2tpbmcgYXQgeW91IFNhZmFyaSksIHNvIG9uIGluaXQgd2UgbWFudWFsbHkgbG9hZCBmb250cyBmb3IgY3VycmVudFxuICAgICAgLy8gdGV4dCBlbGVtZW50cyBvbiBjYW52YXMsIGFuZCByZXJlbmRlciB0aGVtIG9uY2UgZG9uZS4gVGhpcyBhbHNvXG4gICAgICAvLyBzZWVtcyBmYXN0ZXIgZXZlbiBpbiBicm93c2VycyB0aGF0IGRvIGZpcmUgdGhlIGxvYWRpbmdkb25lIGV2ZW50LlxuXG5cbiAgICAgIHRoaXMuZm9udHMubG9hZEZvbnRzRm9yRWxlbWVudHMoc2NlbmUuZWxlbWVudHMpO1xuICAgICAgdGhpcy5yZXNldEhpc3RvcnkoKTtcbiAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lKSwge1xuICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRoaXMucmVmcmVzaERldmljZVN0YXRlID0gY29udGFpbmVyID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgd2lkdGgsXG4gICAgICAgIGhlaWdodFxuICAgICAgfSA9IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGNvbnN0IHNpZGViYXJCcmVha3BvaW50ID0gdGhpcy5wcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT0gbnVsbCA/IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50IDogTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEg7XG4gICAgICB0aGlzLmRldmljZSA9IHVwZGF0ZU9iamVjdCh0aGlzLmRldmljZSwge1xuICAgICAgICBpc0xhbmRzY2FwZTogd2lkdGggPiBoZWlnaHQsXG4gICAgICAgIGlzU21TY3JlZW46IHdpZHRoIDwgTVFfU01fTUFYX1dJRFRILFxuICAgICAgICBpc01vYmlsZTogd2lkdGggPCBNUV9NQVhfV0lEVEhfUE9SVFJBSVQgfHwgaGVpZ2h0IDwgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUgJiYgd2lkdGggPCBNUV9NQVhfV0lEVEhfTEFORFNDQVBFLFxuICAgICAgICBjYW5EZXZpY2VGaXRTaWRlYmFyOiB3aWR0aCA+IHNpZGViYXJCcmVha3BvaW50XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5vblJlc2l6ZSA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZvckVhY2goZWxlbWVudCA9PiBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHt9KTtcbiAgICB9KTtcblxuICAgIHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrID0gKHtcbiAgICAgIGF0TGVhc3RPbmVWaXNpYmxlRWxlbWVudCxcbiAgICAgIHNjcm9sbEJhcnMsXG4gICAgICBlbGVtZW50c1xuICAgIH0pID0+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+IHtcbiAgICAgIC8vIHByZXZlbnQgYnJvd3NlciBwaW5jaCB6b29tIG9uIERPTSBlbGVtZW50c1xuICAgICAgaWYgKCEoZXZlbnQudGFyZ2V0IGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQpICYmIGV2ZW50LmN0cmxLZXkpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLm9uS2V5VXAgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5TUEFDRSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUuaXNCaW5kaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNBcnJvd0tleShldmVudC5rZXkpKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgPyBiaW5kT3JVbmJpbmRTZWxlY3RlZEVsZW1lbnRzKHNlbGVjdGVkRWxlbWVudHMpIDogdW5iaW5kTGluZWFyRWxlbWVudHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuc2V0QWN0aXZlVG9vbCA9IHRvb2wgPT4ge1xuICAgICAgY29uc3QgbmV4dEFjdGl2ZVRvb2wgPSB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHRvb2wpO1xuXG4gICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSA9PT0gXCJoYW5kXCIpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgfSBlbHNlIGlmICghaXNIb2xkaW5nU3BhY2UpIHtcbiAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc1Rvb2xJY29uKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpKSB7XG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc0xpbmVhckVsZW1lbnRUeXBlKG5leHRBY3RpdmVUb29sLnR5cGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICB0aGlzLm9uSW1hZ2VBY3Rpb24oKTtcbiAgICAgIH1cblxuICAgICAgaWYgKG5leHRBY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2wsXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IG5leHRBY3RpdmVUb29sLFxuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuc2V0Q3Vyc29yID0gY3Vyc29yID0+IHtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBjdXJzb3IpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0Q3Vyc29yID0gKCkgPT4ge1xuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiByZXR1cm5zIHdoZXRoZXIgdXNlciBpcyBtYWtpbmcgYSBnZXN0dXJlIHdpdGggPj0gMiBmaW5nZXJzIChwb2ludHMpXG4gICAgICogb24gbyB0b3VjaCBzY3JlZW4gKG5vdCBvbiBhIHRyYWNrcGFkKS4gQ3VycmVudGx5IG9ubHkgcmVsYXRlcyB0byBEYXJ3aW5cbiAgICAgKiAoaU9TL2lQYWRPUyxNYWNPUyksIGJ1dCBtYXkgd29yayBvbiBvdGhlciBkZXZpY2VzIGluIHRoZSBmdXR1cmUgaWZcbiAgICAgKiBHZXN0dXJlRXZlbnQgaXMgc3RhbmRhcmRpemVkLlxuICAgICAqL1xuXG5cbiAgICB0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSA9ICgpID0+IHtcbiAgICAgIC8vIHdlIGRvbid0IHdhbnQgdG8gZGVzZWxlY3Qgd2hlbiB1c2luZyB0cmFja3BhZCwgYW5kIG11bHRpLXBvaW50IGdlc3R1cmVzXG4gICAgICAvLyBvbmx5IHdvcmsgb24gdG91Y2ggc2NyZWVucywgc28gY2hlY2tpbmcgZm9yID49IHBvaW50ZXJzIG1lYW5zIHdlJ3JlIG9uIGFcbiAgICAgIC8vIHRvdWNoc2NyZWVuXG4gICAgICByZXR1cm4gZ2VzdHVyZS5wb2ludGVycy5zaXplID49IDI7XG4gICAgfTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuXG4gICAgdGhpcy5vbkdlc3R1cmVTdGFydCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyB3ZSBvbmx5IHdhbnQgdG8gZGVzZWxlY3Qgb24gdG91Y2ggc2NyZWVucyBiZWNhdXNlIHVzZXIgbWF5IGhhdmUgc2VsZWN0ZWRcbiAgICAgIC8vIGVsZW1lbnRzIGJ5IG1pc3Rha2Ugd2hpbGUgem9vbWluZ1xuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICB9KTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuICAgIHRoaXMub25HZXN0dXJlQ2hhbmdlID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIG9uR2VzdHVyZUNoYW5nZSBvbmx5IGhhcyB6b29tIGZhY3RvciBidXQgbm90IHRoZSBjZW50ZXIuXG4gICAgICAvLyBJZiB3ZSdyZSBvbiBpUGFkIG9yIGlQaG9uZSwgdGhlbiB3ZSByZWNvZ25pemUgbXVsdGktdG91Y2ggYW5kIHdpbGxcbiAgICAgIC8vIHpvb20gaW4gYXQgdGhlIHJpZ2h0IGxvY2F0aW9uIGluIHRoZSB0b3VjaG1vdmUgaGFuZGxlclxuICAgICAgLy8gKGhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlKS5cbiAgICAgIC8vXG4gICAgICAvLyBPbiBNYWNib29rIHRyYWNrcGFkLCB3ZSBkb24ndCBoYXZlIHRob3NlIGV2ZW50cyBzbyB3aWxsIHpvb20gaW4gYXQgdGhlXG4gICAgICAvLyBjdXJyZW50IGxvY2F0aW9uIGluc3RlYWQuXG4gICAgICAvL1xuICAgICAgLy8gQXMgc3VjaCwgYmFpbCBmcm9tIHRoaXMgaGFuZGxlciBvbiB0b3VjaCBkZXZpY2VzLlxuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGluaXRpYWxTY2FsZSA9IGdlc3R1cmUuaW5pdGlhbFNjYWxlO1xuXG4gICAgICBpZiAoaW5pdGlhbFNjYWxlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgICB2aWV3cG9ydFg6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCxcbiAgICAgICAgICB2aWV3cG9ydFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSxcbiAgICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20oaW5pdGlhbFNjYWxlICogZXZlbnQuc2NhbGUpXG4gICAgICAgIH0sIHN0YXRlKSkpO1xuICAgICAgfVxuICAgIH0pOyAvLyBmaXJlcyBvbmx5IG9uIFNhZmFyaVxuXG4gICAgdGhpcy5vbkdlc3R1cmVFbmQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gcmVzZWxlY3QgZWxlbWVudHMgb25seSBvbiB0b3VjaCBzY3JlZW5zIChzZWUgb25HZXN0dXJlU3RhcnQpXG5cbiAgICAgIGlmICh0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSgpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB7fSxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHRoaXMuc3RhdGUucHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHMsIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IG51bGw7XG4gICAgfSk7XG5cbiAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZLFxuICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXIgPSB0cnVlLFxuICAgICAgY29udGFpbmVyXG4gICAgfSkgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgbGV0IHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IGZhbHNlO1xuICAgICAgbGV0IHBhcmVudENlbnRlclBvc2l0aW9uID0gaW5zZXJ0QXRQYXJlbnRDZW50ZXIgJiYgdGhpcy5nZXRUZXh0V3lzaXd5Z1NuYXBwZWRUb0NlbnRlclBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZLCB0aGlzLnN0YXRlLCBjb250YWluZXIpO1xuXG4gICAgICBpZiAoY29udGFpbmVyICYmIHBhcmVudENlbnRlclBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lciA9IGdldEJvdW5kVGV4dEVsZW1lbnQoY29udGFpbmVyKTtcblxuICAgICAgICBpZiAoIWJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lcikge1xuICAgICAgICAgIHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgbGV0IGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBudWxsO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIGlmIChpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHNlbGVjdGVkRWxlbWVudHNbMF07XG4gICAgICAgIH0gZWxzZSBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IGdldEJvdW5kVGV4dEVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZm9udEZhbWlseSA9IChleGlzdGluZ1RleHRFbGVtZW50ID09PSBudWxsIHx8IGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nVGV4dEVsZW1lbnQuZm9udEZhbWlseSkgfHwgdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRGYW1pbHk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gKGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IG51bGwgfHwgZXhpc3RpbmdUZXh0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhpc3RpbmdUZXh0RWxlbWVudC5saW5lSGVpZ2h0KSB8fCBnZXREZWZhdWx0TGluZUhlaWdodChmb250RmFtaWx5KTtcbiAgICAgIGNvbnN0IGZvbnRTaXplID0gdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRTaXplO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyICYmIGNvbnRhaW5lciAmJiAhaXNBcnJvd0VsZW1lbnQoY29udGFpbmVyKSkge1xuICAgICAgICBjb25zdCBmb250U3RyaW5nID0ge1xuICAgICAgICAgIGZvbnRTaXplLFxuICAgICAgICAgIGZvbnRGYW1pbHlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgbWluV2lkdGggPSBnZXRBcHByb3hNaW5MaW5lV2lkdGgoZ2V0Rm9udFN0cmluZyhmb250U3RyaW5nKSwgbGluZUhlaWdodCk7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IGdldEFwcHJveE1pbkxpbmVIZWlnaHQoZm9udFNpemUsIGxpbmVIZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdIZWlnaHQgPSBNYXRoLm1heChjb250YWluZXIuaGVpZ2h0LCBtaW5IZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdXaWR0aCA9IE1hdGgubWF4KGNvbnRhaW5lci53aWR0aCwgbWluV2lkdGgpO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGNvbnRhaW5lciwge1xuICAgICAgICAgIGhlaWdodDogbmV3SGVpZ2h0LFxuICAgICAgICAgIHdpZHRoOiBuZXdXaWR0aFxuICAgICAgICB9KTtcbiAgICAgICAgc2NlbmVYID0gY29udGFpbmVyLnggKyBuZXdXaWR0aCAvIDI7XG4gICAgICAgIHNjZW5lWSA9IGNvbnRhaW5lci55ICsgbmV3SGVpZ2h0IC8gMjtcblxuICAgICAgICBpZiAocGFyZW50Q2VudGVyUG9zaXRpb24pIHtcbiAgICAgICAgICBwYXJlbnRDZW50ZXJQb3NpdGlvbiA9IHRoaXMuZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwgdGhpcy5zdGF0ZSwgY29udGFpbmVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBleGlzdGluZ1RleHRFbGVtZW50ID8gZXhpc3RpbmdUZXh0RWxlbWVudCA6IG5ld1RleHRFbGVtZW50KHtcbiAgICAgICAgeDogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWCA6IHNjZW5lWCxcbiAgICAgICAgeTogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWSA6IHNjZW5lWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIHRleHQ6IFwiXCIsXG4gICAgICAgIGZvbnRTaXplLFxuICAgICAgICBmb250RmFtaWx5LFxuICAgICAgICB0ZXh0QWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gXCJjZW50ZXJcIiA6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1UZXh0QWxpZ24sXG4gICAgICAgIHZlcnRpY2FsQWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gVkVSVElDQUxfQUxJR04uTUlERExFIDogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgICAgY29udGFpbmVySWQ6IHNob3VsZEJpbmRUb0NvbnRhaW5lciA/IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5pZCA6IHVuZGVmaW5lZCxcbiAgICAgICAgZ3JvdXBJZHM6IChfYSA9IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5ncm91cElkcykgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogW10sXG4gICAgICAgIGxpbmVIZWlnaHQsXG4gICAgICAgIGFuZ2xlOiAoX2IgPSBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuYW5nbGUpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDAsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfSk7XG5cbiAgICAgIGlmICghZXhpc3RpbmdUZXh0RWxlbWVudCAmJiBzaG91bGRCaW5kVG9Db250YWluZXIgJiYgY29udGFpbmVyKSB7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoY29udGFpbmVyLCB7XG4gICAgICAgICAgYm91bmRFbGVtZW50czogKGNvbnRhaW5lci5ib3VuZEVsZW1lbnRzIHx8IFtdKS5jb25jYXQoe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGNvbnRhaW5lciAmJiBzaG91bGRCaW5kVG9Db250YWluZXIpIHtcbiAgICAgICAgICBjb25zdCBjb250YWluZXJJbmRleCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudEluZGV4KGNvbnRhaW5lci5pZCk7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50QXRJbmRleChlbGVtZW50LCBjb250YWluZXJJbmRleCArIDEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuICAgICAgdGhpcy5oYW5kbGVUZXh0V3lzaXd5ZyhlbGVtZW50LCB7XG4gICAgICAgIGlzRXhpc3RpbmdFbGVtZW50OiAhIWV4aXN0aW5nVGV4dEVsZW1lbnRcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrID0gZXZlbnQgPT4ge1xuICAgICAgLy8gY2FzZTogZG91YmxlLWNsaWNraW5nIHdpdGggYXJyb3cvbGluZSB0b29sIHNlbGVjdGVkIHdvdWxkIGJvdGggY3JlYXRlXG4gICAgICAvLyB0ZXh0IGFuZCBlbnRlciBtdWx0aUVsZW1lbnQgbW9kZVxuICAgICAgaWYgKHRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gd2Ugc2hvdWxkIG9ubHkgYmUgYWJsZSB0byBkb3VibGUgY2xpY2sgd2hlbiBtb2RlIGlzIHNlbGVjdGlvblxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkpIHtcbiAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICghdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCAhPT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3Ioc2VsZWN0ZWRFbGVtZW50c1swXSwgdGhpcy5zY2VuZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCA9PT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgIGxldCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkR3JvdXBJZHMgPSBnZXRTZWxlY3RlZEdyb3VwSWRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRHcm91cElkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRHcm91cElkID0gaGl0RWxlbWVudCAmJiBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50KGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUuc2VsZWN0ZWRHcm91cElkcyk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkR3JvdXBJZCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogc2VsZWN0ZWRHcm91cElkLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICBlbGVtZW50OiBoaXRFbGVtZW50LFxuICAgICAgICAgICAgICBzdGF0ZTogXCJhY3RpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgc2NlbmVYLCBzY2VuZVkpO1xuXG4gICAgICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgICAgICBpZiAoaGFzQm91bmRUZXh0RWxlbWVudChjb250YWluZXIpIHx8ICFpc1RyYW5zcGFyZW50KGNvbnRhaW5lci5iYWNrZ3JvdW5kQ29sb3IpIHx8IGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94KGNvbnRhaW5lciwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgW3NjZW5lWCwgc2NlbmVZXSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG1pZFBvaW50ID0gZ2V0Q29udGFpbmVyQ2VudGVyKGNvbnRhaW5lciwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBzY2VuZVggPSBtaWRQb2ludC54O1xuICAgICAgICAgICAgc2NlbmVZID0gbWlkUG9pbnQueTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXI6ICFldmVudC5hbHRLZXksXG4gICAgICAgICAgY29udGFpbmVyXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbiA9IChzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpID0+IHtcbiAgICAgIC8vIFJldmVyc2luZyBzbyB3ZSB0cmF2ZXJzZSB0aGUgZWxlbWVudHMgaW4gZGVjcmVhc2luZyBvcmRlclxuICAgICAgLy8gb2Ygei1pbmRleFxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLnNsaWNlKCkucmV2ZXJzZSgpO1xuICAgICAgbGV0IGhpdEVsZW1lbnRJbmRleCA9IEluZmluaXR5O1xuICAgICAgcmV0dXJuIGVsZW1lbnRzLmZpbmQoKGVsZW1lbnQsIGluZGV4KSA9PiB7XG4gICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGVsZW1lbnQuaWQgPT09IGhpdEVsZW1lbnQuaWQpIHtcbiAgICAgICAgICBoaXRFbGVtZW50SW5kZXggPSBpbmRleDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGVtZW50LmxpbmsgJiYgaW5kZXggPD0gaGl0RWxlbWVudEluZGV4ICYmIGlzUG9pbnRIaXR0aW5nTGluayhlbGVtZW50LCB0aGlzLnN0YXRlLCBbc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55XSwgdGhpcy5kZXZpY2UuaXNNb2JpbGUpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVkaXJlY3RUb0xpbmsgPSAoZXZlbnQsIGlzVG91Y2hTY3JlZW4pID0+IHtcbiAgICAgIGNvbnN0IGRyYWdnZWREaXN0YW5jZSA9IGRpc3RhbmNlMmQodGhpcy5sYXN0UG9pbnRlckRvd24uY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlckRvd24uY2xpZW50WSwgdGhpcy5sYXN0UG9pbnRlclVwLmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJVcC5jbGllbnRZKTtcblxuICAgICAgaWYgKCF0aGlzLmhpdExpbmtFbGVtZW50IHx8IC8vIEZvciB0b3VjaCBzY3JlZW4gYWxsb3cgZHJhZ2dpbmcgdGhyZXNob2xkIGVsc2Ugc3RyaWN0IGNoZWNrXG4gICAgICBpc1RvdWNoU2NyZWVuICYmIGRyYWdnZWREaXN0YW5jZSA+IERSQUdHSU5HX1RIUkVTSE9MRCB8fCAhaXNUb3VjaFNjcmVlbiAmJiBkcmFnZ2VkRGlzdGFuY2UgIT09IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBsYXN0UG9pbnRlckRvd25Db29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHModGhpcy5sYXN0UG9pbnRlckRvd24sIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgbGFzdFBvaW50ZXJEb3duSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlckRvd25Db29yZHMueCwgbGFzdFBvaW50ZXJEb3duQ29vcmRzLnldLCB0aGlzLmRldmljZS5pc01vYmlsZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHRoaXMubGFzdFBvaW50ZXJVcCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uID0gaXNQb2ludEhpdHRpbmdMaW5rKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtsYXN0UG9pbnRlclVwQ29vcmRzLngsIGxhc3RQb2ludGVyVXBDb29yZHMueV0sIHRoaXMuZGV2aWNlLmlzTW9iaWxlKTtcblxuICAgICAgaWYgKGxhc3RQb2ludGVyRG93bkhpdHRpbmdMaW5rSWNvbiAmJiBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uKSB7XG4gICAgICAgIGxldCB1cmwgPSB0aGlzLmhpdExpbmtFbGVtZW50Lmxpbms7XG5cbiAgICAgICAgaWYgKHVybCkge1xuICAgICAgICAgIHVybCA9IG5vcm1hbGl6ZUxpbmsodXJsKTtcbiAgICAgICAgICBsZXQgY3VzdG9tRXZlbnQ7XG5cbiAgICAgICAgICBpZiAodGhpcy5wcm9wcy5vbkxpbmtPcGVuKSB7XG4gICAgICAgICAgICBjdXN0b21FdmVudCA9IHdyYXBFdmVudChFVkVOVC5FWENBTElEUkFXX0xJTkssIGV2ZW50Lm5hdGl2ZUV2ZW50KTtcbiAgICAgICAgICAgIHRoaXMucHJvcHMub25MaW5rT3BlbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuaGl0TGlua0VsZW1lbnQpLCB7XG4gICAgICAgICAgICAgIGxpbms6IHVybFxuICAgICAgICAgICAgfSksIGN1c3RvbUV2ZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIShjdXN0b21FdmVudCA9PT0gbnVsbCB8fCBjdXN0b21FdmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogY3VzdG9tRXZlbnQuZGVmYXVsdFByZXZlbnRlZCkpIHtcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldCA9IGlzTG9jYWxMaW5rKHVybCkgPyBcIl9zZWxmXCIgOiBcIl9ibGFua1wiO1xuICAgICAgICAgICAgY29uc3QgbmV3V2luZG93ID0gd2luZG93Lm9wZW4odW5kZWZpbmVkLCB0YXJnZXQpOyAvLyBodHRwczovL21hdGhpYXNieW5lbnMuZ2l0aHViLmlvL3JlbC1ub29wZW5lci9cblxuICAgICAgICAgICAgaWYgKG5ld1dpbmRvdykge1xuICAgICAgICAgICAgICBuZXdXaW5kb3cub3BlbmVyID0gbnVsbDtcbiAgICAgICAgICAgICAgbmV3V2luZG93LmxvY2F0aW9uID0gdXJsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzID0gc2NlbmVDb29yZHMgPT4ge1xuICAgICAgY29uc3QgZnJhbWVzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRnJhbWVzKCkuZmlsdGVyKGZyYW1lID0+IGlzQ3Vyc29ySW5GcmFtZShzY2VuZUNvb3JkcywgZnJhbWUpKTtcbiAgICAgIHJldHVybiBmcmFtZXMubGVuZ3RoID8gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXSA6IG51bGw7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIHRoaXMuc3RhdGUuY3Vyc29yQnV0dG9uKTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuaGFzKGV2ZW50LnBvaW50ZXJJZCkpIHtcbiAgICAgICAgZ2VzdHVyZS5wb2ludGVycy5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICAgICAgeDogZXZlbnQuY2xpZW50WCxcbiAgICAgICAgICB5OiBldmVudC5jbGllbnRZXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbml0aWFsU2NhbGUgPSBnZXN0dXJlLmluaXRpYWxTY2FsZTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMiAmJiBnZXN0dXJlLmxhc3RDZW50ZXIgJiYgaW5pdGlhbFNjYWxlICYmIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlKSB7XG4gICAgICAgIGNvbnN0IGNlbnRlciA9IGdldENlbnRlcihnZXN0dXJlLnBvaW50ZXJzKTtcbiAgICAgICAgY29uc3QgZGVsdGFYID0gY2VudGVyLnggLSBnZXN0dXJlLmxhc3RDZW50ZXIueDtcbiAgICAgICAgY29uc3QgZGVsdGFZID0gY2VudGVyLnkgLSBnZXN0dXJlLmxhc3RDZW50ZXIueTtcbiAgICAgICAgZ2VzdHVyZS5sYXN0Q2VudGVyID0gY2VudGVyO1xuICAgICAgICBjb25zdCBkaXN0YW5jZSA9IGdldERpc3RhbmNlKEFycmF5LmZyb20oZ2VzdHVyZS5wb2ludGVycy52YWx1ZXMoKSkpO1xuICAgICAgICBjb25zdCBzY2FsZUZhY3RvciA9IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIgJiYgdGhpcy5zdGF0ZS5wZW5Nb2RlID8gMSA6IGRpc3RhbmNlIC8gZ2VzdHVyZS5pbml0aWFsRGlzdGFuY2U7XG4gICAgICAgIGNvbnN0IG5leHRab29tID0gc2NhbGVGYWN0b3IgPyBnZXROb3JtYWxpemVkWm9vbShpbml0aWFsU2NhbGUgKiBzY2FsZUZhY3RvcikgOiB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIGNvbnN0IHpvb21TdGF0ZSA9IGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgICB2aWV3cG9ydFg6IGNlbnRlci54LFxuICAgICAgICAgICAgdmlld3BvcnRZOiBjZW50ZXIueSxcbiAgICAgICAgICAgIG5leHRab29tXG4gICAgICAgICAgfSwgc3RhdGUpO1xuICAgICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgICAgIHpvb206IHpvb21TdGF0ZS56b29tLFxuICAgICAgICAgICAgc2Nyb2xsWDogem9vbVN0YXRlLnNjcm9sbFggKyBkZWx0YVggLyBuZXh0Wm9vbSxcbiAgICAgICAgICAgIHNjcm9sbFk6IHpvb21TdGF0ZS5zY3JvbGxZICsgZGVsdGFZIC8gbmV4dFpvb20sXG4gICAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlID0gZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNIb2xkaW5nU3BhY2UgfHwgaXNQYW5uaW5nIHx8IGlzRHJhZ2dpbmdTY3JvbGxCYXIgfHwgaXNIYW5kVG9vbEFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzID0gaXNPdmVyU2Nyb2xsQmFycyhjdXJyZW50U2Nyb2xsQmFycywgZXZlbnQuY2xpZW50WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgZXZlbnQuY2xpZW50WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wKTtcbiAgICAgIGNvbnN0IGlzT3ZlclNjcm9sbEJhciA9IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzLmlzT3ZlckVpdGhlcjtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lUG9pbnRlclgsXG4gICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgIH0gPSBzY2VuZVBvaW50ZXI7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgY29uc3QgZWRpdGluZ0xpbmVhckVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJNb3ZlKGV2ZW50LCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZWRpdGluZ0xpbmVhckVsZW1lbnQgIT09IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSBudWxsIHx8IGVkaXRpbmdMaW5lYXJFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlZGl0aW5nTGluZWFyRWxlbWVudC5sYXN0VW5jb21taXR0ZWRQb2ludCkgIT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0F0Q3Vyc29yKHNjZW5lUG9pbnRlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gY2F1c2VzIHN0YWNrIG92ZXJmbG93IGlmIG5vdCBzeW5jXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50VHlwZSh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgLy8gSG92ZXJpbmcgd2l0aCBhIHNlbGVjdGVkIHRvb2wgb3IgY3JlYXRpbmcgbmV3IGxpbmVhciBlbGVtZW50IHZpYSBjbGlja1xuICAgICAgICAvLyBhbmQgcG9pbnRcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBpZiAoaXNCaW5kaW5nRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ3NGb3JMaW5lYXJFbGVtZW50QXRDb29yZHMoZHJhZ2dpbmdFbGVtZW50LCBbc2NlbmVQb2ludGVyXSwgdGhpcy5zdGF0ZS5zdGFydEJvdW5kRWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3Ioc2NlbmVQb2ludGVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG11bHRpRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHJ4LFxuICAgICAgICAgIHk6IHJ5XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBwb2ludHMsXG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50XG4gICAgICAgIH0gPSBtdWx0aUVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IGxhc3RQb2ludCA9IHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV07XG4gICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChsYXN0UG9pbnQgPT09IGxhc3RDb21taXR0ZWRQb2ludCkge1xuICAgICAgICAgIC8vIGlmIHdlIGhhdmVuJ3QgeWV0IGNyZWF0ZWQgYSB0ZW1wIHBvaW50IGFuZCB3ZSdyZSBiZXlvbmQgY29tbWl0LXpvbmVcbiAgICAgICAgICAvLyB0aHJlc2hvbGQsIGFkZCBhIHBvaW50XG4gICAgICAgICAgaWYgKGRpc3RhbmNlMmQoc2NlbmVQb2ludGVyWCAtIHJ4LCBzY2VuZVBvaW50ZXJZIC0gcnksIGxhc3RQb2ludFswXSwgbGFzdFBvaW50WzFdKSA+PSBMSU5FX0NPTkZJUk1fVEhSRVNIT0xEKSB7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeV1dXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpOyAvLyBpbiB0aGlzIGJyYW5jaCwgd2UncmUgaW5zaWRlIHRoZSBjb21taXQgem9uZSwgYW5kIG5vIHVuY29tbWl0dGVkXG4gICAgICAgICAgICAvLyBwb2ludCBleGlzdHMuIFRodXMgZG8gbm90aGluZyAoZG9uJ3QgYWRkL3JlbW92ZSBwb2ludHMpLlxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID4gMiAmJiBsYXN0Q29tbWl0dGVkUG9pbnQgJiYgZGlzdGFuY2UyZChzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeSwgbGFzdENvbW1pdHRlZFBvaW50WzBdLCBsYXN0Q29tbWl0dGVkUG9pbnRbMV0pIDwgTElORV9DT05GSVJNX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBwb2ludHMuc2xpY2UoMCwgLTEpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgICAgY29uc3QgW2xhc3RDb21taXR0ZWRYLCBsYXN0Q29tbWl0dGVkWV0gPSAoX2EgPSBtdWx0aUVsZW1lbnQgPT09IG51bGwgfHwgbXVsdGlFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBtdWx0aUVsZW1lbnQubGFzdENvbW1pdHRlZFBvaW50KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBbMCwgMF07XG4gICAgICAgICAgbGV0IGR4RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWCAtIHJ4IC0gbGFzdENvbW1pdHRlZFg7XG4gICAgICAgICAgbGV0IGR5RnJvbUxhc3RDb21taXR0ZWQgPSBncmlkWSAtIHJ5IC0gbGFzdENvbW1pdHRlZFk7XG5cbiAgICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpKSB7XG4gICAgICAgICAgICAoe1xuICAgICAgICAgICAgICB3aWR0aDogZHhGcm9tTGFzdENvbW1pdHRlZCxcbiAgICAgICAgICAgICAgaGVpZ2h0OiBkeUZyb21MYXN0Q29tbWl0dGVkXG4gICAgICAgICAgICB9ID0gZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplKCAvLyBhY3R1YWwgY29vcmRpbmF0ZSBvZiB0aGUgbGFzdCBjb21taXR0ZWQgcG9pbnRcbiAgICAgICAgICAgIGxhc3RDb21taXR0ZWRYICsgcngsIGxhc3RDb21taXR0ZWRZICsgcnksIC8vIGN1cnNvci1ncmlkIGNvb3JkaW5hdGVcbiAgICAgICAgICAgIGdyaWRYLCBncmlkWSkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChpc1BhdGhBTG9vcChwb2ludHMsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpIHtcbiAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICB9IC8vIHVwZGF0ZSBsYXN0IHVuY29tbWl0dGVkIHBvaW50XG5cblxuICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMuc2xpY2UoMCwgLTEpLCBbbGFzdENvbW1pdHRlZFggKyBkeEZyb21MYXN0Q29tbWl0dGVkLCBsYXN0Q29tbWl0dGVkWSArIGR5RnJvbUxhc3RDb21taXR0ZWRdXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNEZXNlbGVjdGVkQnV0dG9uID0gQm9vbGVhbihldmVudC5idXR0b25zKTtcblxuICAgICAgaWYgKGhhc0Rlc2VsZWN0ZWRCdXR0b24gfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwidGV4dFwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICFpc092ZXJTY3JvbGxCYXIgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0RWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlKGVsZW1lbnRzLCB0aGlzLnN0YXRlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICBpZiAoZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlICYmIGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS50cmFuc2Zvcm1IYW5kbGVUeXBlKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIGdldEN1cnNvckZvclJlc2l6aW5nRWxlbWVudChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiAxICYmICFpc092ZXJTY3JvbGxCYXIpIHtcbiAgICAgICAgY29uc3QgdHJhbnNmb3JtSGFuZGxlVHlwZSA9IGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzKGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG5cbiAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50KHtcbiAgICAgICAgICAgIHRyYW5zZm9ybUhhbmRsZVR5cGVcbiAgICAgICAgICB9KSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICB0aGlzLmhpdExpbmtFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KTtcblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGl0TGlua0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuaGl0TGlua0VsZW1lbnQuaWRdKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgc2hvd0h5cGVybGlua1Rvb2x0aXAodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoaWRlSHlwZXJsaW5rVG9vbGlwKCk7XG5cbiAgICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgKGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpKSAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSAmJiAhdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiAhdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXApIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogXCJpbmZvXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgaXNUZXh0RWxlbWVudChoaXRFbGVtZW50KSA/IENVUlNPUl9UWVBFLlRFWFQgOiBDVVJTT1JfVFlQRS5DUk9TU0hBSVIpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICB9IGVsc2UgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlSG92ZXJTZWxlY3RlZExpbmVhckVsZW1lbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpO1xuICAgICAgICB9IGVsc2UgaWYgKCAvLyBpZiB1c2luZyBjbWQvY3RybCwgd2UncmUgbm90IGRyYWdnaW5nXG4gICAgICAgICFldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICAgIGlmICgoaGl0RWxlbWVudCB8fCB0aGlzLmlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHNjZW5lUG9pbnRlciwgc2VsZWN0ZWRFbGVtZW50cykpICYmICEoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmxvY2tlZCkpIHtcbiAgICAgICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgZXZlbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICAgICAgZWxlbWVudDogaGl0RWxlbWVudCxcbiAgICAgICAgICAgICAgICAgIHN0YXRlOiBcImhvdmVyXCJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuXG4gICAgICAgICAgICAgIGlmICgoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImhvdmVyXCIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQVVUTyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVFcmFzZXIgPSAoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUsIHNjZW5lUG9pbnRlcikgPT4ge1xuICAgICAgY29uc3QgdXBkYXRlRWxlbWVudElkcyA9IGVsZW1lbnRzID0+IHtcbiAgICAgICAgZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoZWxlbWVudC5sb2NrZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZHNUb1VwZGF0ZS5wdXNoKGVsZW1lbnQuaWQpO1xuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSkge1xuICAgICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlbWVudC5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXS5lcmFzZSkge1xuICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdLmVyYXNlID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmICghcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSA9IHtcbiAgICAgICAgICAgICAgZXJhc2U6IHRydWUsXG4gICAgICAgICAgICAgIG9wYWNpdHk6IGVsZW1lbnQub3BhY2l0eVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfTtcblxuICAgICAgY29uc3QgaWRzVG9VcGRhdGUgPSBbXTtcbiAgICAgIGNvbnN0IGRpc3RhbmNlID0gZGlzdGFuY2UyZChwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnksIHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICBjb25zdCB0aHJlc2hvbGQgPSAxMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgIGNvbnN0IHBvaW50ID0gT2JqZWN0LmFzc2lnbih7fSwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzKTtcbiAgICAgIGxldCBzYW1wbGluZ0ludGVydmFsID0gMDtcblxuICAgICAgd2hpbGUgKHNhbXBsaW5nSW50ZXJ2YWwgPD0gZGlzdGFuY2UpIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbihwb2ludC54LCBwb2ludC55KTtcbiAgICAgICAgdXBkYXRlRWxlbWVudElkcyhoaXRFbGVtZW50cyk7IC8vIEV4aXQgc2luY2Ugd2UgcmVhY2hlZCBjdXJyZW50IHBvaW50XG5cbiAgICAgICAgaWYgKHNhbXBsaW5nSW50ZXJ2YWwgPT09IGRpc3RhbmNlKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gLy8gQ2FsY3VsYXRlIG5leHQgcG9pbnQgaW4gdGhlIGxpbmUgYXQgYSBkaXN0YW5jZSBvZiBzYW1wbGluZyBpbnRlcnZhbFxuXG5cbiAgICAgICAgc2FtcGxpbmdJbnRlcnZhbCA9IE1hdGgubWluKHNhbXBsaW5nSW50ZXJ2YWwgKyB0aHJlc2hvbGQsIGRpc3RhbmNlKTtcbiAgICAgICAgY29uc3QgZGlzdGFuY2VSYXRpbyA9IHNhbXBsaW5nSW50ZXJ2YWwgLyBkaXN0YW5jZTtcbiAgICAgICAgY29uc3QgbmV4dFggPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueCArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueDtcbiAgICAgICAgY29uc3QgbmV4dFkgPSAoMSAtIGRpc3RhbmNlUmF0aW8pICogcG9pbnQueSArIGRpc3RhbmNlUmF0aW8gKiBzY2VuZVBvaW50ZXIueTtcbiAgICAgICAgcG9pbnQueCA9IG5leHRYO1xuICAgICAgICBwb2ludC55ID0gbmV4dFk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoZWxlID0+IHtcbiAgICAgICAgY29uc3QgaWQgPSBpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBpZHNUb1VwZGF0ZS5pbmNsdWRlcyhlbGUuY29udGFpbmVySWQpID8gZWxlLmNvbnRhaW5lcklkIDogZWxlLmlkO1xuXG4gICAgICAgIGlmIChpZHNUb1VwZGF0ZS5pbmNsdWRlcyhpZCkpIHtcbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtpZF0uZXJhc2UgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgICAgICBvcGFjaXR5OiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXS5vcGFjaXR5XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3RWxlbWVudFdpdGgoZWxlLCB7XG4gICAgICAgICAgICAgIG9wYWNpdHk6IEVMRU1FTlRfUkVBRFlfVE9fRVJBU0VfT1BBQ0lUWVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBzY2VuZVBvaW50ZXIueDtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gc2NlbmVQb2ludGVyLnk7XG4gICAgfTsgLy8gc2V0IHRvdWNoIG1vdmluZyBmb3IgbW9iaWxlIGNvbnRleHQgbWVudVxuXG5cbiAgICB0aGlzLmhhbmRsZVRvdWNoTW92ZSA9IGV2ZW50ID0+IHtcbiAgICAgIGludmFsaWRhdGVDb250ZXh0TWVudSA9IHRydWU7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24gPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBzaW5jZSBjb250ZXh0TWVudSBvcHRpb25zIGFyZSBwb3RlbnRpYWxseSBldmFsdWF0ZWQgb24gZWFjaCByZW5kZXIsXG4gICAgICAvLyBhbmQgYW4gY29udGV4dE1lbnUgYWN0aW9uIG1heSBkZXBlbmQgb24gc2VsZWN0aW9uIHN0YXRlLCB3ZSBtdXN0XG4gICAgICAvLyBjbG9zZSB0aGUgY29udGV4dE1lbnUgYmVmb3JlIHdlIHVwZGF0ZSB0aGUgc2VsZWN0aW9uIG9uIHBvaW50ZXJEb3duXG4gICAgICAvLyAoZS5nLiByZXNldHRpbmcgc2VsZWN0aW9uKVxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnVwZGF0ZUdlc3R1cmVPblBvaW50ZXJEb3duKGV2ZW50KTsgLy8gaWYgZHJhZ2dpbmcgZWxlbWVudCBpcyBmcmVlZHJhdyBhbmQgYW5vdGhlciBwb2ludGVyZG93biBldmVudCBvY2N1cnNcbiAgICAgIC8vIGEgc2Vjb25kIGZpbmdlciBpcyBvbiB0aGUgc2NyZWVuXG4gICAgICAvLyBkaXNjYXJkIHRoZSBmcmVlZHJhdyBlbGVtZW50IGlmIGl0IGlzIHZlcnkgc2hvcnQgYmVjYXVzZSBpdCBpcyBsaWtlbHlcbiAgICAgIC8vIGp1c3QgYSBzcGlrZSwgb3RoZXJ3aXNlIGZpbmFsaXplIHRoZSBmcmVlZHJhdyBlbGVtZW50IHdoZW4gdGhlIHNlY29uZFxuICAgICAgLy8gZmluZ2VyIGlzIGxpZnRlZFxuXG4gICAgICBpZiAoZXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIiAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50O1xuICAgICAgICB0aGlzLnVwZGF0ZVNjZW5lKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZWxlbWVudC5wb2ludHMubGVuZ3RoIDwgMTAgPyB7XG4gICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSBlbGVtZW50LmlkKVxuICAgICAgICB9IDoge30pLCB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5rZXlzKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5maWx0ZXIoa2V5ID0+IGtleSAhPT0gZWxlbWVudC5pZCkucmVkdWNlKChvYmosIGtleSkgPT4ge1xuICAgICAgICAgICAgICBvYmpba2V5XSA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2tleV07XG4gICAgICAgICAgICAgIHJldHVybiBvYmo7XG4gICAgICAgICAgICB9LCB7fSksIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gcmVtb3ZlIGFueSBhY3RpdmUgc2VsZWN0aW9uIHdoZW4gd2Ugc3RhcnQgdG8gaW50ZXJhY3Qgd2l0aCBjYW52YXNcbiAgICAgIC8vIChtYWlubHksIHdlIGNhcmUgYWJvdXQgcmVtb3Zpbmcgc2VsZWN0aW9uIG91dHNpZGUgdGhlIGNvbXBvbmVudCB3aGljaFxuICAgICAgLy8gIHdvdWxkIHByZXZlbnQgb3VyIGNvcHkgaGFuZGxpbmcgb3RoZXJ3aXNlKVxuXG5cbiAgICAgIGNvbnN0IHNlbGVjdGlvbiA9IGRvY3VtZW50LmdldFNlbGVjdGlvbigpO1xuXG4gICAgICBpZiAoc2VsZWN0aW9uID09PSBudWxsIHx8IHNlbGVjdGlvbiA9PT0gdm9pZCAwID8gdm9pZCAwIDogc2VsZWN0aW9uLmFuY2hvck5vZGUpIHtcbiAgICAgICAgc2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlT3BlbkNvbnRleHRNZW51QWZ0ZXJQb2ludGVyRG93bk9uVG91Y2hEZXZpY2VzKGV2ZW50KTtcbiAgICAgIHRoaXMubWF5YmVDbGVhbnVwQWZ0ZXJNaXNzaW5nUG9pbnRlclVwKGV2ZW50KTsgLy9maXJlcyBvbmx5IG9uY2UsIGlmIHBlbiBpcyBkZXRlY3RlZCwgcGVuTW9kZSBpcyBlbmFibGVkXG4gICAgICAvL3RoZSB1c2VyIGNhbiBkaXNhYmxlIHRoaXMgYnkgdG9nZ2xpbmcgdGhlIHBlbk1vZGUgYnV0dG9uXG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5wZW5EZXRlY3RlZCAmJiBldmVudC5wb2ludGVyVHlwZSA9PT0gXCJwZW5cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHBlbk1vZGU6IHRydWUsXG4gICAgICAgICAgICBwZW5EZXRlY3RlZDogdHJ1ZVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4gJiYgW1wicGVuXCIsIFwidG91Y2hcIl0uaW5jbHVkZXMoZXZlbnQucG9pbnRlclR5cGUpKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gdXBkYXRlT2JqZWN0KHRoaXMuZGV2aWNlLCB7XG4gICAgICAgICAgaXNUb3VjaFNjcmVlbjogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUGFubmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubGFzdFBvaW50ZXJEb3duID0gZXZlbnQ7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgbGFzdFBvaW50ZXJEb3duV2l0aDogZXZlbnQucG9pbnRlclR5cGUsXG4gICAgICAgIGN1cnNvckJ1dHRvbjogXCJkb3duXCJcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCBcImRvd25cIik7XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZUNhbnZhc1BhblVzaW5nV2hlZWxPclNwYWNlRHJhZyhldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBvbmx5IGhhbmRsZSBsZWZ0IG1vdXNlIGJ1dHRvbiBvciB0b3VjaFxuXG5cbiAgICAgIGlmIChldmVudC5idXR0b24gIT09IFBPSU5URVJfQlVUVE9OLk1BSU4gJiYgZXZlbnQuYnV0dG9uICE9PSBQT0lOVEVSX0JVVFRPTi5UT1VDSCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIGRvbid0IHNlbGVjdCB3aGlsZSBwYW5uaW5nXG5cblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA+IDEpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBTdGF0ZSBmb3IgdGhlIGR1cmF0aW9uIG9mIGEgcG9pbnRlciBpbnRlcmFjdGlvbiwgd2hpY2ggc3RhcnRzIHdpdGggYVxuICAgICAgLy8gcG9pbnRlckRvd24gZXZlbnQsIGVuZHMgd2l0aCBhIHBvaW50ZXJVcCBldmVudCAob3IgYW5vdGhlciBwb2ludGVyRG93bilcblxuXG4gICAgICBjb25zdCBwb2ludGVyRG93blN0YXRlID0gdGhpcy5pbml0aWFsUG9pbnRlckRvd25TdGF0ZShldmVudCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogZmFsc2VcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVEcmFnZ2luZ1Njcm9sbEJhcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmNsZWFyU2VsZWN0aW9uSWZOb3RVc2luZ1NlbGVjdGlvbigpO1xuICAgICAgdGhpcy51cGRhdGVCaW5kaW5nRW5hYmxlZE9uUG9pbnRlck1vdmUoZXZlbnQpO1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVTZWxlY3Rpb25PblBvaW50ZXJEb3duKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGFsbG93T25Qb2ludGVyRG93biA9ICF0aGlzLnN0YXRlLnBlbk1vZGUgfHwgZXZlbnQucG9pbnRlclR5cGUgIT09IFwidG91Y2hcIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJ0ZXh0XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIjtcblxuICAgICAgaWYgKCFhbGxvd09uUG9pbnRlckRvd24pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlVGV4dE9uUG9pbnRlckRvd24oZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImFycm93XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGluZVwiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlTGluZWFyRWxlbWVudE9uUG9pbnRlckRvd24oZXZlbnQsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlLCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICAvLyByZXNldCBpbWFnZSBwcmV2aWV3IG9uIHBvaW50ZXJkb3duXG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5DUk9TU0hBSVIpOyAvLyByZXRyaWV2ZSB0aGUgbGF0ZXN0IGVsZW1lbnQgYXMgdGhlIHN0YXRlIG1heSBiZSBzdGFsZVxuXG4gICAgICAgIGNvbnN0IHBlbmRpbmdJbWFnZUVsZW1lbnQgPSB0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCAmJiB0aGlzLnNjZW5lLmdldEVsZW1lbnQodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQpO1xuXG4gICAgICAgIGlmICghcGVuZGluZ0ltYWdlRWxlbWVudCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogcGVuZGluZ0ltYWdlRWxlbWVudCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogcGVuZGluZ0ltYWdlRWxlbWVudCxcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGwsXG4gICAgICAgICAgbXVsdGlFbGVtZW50OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBtdXRhdGVFbGVtZW50KHBlbmRpbmdJbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVGcmVlRHJhd0VsZW1lbnRPblBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImN1c3RvbVwiKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUZyYW1lRWxlbWVudE9uUG9pbnRlckRvd24ocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImhhbmRcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUdlbmVyaWNFbGVtZW50T25Qb2ludGVyRG93bih0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vblBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB0aGlzLm9uUG9pbnRlck1vdmVGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgY29uc3Qgb25Qb2ludGVyVXAgPSB0aGlzLm9uUG9pbnRlclVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5RG93biA9IHRoaXMub25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uS2V5VXAgPSB0aGlzLm9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgbGFzdFBvaW50ZXJVcCA9IG9uUG9pbnRlclVwO1xuXG4gICAgICBpZiAoIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgb25LZXlEb3duKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIG9uS2V5VXApO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSA9IG9uUG9pbnRlck1vdmU7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25VcCA9IG9uUG9pbnRlclVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5VXAgPSBvbktleVVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5RG93biA9IG9uS2V5RG93bjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnJlbW92ZVBvaW50ZXIoZXZlbnQpO1xuICAgICAgdGhpcy5sYXN0UG9pbnRlclVwID0gZXZlbnQ7XG4gICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiBldmVudC5jbGllbnRYLFxuICAgICAgICBjbGllbnRZOiBldmVudC5jbGllbnRZXG4gICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGNsaWNrbGVuZ3RoID0gZXZlbnQudGltZVN0YW1wIC0gKChfYiA9IChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudGltZVN0YW1wKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiAwKTtcblxuICAgICAgaWYgKHRoaXMuZGV2aWNlLmlzTW9iaWxlICYmIGNsaWNrbGVuZ3RoIDwgMzAwKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG5cbiAgICAgICAgaWYgKGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkgJiYgdGhpcy5pc0VtYmVkZGFibGVDZW50ZXIoaGl0RWxlbWVudCwgZXZlbnQsIHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSkpIHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayhoaXRFbGVtZW50KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4pIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgICAgdGhpcy5oaXRMaW5rRWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudExpbmtBdFBvc2l0aW9uKHNjZW5lUG9pbnRlciwgaGl0RWxlbWVudCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmhpdExpbmtFbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0aGlzLmhpdExpbmtFbGVtZW50LmlkXSkge1xuICAgICAgICBpZiAoY2xpY2tsZW5ndGggPCAzMDAgJiYgdGhpcy5oaXRMaW5rRWxlbWVudC50eXBlID09PSBcImVtYmVkZGFibGVcIiAmJiAhaXNQb2ludEhpdHRpbmdMaW5rSWNvbih0aGlzLmhpdExpbmtFbGVtZW50LCB0aGlzLnN0YXRlLCBbc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55XSkpIHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayh0aGlzLmhpdExpbmtFbGVtZW50KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnJlZGlyZWN0VG9MaW5rKGV2ZW50LCB0aGlzLmRldmljZS5pc1RvdWNoU2NyZWVuKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsLFxuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge31cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVPcGVuQ29udGV4dE1lbnVBZnRlclBvaW50ZXJEb3duT25Ub3VjaERldmljZXMgPSBldmVudCA9PiB7XG4gICAgICAvLyBkZWFsIHdpdGggb3BlbmluZyBjb250ZXh0IG1lbnUgb24gdG91Y2ggZGV2aWNlc1xuICAgICAgaWYgKGV2ZW50LnBvaW50ZXJUeXBlID09PSBcInRvdWNoXCIpIHtcbiAgICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKHRvdWNoVGltZW91dCkge1xuICAgICAgICAgIC8vIElmIHRoZXJlJ3MgYWxyZWFkeSBhIHRvdWNoVGltZW91dCwgdGhpcyBtZWFucyB0aGF0IHRoZXJlJ3MgYW5vdGhlclxuICAgICAgICAgIC8vIHRvdWNoIGRvd24gYW5kIHdlIGFyZSBkb2luZyBhbm90aGVyIHRvdWNoLCBzbyB3ZSBzaG91bGRuJ3Qgb3BlbiB0aGVcbiAgICAgICAgICAvLyBjb250ZXh0IG1lbnUuXG4gICAgICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBvcGVuIHRoZSBjb250ZXh0IG1lbnUgd2l0aCB0aGUgZmlyc3QgdG91Y2gncyBjbGllbnRYIGFuZCBjbGllbnRZXG4gICAgICAgICAgLy8gaWYgdGhlIHRvdWNoIGlzIG5vdCBtb3ZpbmdcbiAgICAgICAgICB0b3VjaFRpbWVvdXQgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICB0b3VjaFRpbWVvdXQgPSAwO1xuXG4gICAgICAgICAgICBpZiAoIWludmFsaWRhdGVDb250ZXh0TWVudSkge1xuICAgICAgICAgICAgICB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51KGV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCBUT1VDSF9DVFhfTUVOVV9USU1FT1VUKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0Q29udGV4dE1lbnVUaW1lciA9ICgpID0+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/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIGVkaXRpbmdHcm91cElkOiB0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICBbZWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgfVxuICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogaXNMaW5lYXJFbGVtZW50KGVsZW1lbnQpID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZWxlbWVudCwgdGhpcy5zY2VuZSkgOiBudWxsXG4gICAgICB9KSA6IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZmFsc2VcbiAgICAgIH0pLCAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiB7XG4gICAgICAgICAgICB0b3AsXG4gICAgICAgICAgICBsZWZ0LFxuICAgICAgICAgICAgaXRlbXM6IHRoaXMuZ2V0Q29udGV4dE1lbnVJdGVtcyh0eXBlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudCA9IChwb2ludGVyRG93blN0YXRlLCBldmVudCkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBkcmFnZ2luZ0VsZW1lbnQgPSB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudDtcbiAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHM7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcInNlbGVjdGlvblwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcImVyYXNlclwiKSB7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksIHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyQ29vcmRzLngpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBwb2ludGVyQ29vcmRzLnkpLCBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCBpbWFnZSA9IGlzSW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSAmJiAoKF9hID0gdGhpcy5pbWFnZUNhY2hlLmdldChkcmFnZ2luZ0VsZW1lbnQuZmlsZUlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmltYWdlKTtcbiAgICAgICAgY29uc3QgYXNwZWN0UmF0aW8gPSBpbWFnZSAmJiAhKGltYWdlIGluc3RhbmNlb2YgUHJvbWlzZSkgPyBpbWFnZS53aWR0aCAvIGltYWdlLmhlaWdodCA6IG51bGw7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnksIGdyaWRYLCBncmlkWSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCwgZ3JpZFgpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55LCBncmlkWSksIGlzSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgPyAhc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCkgOiBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCksIGFzcGVjdFJhdGlvKTtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKFtkcmFnZ2luZ0VsZW1lbnRdKTsgLy8gaGlnaGxpZ2h0IGVsZW1lbnRzIHRoYXQgYXJlIHRvIGJlIGFkZGVkIHRvIGZyYW1lcyBvbiBmcmFtZXMgY3JlYXRpb25cblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWxlbWVudHNUb0hpZ2hsaWdodDogZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMubWF5YmVIYW5kbGVSZXNpemUgPSAocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpID0+IHtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBzZWxlY3RlZEZyYW1lcyA9IHNlbGVjdGVkRWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuICAgICAgY29uc3QgdHJhbnNmb3JtSGFuZGxlVHlwZSA9IHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGU7XG5cbiAgICAgIGlmIChzZWxlY3RlZEZyYW1lcy5sZW5ndGggPiAwICYmIHRyYW5zZm9ybUhhbmRsZVR5cGUgPT09IFwicm90YXRpb25cIikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAvLyBUT0RPOiByZW5hbWUgdGhpcyBzdGF0ZSBmaWVsZCB0byBcImlzU2NhbGluZ1wiIHRvIGRpc3Rpbmd1aXNoXG4gICAgICAgIC8vIGl0IGZyb20gdGhlIGdlbmVyaWMgXCJpc1Jlc2l6aW5nXCIgd2hpY2ggaW5jbHVkZXMgc2NhbGluZyBhbmRcbiAgICAgICAgLy8gcm90YXRpbmdcbiAgICAgICAgaXNSZXNpemluZzogdHJhbnNmb3JtSGFuZGxlVHlwZSAmJiB0cmFuc2Zvcm1IYW5kbGVUeXBlICE9PSBcInJvdGF0aW9uXCIsXG4gICAgICAgIGlzUm90YXRpbmc6IHRyYW5zZm9ybUhhbmRsZVR5cGUgPT09IFwicm90YXRpb25cIixcbiAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzO1xuICAgICAgY29uc3QgW3Jlc2l6ZVgsIHJlc2l6ZVldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCAtIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldC54LCBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5vZmZzZXQueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcCA9IG5ldyBNYXAoKTtcbiAgICAgIHNlbGVjdGVkRnJhbWVzLmZvckVhY2goZnJhbWUgPT4ge1xuICAgICAgICBjb25zdCBlbGVtZW50c0luRnJhbWUgPSBnZXRGcmFtZUVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLmlkKTtcbiAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgZnJhbWVFbGVtZW50c09mZnNldHNNYXAuc2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCwge1xuICAgICAgICAgICAgeDogZWxlbWVudC54IC0gZnJhbWUueCxcbiAgICAgICAgICAgIHk6IGVsZW1lbnQueSAtIGZyYW1lLnlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHRyYW5zZm9ybUVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUsIHRyYW5zZm9ybUhhbmRsZVR5cGUsIHNlbGVjdGVkRWxlbWVudHMsIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmFycm93RGlyZWN0aW9uLCBzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZShldmVudCksIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIoZXZlbnQpLCBzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0ltYWdlRWxlbWVudChzZWxlY3RlZEVsZW1lbnRzWzBdKSA/ICFzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSA6IHNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpLCByZXNpemVYLCByZXNpemVZLCBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5jZW50ZXIueCwgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuY2VudGVyLnkpKSB7XG4gICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgY29uc3QgZWxlbWVudHNUb0hpZ2hsaWdodCA9IG5ldyBTZXQoKTtcbiAgICAgICAgc2VsZWN0ZWRGcmFtZXMuZm9yRWFjaChmcmFtZSA9PiB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudHNJbkZyYW1lID0gZ2V0RnJhbWVFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBmcmFtZS5pZCk7IC8vIGtlZXAgZWxlbWVudHMnIHBvc2l0aW9ucyByZWxhdGl2ZSB0byB0aGVpciBmcmFtZXMgb24gZnJhbWVzIHJlc2l6aW5nXG5cbiAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZSkge1xuICAgICAgICAgICAgaWYgKHRyYW5zZm9ybUhhbmRsZVR5cGUuaW5jbHVkZXMoXCJ3XCIpKSB7XG4gICAgICAgICAgICAgIGVsZW1lbnRzSW5GcmFtZS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgIHg6IGZyYW1lLnggKyAoKChfYSA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EueCkgfHwgMCksXG4gICAgICAgICAgICAgICAgICB5OiBmcmFtZS55ICsgKCgoX2IgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnkpIHx8IDApXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZS5pbmNsdWRlcyhcIm5cIikpIHtcbiAgICAgICAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgeDogZnJhbWUueCArICgoKF9hID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS54KSB8fCAwKSxcbiAgICAgICAgICAgICAgICAgIHk6IGZyYW1lLnkgKyAoKChfYiA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IueSkgfHwgMClcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZnJhbWUsIHRoaXMuc3RhdGUpLmZvckVhY2goZWxlbWVudCA9PiBlbGVtZW50c1RvSGlnaGxpZ2h0LmFkZChlbGVtZW50KSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBbLi4uZWxlbWVudHNUb0hpZ2hsaWdodF1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0Q29udGV4dE1lbnVJdGVtcyA9IHR5cGUgPT4ge1xuICAgICAgY29uc3Qgb3B0aW9ucyA9IFtdO1xuICAgICAgb3B0aW9ucy5wdXNoKGFjdGlvbkNvcHlBc1BuZywgYWN0aW9uQ29weUFzU3ZnKTsgLy8gY2FudmFzIGNvbnRleHRNZW51XG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICAgIGlmICh0eXBlID09PSBcImNhbnZhc1wiKSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICAgIHJldHVybiBbLi4ub3B0aW9ucywgYWN0aW9uVG9nZ2xlR3JpZE1vZGUsIGFjdGlvblRvZ2dsZVplbk1vZGUsIGFjdGlvblRvZ2dsZVZpZXdNb2RlLCBhY3Rpb25Ub2dnbGVTdGF0c107XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gW2FjdGlvblBhc3RlLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Db3B5QXNQbmcsIGFjdGlvbkNvcHlBc1N2ZywgY29weVRleHQsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvblNlbGVjdEFsbCwgYWN0aW9uVW5sb2NrQWxsRWxlbWVudHMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvblRvZ2dsZUdyaWRNb2RlLCBhY3Rpb25Ub2dnbGVaZW5Nb2RlLCBhY3Rpb25Ub2dnbGVWaWV3TW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHNdO1xuICAgICAgfSAvLyBlbGVtZW50IGNvbnRleHRNZW51XG4gICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuICAgICAgb3B0aW9ucy5wdXNoKGNvcHlUZXh0KTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHJldHVybiBbYWN0aW9uQ29weSwgLi4ub3B0aW9uc107XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBbYWN0aW9uQ3V0LCBhY3Rpb25Db3B5LCBhY3Rpb25QYXN0ZSwgYWN0aW9uU2VsZWN0QWxsRWxlbWVudHNJbkZyYW1lLCBhY3Rpb25SZW1vdmVBbGxFbGVtZW50c0Zyb21GcmFtZSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgLi4ub3B0aW9ucywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQ29weVN0eWxlcywgYWN0aW9uUGFzdGVTdHlsZXMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkdyb3VwLCBhY3Rpb25VbmJpbmRUZXh0LCBhY3Rpb25CaW5kVGV4dCwgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciwgYWN0aW9uVW5ncm91cCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uQWRkVG9MaWJyYXJ5LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25TZW5kQmFja3dhcmQsIGFjdGlvbkJyaW5nRm9yd2FyZCwgYWN0aW9uU2VuZFRvQmFjaywgYWN0aW9uQnJpbmdUb0Zyb250LCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25GbGlwSG9yaXpvbnRhbCwgYWN0aW9uRmxpcFZlcnRpY2FsLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Ub2dnbGVMaW5lYXJFZGl0b3IsIGFjdGlvbkxpbmssIGFjdGlvbkR1cGxpY2F0ZVNlbGVjdGlvbiwgYWN0aW9uVG9nZ2xlRWxlbWVudExvY2ssIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkRlbGV0ZVNlbGVjdGVkXTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVXaGVlbCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAoaXNQYW5uaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICBkZWx0YVgsXG4gICAgICAgIGRlbHRhWVxuICAgICAgfSA9IGV2ZW50OyAvLyBub3RlIHRoYXQgZXZlbnQuY3RybEtleSBpcyBuZWNlc3NhcnkgdG8gaGFuZGxlIHBpbmNoIHpvb21pbmdcblxuICAgICAgaWYgKGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuY3RybEtleSkge1xuICAgICAgICBjb25zdCBzaWduID0gTWF0aC5zaWduKGRlbHRhWSk7XG4gICAgICAgIGNvbnN0IE1BWF9TVEVQID0gWk9PTV9TVEVQICogMTAwO1xuICAgICAgICBjb25zdCBhYnNEZWx0YSA9IE1hdGguYWJzKGRlbHRhWSk7XG4gICAgICAgIGxldCBkZWx0YSA9IGRlbHRhWTtcblxuICAgICAgICBpZiAoYWJzRGVsdGEgPiBNQVhfU1RFUCkge1xuICAgICAgICAgIGRlbHRhID0gTUFYX1NURVAgKiBzaWduO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG5ld1pvb20gPSB0aGlzLnN0YXRlLnpvb20udmFsdWUgLSBkZWx0YSAvIDEwMDsgLy8gaW5jcmVhc2Ugem9vbSBzdGVwcyB0aGUgbW9yZSB6b29tZWQtaW4gd2UgYXJlIChhcHBsaWVzIHRvID4xMDAlIG9ubHkpXG5cbiAgICAgICAgbmV3Wm9vbSArPSBNYXRoLmxvZzEwKE1hdGgubWF4KDEsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpICogLXNpZ24gKiAvLyByZWR1Y2VkIGFtcGxpZmljYXRpb24gZm9yIHNtYWxsIGRlbHRhcyAoc21hbGwgbW92ZW1lbnRzIG9uIGEgdHJhY2twYWQpXG4gICAgICAgIE1hdGgubWluKDEsIGFic0RlbHRhIC8gMjApO1xuICAgICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyhzdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgdmlld3BvcnRYOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsXG4gICAgICAgICAgdmlld3BvcnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnksXG4gICAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKG5ld1pvb20pXG4gICAgICAgIH0sIHN0YXRlKSksIHtcbiAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgfSkpO1xuICAgICAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gc2Nyb2xsIGhvcml6b250YWxseSB3aGVuIHNoaWZ0IHByZXNzZWRcblxuXG4gICAgICBpZiAoZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoKHtcbiAgICAgICAgICB6b29tLFxuICAgICAgICAgIHNjcm9sbFhcbiAgICAgICAgfSkgPT4gKHtcbiAgICAgICAgICAvLyBvbiBNYWMsIHNoaWZ0K3doZWVsIHRlbmRzIHRvIHJlc3VsdCBpbiBkZWx0YVhcbiAgICAgICAgICBzY3JvbGxYOiBzY3JvbGxYIC0gKGRlbHRhWSB8fCBkZWx0YVgpIC8gem9vbS52YWx1ZVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoKHtcbiAgICAgICAgem9vbSxcbiAgICAgICAgc2Nyb2xsWCxcbiAgICAgICAgc2Nyb2xsWVxuICAgICAgfSkgPT4gKHtcbiAgICAgICAgc2Nyb2xsWDogc2Nyb2xsWCAtIGRlbHRhWCAvIHpvb20udmFsdWUsXG4gICAgICAgIHNjcm9sbFk6IHNjcm9sbFkgLSBkZWx0YVkgLyB6b29tLnZhbHVlXG4gICAgICB9KSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnNhdmVQb2ludGVyID0gKHgsIHksIGJ1dHRvbikgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgaWYgKCF4IHx8ICF5KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgIGNsaWVudFg6IHgsXG4gICAgICAgIGNsaWVudFk6IHlcbiAgICAgIH0sIHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoaXNOYU4ocG9pbnRlci54KSB8fCBpc05hTihwb2ludGVyLnkpKSB7Ly8gc29tZXRpbWVzIHRoZSBwb2ludGVyIGdvZXMgb2ZmIHNjcmVlblxuICAgICAgfVxuXG4gICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKS5vblBvaW50ZXJVcGRhdGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5jYWxsKF9hLCB7XG4gICAgICAgIHBvaW50ZXIsXG4gICAgICAgIGJ1dHRvbixcbiAgICAgICAgcG9pbnRlcnNNYXA6IGdlc3R1cmUucG9pbnRlcnNcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0U2hvdWxkQ2FjaGVJZ25vcmVab29tRGVib3VuY2VkID0gZGVib3VuY2UoKCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLnVubW91bnRlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IGZhbHNlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0sIDMwMCk7XG5cbiAgICB0aGlzLnVwZGF0ZURPTVJlY3QgPSBjYiA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGlmICgoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jdXJyZW50KSB7XG4gICAgICAgIGNvbnN0IGV4Y2FsaWRyYXdDb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHdpZHRoLFxuICAgICAgICAgIGhlaWdodCxcbiAgICAgICAgICBsZWZ0OiBvZmZzZXRMZWZ0LFxuICAgICAgICAgIHRvcDogb2Zmc2V0VG9wXG4gICAgICAgIH0gPSBleGNhbGlkcmF3Q29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgd2lkdGg6IGN1cnJlbnRXaWR0aCxcbiAgICAgICAgICBoZWlnaHQ6IGN1cnJlbnRIZWlnaHQsXG4gICAgICAgICAgb2Zmc2V0VG9wOiBjdXJyZW50T2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnQ6IGN1cnJlbnRPZmZzZXRMZWZ0XG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuXG4gICAgICAgIGlmICh3aWR0aCA9PT0gY3VycmVudFdpZHRoICYmIGhlaWdodCA9PT0gY3VycmVudEhlaWdodCAmJiBvZmZzZXRMZWZ0ID09PSBjdXJyZW50T2Zmc2V0TGVmdCAmJiBvZmZzZXRUb3AgPT09IGN1cnJlbnRPZmZzZXRUb3ApIHtcbiAgICAgICAgICBpZiAoY2IpIHtcbiAgICAgICAgICAgIGNiKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgIG9mZnNldExlZnQsXG4gICAgICAgICAgb2Zmc2V0VG9wXG4gICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICBjYiAmJiBjYigpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5yZWZyZXNoID0gKCkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZShPYmplY3QuYXNzaWduKHt9LCB0aGlzLmdldENhbnZhc09mZnNldHMoKSkpO1xuICAgIH07XG5cbiAgICBjb25zdCBkZWZhdWx0QXBwU3RhdGUgPSBnZXREZWZhdWx0QXBwU3RhdGUoKTtcbiAgICBjb25zdCB7XG4gICAgICBleGNhbGlkcmF3UmVmLFxuICAgICAgdmlld01vZGVFbmFibGVkID0gZmFsc2UsXG4gICAgICB6ZW5Nb2RlRW5hYmxlZCA9IGZhbHNlLFxuICAgICAgZ3JpZE1vZGVFbmFibGVkID0gZmFsc2UsXG4gICAgICB0aGVtZSA9IGRlZmF1bHRBcHBTdGF0ZS50aGVtZSxcbiAgICAgIG5hbWUgPSBkZWZhdWx0QXBwU3RhdGUubmFtZVxuICAgIH0gPSBwcm9wcztcbiAgICB0aGlzLnN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZGVmYXVsdEFwcFN0YXRlKSwge1xuICAgICAgdGhlbWUsXG4gICAgICBpc0xvYWRpbmc6IHRydWVcbiAgICB9KSwgdGhpcy5nZXRDYW52YXNPZmZzZXRzKCkpLCB7XG4gICAgICB2aWV3TW9kZUVuYWJsZWQsXG4gICAgICB6ZW5Nb2RlRW5hYmxlZCxcbiAgICAgIGdyaWRTaXplOiBncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsLFxuICAgICAgbmFtZSxcbiAgICAgIHdpZHRoOiB3aW5kb3cuaW5uZXJXaWR0aCxcbiAgICAgIGhlaWdodDogd2luZG93LmlubmVySGVpZ2h0XG4gICAgfSk7XG4gICAgdGhpcy5pZCA9IG5hbm9pZCgpO1xuICAgIHRoaXMubGlicmFyeSA9IG5ldyBMaWJyYXJ5KHRoaXMpO1xuICAgIHRoaXMuc2NlbmUgPSBuZXcgU2NlbmUoKTtcbiAgICB0aGlzLmNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgdGhpcy5yYyA9IHJvdWdoLmNhbnZhcyh0aGlzLmNhbnZhcyk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcblxuICAgIGlmIChleGNhbGlkcmF3UmVmKSB7XG4gICAgICBjb25zdCByZWFkeVByb21pc2UgPSBcImN1cnJlbnRcIiBpbiBleGNhbGlkcmF3UmVmICYmICgoX2EgPSBleGNhbGlkcmF3UmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZWFkeVByb21pc2UpIHx8IHJlc29sdmFibGVQcm9taXNlKCk7XG4gICAgICBjb25zdCBhcGkgPSB7XG4gICAgICAgIHJlYWR5OiB0cnVlLFxuICAgICAgICByZWFkeVByb21pc2UsXG4gICAgICAgIHVwZGF0ZVNjZW5lOiB0aGlzLnVwZGF0ZVNjZW5lLFxuICAgICAgICB1cGRhdGVMaWJyYXJ5OiB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSxcbiAgICAgICAgYWRkRmlsZXM6IHRoaXMuYWRkRmlsZXMsXG4gICAgICAgIHJlc2V0U2NlbmU6IHRoaXMucmVzZXRTY2VuZSxcbiAgICAgICAgZ2V0U2NlbmVFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQ6IHRoaXMuZ2V0U2NlbmVFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQsXG4gICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICBjbGVhcjogdGhpcy5yZXNldEhpc3RvcnlcbiAgICAgICAgfSxcbiAgICAgICAgc2Nyb2xsVG9Db250ZW50OiB0aGlzLnNjcm9sbFRvQ29udGVudCxcbiAgICAgICAgZ2V0U2NlbmVFbGVtZW50czogdGhpcy5nZXRTY2VuZUVsZW1lbnRzLFxuICAgICAgICBnZXRBcHBTdGF0ZTogKCkgPT4gdGhpcy5zdGF0ZSxcbiAgICAgICAgZ2V0RmlsZXM6ICgpID0+IHRoaXMuZmlsZXMsXG4gICAgICAgIHJlZnJlc2g6IHRoaXMucmVmcmVzaCxcbiAgICAgICAgc2V0VG9hc3Q6IHRoaXMuc2V0VG9hc3QsXG4gICAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgICBzZXRBY3RpdmVUb29sOiB0aGlzLnNldEFjdGl2ZVRvb2wsXG4gICAgICAgIHNldEN1cnNvcjogdGhpcy5zZXRDdXJzb3IsXG4gICAgICAgIHJlc2V0Q3Vyc29yOiB0aGlzLnJlc2V0Q3Vyc29yLFxuICAgICAgICB1cGRhdGVGcmFtZVJlbmRlcmluZzogdGhpcy51cGRhdGVGcmFtZVJlbmRlcmluZyxcbiAgICAgICAgdG9nZ2xlU2lkZWJhcjogdGhpcy50b2dnbGVTaWRlYmFyXG4gICAgICB9O1xuXG4gICAgICBpZiAodHlwZW9mIGV4Y2FsaWRyYXdSZWYgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBleGNhbGlkcmF3UmVmKGFwaSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBleGNhbGlkcmF3UmVmLmN1cnJlbnQgPSBhcGk7XG4gICAgICB9XG5cbiAgICAgIHJlYWR5UHJvbWlzZS5yZXNvbHZlKGFwaSk7XG4gICAgfVxuXG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWUgPSB7XG4gICAgICBjb250YWluZXI6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LFxuICAgICAgaWQ6IHRoaXMuaWRcbiAgICB9O1xuICAgIHRoaXMuZm9udHMgPSBuZXcgRm9udHMoe1xuICAgICAgc2NlbmU6IHRoaXMuc2NlbmUsXG4gICAgICBvblNjZW5lVXBkYXRlZDogdGhpcy5vblNjZW5lVXBkYXRlZFxuICAgIH0pO1xuICAgIHRoaXMuaGlzdG9yeSA9IG5ldyBIaXN0b3J5KCk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyID0gbmV3IEFjdGlvbk1hbmFnZXIodGhpcy5zeW5jQWN0aW9uUmVzdWx0LCAoKSA9PiB0aGlzLnN0YXRlLCAoKSA9PiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBbGwoYWN0aW9ucyk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVVuZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWN0aW9uKGNyZWF0ZVJlZG9BY3Rpb24odGhpcy5oaXN0b3J5KSk7XG4gIH1cblxuICBvbldpbmRvd01lc3NhZ2UoZXZlbnQpIHtcbiAgICBpZiAoZXZlbnQub3JpZ2luICE9PSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiICYmIGV2ZW50Lm9yaWdpbiAhPT0gXCJodHRwczovL3d3dy55b3V0dWJlLmNvbVwiKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IGRhdGEgPSBudWxsO1xuXG4gICAgdHJ5IHtcbiAgICAgIGRhdGEgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG5cbiAgICBpZiAoIWRhdGEpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKGV2ZW50Lm9yaWdpbikge1xuICAgICAgY2FzZSBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbVwiOlxuICAgICAgICAvL0FsbG93aW5nIGZvciBtdWx0aXBsZSBpbnN0YW5jZXMgb2YgRXhjYWxpZHJhdyBydW5uaW5nIGluIHRoZSB3aW5kb3dcbiAgICAgICAgaWYgKGRhdGEubWV0aG9kID09PSBcInBhdXNlZFwiKSB7XG4gICAgICAgICAgbGV0IHNvdXJjZSA9IG51bGw7XG4gICAgICAgICAgY29uc3QgaWZyYW1lcyA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvckFsbChcImlmcmFtZS5leGNhbGlkcmF3X19lbWJlZGRhYmxlXCIpO1xuXG4gICAgICAgICAgaWYgKCFpZnJhbWVzKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBmb3IgKGNvbnN0IGlmcmFtZSBvZiBpZnJhbWVzKSB7XG4gICAgICAgICAgICBpZiAoaWZyYW1lLmNvbnRlbnRXaW5kb3cgPT09IGV2ZW50LnNvdXJjZSkge1xuICAgICAgICAgICAgICBzb3VyY2UgPSBpZnJhbWUuY29udGVudFdpbmRvdztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzb3VyY2UgPT09IG51bGwgfHwgc291cmNlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBzb3VyY2UucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgbWV0aG9kOiBkYXRhLnZhbHVlID8gXCJwbGF5XCIgOiBcInBhdXNlXCIsXG4gICAgICAgICAgICB2YWx1ZTogdHJ1ZVxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBcImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tXCI6XG4gICAgICAgIGlmIChkYXRhLmV2ZW50ID09PSBcImluZm9EZWxpdmVyeVwiICYmIGRhdGEuaW5mbyAmJiBkYXRhLmlkICYmIHR5cGVvZiBkYXRhLmluZm8ucGxheWVyU3RhdGUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICBjb25zdCBpZCA9IGRhdGEuaWQ7XG4gICAgICAgICAgY29uc3QgcGxheWVyU3RhdGUgPSBkYXRhLmluZm8ucGxheWVyU3RhdGU7XG5cbiAgICAgICAgICBpZiAoT2JqZWN0LnZhbHVlcyhZT1VUVUJFX1NUQVRFUykuaW5jbHVkZXMocGxheWVyU3RhdGUpKSB7XG4gICAgICAgICAgICBZT1VUVUJFX1ZJREVPX1NUQVRFUy5zZXQoaWQsIHBsYXllclN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICB1cGRhdGVFbWJlZGRhYmxlUmVmKGlkLCByZWYpIHtcbiAgICBpZiAocmVmKSB7XG4gICAgICB0aGlzLmlGcmFtZVJlZnMuc2V0KGlkLCByZWYpO1xuICAgIH1cbiAgfVxuXG4gIGdldEhUTUxJRnJhbWVFbGVtZW50KGlkKSB7XG4gICAgcmV0dXJuIHRoaXMuaUZyYW1lUmVmcy5nZXQoaWQpO1xuICB9XG5cbiAgaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKGVsZW1lbnQpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG5cbiAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpID09PSBlbGVtZW50ICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiYWN0aXZlXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9IC8vIFRoZSBkZWxheSBzZXJ2ZXMgdHdvIHB1cnBvc2VzXG4gICAgLy8gMS4gVG8gcHJldmVudCBmaXJzdCBjbGljayBwcm9wYWdhdGluZyB0byBpZnJhbWUgb24gbW9iaWxlLFxuICAgIC8vICAgIGVsc2UgdGhlIGNsaWNrIHdpbGwgaW1tZWRpYXRlbHkgc3RhcnQgYW5kIHN0b3AgdGhlIHZpZGVvXG4gICAgLy8gMi4gSWYgdGhlIHVzZXIgZG91YmxlIGNsaWNrcyB0aGUgZnJhbWUgY2VudGVyIHRvIGFjdGl2YXRlIGl0XG4gICAgLy8gICAgd2l0aG91dCB0aGUgZGVsYXkgeW91dHViZSB3aWxsIGltbWVkaWF0ZWx5IG9wZW4gdGhlIHZpZGVvXG4gICAgLy8gICAgaW4gZnVsbHNjcmVlbiBtb2RlXG5cblxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IHtcbiAgICAgICAgICBlbGVtZW50LFxuICAgICAgICAgIHN0YXRlOiBcImFjdGl2ZVwiXG4gICAgICAgIH0sXG4gICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgIFtlbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgIHNlbGVjdGlvbkVsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH0sIDEwMCk7XG4gICAgY29uc3QgaWZyYW1lID0gdGhpcy5nZXRIVE1MSUZyYW1lRWxlbWVudChlbGVtZW50LmlkKTtcblxuICAgIGlmICghKGlmcmFtZSA9PT0gbnVsbCB8fCBpZnJhbWUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGlmcmFtZS5jb250ZW50V2luZG93KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpZnJhbWUuc3JjLmluY2x1ZGVzKFwieW91dHViZVwiKSkge1xuICAgICAgY29uc3Qgc3RhdGUgPSBZT1VUVUJFX1ZJREVPX1NUQVRFUy5nZXQoZWxlbWVudC5pZCk7XG5cbiAgICAgIGlmICghc3RhdGUpIHtcbiAgICAgICAgWU9VVFVCRV9WSURFT19TVEFURVMuc2V0KGVsZW1lbnQuaWQsIFlPVVRVQkVfU1RBVEVTLlVOU1RBUlRFRCk7XG4gICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBldmVudDogXCJsaXN0ZW5pbmdcIixcbiAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgfVxuXG4gICAgICBzd2l0Y2ggKHN0YXRlKSB7XG4gICAgICAgIGNhc2UgWU9VVFVCRV9TVEFURVMuUExBWUlORzpcbiAgICAgICAgY2FzZSBZT1VUVUJFX1NUQVRFUy5CVUZGRVJJTkc6XG4gICAgICAgICAgKF9jID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBhdXNlVmlkZW9cIixcbiAgICAgICAgICAgIGFyZ3M6IFwiXCJcbiAgICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgKF9kID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBldmVudDogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICBmdW5jOiBcInBsYXlWaWRlb1wiLFxuICAgICAgICAgICAgYXJnczogXCJcIlxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGlmcmFtZS5zcmMuaW5jbHVkZXMoXCJwbGF5ZXIudmltZW8uY29tXCIpKSB7XG4gICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIG1ldGhvZDogXCJwYXVzZWRcIiAvL3ZpZGVvIHBsYXkvcGF1c2UgaW4gb25XaW5kb3dNZXNzYWdlIGhhbmRsZXJcblxuICAgICAgfSksIFwiKlwiKTtcbiAgICB9XG4gIH1cblxuICBpc0VtYmVkZGFibGVDZW50ZXIoZWwsIGV2ZW50LCBzY2VuZVgsIHNjZW5lWSkge1xuICAgIHZhciBfYSwgX2I7XG5cbiAgICByZXR1cm4gZWwgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQuc2hpZnRLZXkgJiYgIWV2ZW50Lm1ldGFLZXkgJiYgIWV2ZW50LmN0cmxLZXkgJiYgKCgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSAhPT0gZWwgfHwgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJob3ZlclwiIHx8ICF0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpICYmIHNjZW5lWCA+PSBlbC54ICsgZWwud2lkdGggLyAzICYmIHNjZW5lWCA8PSBlbC54ICsgMiAqIGVsLndpZHRoIC8gMyAmJiBzY2VuZVkgPj0gZWwueSArIGVsLmhlaWdodCAvIDMgJiYgc2NlbmVZIDw9IGVsLnkgKyAyICogZWwuaGVpZ2h0IC8gMztcbiAgfVxuXG4gIHJlbmRlckVtYmVkZGFibGVzKCkge1xuICAgIGNvbnN0IHNjYWxlID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRXaWR0aCA9IHRoaXMuc3RhdGUud2lkdGg7XG4gICAgY29uc3Qgbm9ybWFsaXplZEhlaWdodCA9IHRoaXMuc3RhdGUuaGVpZ2h0O1xuICAgIGNvbnN0IGVtYmVkZGFibGVFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsID0+IGlzRW1iZWRkYWJsZUVsZW1lbnQoZWwpICYmICEhZWwudmFsaWRhdGVkKTtcbiAgICByZXR1cm4gX2pzeChfRnJhZ21lbnQsIHtcbiAgICAgIGNoaWxkcmVuOiBlbWJlZGRhYmxlRWxlbWVudHMubWFwKGVsID0+IHtcbiAgICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaDtcblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogZWwueCxcbiAgICAgICAgICBzY2VuZVk6IGVsLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGVtYmVkTGluayA9IGdldEVtYmVkTGluayh0b1ZhbGlkVVJMKGVsLmxpbmsgfHwgXCJcIikpO1xuICAgICAgICBjb25zdCBpc1Zpc2libGUgPSBpc0VsZW1lbnRJblZpZXdwb3J0KGVsLCBub3JtYWxpemVkV2lkdGgsIG5vcm1hbGl6ZWRIZWlnaHQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBpc0FjdGl2ZSA9ICgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSA9PT0gZWwgJiYgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJhY3RpdmVcIjtcbiAgICAgICAgY29uc3QgaXNIb3ZlcmVkID0gKChfYyA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmVsZW1lbnQpID09PSBlbCAmJiAoKF9kID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Quc3RhdGUpID09PSBcImhvdmVyXCI7XG4gICAgICAgIHJldHVybiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgIGNsYXNzTmFtZTogY2xzeChcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtY29udGFpbmVyXCIsIHtcbiAgICAgICAgICAgIFwiaXMtaG92ZXJlZFwiOiBpc0hvdmVyZWRcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgdHJhbnNmb3JtOiBpc1Zpc2libGUgPyBgdHJhbnNsYXRlKCR7eCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdH1weCwgJHt5IC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3B9cHgpIHNjYWxlKCR7c2NhbGV9KWAgOiBcIm5vbmVcIixcbiAgICAgICAgICAgIGRpc3BsYXk6IGlzVmlzaWJsZSA/IFwiYmxvY2tcIiA6IFwibm9uZVwiLFxuICAgICAgICAgICAgb3BhY2l0eTogZWwub3BhY2l0eSAvIDEwMCxcbiAgICAgICAgICAgIFtcIi0tZW1iZWRkYWJsZS1yYWRpdXNcIl06IGAke2dldENvcm5lclJhZGl1cyhNYXRoLm1pbihlbC53aWR0aCwgZWwuaGVpZ2h0KSwgZWwpfXB4YFxuICAgICAgICAgIH1cbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBfanN4cyhcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgIC8vdGhpcyBpcyBhIGhhY2sgdGhhdCBhZGRyZXNzZXMgaXNzZSB3aXRoIGVtYmVkZGVkIGV4Y2FsaWRyYXcuY29tIGVtYmVkZGFibGVcbiAgICAgICAgICAgIC8vaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzY2OTEjaXNzdWVjb21tZW50LTE2MDczODM5MzhcblxuICAgICAgICAgICAgLypyZWY9eyhyZWYpID0+IHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgICAgICAgICAgY29uc3Qgc2ggPSBjb250YWluZXIuc2Nyb2xsSGVpZ2h0O1xuICAgICAgICAgICAgICBjb25zdCBjaCA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQ7XG4gICAgICAgICAgICAgIGlmIChzaCAhPT0gY2gpIHtcbiAgICAgICAgICAgICAgICBjb250YWluZXIuc3R5bGUuaGVpZ2h0ID0gYCR7c2h9cHhgO1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgY29udGFpbmVyLnN0eWxlLmhlaWdodCA9IGAxMDAlYDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfX0qL1xuICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtY29udGFpbmVyX19pbm5lclwiLFxuICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgd2lkdGg6IGlzVmlzaWJsZSA/IGAke2VsLndpZHRofXB4YCA6IDAsXG4gICAgICAgICAgICAgIGhlaWdodDogaXNWaXNpYmxlID8gYCR7ZWwuaGVpZ2h0fXB4YCA6IDAsXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogaXNWaXNpYmxlID8gYHJvdGF0ZSgke2VsLmFuZ2xlfXJhZClgIDogXCJub25lXCIsXG4gICAgICAgICAgICAgIHBvaW50ZXJFdmVudHM6IGlzQWN0aXZlID8gUE9JTlRFUl9FVkVOVFMuZW5hYmxlZCA6IFBPSU5URVJfRVZFTlRTLmRpc2FibGVkXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgY2hpbGRyZW46IFtpc0hvdmVyZWQgJiYgX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGUtaGludFwiXG4gICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgIGNoaWxkcmVuOiB0KFwiYnV0dG9ucy5lbWJlZGRhYmxlSW50ZXJhY3Rpb25CdXR0b25cIilcbiAgICAgICAgICAgIH0pKSwgX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGVfX291dGVyXCIsXG4gICAgICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICAgICAgcGFkZGluZzogYCR7ZWwuc3Ryb2tlV2lkdGh9cHhgXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IChfZyA9IChfZiA9IChfZSA9IHRoaXMucHJvcHMpLnJlbmRlckVtYmVkZGFibGUpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5jYWxsKF9lLCBlbCwgdGhpcy5zdGF0ZSkpICE9PSBudWxsICYmIF9nICE9PSB2b2lkIDAgPyBfZyA6IF9qc3goXCJpZnJhbWVcIiwge1xuICAgICAgICAgICAgICAgIHJlZjogcmVmID0+IHRoaXMudXBkYXRlRW1iZWRkYWJsZVJlZihlbC5pZCwgcmVmKSxcbiAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZVwiLFxuICAgICAgICAgICAgICAgIHNyY0RvYzogKGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay50eXBlKSA9PT0gXCJkb2N1bWVudFwiID8gZW1iZWRMaW5rLnNyY2RvYyh0aGlzLnN0YXRlLnRoZW1lKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBzcmM6IChlbWJlZExpbmsgPT09IG51bGwgfHwgZW1iZWRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbWJlZExpbmsudHlwZSkgIT09IFwiZG9jdW1lbnRcIiA/IChfaCA9IGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay5saW5rKSAhPT0gbnVsbCAmJiBfaCAhPT0gdm9pZCAwID8gX2ggOiBcIlwiIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcS8xODQ3MDAxNVxuICAgICAgICAgICAgICAgIHNjcm9sbGluZzogXCJub1wiLFxuICAgICAgICAgICAgICAgIHJlZmVycmVyUG9saWN5OiBcIm5vLXJlZmVycmVyLXdoZW4tZG93bmdyYWRlXCIsXG4gICAgICAgICAgICAgICAgdGl0bGU6IFwiRXhjYWxpZHJhdyBFbWJlZGRlZCBDb250ZW50XCIsXG4gICAgICAgICAgICAgICAgYWxsb3c6IFwiYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZVwiLFxuICAgICAgICAgICAgICAgIGFsbG93RnVsbFNjcmVlbjogdHJ1ZSxcbiAgICAgICAgICAgICAgICBzYW5kYm94OiBcImFsbG93LXNhbWUtb3JpZ2luIGFsbG93LXNjcmlwdHMgYWxsb3ctZm9ybXMgYWxsb3ctcG9wdXBzIGFsbG93LXBvcHVwcy10by1lc2NhcGUtc2FuZGJveCBhbGxvdy1wcmVzZW50YXRpb24gYWxsb3ctZG93bmxvYWRzXCJcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pKV1cbiAgICAgICAgICB9KSlcbiAgICAgICAgfSksIGVsLmlkKTtcbiAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICByZW5kZXIoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2M7XG5cbiAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHtcbiAgICAgIHJlbmRlclRvcFJpZ2h0VUksXG4gICAgICByZW5kZXJDdXN0b21TdGF0c1xuICAgIH0gPSB0aGlzLnByb3BzO1xuICAgIGNvbnN0IHZlcnNpb25Ob25jZSA9IHRoaXMuc2NlbmUuZ2V0VmVyc2lvbk5vbmNlKCk7XG4gICAgY29uc3Qge1xuICAgICAgY2FudmFzRWxlbWVudHMsXG4gICAgICB2aXNpYmxlRWxlbWVudHNcbiAgICB9ID0gdGhpcy5yZW5kZXJlci5nZXRSZW5kZXJhYmxlRWxlbWVudHMoe1xuICAgICAgdmVyc2lvbk5vbmNlLFxuICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLFxuICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgb2Zmc2V0VG9wOiB0aGlzLnN0YXRlLm9mZnNldFRvcCxcbiAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCxcbiAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgIGhlaWdodDogdGhpcy5zdGF0ZS5oZWlnaHQsXG4gICAgICB3aWR0aDogdGhpcy5zdGF0ZS53aWR0aCxcbiAgICAgIGVkaXRpbmdFbGVtZW50OiB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50LFxuICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiB0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZFxuICAgIH0pO1xuICAgIHJldHVybiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgY2xhc3NOYW1lOiBjbHN4KFwiZXhjYWxpZHJhdyBleGNhbGlkcmF3LWNvbnRhaW5lclwiLCB7XG4gICAgICAgIFwiZXhjYWxpZHJhdy0tdmlldy1tb2RlXCI6IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkLFxuICAgICAgICBcImV4Y2FsaWRyYXctLW1vYmlsZVwiOiB0aGlzLmRldmljZS5pc01vYmlsZVxuICAgICAgfSksXG4gICAgICBzdHlsZToge1xuICAgICAgICBbXCItLXVpLXBvaW50ZXJFdmVudHNcIl06IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCB8fCB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLnJlc2l6aW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICYmICFpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID8gUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5lbmFibGVkXG4gICAgICB9LFxuICAgICAgcmVmOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYsXG4gICAgICBvbkRyb3A6IHRoaXMuaGFuZGxlQXBwT25Ecm9wLFxuICAgICAgdGFiSW5kZXg6IDAsXG4gICAgICBvbktleURvd246IHRoaXMucHJvcHMuaGFuZGxlS2V5Ym9hcmRHbG9iYWxseSA/IHVuZGVmaW5lZCA6IHRoaXMub25LZXlEb3duXG4gICAgfSwge1xuICAgICAgY2hpbGRyZW46IF9qc3goQXBwQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgIHZhbHVlOiB0aGlzXG4gICAgICB9LCB7XG4gICAgICAgIGNoaWxkcmVuOiBfanN4KEFwcFByb3BzQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdmFsdWU6IHRoaXMucHJvcHNcbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJWYWx1ZVxuICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KERldmljZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5kZXZpY2VcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc2V0QXBwU3RhdGVcbiAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc3RhdGVcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICBjaGlsZHJlbjogX2pzeHMoRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpXG4gICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbX2pzeHMoRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5hY3Rpb25NYW5hZ2VyXG4gICAgICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW19qc3goTGF5ZXJVSSwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmVDYW52YXM6IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVzOiB0aGlzLmZpbGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0QXBwU3RhdGU6IHRoaXMuc2V0QXBwU3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25NYW5hZ2VyOiB0aGlzLmFjdGlvbk1hbmFnZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uTG9ja1RvZ2dsZTogdGhpcy50b2dnbGVMb2NrLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25QZW5Nb2RlVG9nZ2xlOiB0aGlzLnRvZ2dsZVBlbk1vZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkhhbmRUb29sVG9nZ2xlOiB0aGlzLm9uSGFuZFRvb2xUb2dnbGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBsYW5nQ29kZTogZ2V0TGFuZ3VhZ2UoKS5jb2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyVG9wUmlnaHRVSTogcmVuZGVyVG9wUmlnaHRVSSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlckN1c3RvbVN0YXRzOiByZW5kZXJDdXN0b21TdGF0cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dFeGl0WmVuTW9kZUJ0bjogdHlwZW9mICgoX2EgPSB0aGlzLnByb3BzKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuemVuTW9kZUVuYWJsZWQpID09PSBcInVuZGVmaW5lZFwiICYmIHRoaXMuc3RhdGUuemVuTW9kZUVuYWJsZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBVSU9wdGlvbnM6IHRoaXMucHJvcHMuVUlPcHRpb25zLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25JbWFnZUFjdGlvbjogdGhpcy5vbkltYWdlQWN0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25FeHBvcnRJbWFnZTogdGhpcy5vbkV4cG9ydEltYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyV2VsY29tZVNjcmVlbjogIXRoaXMuc3RhdGUuaXNMb2FkaW5nICYmIHRoaXMuc3RhdGUuc2hvd1dlbGNvbWVTY3JlZW4gJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgIXRoaXMuc3RhdGUuemVuTW9kZUVuYWJsZWQgJiYgIXRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubGVuZ3RoLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwOiB0aGlzXG4gICAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IHRoaXMucHJvcHMuY2hpbGRyZW5cbiAgICAgICAgICAgICAgICAgICAgICB9KSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctdGV4dEVkaXRvckNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctY29udGV4dE1lbnVDb250YWluZXJcIlxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KFwiZGl2XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3LWV5ZS1kcm9wcGVyLWNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmICF0aGlzLnN0YXRlLmNvbnRleHRNZW51ICYmIHRoaXMuc3RhdGUuc2hvd0h5cGVybGlua1BvcHVwICYmIF9qc3goSHlwZXJsaW5rLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50OiBzZWxlY3RlZEVsZW1lbnRzWzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0QXBwU3RhdGU6IHRoaXMuc2V0QXBwU3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkxpbmtPcGVuOiB0aGlzLnByb3BzLm9uTGlua09wZW4sXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRUb2FzdDogdGhpcy5zZXRUb2FzdFxuICAgICAgICAgICAgICAgICAgICAgIH0sIHNlbGVjdGVkRWxlbWVudHNbMF0uaWQpLCB0aGlzLnN0YXRlLnRvYXN0ICE9PSBudWxsICYmIF9qc3goVG9hc3QsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IHRoaXMuc3RhdGUudG9hc3QubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xvc2U6ICgpID0+IHRoaXMuc2V0VG9hc3QobnVsbCksXG4gICAgICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogdGhpcy5zdGF0ZS50b2FzdC5kdXJhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsb3NhYmxlOiB0aGlzLnN0YXRlLnRvYXN0LmNsb3NhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHRoaXMuc3RhdGUuY29udGV4dE1lbnUgJiYgX2pzeChDb250ZXh0TWVudSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbXM6IHRoaXMuc3RhdGUuY29udGV4dE1lbnUuaXRlbXMsXG4gICAgICAgICAgICAgICAgICAgICAgICB0b3A6IHRoaXMuc3RhdGUuY29udGV4dE1lbnUudG9wLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGVmdDogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS5sZWZ0LFxuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uTWFuYWdlcjogdGhpcy5hY3Rpb25NYW5hZ2VyXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goU3RhdGljQ2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmM6IHRoaXMucmMsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogY2FudmFzRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB2aXNpYmxlRWxlbWVudHM6IHZpc2libGVFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb25Ob25jZTogdmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uTm9uY2U6IChfYiA9IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyQ29uZmlnOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlQ2FjaGU6IHRoaXMuaW1hZ2VDYWNoZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaXNFeHBvcnRpbmc6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJHcmlkOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goSW50ZXJhY3RpdmVDYW52YXMsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lclJlZjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmludGVyYWN0aXZlQ2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IGNhbnZhc0VsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZUVsZW1lbnRzOiB2aXNpYmxlRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzOiBzZWxlY3RlZEVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmVyc2lvbk5vbmNlOiB2ZXJzaW9uTm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25Ob25jZTogKF9jID0gdGhpcy5zdGF0ZS5zZWxlY3Rpb25FbGVtZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MudmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGU6IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJJbnRlcmFjdGl2ZVNjZW5lQ2FsbGJhY2s6IHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlQ2FudmFzUmVmOiB0aGlzLmhhbmRsZUludGVyYWN0aXZlQ2FudmFzUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Db250ZXh0TWVudTogdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlck1vdmU6IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJVcDogdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJDYW5jZWw6IHRoaXMucmVtb3ZlUG9pbnRlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uVG91Y2hNb3ZlOiB0aGlzLmhhbmRsZVRvdWNoTW92ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlckRvd246IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24sXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkRvdWJsZUNsaWNrOiB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHRoaXMucmVuZGVyRnJhbWVOYW1lcygpXVxuICAgICAgICAgICAgICAgICAgICB9KSksIHRoaXMucmVuZGVyRW1iZWRkYWJsZXMoKV1cbiAgICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgIH0pKVxuICAgICAgICB9KSlcbiAgICAgIH0pKVxuICAgIH0pKTtcbiAgfVxuXG4gIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgIHZhciBfYSwgX2I7XG5cbiAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlLmNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IEVOVi5URVNUIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICAgICAgICBjb25zdCBzZXRTdGF0ZSA9IHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMod2luZG93LmgsIHtcbiAgICAgICAgICBzdGF0ZToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZ2V0OiAoKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2V0U3RhdGU6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiAoLi4uYXJncykgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSguLi5hcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIGFwcDoge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHRoaXNcbiAgICAgICAgICB9LFxuICAgICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmhpc3RvcnlcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNjZW5lLmFkZENhbGxiYWNrKHRoaXMub25TY2VuZVVwZGF0ZWQpO1xuICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVycygpO1xuXG4gICAgICBpZiAodGhpcy5wcm9wcy5hdXRvRm9jdXMgJiYgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQgJiYgLy8gYm91bmRpbmcgcmVjdHMgZG9uJ3Qgd29yayBpbiB0ZXN0cyBzbyB1cGRhdGluZ1xuICAgICAgLy8gdGhlIHN0YXRlIG9uIGluaXQgd291bGQgcmVzdWx0IGluIG1ha2luZyB0aGUgdGVzdCBlbnZpcm8gcnVuXG4gICAgICAvLyBpbiBtb2JpbGUgYnJlYWtwb2ludCAoMCB3aWR0aC9oZWlnaHQpLCBtYWtpbmcgZXZlcnl0aGluZyBmYWlsXG4gICAgICAhaXNUZXN0RW52KCkpIHtcbiAgICAgICAgdGhpcy5yZWZyZXNoRGV2aWNlU3RhdGUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAoXCJSZXNpemVPYnNlcnZlclwiIGluIHdpbmRvdyAmJiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkpIHtcbiAgICAgICAgdGhpcy5yZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcigoKSA9PiB7XG4gICAgICAgICAgLy8gcmVjb21wdXRlIGRldmljZSBkaW1lbnNpb25zIHN0YXRlXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgICAgICAgdGhpcy5yZWZyZXNoRGV2aWNlU3RhdGUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpOyAvLyByZWZyZXNoIG9mZnNldHNcbiAgICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAgICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgKF9iID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLm9ic2VydmUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgfSBlbHNlIGlmICh3aW5kb3cubWF0Y2hNZWRpYSkge1xuICAgICAgICBjb25zdCBtZFNjcmVlblF1ZXJ5ID0gd2luZG93Lm1hdGNoTWVkaWEoYChtYXgtd2lkdGg6ICR7TVFfTUFYX1dJRFRIX1BPUlRSQUlUfXB4KSwgKG1heC1oZWlnaHQ6ICR7TVFfTUFYX0hFSUdIVF9MQU5EU0NBUEV9cHgpIGFuZCAobWF4LXdpZHRoOiAke01RX01BWF9XSURUSF9MQU5EU0NBUEV9cHgpYCk7XG4gICAgICAgIGNvbnN0IHNtU2NyZWVuUXVlcnkgPSB3aW5kb3cubWF0Y2hNZWRpYShgKG1heC13aWR0aDogJHtNUV9TTV9NQVhfV0lEVEh9cHgpYCk7XG4gICAgICAgIGNvbnN0IGNhbkRldmljZUZpdFNpZGViYXJNZWRpYVF1ZXJ5ID0gd2luZG93Lm1hdGNoTWVkaWEoYChtaW4td2lkdGg6ICR7Ly8gTk9URSB0aGlzIHdvbid0IHVwZGF0ZSBpZiBhIGRpZmZlcmVudCBicmVha3BvaW50IGlzIHN1cHBsaWVkXG4gICAgICAgIC8vIGFmdGVyIG1vdW50XG4gICAgICAgIHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50ICE9IG51bGwgPyB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCA6IE1RX1JJR0hUX1NJREVCQVJfTUlOX1dJRFRIfXB4KWApO1xuXG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgdGhpcy5kZXZpY2UgPSB1cGRhdGVPYmplY3QodGhpcy5kZXZpY2UsIHtcbiAgICAgICAgICAgIGlzU21TY3JlZW46IHNtU2NyZWVuUXVlcnkubWF0Y2hlcyxcbiAgICAgICAgICAgIGlzTW9iaWxlOiBtZFNjcmVlblF1ZXJ5Lm1hdGNoZXMsXG4gICAgICAgICAgICBjYW5EZXZpY2VGaXRTaWRlYmFyOiBjYW5EZXZpY2VGaXRTaWRlYmFyTWVkaWFRdWVyeS5tYXRjaGVzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbWRTY3JlZW5RdWVyeS5hZGRMaXN0ZW5lcihoYW5kbGVyKTtcblxuICAgICAgICB0aGlzLmRldGFjaElzTW9iaWxlTXFIYW5kbGVyID0gKCkgPT4gbWRTY3JlZW5RdWVyeS5yZW1vdmVMaXN0ZW5lcihoYW5kbGVyKTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VhcmNoUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoLnNsaWNlKDEpKTtcblxuICAgICAgaWYgKHNlYXJjaFBhcmFtcy5oYXMoXCJ3ZWItc2hhcmUtdGFyZ2V0XCIpKSB7XG4gICAgICAgIC8vIE9idGFpbiBhIGZpbGUgdGhhdCB3YXMgc2hhcmVkIHZpYSB0aGUgV2ViIFNoYXJlIFRhcmdldCBBUEkuXG4gICAgICAgIHRoaXMucmVzdG9yZUZpbGVGcm9tU2hhcmUoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCh0aGlzLmluaXRpYWxpemVTY2VuZSk7XG4gICAgICB9IC8vIG5vdGUgdGhhdCB0aGlzIGNoZWNrIHNlZW1zIHRvIGFsd2F5cyBwYXNzIGluIGxvY2FsaG9zdFxuXG5cbiAgICAgIGlmIChpc0JyYXZlKCkgJiYgIWlzTWVhc3VyZVRleHRTdXBwb3J0ZWQoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IF9qc3goQnJhdmVNZWFzdXJlVGV4dEVycm9yLCB7fSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICB2YXIgX2E7XG5cbiAgICB0aGlzLnJlbmRlcmVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLnNjZW5lID0gbmV3IFNjZW5lKCk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcbiAgICB0aGlzLmZpbGVzID0ge307XG4gICAgdGhpcy5pbWFnZUNhY2hlLmNsZWFyKCk7XG4gICAgKF9hID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmRpc2Nvbm5lY3QoKTtcbiAgICB0aGlzLnVubW91bnRlZCA9IHRydWU7XG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHRoaXMuc2NlbmUuZGVzdHJveSgpO1xuICAgIHRoaXMubGlicmFyeS5kZXN0cm95KCk7XG4gICAgU2hhcGVDYWNoZS5kZXN0cm95KCk7XG4gICAgY2xlYXJUaW1lb3V0KHRvdWNoVGltZW91dCk7XG4gICAgaXNTb21lRWxlbWVudFNlbGVjdGVkLmNsZWFyQ2FjaGUoKTtcbiAgICBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzLmNsZWFyQ2FjaGUoKTtcbiAgICB0b3VjaFRpbWVvdXQgPSAwO1xuICB9XG5cbiAgcmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZTtcblxuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGhpcy5yZW1vdmVQb2ludGVyKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkNPUFksIHRoaXMub25Db3B5KTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5DVVQsIHRoaXMub25DdXQpO1xuICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5XSEVFTCwgdGhpcy5vbldoZWVsKTtcbiAgICAoX2IgPSB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5TQ1JPTEwsIHRoaXMub25TY3JvbGwpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgdGhpcy5vbktleURvd24sIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1PVVNFX01PVkUsIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfYyA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9kID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX1NUQVJULCB0aGlzLm9uR2VzdHVyZVN0YXJ0LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0NIQU5HRSwgdGhpcy5vbkdlc3R1cmVDaGFuZ2UsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfRU5ELCB0aGlzLm9uR2VzdHVyZUVuZCwgZmFsc2UpO1xuICAgIChfZSA9IHRoaXMuZGV0YWNoSXNNb2JpbGVNcUhhbmRsZXIpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5jYWxsKHRoaXMpO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gIH1cblxuICBhZGRFdmVudExpc3RlbmVycygpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lO1xuXG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0aGlzLnJlbW92ZVBvaW50ZXIpOyAvLyAjMzU1M1xuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5DT1BZLCB0aGlzLm9uQ29weSk7XG4gICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLm9uV2hlZWwsIHtcbiAgICAgIHBhc3NpdmU6IGZhbHNlXG4gICAgfSk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5oYW5kbGVLZXlib2FyZEdsb2JhbGx5KSB7XG4gICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHRoaXMub25LZXlEb3duLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwLCB7XG4gICAgICBwYXNzaXZlOiB0cnVlXG4gICAgfSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5NT1VTRV9NT1ZFLCB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbik7IC8vIHJlcmVuZGVyIHRleHQgZWxlbWVudHMgb24gZm9udCBsb2FkIHRvIGZpeCAjNjM3ICYmICMxNTUzXG5cbiAgICAoX2MgPSAoX2IgPSBkb2N1bWVudC5mb250cykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmFkZEV2ZW50TGlzdGVuZXIpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5jYWxsKF9iLCBcImxvYWRpbmdkb25lXCIsIGV2ZW50ID0+IHtcbiAgICAgIGNvbnN0IGxvYWRlZEZvbnRGYWNlcyA9IGV2ZW50LmZvbnRmYWNlcztcbiAgICAgIHRoaXMuZm9udHMub25Gb250c0xvYWRlZChsb2FkZWRGb250RmFjZXMpO1xuICAgIH0pOyAvLyBTYWZhcmktb25seSBkZXNrdG9wIHBpbmNoIHpvb21cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9TVEFSVCwgdGhpcy5vbkdlc3R1cmVTdGFydCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9DSEFOR0UsIHRoaXMub25HZXN0dXJlQ2hhbmdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0VORCwgdGhpcy5vbkdlc3R1cmVFbmQsIGZhbHNlKTtcblxuICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHRoaXMucGFzdGVGcm9tQ2xpcGJvYXJkKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkNVVCwgdGhpcy5vbkN1dCk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5kZXRlY3RTY3JvbGwpIHtcbiAgICAgIHRoaXMubmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIgPSBnZXROZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lcih0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCk7XG4gICAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuU0NST0xMLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICB9XG5cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfZCA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9lID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gIH1cblxuICBjb21wb25lbnREaWRVcGRhdGUocHJldlByb3BzLCBwcmV2U3RhdGUpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZjtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMoKTtcblxuICAgIGlmICghdGhpcy5zdGF0ZS5zaG93V2VsY29tZVNjcmVlbiAmJiAhdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5sZW5ndGgpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzaG93V2VsY29tZVNjcmVlbjogdHJ1ZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50ICYmIHByZXZQcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT09IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50KSB7XG4gICAgICB0aGlzLnJlZnJlc2hEZXZpY2VTdGF0ZSh0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZTdGF0ZS5zY3JvbGxYICE9PSB0aGlzLnN0YXRlLnNjcm9sbFggfHwgcHJldlN0YXRlLnNjcm9sbFkgIT09IHRoaXMuc3RhdGUuc2Nyb2xsWSkge1xuICAgICAgKF9iID0gKF9hID0gdGhpcy5wcm9wcykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm9uU2Nyb2xsQ2hhbmdlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuY2FsbChfYSwgdGhpcy5zdGF0ZS5zY3JvbGxYLCB0aGlzLnN0YXRlLnNjcm9sbFkpO1xuICAgIH1cblxuICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcykubGVuZ3RoICYmIGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICB9KVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImVyYXNlclwiICYmIHByZXZTdGF0ZS50aGVtZSAhPT0gdGhpcy5zdGF0ZS50aGVtZSkge1xuICAgICAgc2V0RXJhc2VyQ3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUudGhlbWUpO1xuICAgIH0gLy8gSGlkZSBoeXBlcmxpbmsgcG9wdXAgaWYgc2hvd24gd2hlbiBlbGVtZW50IHR5cGUgaXMgbm90IHNlbGVjdGlvblxuXG5cbiAgICBpZiAocHJldlN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZmFsc2VcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMubGFuZ0NvZGUgIT09IHRoaXMucHJvcHMubGFuZ0NvZGUpIHtcbiAgICAgIHRoaXMudXBkYXRlTGFuZ3VhZ2UoKTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLnZpZXdNb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB2aWV3TW9kZUVuYWJsZWQ6ICEhdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWRcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2U3RhdGUudmlld01vZGVFbmFibGVkICE9PSB0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVycygpO1xuICAgICAgdGhpcy5kZXNlbGVjdEVsZW1lbnRzKCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy56ZW5Nb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHplbk1vZGVFbmFibGVkOiAhIXRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWRcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMudGhlbWUgIT09IHRoaXMucHJvcHMudGhlbWUgJiYgdGhpcy5wcm9wcy50aGVtZSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHRoZW1lOiB0aGlzLnByb3BzLnRoZW1lXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLmdyaWRNb2RlRW5hYmxlZCAhPT0gdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBncmlkU2l6ZTogdGhpcy5wcm9wcy5ncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5wcm9wcy5uYW1lICYmIHByZXZQcm9wcy5uYW1lICE9PSB0aGlzLnByb3BzLm5hbWUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBuYW1lOiB0aGlzLnByb3BzLm5hbWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIChfYyA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuY2xhc3NMaXN0LnRvZ2dsZShcInRoZW1lLS1kYXJrXCIsIHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiKTtcblxuICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZF0pIHtcbiAgICAgIC8vIGRlZmVyIHNvIHRoYXQgdGhlIGNvbW1pdFRvSGlzdG9yeSBmbGFnIGlzbid0IHJlc2V0IHZpYSBjdXJyZW50IHVwZGF0ZVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIC8vIGV4ZWN1dGUgb25seSBpZiB0aGUgY29uZGl0aW9uIHN0aWxsIGhvbGRzIHdoZW4gdGhlIGRlZmVycmVkIGNhbGxiYWNrXG4gICAgICAgIC8vIGV4ZWN1dGVzIChpdCBjYW4gYmUgc2NoZWR1bGVkIG11bHRpcGxlIHRpbWVzIGRlcGVuZGluZyBvbiBob3dcbiAgICAgICAgLy8gbWFueSB0aW1lcyB0aGUgY29tcG9uZW50IHJlbmRlcnMpXG4gICAgICAgIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgfSk7XG4gICAgfSAvLyBmYWlsc2FmZSBpbiBjYXNlIHRoZSBzdGF0ZSBpcyBiZWluZyB1cGRhdGVkIGluIGluY29ycmVjdCBvcmRlciByZXN1bHRpbmdcbiAgICAvLyBpbiB0aGUgZWRpdGluZ0VsZW1lbnQgYmVpbmcgbm93IGEgZGVsZXRlZCBlbGVtZW50XG5cblxuICAgIGlmICgoX2QgPSB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuaXNEZWxldGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuZWxlbWVudElkXSkge1xuICAgICAgLy8gVG8gbWFrZSBzdXJlIGBzZWxlY3RlZExpbmVhckVsZW1lbnRgIGlzIGluIHN5bmMgd2l0aCBgc2VsZWN0ZWRFbGVtZW50SWRzYCwgaG93ZXZlciB0aGlzIHNob3VsZG4ndCBiZSBuZWVkZWQgb25jZVxuICAgICAgLy8gd2UgaGF2ZSBhIHNpbmdsZSBBUEkgdG8gdXBkYXRlIGBzZWxlY3RlZEVsZW1lbnRJZHNgXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBjb25zdCB7XG4gICAgICBtdWx0aUVsZW1lbnRcbiAgICB9ID0gcHJldlN0YXRlO1xuXG4gICAgaWYgKHByZXZTdGF0ZS5hY3RpdmVUb29sICE9PSB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wgJiYgbXVsdGlFbGVtZW50ICE9IG51bGwgJiYgaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSAmJiBpc0JpbmRpbmdFbGVtZW50KG11bHRpRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICBtYXliZUJpbmRMaW5lYXJFbGVtZW50KG11bHRpRWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZSwgdHVwbGVUb0Nvb3JzKExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0UG9pbnRBdEluZGV4R2xvYmFsQ29vcmRpbmF0ZXMobXVsdGlFbGVtZW50LCAtMSkpKTtcbiAgICB9XG5cbiAgICB0aGlzLmhpc3RvcnkucmVjb3JkKHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkpOyAvLyBEbyBub3Qgbm90aWZ5IGNvbnN1bWVycyBpZiB3ZSdyZSBzdGlsbCBsb2FkaW5nIHRoZSBzY2VuZS4gQW1vbmcgb3RoZXJcbiAgICAvLyBwb3RlbnRpYWwgaXNzdWVzLCB0aGlzIGZpeGVzIGEgY2FzZSB3aGVyZSB0aGUgdGFiIGlzbid0IGZvY3VzZWQgZHVyaW5nXG4gICAgLy8gaW5pdCwgd2hpY2ggd291bGQgdHJpZ2dlciBvbkNoYW5nZSB3aXRoIGVtcHR5IGVsZW1lbnRzLCB3aGljaCB3b3VsZCB0aGVuXG4gICAgLy8gb3ZlcnJpZGUgd2hhdGV2ZXIgaXMgaW4gbG9jYWxTdG9yYWdlIGN1cnJlbnRseS5cblxuICAgIGlmICghdGhpcy5zdGF0ZS5pc0xvYWRpbmcpIHtcbiAgICAgIChfZiA9IChfZSA9IHRoaXMucHJvcHMpLm9uQ2hhbmdlKSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuY2FsbChfZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcyk7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIHJlc2V0VGFwVHdpY2UoKSB7XG4gICAgZGlkVGFwVHdpY2UgPSBmYWxzZTtcbiAgfVxuXG4gIGFkZFRleHRGcm9tUGFzdGUodGV4dCwgaXNQbGFpblBhc3RlID0gZmFsc2UpIHtcbiAgICBjb25zdCB7XG4gICAgICB4LFxuICAgICAgeVxuICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgY2xpZW50WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgY2xpZW50WTogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55XG4gICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgY29uc3QgdGV4dEVsZW1lbnRQcm9wcyA9IHtcbiAgICAgIHgsXG4gICAgICB5LFxuICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICB0ZXh0LFxuICAgICAgZm9udFNpemU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250U2l6ZSxcbiAgICAgIGZvbnRGYW1pbHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250RmFtaWx5LFxuICAgICAgdGV4dEFsaWduOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtVGV4dEFsaWduLFxuICAgICAgdmVydGljYWxBbGlnbjogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgIGxvY2tlZDogZmFsc2VcbiAgICB9O1xuICAgIGNvbnN0IExJTkVfR0FQID0gMTA7XG4gICAgbGV0IGN1cnJlbnRZID0geTtcbiAgICBjb25zdCBsaW5lcyA9IGlzUGxhaW5QYXN0ZSA/IFt0ZXh0XSA6IHRleHQuc3BsaXQoXCJcXG5cIik7XG4gICAgY29uc3QgdGV4dEVsZW1lbnRzID0gbGluZXMucmVkdWNlKChhY2MsIGxpbmUsIGlkeCkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCB0ZXh0ID0gbGluZS50cmltKCk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gZ2V0RGVmYXVsdExpbmVIZWlnaHQodGV4dEVsZW1lbnRQcm9wcy5mb250RmFtaWx5KTtcblxuICAgICAgaWYgKHRleHQubGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHk6IGN1cnJlbnRZXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBlbGVtZW50ID0gbmV3VGV4dEVsZW1lbnQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0ZXh0RWxlbWVudFByb3BzKSwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeTogY3VycmVudFksXG4gICAgICAgICAgdGV4dCxcbiAgICAgICAgICBsaW5lSGVpZ2h0LFxuICAgICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgICB9KSk7XG4gICAgICAgIGFjYy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICBjdXJyZW50WSArPSBlbGVtZW50LmhlaWdodCArIExJTkVfR0FQO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcHJldkxpbmUgPSAoX2EgPSBsaW5lc1tpZHggLSAxXSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRyaW0oKTsgLy8gYWRkIHBhcmFncmFwaCBvbmx5IGlmIHByZXZpb3VzIGxpbmUgd2FzIG5vdCBlbXB0eSwgSU9XIGRvbid0IGFkZFxuICAgICAgICAvLyBtb3JlIHRoYW4gb25lIGVtcHR5IGxpbmVcblxuICAgICAgICBpZiAocHJldkxpbmUpIHtcbiAgICAgICAgICBjdXJyZW50WSArPSBnZXRMaW5lSGVpZ2h0SW5QeCh0ZXh0RWxlbWVudFByb3BzLmZvbnRTaXplLCBsaW5lSGVpZ2h0KSArIExJTkVfR0FQO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwgW10pO1xuXG4gICAgaWYgKHRleHRFbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBmcmFtZUlkID0gdGV4dEVsZW1lbnRzWzBdLmZyYW1lSWQ7XG5cbiAgICBpZiAoZnJhbWVJZCkge1xuICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50c0F0SW5kZXgodGV4dEVsZW1lbnRzLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRJbmRleChmcmFtZUlkKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCAuLi50ZXh0RWxlbWVudHNdKTtcbiAgICB9XG5cbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmZyb21FbnRyaWVzKHRleHRFbGVtZW50cy5tYXAoZWwgPT4gW2VsLmlkLCB0cnVlXSkpLCB0aGlzLnN0YXRlKVxuICAgIH0pO1xuXG4gICAgaWYgKCFpc1BsYWluUGFzdGUgJiYgdGV4dEVsZW1lbnRzLmxlbmd0aCA+IDEgJiYgUExBSU5fUEFTVEVfVE9BU1RfU0hPV04gPT09IGZhbHNlICYmICF0aGlzLmRldmljZS5pc01vYmlsZSkge1xuICAgICAgdGhpcy5zZXRUb2FzdCh7XG4gICAgICAgIG1lc3NhZ2U6IHQoXCJ0b2FzdC5wYXN0ZUFzU2luZ2xlRWxlbWVudFwiLCB7XG4gICAgICAgICAgc2hvcnRjdXQ6IGdldFNob3J0Y3V0S2V5KFwiQ3RybE9yQ21kK1NoaWZ0K1ZcIilcbiAgICAgICAgfSksXG4gICAgICAgIGR1cmF0aW9uOiA1MDAwXG4gICAgICB9KTtcbiAgICAgIFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gIH1cblxuICBoYW5kbGVUZXh0V3lzaXd5ZyhlbGVtZW50LCB7XG4gICAgaXNFeGlzdGluZ0VsZW1lbnQgPSBmYWxzZVxuICB9KSB7XG4gICAgY29uc3QgdXBkYXRlRWxlbWVudCA9ICh0ZXh0LCBvcmlnaW5hbFRleHQsIGlzRGVsZXRlZCkgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoWy4uLnRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKF9lbGVtZW50ID0+IHtcbiAgICAgICAgaWYgKF9lbGVtZW50LmlkID09PSBlbGVtZW50LmlkICYmIGlzVGV4dEVsZW1lbnQoX2VsZW1lbnQpKSB7XG4gICAgICAgICAgcmV0dXJuIHVwZGF0ZVRleHRFbGVtZW50KF9lbGVtZW50LCB7XG4gICAgICAgICAgICB0ZXh0LFxuICAgICAgICAgICAgaXNEZWxldGVkLFxuICAgICAgICAgICAgb3JpZ2luYWxUZXh0XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2VsZW1lbnQ7XG4gICAgICB9KV0pO1xuICAgIH07XG5cbiAgICB0ZXh0V3lzaXd5Zyh7XG4gICAgICBpZDogZWxlbWVudC5pZCxcbiAgICAgIGNhbnZhczogdGhpcy5jYW52YXMsXG4gICAgICBnZXRWaWV3cG9ydENvb3JkczogKHgsIHkpID0+IHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHZpZXdwb3J0WCxcbiAgICAgICAgICB5OiB2aWV3cG9ydFlcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiB4LFxuICAgICAgICAgIHNjZW5lWTogeVxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgcmV0dXJuIFt2aWV3cG9ydFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIHZpZXdwb3J0WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wXTtcbiAgICAgIH0sXG4gICAgICBvbkNoYW5nZTogd2l0aEJhdGNoZWRVcGRhdGVzKHRleHQgPT4ge1xuICAgICAgICB1cGRhdGVFbGVtZW50KHRleHQsIHRleHQsIGZhbHNlKTtcblxuICAgICAgICBpZiAoaXNOb25EZWxldGVkRWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICAgIHVwZGF0ZUJvdW5kRWxlbWVudHMoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0pLFxuICAgICAgb25TdWJtaXQ6IHdpdGhCYXRjaGVkVXBkYXRlcygoe1xuICAgICAgICB0ZXh0LFxuICAgICAgICB2aWFLZXlib2FyZCxcbiAgICAgICAgb3JpZ2luYWxUZXh0XG4gICAgICB9KSA9PiB7XG4gICAgICAgIGNvbnN0IGlzRGVsZXRlZCA9ICF0ZXh0LnRyaW0oKTtcbiAgICAgICAgdXBkYXRlRWxlbWVudCh0ZXh0LCBvcmlnaW5hbFRleHQsIGlzRGVsZXRlZCk7IC8vIHNlbGVjdCB0aGUgY3JlYXRlZCB0ZXh0IGVsZW1lbnQgb25seSBpZiBzdWJtaXR0aW5nIHZpYSBrZXlib2FyZFxuICAgICAgICAvLyAod2hlbiBzdWJtaXR0aW5nIHZpYSBjbGljayBpdCBzaG91bGQgYWN0IGFzIHNpZ25hbCB0byBkZXNlbGVjdClcblxuICAgICAgICBpZiAoIWlzRGVsZXRlZCAmJiB2aWFLZXlib2FyZCkge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRJZFRvU2VsZWN0ID0gZWxlbWVudC5jb250YWluZXJJZCA/IGVsZW1lbnQuY29udGFpbmVySWQgOiBlbGVtZW50LmlkO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgW2VsZW1lbnRJZFRvU2VsZWN0XTogdHJ1ZVxuICAgICAgICAgICAgfSksIHByZXZTdGF0ZSlcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNEZWxldGVkKSB7XG4gICAgICAgICAgZml4QmluZGluZ3NBZnRlckRlbGV0aW9uKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIFtlbGVtZW50XSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWlzRGVsZXRlZCB8fCBpc0V4aXN0aW5nRWxlbWVudCkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogbnVsbFxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLmxvY2tlZCkge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfSksXG4gICAgICBlbGVtZW50LFxuICAgICAgZXhjYWxpZHJhd0NvbnRhaW5lcjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQsXG4gICAgICBhcHA6IHRoaXNcbiAgICB9KTsgLy8gZGVzZWxlY3QgYWxsIG90aGVyIGVsZW1lbnRzIHdoZW4gaW5zZXJ0aW5nIHRleHRcblxuICAgIHRoaXMuZGVzZWxlY3RFbGVtZW50cygpOyAvLyBkbyBhbiBpbml0aWFsIHVwZGF0ZSB0byByZS1pbml0aWFsaXplIGVsZW1lbnQgcG9zaXRpb24gc2luY2Ugd2Ugd2VyZVxuICAgIC8vIG1vZGlmeWluZyBlbGVtZW50J3MgeC95IGZvciBzYWtlIG9mIGVkaXRvciAoY2FzZTogc3luY2luZyB0byByZW1vdGUpXG5cbiAgICB1cGRhdGVFbGVtZW50KGVsZW1lbnQudGV4dCwgZWxlbWVudC5vcmlnaW5hbFRleHQsIGZhbHNlKTtcbiAgfVxuXG4gIGRlc2VsZWN0RWxlbWVudHMoKSB7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgfSk7XG4gIH1cblxuICBnZXRUZXh0RWxlbWVudEF0UG9zaXRpb24oeCwgeSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHgsIHksIHtcbiAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlXG4gICAgfSk7XG5cbiAgICBpZiAoZWxlbWVudCAmJiBpc1RleHRFbGVtZW50KGVsZW1lbnQpICYmICFlbGVtZW50LmlzRGVsZXRlZCkge1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBnZXRFbGVtZW50QXRQb3NpdGlvbih4LCB5LCBvcHRzKSB7XG4gICAgY29uc3QgYWxsSGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbih4LCB5LCBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQsIG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5pbmNsdWRlTG9ja2VkRWxlbWVudHMpO1xuXG4gICAgaWYgKGFsbEhpdEVsZW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIGlmIChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucHJlZmVyU2VsZWN0ZWQpIHtcbiAgICAgICAgZm9yIChsZXQgaW5kZXggPSBhbGxIaXRFbGVtZW50cy5sZW5ndGggLSAxOyBpbmRleCA+IC0xOyBpbmRleC0tKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2FsbEhpdEVsZW1lbnRzW2luZGV4XS5pZF0pIHtcbiAgICAgICAgICAgIHJldHVybiBhbGxIaXRFbGVtZW50c1tpbmRleF07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleCA9IGFsbEhpdEVsZW1lbnRzW2FsbEhpdEVsZW1lbnRzLmxlbmd0aCAtIDFdOyAvLyBJZiB3ZSdyZSBoaXR0aW5nIGVsZW1lbnQgd2l0aCBoaWdoZXN0IHotaW5kZXggb25seSBvbiBpdHMgYm91bmRpbmcgYm94XG4gICAgICAvLyB3aGlsZSBhbHNvIGhpdHRpbmcgb3RoZXIgZWxlbWVudCBmaWd1cmUsIHRoZSBsYXR0ZXIgc2hvdWxkIGJlIGNvbnNpZGVyZWQuXG5cbiAgICAgIHJldHVybiBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQoZWxlbWVudFdpdGhIaWdoZXN0WkluZGV4LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCB4LCB5KSA/IGFsbEhpdEVsZW1lbnRzW2FsbEhpdEVsZW1lbnRzLmxlbmd0aCAtIDJdIDogZWxlbWVudFdpdGhIaWdoZXN0WkluZGV4O1xuICAgIH1cblxuICAgIGlmIChhbGxIaXRFbGVtZW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHJldHVybiBhbGxIaXRFbGVtZW50c1swXTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGdldEVsZW1lbnRzQXRQb3NpdGlvbih4LCB5LCBpbmNsdWRlQm91bmRUZXh0RWxlbWVudCA9IGZhbHNlLCBpbmNsdWRlTG9ja2VkRWxlbWVudHMgPSBmYWxzZSkge1xuICAgIGNvbnN0IGVsZW1lbnRzID0gaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgJiYgaW5jbHVkZUxvY2tlZEVsZW1lbnRzID8gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSA6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkuZmlsdGVyKGVsZW1lbnQgPT4gKGluY2x1ZGVMb2NrZWRFbGVtZW50cyB8fCAhZWxlbWVudC5sb2NrZWQpICYmIChpbmNsdWRlQm91bmRUZXh0RWxlbWVudCB8fCAhKGlzVGV4dEVsZW1lbnQoZWxlbWVudCkgJiYgZWxlbWVudC5jb250YWluZXJJZCkpKTtcbiAgICByZXR1cm4gZ2V0RWxlbWVudHNBdFBvc2l0aW9uKGVsZW1lbnRzLCBlbGVtZW50ID0+IGhpdFRlc3QoZWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgeCwgeSkpLmZpbHRlcihlbGVtZW50ID0+IHtcbiAgICAgIC8vIGhpdHRpbmcgYSBmcmFtZSdzIGVsZW1lbnQgZnJvbSBvdXRzaWRlIHRoZSBmcmFtZSBpcyBub3QgY29uc2lkZXJlZCBhIGhpdFxuICAgICAgY29uc3QgY29udGFpbmluZ0ZyYW1lID0gZ2V0Q29udGFpbmluZ0ZyYW1lKGVsZW1lbnQpO1xuICAgICAgcmV0dXJuIGNvbnRhaW5pbmdGcmFtZSAmJiB0aGlzLnN0YXRlLmZyYW1lUmVuZGVyaW5nLmVuYWJsZWQgJiYgdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5jbGlwID8gaXNDdXJzb3JJbkZyYW1lKHtcbiAgICAgICAgeCxcbiAgICAgICAgeVxuICAgICAgfSwgY29udGFpbmluZ0ZyYW1lKSA6IHRydWU7XG4gICAgfSk7XG4gIH1cblxuICBoYW5kbGVIb3ZlclNlbGVjdGVkTGluZWFyRWxlbWVudChsaW5lYXJFbGVtZW50RWRpdG9yLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSB7XG4gICAgY29uc3QgZWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0RWxlbWVudChsaW5lYXJFbGVtZW50RWRpdG9yLmVsZW1lbnRJZCk7XG4gICAgY29uc3QgYm91bmRUZXh0RWxlbWVudCA9IGdldEJvdW5kVGV4dEVsZW1lbnQoZWxlbWVudCk7XG5cbiAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgIGxldCBob3ZlclBvaW50SW5kZXggPSAtMTtcbiAgICAgIGxldCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzID0gbnVsbDtcblxuICAgICAgaWYgKGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94KGVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIFtzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZXSkpIHtcbiAgICAgICAgaG92ZXJQb2ludEluZGV4ID0gTGluZWFyRWxlbWVudEVkaXRvci5nZXRQb2ludEluZGV4VW5kZXJDdXJzb3IoZWxlbWVudCwgdGhpcy5zdGF0ZS56b29tLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKTtcbiAgICAgICAgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3JkcyA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0U2VnbWVudE1pZHBvaW50SGl0Q29vcmRzKGxpbmVhckVsZW1lbnRFZGl0b3IsIHtcbiAgICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKGhvdmVyUG9pbnRJbmRleCA+PSAwIHx8IHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuUE9JTlRFUik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHNob3VsZFNob3dCb3VuZGluZ0JveChbZWxlbWVudF0sIHRoaXMuc3RhdGUpICYmIGlzSGl0dGluZ0VsZW1lbnRCb3VuZGluZ0JveFdpdGhvdXRIaXR0aW5nRWxlbWVudChlbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSkge1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG4gICAgICB9IGVsc2UgaWYgKGJvdW5kVGV4dEVsZW1lbnQgJiYgaGl0VGVzdChib3VuZFRleHRFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZKSkge1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5ob3ZlclBvaW50SW5kZXggIT09IGhvdmVyUG9pbnRJbmRleCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICBob3ZlclBvaW50SW5kZXhcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFMaW5lYXJFbGVtZW50RWRpdG9yLmFyZVBvaW50c0VxdWFsKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LnNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMsIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHNcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkFVVE8pO1xuICAgIH1cbiAgfVxuXG4gIG1heWJlQ2xlYW51cEFmdGVyTWlzc2luZ1BvaW50ZXJVcChldmVudCkge1xuICAgIGlmIChsYXN0UG9pbnRlclVwICE9PSBudWxsKSB7XG4gICAgICAvLyBVbmZvcnR1bmF0ZWx5LCBzb21ldGltZXMgd2UgZG9uJ3QgZ2V0IGEgcG9pbnRlcnVwIGFmdGVyIGEgcG9pbnRlcmRvd24sXG4gICAgICAvLyB0aGlzIGNhbiBoYXBwZW4gd2hlbiBhIGNvbnRleHR1YWwgbWVudSBvciBhbGVydCBpcyB0cmlnZ2VyZWQuIEluIG9yZGVyIHRvIGF2b2lkXG4gICAgICAvLyBiZWluZyBpbiBhIHdlaXJkIHN0YXRlLCB3ZSBjbGVhbiB1cCBvbiB0aGUgbmV4dCBwb2ludGVyZG93blxuICAgICAgbGFzdFBvaW50ZXJVcChldmVudCk7XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlR2VzdHVyZU9uUG9pbnRlckRvd24oZXZlbnQpIHtcbiAgICBnZXN0dXJlLnBvaW50ZXJzLnNldChldmVudC5wb2ludGVySWQsIHtcbiAgICAgIHg6IGV2ZW50LmNsaWVudFgsXG4gICAgICB5OiBldmVudC5jbGllbnRZXG4gICAgfSk7XG5cbiAgICBpZiAoZ2VzdHVyZS5wb2ludGVycy5zaXplID09PSAyKSB7XG4gICAgICBnZXN0dXJlLmxhc3RDZW50ZXIgPSBnZXRDZW50ZXIoZ2VzdHVyZS5wb2ludGVycyk7XG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlID0gZ2V0RGlzdGFuY2UoQXJyYXkuZnJvbShnZXN0dXJlLnBvaW50ZXJzLnZhbHVlcygpKSk7XG4gICAgfVxuICB9XG5cbiAgaW5pdGlhbFBvaW50ZXJEb3duU3RhdGUoZXZlbnQpIHtcbiAgICBjb25zdCBvcmlnaW4gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgY29uc3QgW21pblgsIG1pblksIG1heFgsIG1heFldID0gZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgIHJldHVybiB7XG4gICAgICBvcmlnaW4sXG4gICAgICB3aXRoQ21kT3JDdHJsOiBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSxcbiAgICAgIG9yaWdpbkluR3JpZDogdHVwbGVUb0Nvb3JzKGdldEdyaWRQb2ludChvcmlnaW4ueCwgb3JpZ2luLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpKSxcbiAgICAgIHNjcm9sbGJhcnM6IGlzT3ZlclNjcm9sbEJhcnMoY3VycmVudFNjcm9sbEJhcnMsIGV2ZW50LmNsaWVudFggLSB0aGlzLnN0YXRlLm9mZnNldExlZnQsIGV2ZW50LmNsaWVudFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcCksXG4gICAgICAvLyB3ZSBuZWVkIHRvIGR1cGxpY2F0ZSBiZWNhdXNlIHdlJ2xsIGJlIHVwZGF0aW5nIHRoaXMgc3RhdGVcbiAgICAgIGxhc3RDb29yZHM6IE9iamVjdC5hc3NpZ24oe30sIG9yaWdpbiksXG4gICAgICBvcmlnaW5hbEVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgIGFjYy5zZXQoZWxlbWVudC5pZCwgZGVlcENvcHlFbGVtZW50KGVsZW1lbnQpKTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIG5ldyBNYXAoKSksXG4gICAgICByZXNpemU6IHtcbiAgICAgICAgaGFuZGxlVHlwZTogZmFsc2UsXG4gICAgICAgIGlzUmVzaXppbmc6IGZhbHNlLFxuICAgICAgICBvZmZzZXQ6IHtcbiAgICAgICAgICB4OiAwLFxuICAgICAgICAgIHk6IDBcbiAgICAgICAgfSxcbiAgICAgICAgYXJyb3dEaXJlY3Rpb246IFwib3JpZ2luXCIsXG4gICAgICAgIGNlbnRlcjoge1xuICAgICAgICAgIHg6IChtYXhYICsgbWluWCkgLyAyLFxuICAgICAgICAgIHk6IChtYXhZICsgbWluWSkgLyAyXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBoaXQ6IHtcbiAgICAgICAgZWxlbWVudDogbnVsbCxcbiAgICAgICAgYWxsSGl0RWxlbWVudHM6IFtdLFxuICAgICAgICB3YXNBZGRlZFRvU2VsZWN0aW9uOiBmYWxzZSxcbiAgICAgICAgaGFzQmVlbkR1cGxpY2F0ZWQ6IGZhbHNlLFxuICAgICAgICBoYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50czogdGhpcy5pc0hpdHRpbmdDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cyhvcmlnaW4sIHNlbGVjdGVkRWxlbWVudHMpXG4gICAgICB9LFxuICAgICAgZHJhZzoge1xuICAgICAgICBoYXNPY2N1cnJlZDogZmFsc2UsXG4gICAgICAgIG9mZnNldDogbnVsbFxuICAgICAgfSxcbiAgICAgIGV2ZW50TGlzdGVuZXJzOiB7XG4gICAgICAgIG9uTW92ZTogbnVsbCxcbiAgICAgICAgb25VcDogbnVsbCxcbiAgICAgICAgb25LZXlVcDogbnVsbCxcbiAgICAgICAgb25LZXlEb3duOiBudWxsXG4gICAgICB9LFxuICAgICAgYm94U2VsZWN0aW9uOiB7XG4gICAgICAgIGhhc09jY3VycmVkOiBmYWxzZVxuICAgICAgfSxcbiAgICAgIGVsZW1lbnRJZHNUb0VyYXNlOiB7fVxuICAgIH07XG4gIH0gLy8gUmV0dXJucyB3aGV0aGVyIHRoZSBldmVudCBpcyBhIGRyYWdnaW5nIGEgc2Nyb2xsYmFyXG5cblxuICBoYW5kbGVEcmFnZ2luZ1Njcm9sbEJhcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkge1xuICAgIGlmICghKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJFaXRoZXIgJiYgIXRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlzRHJhZ2dpbmdTY3JvbGxCYXIgPSB0cnVlO1xuICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gZXZlbnQuY2xpZW50WDtcbiAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IGV2ZW50LmNsaWVudFk7XG4gICAgY29uc3Qgb25Qb2ludGVyTW92ZSA9IHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZChldmVudCA9PiB7XG4gICAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQ7XG5cbiAgICAgIGlmICghKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgfSk7XG4gICAgY29uc3Qgb25Qb2ludGVyVXAgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoKCkgPT4ge1xuICAgICAgaXNEcmFnZ2luZ1Njcm9sbEJhciA9IGZhbHNlO1xuICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICBsYXN0UG9pbnRlclVwID0gbnVsbDtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIlxuICAgICAgfSk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgb25Qb2ludGVyVXApO1xuICAgICAgb25Qb2ludGVyTW92ZS5mbHVzaCgpO1xuICAgIH0pO1xuICAgIGxhc3RQb2ludGVyVXAgPSBvblBvaW50ZXJVcDtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGlzQVNlbGVjdGVkRWxlbWVudChoaXRFbGVtZW50KSB7XG4gICAgcmV0dXJuIGhpdEVsZW1lbnQgIT0gbnVsbCAmJiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXTtcbiAgfVxuXG4gIGlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKHBvaW50LCBzZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoIDwgMikge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gLy8gSG93IG1hbnkgcGl4ZWxzIG9mZiB0aGUgc2hhcGUgYm91bmRhcnkgd2Ugc3RpbGwgY29uc2lkZXIgYSBoaXRcblxuXG4gICAgY29uc3QgdGhyZXNob2xkID0gMTAgLyB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgY29uc3QgW3gxLCB5MSwgeDIsIHkyXSA9IGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICByZXR1cm4gcG9pbnQueCA+IHgxIC0gdGhyZXNob2xkICYmIHBvaW50LnggPCB4MiArIHRocmVzaG9sZCAmJiBwb2ludC55ID4geTEgLSB0aHJlc2hvbGQgJiYgcG9pbnQueSA8IHkyICsgdGhyZXNob2xkO1xuICB9XG5cbiAgZ2V0Q3VycmVudEl0ZW1Sb3VuZG5lc3MoZWxlbWVudFR5cGUpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdW5kbmVzcyA9PT0gXCJyb3VuZFwiID8ge1xuICAgICAgdHlwZTogaXNVc2luZ0FkYXB0aXZlUmFkaXVzKGVsZW1lbnRUeXBlKSA/IFJPVU5ETkVTUy5BREFQVElWRV9SQURJVVMgOiBST1VORE5FU1MuUFJPUE9SVElPTkFMX1JBRElVU1xuICAgIH0gOiBudWxsO1xuICB9XG5cbiAgb25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIFByZXZlbnRzIGZvY3VzIGZyb20gZXNjYXBpbmcgZXhjYWxpZHJhdyB0YWJcbiAgICAgIGV2ZW50LmtleSA9PT0gS0VZUy5BTFQgJiYgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKHRoaXMubWF5YmVIYW5kbGVSZXNpemUocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudChwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgfSk7XG4gIH1cblxuICBvblBvaW50ZXJNb3ZlRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZChldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBXZSBuZWVkIHRvIGluaXRpYWxpemUgZHJhZ09mZnNldFhZIG9ubHkgYWZ0ZXIgd2UndmUgdXBkYXRlZFxuICAgICAgLy8gYHN0YXRlLnNlbGVjdGVkRWxlbWVudElkc2Agb24gcG9pbnRlckRvd24uIERvaW5nIGl0IGhlcmUgaW4gcG9pbnRlck1vdmVcbiAgICAgIC8vIGV2ZW50IGhhbmRsZXIgc2hvdWxkIGhvcGVmdWxseSBlbnN1cmUgd2UncmUgYWxyZWFkeSB3b3JraW5nIHdpdGhcbiAgICAgIC8vIHRoZSB1cGRhdGVkIHN0YXRlLlxuXG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0ID09PSBudWxsKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5vZmZzZXQgPSB0dXBsZVRvQ29vcnMoZ2V0RHJhZ09mZnNldFhZKHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQ7XG5cbiAgICAgIGlmICghKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICB0aGlzLmhhbmRsZUVyYXNlcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSwgcG9pbnRlckNvb3Jkcyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpOyAvLyBmb3IgYXJyb3dzL2xpbmVzLCBkb24ndCBzdGFydCBkcmFnZ2luZyB1bnRpbCBhIGdpdmVuIHRocmVzaG9sZFxuICAgICAgLy8gdG8gZW5zdXJlIHdlIGRvbid0IGNyZWF0ZSBhIDItcG9pbnQgYXJyb3cgYnkgbWlzdGFrZSB3aGVuXG4gICAgICAvLyB1c2VyIGNsaWNrcyBtb3VzZSBpbiBhIHdheSB0aGF0IGl0IG1vdmVzIGEgdGlueSBiaXQgKHRodXNcbiAgICAgIC8vIHRyaWdnZXJpbmcgcG9pbnRlcm1vdmUpXG5cbiAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJhcnJvd1wiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxpbmVcIikpIHtcbiAgICAgICAgaWYgKGRpc3RhbmNlMmQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpIDwgRFJBR0dJTkdfVEhSRVNIT0xEKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5pc1Jlc2l6aW5nKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gcG9pbnRlckNvb3Jkcy54O1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcblxuICAgICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudEVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQ7XG5cbiAgICAgICAgaWYgKExpbmVhckVsZW1lbnRFZGl0b3Iuc2hvdWxkQWRkTWlkcG9pbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHBvaW50ZXJDb29yZHMsIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgICAgY29uc3QgcmV0ID0gTGluZWFyRWxlbWVudEVkaXRvci5hZGRNaWRwb2ludCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgcG9pbnRlckNvb3JkcywgdGhpcy5zdGF0ZSwgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKTtcblxuICAgICAgICAgIGlmICghcmV0KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG5cblxuICAgICAgICAgIGZsdXNoU3luYygoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZTogcmV0LnBvaW50ZXJEb3duU3RhdGUsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IHJldC5zZWxlY3RlZFBvaW50c0luZGljZXNcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGU6IHJldC5wb2ludGVyRG93blN0YXRlLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRQb2ludHNJbmRpY2VzOiByZXQuc2VsZWN0ZWRQb2ludHNJbmRpY2VzXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2UgaWYgKGxpbmVhckVsZW1lbnRFZGl0b3IucG9pbnRlckRvd25TdGF0ZS5zZWdtZW50TWlkcG9pbnQudmFsdWUgIT09IG51bGwgJiYgIWxpbmVhckVsZW1lbnRFZGl0b3IucG9pbnRlckRvd25TdGF0ZS5zZWdtZW50TWlkcG9pbnQuYWRkZWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBkaWREcmFnID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludERyYWdnaW5nKGV2ZW50LCB0aGlzLnN0YXRlLCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgKGVsZW1lbnQsIHBvaW50c1NjZW5lQ29vcmRzKSA9PiB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhlbGVtZW50LCBwb2ludHNTY2VuZUNvb3Jkcyk7XG4gICAgICAgIH0sIGxpbmVhckVsZW1lbnRFZGl0b3IpO1xuXG4gICAgICAgIGlmIChkaWREcmFnKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBwb2ludGVyQ29vcmRzLnk7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgIGlzRHJhZ2dpbmc6IHRydWVcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICBpc0RyYWdnaW5nOiB0cnVlXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgaGFzSGl0QVNlbGVjdGVkRWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiB0aGlzLmlzQVNlbGVjdGVkRWxlbWVudChlbGVtZW50KSk7XG4gICAgICBjb25zdCBpc1NlbGVjdGluZ1BvaW50c0luTGluZUVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZXZlbnQuc2hpZnRLZXkgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgPT09ICgoX2EgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaWQpO1xuXG4gICAgICBpZiAoKGhhc0hpdEFTZWxlY3RlZEVsZW1lbnQgfHwgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpICYmICFpc1NlbGVjdGluZ1BvaW50c0luTGluZUVkaXRvcikge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmV2ZXJ5KGVsZW1lbnQgPT4gZWxlbWVudC5sb2NrZWQpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50c0hhc0FGcmFtZSA9IHNlbGVjdGVkRWxlbWVudHMuZmluZChlID0+IGlzRnJhbWVFbGVtZW50KGUpKTtcbiAgICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMocG9pbnRlckNvb3Jkcyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGZyYW1lVG9IaWdobGlnaHQ6IHRvcExheWVyRnJhbWUgJiYgIXNlbGVjdGVkRWxlbWVudHNIYXNBRnJhbWUgPyB0b3BMYXllckZyYW1lIDogbnVsbFxuICAgICAgICB9KTsgLy8gTWFya2luZyB0aGF0IGNsaWNrIHdhcyB1c2VkIGZvciBkcmFnZ2luZyB0byBjaGVja1xuICAgICAgICAvLyBpZiBlbGVtZW50cyBzaG91bGQgYmUgZGVzZWxlY3RlZCBvbiBwb2ludGVydXBcblxuICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkOiB0cnVlXG4gICAgICAgIH0pOyAvLyBwcmV2ZW50IGRyYWdnaW5nIGV2ZW4gaWYgd2UncmUgbm8gbG9uZ2VyIGhvbGRpbmcgY21kL2N0cmwgb3RoZXJ3aXNlXG4gICAgICAgIC8vIGl0IHdvdWxkIGhhdmUgd2VpcmQgcmVzdWx0cyAoc3R1ZmYganVtcGluZyBhbGwgb3ZlciB0aGUgc2NyZWVuKVxuICAgICAgICAvLyBDaGVja2luZyBmb3IgZWRpdGluZ0VsZW1lbnQgdG8gYXZvaWQganVtcCB3aGlsZSBlZGl0aW5nIG9uIG1vYmlsZSAjNjUwM1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDAgJiYgIXBvaW50ZXJEb3duU3RhdGUud2l0aENtZE9yQ3RybCAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAmJiAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpICE9PSBcImFjdGl2ZVwiKSB7XG4gICAgICAgICAgY29uc3QgW2RyYWdYLCBkcmFnWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54IC0gcG9pbnRlckRvd25TdGF0ZS5kcmFnLm9mZnNldC54LCBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0LnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICAgIGNvbnN0IFtkcmFnRGlzdGFuY2VYLCBkcmFnRGlzdGFuY2VZXSA9IFtNYXRoLmFicyhwb2ludGVyQ29vcmRzLnggLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54KSwgTWF0aC5hYnMocG9pbnRlckNvb3Jkcy55IC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSldOyAvLyBXZSBvbmx5IGRyYWcgaW4gb25lIGRpcmVjdGlvbiBpZiBzaGlmdCBpcyBwcmVzc2VkXG5cbiAgICAgICAgICBjb25zdCBsb2NrRGlyZWN0aW9uID0gZXZlbnQuc2hpZnRLZXk7IC8vIHdoZW4gd2UncmUgZWRpdGluZyB0aGUgbmFtZSBvZiBhIGZyYW1lLCB3ZSB3YW50IHRoZSB1c2VyIHRvIGJlXG4gICAgICAgICAgLy8gYWJsZSB0byBzZWxlY3QgYW5kIGludGVyYWN0IHdpdGggdGhlIHRleHQgaW5wdXRcblxuICAgICAgICAgICF0aGlzLnN0YXRlLmVkaXRpbmdGcmFtZSAmJiBkcmFnU2VsZWN0ZWRFbGVtZW50cyhwb2ludGVyRG93blN0YXRlLCBzZWxlY3RlZEVsZW1lbnRzLCBkcmFnWCwgZHJhZ1ksIGxvY2tEaXJlY3Rpb24sIGRyYWdEaXN0YW5jZVgsIGRyYWdEaXN0YW5jZVksIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUpO1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKTsgLy8gV2UgZHVwbGljYXRlIHRoZSBzZWxlY3RlZCBlbGVtZW50IGlmIGFsdCBpcyBwcmVzc2VkIG9uIHBvaW50ZXIgbW92ZVxuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQpIHtcbiAgICAgICAgICAgIC8vIE1vdmUgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBlbGVtZW50cyB0byB0aGUgdG9wIG9mIHRoZSB6IGluZGV4IHN0YWNrLCBhbmRcbiAgICAgICAgICAgIC8vIHB1dCB0aGUgZHVwbGljYXRlcyB3aGVyZSB0aGUgc2VsZWN0ZWQgZWxlbWVudHMgdXNlZCB0byBiZS5cbiAgICAgICAgICAgIC8vICh0aGUgb3JpZ2luIHBvaW50IHdoZXJlIHRoZSBkcmFnZ2luZyBzdGFydGVkKVxuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29uc3QgbmV4dEVsZW1lbnRzID0gW107XG4gICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvQXBwZW5kID0gW107XG4gICAgICAgICAgICBjb25zdCBncm91cElkTWFwID0gbmV3IE1hcCgpO1xuICAgICAgICAgICAgY29uc3Qgb2xkSWRUb0R1cGxpY2F0ZWRJZCA9IG5ldyBNYXAoKTtcbiAgICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuICAgICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50SWRzID0gbmV3IFNldCh0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzLFxuICAgICAgICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZSxcbiAgICAgICAgICAgICAgaW5jbHVkZUVsZW1lbnRzSW5GcmFtZXM6IHRydWVcbiAgICAgICAgICAgIH0pLm1hcChlbGVtZW50ID0+IGVsZW1lbnQuaWQpKTtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRJZHMuaGFzKGVsZW1lbnQuaWQpIHx8IC8vIGNhc2U6IHRoZSBzdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMgbWlnaHQgbm90IGhhdmUgYmVlblxuICAgICAgICAgICAgICAvLyB1cGRhdGVkIHlldCBieSB0aGUgdGltZSB0aGlzIG1vdXNlbW92ZSBldmVudCBpcyBmaXJlZFxuICAgICAgICAgICAgICBlbGVtZW50LmlkID09PSAoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmlkKSAmJiBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZHVwbGljYXRlZEVsZW1lbnQgPSBkdXBsaWNhdGVFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQsIGdyb3VwSWRNYXAsIGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IFtvcmlnaW5EcmFnWCwgb3JpZ2luRHJhZ1ldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnggLSBwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0LngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkgLSBwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0LnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHVwbGljYXRlZEVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgIHg6IGR1cGxpY2F0ZWRFbGVtZW50LnggKyAob3JpZ2luRHJhZ1ggLSBkcmFnWCksXG4gICAgICAgICAgICAgICAgICB5OiBkdXBsaWNhdGVkRWxlbWVudC55ICsgKG9yaWdpbkRyYWdZIC0gZHJhZ1kpXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzLnB1c2goZHVwbGljYXRlZEVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIGVsZW1lbnRzVG9BcHBlbmQucHVzaChlbGVtZW50KTtcbiAgICAgICAgICAgICAgICBvbGRJZFRvRHVwbGljYXRlZElkLnNldChlbGVtZW50LmlkLCBkdXBsaWNhdGVkRWxlbWVudC5pZCk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzLnB1c2goZWxlbWVudCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbmV4dFNjZW5lRWxlbWVudHMgPSBbLi4ubmV4dEVsZW1lbnRzLCAuLi5lbGVtZW50c1RvQXBwZW5kXTtcbiAgICAgICAgICAgIGJpbmRUZXh0VG9TaGFwZUFmdGVyRHVwbGljYXRpb24obmV4dEVsZW1lbnRzLCBlbGVtZW50c1RvQXBwZW5kLCBvbGRJZFRvRHVwbGljYXRlZElkKTtcbiAgICAgICAgICAgIGZpeEJpbmRpbmdzQWZ0ZXJEdXBsaWNhdGlvbihuZXh0U2NlbmVFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCwgXCJkdXBsaWNhdGVzU2VydmVBc09sZFwiKTtcbiAgICAgICAgICAgIGJpbmRFbGVtZW50c1RvRnJhbWVzQWZ0ZXJEdXBsaWNhdGlvbihuZXh0U2NlbmVFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCk7XG4gICAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0U2NlbmVFbGVtZW50cyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IC8vIEl0IGlzIHZlcnkgaW1wb3J0YW50IHRvIHJlYWQgdGhpcy5zdGF0ZSB3aXRoaW4gZWFjaCBtb3ZlIGV2ZW50LFxuICAgICAgLy8gb3RoZXJ3aXNlIHdlIHdvdWxkIHJlYWQgYSBzdGFsZSBvbmUhXG5cblxuICAgICAgY29uc3QgZHJhZ2dpbmdFbGVtZW50ID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQ7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgY29uc3QgZHggPSBwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgY29uc3QgZHkgPSBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcbiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9pbnRzLmxlbmd0aCA+IDAgJiYgcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXTtcbiAgICAgICAgY29uc3QgZGlzY2FyZFBvaW50ID0gbGFzdFBvaW50ICYmIGxhc3RQb2ludFswXSA9PT0gZHggJiYgbGFzdFBvaW50WzFdID09PSBkeTtcblxuICAgICAgICBpZiAoIWRpc2NhcmRQb2ludCkge1xuICAgICAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGRyYWdnaW5nRWxlbWVudC5zaW11bGF0ZVByZXNzdXJlID8gZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcyA6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucHJlc3N1cmVzLCBldmVudC5wcmVzc3VyZV07XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dLFxuICAgICAgICAgICAgcHJlc3N1cmVzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoaXNMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgbGV0IGR4ID0gZ3JpZFggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgbGV0IGR5ID0gZ3JpZFkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcblxuICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpICYmIHBvaW50cy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICAoe1xuICAgICAgICAgICAgd2lkdGg6IGR4LFxuICAgICAgICAgICAgaGVpZ2h0OiBkeVxuICAgICAgICAgIH0gPSBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUoZHJhZ2dpbmdFbGVtZW50LngsIGRyYWdnaW5nRWxlbWVudC55LCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBvaW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLCBbZHgsIGR5XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cy5zbGljZSgwLCAtMSksIFtkeCwgZHldXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgICAgICAvLyBXaGVuIGNyZWF0aW5nIGEgbGluZWFyIGVsZW1lbnQgYnkgZHJhZ2dpbmdcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdzRm9yTGluZWFyRWxlbWVudEF0Q29vcmRzKGRyYWdnaW5nRWxlbWVudCwgW3BvaW50ZXJDb29yZHNdLCB0aGlzLnN0YXRlLnN0YXJ0Qm91bmRFbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuICAgICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuYm94U2VsZWN0aW9uLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpOyAvLyBib3gtc2VsZWN0IGxpbmUgZWRpdG9yIHBvaW50c1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVCb3hTZWxlY3Rpb24oZXZlbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKSk7IC8vIHJlZ3VsYXIgYm94LXNlbGVjdFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxldCBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IHRydWU7XG5cbiAgICAgICAgICBpZiAoIWV2ZW50LnNoaWZ0S2V5ICYmIGlzU29tZUVsZW1lbnRTZWxlY3RlZChlbGVtZW50cywgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLndpdGhDbWRPckN0cmwgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgICAgW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uID0gZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24oZWxlbWVudHMsIGRyYWdnaW5nRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2hvdWxkUmV1c2VTZWxlY3Rpb24gJiYgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgIGFjY1tlbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgICAgIHJldHVybiBhY2M7XG4gICAgICAgICAgICB9LCB7fSkpO1xuXG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICAvLyBpZiB1c2luZyBjdHJsL2NtZCwgc2VsZWN0IHRoZSBoaXRFbGVtZW50IG9ubHkgaWYgd2VcbiAgICAgICAgICAgICAgLy8gaGF2ZW4ndCBib3gtc2VsZWN0ZWQgYW55dGhpbmcgZWxzZVxuICAgICAgICAgICAgICBpZiAoIWVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudC5pZF0gPSB0cnVlO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXZTdGF0ZSA9ICFzaG91bGRSZXVzZVNlbGVjdGlvbiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGxcbiAgICAgICAgICAgIH0pIDogcHJldlN0YXRlO1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dFNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgLy8gc2VsZWN0IGxpbmVhciBlbGVtZW50IG9ubHkgd2hlbiB3ZSBoYXZlbid0IGJveC1zZWxlY3RlZCBhbnl0aGluZyBlbHNlXG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24ubGVuZ3RoID09PSAxICYmIGlzTGluZWFyRWxlbWVudChlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSwgdGhpcy5zY2VuZSkgOiBudWxsLFxuICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCA9PT0gMSAmJiAoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0ubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdKSkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9IC8vIFJldHVybnMgd2hldGhlciB0aGUgcG9pbnRlciBtb3ZlIGhhcHBlbmVkIG92ZXIgZWl0aGVyIHNjcm9sbGJhclxuXG5cbiAgaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSkge1xuICAgIGlmIChwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVySG9yaXpvbnRhbCkge1xuICAgICAgY29uc3QgeCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICBjb25zdCBkeCA9IHggLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueDtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYIC0gZHggLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSB4O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJWZXJ0aWNhbCkge1xuICAgICAgY29uc3QgeSA9IGV2ZW50LmNsaWVudFk7XG4gICAgICBjb25zdCBkeSA9IHkgLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueTtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZIC0gZHkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSB5O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgb25Qb2ludGVyVXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGNoaWxkRXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2Y7XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSkge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZS5mbHVzaCgpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIGRyYWdnaW5nRWxlbWVudCxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50LFxuICAgICAgICBtdWx0aUVsZW1lbnQsXG4gICAgICAgIGFjdGl2ZVRvb2wsXG4gICAgICAgIGlzUmVzaXppbmcsXG4gICAgICAgIGlzUm90YXRpbmdcbiAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzUmVzaXppbmc6IGZhbHNlLFxuICAgICAgICBpc1JvdGF0aW5nOiBmYWxzZSxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50OiBudWxsLFxuICAgICAgICBzZWxlY3Rpb25FbGVtZW50OiBudWxsLFxuICAgICAgICBmcmFtZVRvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIixcbiAgICAgICAgLy8gdGV4dCBlbGVtZW50cyBhcmUgcmVzZXQgb24gZmluYWxpemUsIGFuZCByZXNldHRpbmcgb24gcG9pbnRlcnVwXG4gICAgICAgIC8vIG1heSBjYXVzZSBpc3N1ZXMgd2l0aCBkb3VibGUgdGFwc1xuICAgICAgICBlZGl0aW5nRWxlbWVudDogbXVsdGlFbGVtZW50IHx8IGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPyB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50IDogbnVsbFxuICAgICAgfSk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGNoaWxkRXZlbnQuY2xpZW50WCwgY2hpbGRFdmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IGZhbHNlXG4gICAgICB9KTsgLy8gSGFuZGxlIGVuZCBvZiBkcmFnZ2luZyBhIHBvaW50IG9mIGEgbGluZWFyIGVsZW1lbnQsIG1pZ2h0IGNsb3NlIGEgbG9vcFxuICAgICAgLy8gYW5kIHNldHMgYmluZGluZyBlbGVtZW50XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5ib3hTZWxlY3Rpb24uaGFzT2NjdXJyZWQgJiYgKChfYiA9IChfYSA9IHBvaW50ZXJEb3duU3RhdGUuaGl0KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/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");
2467
2467
 
2468
2468
  /***/ }),
2469
2469
 
@@ -4223,7 +4223,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
4223
4223
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4224
4224
 
4225
4225
  "use strict";
4226
- 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/${\"@excalidraw/excalidraw\"}@${\"0.16.0-f8b3692\"}/dist/`;\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9wdWJsaWNQYXRoLmpzLmpzIiwibWFwcGluZ3MiOiI7O0FBQXNDOztBQUV0QyxJQUFJLGFBQW9CLEtBQUssZ0RBQVE7QUFDckM7O0FBRUE7QUFDQSxFQUFFLHFCQUF1Qix3REFBd0Qsd0JBQXlCLENBQUMsR0FBRyxnQkFBNEIsQ0FBQztBQUMzSSIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3B1YmxpY1BhdGguanM/MGUzMSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBFTlYgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5cbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gRU5WLlRFU1QpIHtcbiAgLyogZXNsaW50LWRpc2FibGUgKi9cblxuICAvKiBnbG9iYWwgX193ZWJwYWNrX3B1YmxpY19wYXRoX186d3JpdGFibGUgKi9cbiAgX193ZWJwYWNrX3B1YmxpY19wYXRoX18gPSB3aW5kb3cuRVhDQUxJRFJBV19BU1NFVF9QQVRIIHx8IGBodHRwczovL3VucGtnLmNvbS8ke3Byb2Nlc3MuZW52LlZJVEVfUEtHX05BTUV9QCR7cHJvY2Vzcy5lbnYuVklURV9QS0dfVkVSU0lPTn0vZGlzdC9gO1xufSJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./publicPath.js\n");
4226
+ 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/${\"@excalidraw/excalidraw\"}@${\"0.16.1-4765f55\"}/dist/`;\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9wdWJsaWNQYXRoLmpzLmpzIiwibWFwcGluZ3MiOiI7O0FBQXNDOztBQUV0QyxJQUFJLGFBQW9CLEtBQUssZ0RBQVE7QUFDckM7O0FBRUE7QUFDQSxFQUFFLHFCQUF1Qix3REFBd0Qsd0JBQXlCLENBQUMsR0FBRyxnQkFBNEIsQ0FBQztBQUMzSSIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3B1YmxpY1BhdGguanM/MGUzMSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBFTlYgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5cbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gRU5WLlRFU1QpIHtcbiAgLyogZXNsaW50LWRpc2FibGUgKi9cblxuICAvKiBnbG9iYWwgX193ZWJwYWNrX3B1YmxpY19wYXRoX186d3JpdGFibGUgKi9cbiAgX193ZWJwYWNrX3B1YmxpY19wYXRoX18gPSB3aW5kb3cuRVhDQUxJRFJBV19BU1NFVF9QQVRIIHx8IGBodHRwczovL3VucGtnLmNvbS8ke3Byb2Nlc3MuZW52LlZJVEVfUEtHX05BTUV9QCR7cHJvY2Vzcy5lbnYuVklURV9QS0dfVkVSU0lPTn0vZGlzdC9gO1xufSJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./publicPath.js\n");
4227
4227
 
4228
4228
  /***/ }),
4229
4229
 
@@ -4256,7 +4256,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
4256
4256
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4257
4257
 
4258
4258
  "use strict";
4259
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nconst polyfill = () => {\n if (!Array.prototype.at) {\n // Taken from https://github.com/tc39/proposal-relative-indexing-method#polyfill so that it works in tests\n\n /* eslint-disable */\n Object.defineProperty(Array.prototype, \"at\", {\n value: function (n) {\n // ToInteger() abstract op\n n = Math.trunc(n) || 0; // Allow negative indexing from the end\n\n if (n < 0) {\n n += this.length;\n } // OOB access is guaranteed to return undefined\n\n\n if (n < 0 || n >= this.length) {\n return undefined;\n } // Otherwise, this is just normal property access\n\n\n return this[n];\n },\n writable: true,\n enumerable: false,\n configurable: true\n });\n }\n};\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (polyfill);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vcG9seWZpbGwudHMuanMiLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQzs7QUFFaEM7QUFDQTtBQUNBLFVBQVU7OztBQUdWO0FBQ0E7QUFDQSxVQUFVOzs7QUFHVjtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQSxpRUFBZSxRQUFRIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL3BvbHlmaWxsLnRzPzQ5ZGMiXSwic291cmNlc0NvbnRlbnQiOlsiY29uc3QgcG9seWZpbGwgPSAoKSA9PiB7XG4gIGlmICghQXJyYXkucHJvdG90eXBlLmF0KSB7XG4gICAgLy8gVGFrZW4gZnJvbSBodHRwczovL2dpdGh1Yi5jb20vdGMzOS9wcm9wb3NhbC1yZWxhdGl2ZS1pbmRleGluZy1tZXRob2QjcG9seWZpbGwgc28gdGhhdCBpdCB3b3JrcyBpbiB0ZXN0c1xuXG4gICAgLyogZXNsaW50LWRpc2FibGUgKi9cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoQXJyYXkucHJvdG90eXBlLCBcImF0XCIsIHtcbiAgICAgIHZhbHVlOiBmdW5jdGlvbiAobikge1xuICAgICAgICAvLyBUb0ludGVnZXIoKSBhYnN0cmFjdCBvcFxuICAgICAgICBuID0gTWF0aC50cnVuYyhuKSB8fCAwOyAvLyBBbGxvdyBuZWdhdGl2ZSBpbmRleGluZyBmcm9tIHRoZSBlbmRcblxuICAgICAgICBpZiAobiA8IDApIHtcbiAgICAgICAgICBuICs9IHRoaXMubGVuZ3RoO1xuICAgICAgICB9IC8vIE9PQiBhY2Nlc3MgaXMgZ3VhcmFudGVlZCB0byByZXR1cm4gdW5kZWZpbmVkXG5cblxuICAgICAgICBpZiAobiA8IDAgfHwgbiA+PSB0aGlzLmxlbmd0aCkge1xuICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH0gLy8gT3RoZXJ3aXNlLCB0aGlzIGlzIGp1c3Qgbm9ybWFsIHByb3BlcnR5IGFjY2Vzc1xuXG5cbiAgICAgICAgcmV0dXJuIHRoaXNbbl07XG4gICAgICB9LFxuICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICB9XG59O1xuXG5leHBvcnQgZGVmYXVsdCBwb2x5ZmlsbDsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../polyfill.ts\n");
4259
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nconst polyfill = () => {\n if (!Array.prototype.at) {\n // Taken from https://github.com/tc39/proposal-relative-indexing-method#polyfill so that it works in tests\n\n /* eslint-disable */\n Object.defineProperty(Array.prototype, \"at\", {\n value: function (n) {\n // ToInteger() abstract op\n n = Math.trunc(n) || 0; // Allow negative indexing from the end\n\n if (n < 0) {\n n += this.length;\n } // OOB access is guaranteed to return undefined\n\n\n if (n < 0 || n >= this.length) {\n return undefined;\n } // Otherwise, this is just normal property access\n\n\n return this[n];\n },\n writable: true,\n enumerable: false,\n configurable: true\n });\n }\n\n if (!Element.prototype.replaceChildren) {\n Element.prototype.replaceChildren = function (...nodes) {\n this.innerHTML = \"\";\n this.append(...nodes);\n };\n }\n};\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (polyfill);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vcG9seWZpbGwudHMuanMiLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQzs7QUFFaEM7QUFDQTtBQUNBLFVBQVU7OztBQUdWO0FBQ0E7QUFDQSxVQUFVOzs7QUFHVjtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsaUVBQWUsUUFBUSIsInNvdXJjZXMiOlsid2VicGFjazovLy8uLi8uLi9wb2x5ZmlsbC50cz80OWRjIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHBvbHlmaWxsID0gKCkgPT4ge1xuICBpZiAoIUFycmF5LnByb3RvdHlwZS5hdCkge1xuICAgIC8vIFRha2VuIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL3RjMzkvcHJvcG9zYWwtcmVsYXRpdmUtaW5kZXhpbmctbWV0aG9kI3BvbHlmaWxsIHNvIHRoYXQgaXQgd29ya3MgaW4gdGVzdHNcblxuICAgIC8qIGVzbGludC1kaXNhYmxlICovXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEFycmF5LnByb3RvdHlwZSwgXCJhdFwiLCB7XG4gICAgICB2YWx1ZTogZnVuY3Rpb24gKG4pIHtcbiAgICAgICAgLy8gVG9JbnRlZ2VyKCkgYWJzdHJhY3Qgb3BcbiAgICAgICAgbiA9IE1hdGgudHJ1bmMobikgfHwgMDsgLy8gQWxsb3cgbmVnYXRpdmUgaW5kZXhpbmcgZnJvbSB0aGUgZW5kXG5cbiAgICAgICAgaWYgKG4gPCAwKSB7XG4gICAgICAgICAgbiArPSB0aGlzLmxlbmd0aDtcbiAgICAgICAgfSAvLyBPT0IgYWNjZXNzIGlzIGd1YXJhbnRlZWQgdG8gcmV0dXJuIHVuZGVmaW5lZFxuXG5cbiAgICAgICAgaWYgKG4gPCAwIHx8IG4gPj0gdGhpcy5sZW5ndGgpIHtcbiAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9IC8vIE90aGVyd2lzZSwgdGhpcyBpcyBqdXN0IG5vcm1hbCBwcm9wZXJ0eSBhY2Nlc3NcblxuXG4gICAgICAgIHJldHVybiB0aGlzW25dO1xuICAgICAgfSxcbiAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgfVxuXG4gIGlmICghRWxlbWVudC5wcm90b3R5cGUucmVwbGFjZUNoaWxkcmVuKSB7XG4gICAgRWxlbWVudC5wcm90b3R5cGUucmVwbGFjZUNoaWxkcmVuID0gZnVuY3Rpb24gKC4uLm5vZGVzKSB7XG4gICAgICB0aGlzLmlubmVySFRNTCA9IFwiXCI7XG4gICAgICB0aGlzLmFwcGVuZCguLi5ub2Rlcyk7XG4gICAgfTtcbiAgfVxufTtcblxuZXhwb3J0IGRlZmF1bHQgcG9seWZpbGw7Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../polyfill.ts\n");
4260
4260
 
4261
4261
  /***/ }),
4262
4262
 
@@ -4377,7 +4377,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
4377
4377
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4378
4378
 
4379
4379
  "use strict";
4380
- 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 */ \"getExportSize\": () => (/* binding */ getExportSize)\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 _appState__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../appState */ \"../../appState.ts\");\n/* harmony import */ var _data_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../data/json */ \"../../data/json.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../element/image */ \"../../element/image.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 -->`;\nconst exportToCanvas = (elements, appState, files, {\n exportBackground,\n exportPadding = _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_EXPORT_PADDING,\n viewBackgroundColor\n}, createCanvas = (width, height) => {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width * appState.exportScale;\n canvas.height = height * appState.exportScale;\n return {\n canvas,\n scale: appState.exportScale\n };\n}) => __awaiter(void 0, void 0, void 0, function* () {\n const [minX, minY, width, height] = getCanvasSize(elements, exportPadding);\n const {\n canvas,\n scale = 1\n } = createCanvas(width, height);\n const defaultAppState = (0,_appState__WEBPACK_IMPORTED_MODULE_5__.getDefaultAppState)();\n const {\n imageCache\n } = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_7__.updateImageCache)({\n imageCache: new Map(),\n fileIds: (0,_element_image__WEBPACK_IMPORTED_MODULE_7__.getInitializedImageElements)(elements).map(element => element.fileId),\n files\n });\n const onlyExportingSingleFrame = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.isOnlyExportingSingleFrame)(elements);\n (0,_renderer_renderScene__WEBPACK_IMPORTED_MODULE_2__.renderStaticScene)({\n canvas,\n rc: roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_0__[\"default\"].canvas(canvas),\n elements,\n visibleElements: elements,\n scale,\n appState: Object.assign(Object.assign({}, appState), {\n viewBackgroundColor: exportBackground ? viewBackgroundColor : null,\n scrollX: -minX + (onlyExportingSingleFrame ? 0 : exportPadding),\n scrollY: -minY + (onlyExportingSingleFrame ? 0 : exportPadding),\n zoom: defaultAppState.zoom,\n shouldCacheIgnoreZoom: false,\n theme: appState.exportWithDarkMode ? \"dark\" : \"light\"\n }),\n renderConfig: {\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 _a, _b, _c;\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) ? (_a = opts === null || opts === void 0 ? void 0 : opts.serializeAsJSON) === null || _a === void 0 ? void 0 : _a.call(opts) : (0,_data_json__WEBPACK_IMPORTED_MODULE_6__.serializeAsJSON)(elements, appState, files || {}, \"local\")\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n const [minX, minY, width, height] = getCanvasSize(elements, exportPadding); // 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/${\"@excalidraw/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\":\"@excalidraw/excalidraw\",\"VITE_PKG_VERSION\":\"0.16.0-f8b3692\",\"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 = ((_c = (_b = _Scene__WEBPACK_IMPORTED_MODULE_8__[\"default\"].getScene(elements[0])) === null || _b === void 0 ? void 0 : _b.getNonDeletedElements()) === null || _c === void 0 ? void 0 : _c.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(\"${assetPath}Virgil.woff2\");\n }\n @font-face {\n font-family: \"Cascadia\";\n src: url(\"${assetPath}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, exportPadding) => {\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) + (onlyExportingSingleFrame ? 0 : exportPadding * 2);\n const height = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.distance)(minY, maxY) + (onlyExportingSingleFrame ? 0 : exportPadding * 2);\n return [minX, minY, width, height];\n};\n\nconst getExportSize = (elements, exportPadding, scale) => {\n const [,, width, height] = getCanvasSize(elements, exportPadding).map(dimension => Math.trunc(dimension * scale));\n return [width, height];\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNBLEtBQUssSUFBSSxHQUFHO0FBQ1o7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDs7QUFFQSxtQ0FBbUMsZ0VBQWU7QUFDbEQsZ0JBQWdCLGdEQUFRO0FBQ3hCLGlCQUFpQixnREFBUTtBQUN6QjtBQUNBOztBQUVPO0FBQ1A7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL3NjZW5lL2V4cG9ydC50cz8zZjRlIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX2F3YWl0ZXIgPSB0aGlzICYmIHRoaXMuX19hd2FpdGVyIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcbiAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkge1xuICAgICAgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7XG4gICAgfVxuXG4gICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xuICB9KTtcbn07XG5cbmltcG9ydCByb3VnaCBmcm9tIFwicm91Z2hqcy9iaW4vcm91Z2hcIjtcbmltcG9ydCB7IGdldENvbW1vbkJvdW5kcywgZ2V0RWxlbWVudEFic29sdXRlQ29vcmRzIH0gZnJvbSBcIi4uL2VsZW1lbnQvYm91bmRzXCI7XG5pbXBvcnQgeyByZW5kZXJTY2VuZVRvU3ZnLCByZW5kZXJTdGF0aWNTY2VuZSB9IGZyb20gXCIuLi9yZW5kZXJlci9yZW5kZXJTY2VuZVwiO1xuaW1wb3J0IHsgZGlzdGFuY2UsIGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgeyBERUZBVUxUX0VYUE9SVF9QQURESU5HLCBTVkdfTlMsIFRIRU1FX0ZJTFRFUiB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGdldERlZmF1bHRBcHBTdGF0ZSB9IGZyb20gXCIuLi9hcHBTdGF0ZVwiO1xuaW1wb3J0IHsgc2VyaWFsaXplQXNKU09OIH0gZnJvbSBcIi4uL2RhdGEvanNvblwiO1xuaW1wb3J0IHsgZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzLCB1cGRhdGVJbWFnZUNhY2hlIH0gZnJvbSBcIi4uL2VsZW1lbnQvaW1hZ2VcIjtcbmltcG9ydCBTY2VuZSBmcm9tIFwiLi9TY2VuZVwiO1xuZXhwb3J0IGNvbnN0IFNWR19FWFBPUlRfVEFHID0gYDwhLS0gc3ZnLXNvdXJjZTpleGNhbGlkcmF3IC0tPmA7XG5leHBvcnQgY29uc3QgZXhwb3J0VG9DYW52YXMgPSAoZWxlbWVudHMsIGFwcFN0YXRlLCBmaWxlcywge1xuICBleHBvcnRCYWNrZ3JvdW5kLFxuICBleHBvcnRQYWRkaW5nID0gREVGQVVMVF9FWFBPUlRfUEFERElORyxcbiAgdmlld0JhY2tncm91bmRDb2xvclxufSwgY3JlYXRlQ2FudmFzID0gKHdpZHRoLCBoZWlnaHQpID0+IHtcbiAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgY2FudmFzLndpZHRoID0gd2lkdGggKiBhcHBTdGF0ZS5leHBvcnRTY2FsZTtcbiAgY2FudmFzLmhlaWdodCA9IGhlaWdodCAqIGFwcFN0YXRlLmV4cG9ydFNjYWxlO1xuICByZXR1cm4ge1xuICAgIGNhbnZhcyxcbiAgICBzY2FsZTogYXBwU3RhdGUuZXhwb3J0U2NhbGVcbiAgfTtcbn0pID0+IF9fYXdhaXRlcih2b2lkIDAsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICBjb25zdCBbbWluWCwgbWluWSwgd2lkdGgsIGhlaWdodF0gPSBnZXRDYW52YXNTaXplKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nKTtcbiAgY29uc3Qge1xuICAgIGNhbnZhcyxcbiAgICBzY2FsZSA9IDFcbiAgfSA9IGNyZWF0ZUNhbnZhcyh3aWR0aCwgaGVpZ2h0KTtcbiAgY29uc3QgZGVmYXVsdEFwcFN0YXRlID0gZ2V0RGVmYXVsdEFwcFN0YXRlKCk7XG4gIGNvbnN0IHtcbiAgICBpbWFnZUNhY2hlXG4gIH0gPSB5aWVsZCB1cGRhdGVJbWFnZUNhY2hlKHtcbiAgICBpbWFnZUNhY2hlOiBuZXcgTWFwKCksXG4gICAgZmlsZUlkczogZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzKGVsZW1lbnRzKS5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgZmlsZXNcbiAgfSk7XG4gIGNvbnN0IG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA9IGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKGVsZW1lbnRzKTtcbiAgcmVuZGVyU3RhdGljU2NlbmUoe1xuICAgIGNhbnZhcyxcbiAgICByYzogcm91Z2guY2FudmFzKGNhbnZhcyksXG4gICAgZWxlbWVudHMsXG4gICAgdmlzaWJsZUVsZW1lbnRzOiBlbGVtZW50cyxcbiAgICBzY2FsZSxcbiAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBhcHBTdGF0ZSksIHtcbiAgICAgIHZpZXdCYWNrZ3JvdW5kQ29sb3I6IGV4cG9ydEJhY2tncm91bmQgPyB2aWV3QmFja2dyb3VuZENvbG9yIDogbnVsbCxcbiAgICAgIHNjcm9sbFg6IC1taW5YICsgKG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IDAgOiBleHBvcnRQYWRkaW5nKSxcbiAgICAgIHNjcm9sbFk6IC1taW5ZICsgKG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IDAgOiBleHBvcnRQYWRkaW5nKSxcbiAgICAgIHpvb206IGRlZmF1bHRBcHBTdGF0ZS56b29tLFxuICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZSxcbiAgICAgIHRoZW1lOiBhcHBTdGF0ZS5leHBvcnRXaXRoRGFya01vZGUgPyBcImRhcmtcIiA6IFwibGlnaHRcIlxuICAgIH0pLFxuICAgIHJlbmRlckNvbmZpZzoge1xuICAgICAgaW1hZ2VDYWNoZSxcbiAgICAgIHJlbmRlckdyaWQ6IGZhbHNlLFxuICAgICAgaXNFeHBvcnRpbmc6IHRydWVcbiAgICB9XG4gIH0pO1xuICByZXR1cm4gY2FudmFzO1xufSk7XG5leHBvcnQgY29uc3QgZXhwb3J0VG9TdmcgPSAoZWxlbWVudHMsIGFwcFN0YXRlLCBmaWxlcywgb3B0cykgPT4gX19hd2FpdGVyKHZvaWQgMCwgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gIHZhciBfYSwgX2IsIF9jO1xuXG4gIGNvbnN0IHtcbiAgICBleHBvcnRQYWRkaW5nID0gREVGQVVMVF9FWFBPUlRfUEFERElORyxcbiAgICB2aWV3QmFja2dyb3VuZENvbG9yLFxuICAgIGV4cG9ydFNjYWxlID0gMSxcbiAgICBleHBvcnRFbWJlZFNjZW5lXG4gIH0gPSBhcHBTdGF0ZTtcbiAgbGV0IG1ldGFkYXRhID0gXCJcIjtcblxuICBpZiAoZXhwb3J0RW1iZWRTY2VuZSkge1xuICAgIHRyeSB7XG4gICAgICBtZXRhZGF0YSA9IHlpZWxkICh5aWVsZCBpbXBvcnQoXG4gICAgICAvKiB3ZWJwYWNrQ2h1bmtOYW1lOiBcImltYWdlXCIgKi9cbiAgICAgIFwiLi4vLi4vc3JjL2RhdGEvaW1hZ2VcIikpLmVuY29kZVN2Z01ldGFkYXRhKHtcbiAgICAgICAgdGV4dDogKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5zZXJpYWxpemVBc0pTT04pID8gKF9hID0gb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnNlcmlhbGl6ZUFzSlNPTikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwob3B0cykgOiBzZXJpYWxpemVBc0pTT04oZWxlbWVudHMsIGFwcFN0YXRlLCBmaWxlcyB8fCB7fSwgXCJsb2NhbFwiKVxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IFttaW5YLCBtaW5ZLCB3aWR0aCwgaGVpZ2h0XSA9IGdldENhbnZhc1NpemUoZWxlbWVudHMsIGV4cG9ydFBhZGRpbmcpOyAvLyBpbml0aWFsaXplIFNWRyByb290XG5cbiAgY29uc3Qgc3ZnUm9vdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsIFwic3ZnXCIpO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcInZlcnNpb25cIiwgXCIxLjFcIik7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwieG1sbnNcIiwgU1ZHX05TKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJ2aWV3Qm94XCIsIGAwIDAgJHt3aWR0aH0gJHtoZWlnaHR9YCk7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwid2lkdGhcIiwgYCR7d2lkdGggKiBleHBvcnRTY2FsZX1gKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJoZWlnaHRcIiwgYCR7aGVpZ2h0ICogZXhwb3J0U2NhbGV9YCk7XG5cbiAgaWYgKGFwcFN0YXRlLmV4cG9ydFdpdGhEYXJrTW9kZSkge1xuICAgIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwiZmlsdGVyXCIsIFRIRU1FX0ZJTFRFUik7XG4gIH1cblxuICBsZXQgYXNzZXRQYXRoID0gXCJodHRwczovL2V4Y2FsaWRyYXcuY29tL1wiOyAvLyBBc3NldCBwYXRoIG5lZWRzIHRvIGJlIGRldGVybWluZWQgb25seSB3aGVuIHVzaW5nIHBhY2thZ2VcblxuICBpZiAocHJvY2Vzcy5lbnYuVklURV9JU19FWENBTElEUkFXX05QTV9QQUNLQUdFKSB7XG4gICAgYXNzZXRQYXRoID0gd2luZG93LkVYQ0FMSURSQVdfQVNTRVRfUEFUSCB8fCBgaHR0cHM6Ly91bnBrZy5jb20vJHtwcm9jZXNzLmVudi5WSVRFX1BLR19OQU1FfUAke3Byb2Nlc3MuZW52LlBLR19WRVJTSU9OfWA7XG5cbiAgICBpZiAoYXNzZXRQYXRoID09PSBudWxsIHx8IGFzc2V0UGF0aCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYXNzZXRQYXRoLnN0YXJ0c1dpdGgoXCIvXCIpKSB7XG4gICAgICBhc3NldFBhdGggPSBhc3NldFBhdGgucmVwbGFjZShcIi9cIiwgYCR7d2luZG93LmxvY2F0aW9uLm9yaWdpbn0vYCk7XG4gICAgfVxuXG4gICAgYXNzZXRQYXRoID0gYCR7YXNzZXRQYXRofS9kaXN0L2V4Y2FsaWRyYXctYXNzZXRzL2A7XG4gIH0gLy8gZG8gbm90IGFwcGx5IGNsaXBwaW5nIHdoZW4gd2UncmUgZXhwb3J0aW5nIHRoZSB3aG9sZSBzY2VuZVxuXG5cbiAgY29uc3QgaXNFeHBvcnRpbmdXaG9sZUNhbnZhcyA9ICgoX2MgPSAoX2IgPSBTY2VuZS5nZXRTY2VuZShlbGVtZW50c1swXSkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5nZXROb25EZWxldGVkRWxlbWVudHMoKSkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmxlbmd0aCkgPT09IGVsZW1lbnRzLmxlbmd0aDtcbiAgY29uc3Qgb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID0gaXNPbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUoZWxlbWVudHMpO1xuICBjb25zdCBvZmZzZXRYID0gLW1pblggKyAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gMCA6IGV4cG9ydFBhZGRpbmcpO1xuICBjb25zdCBvZmZzZXRZID0gLW1pblkgKyAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gMCA6IGV4cG9ydFBhZGRpbmcpO1xuICBjb25zdCBleHBvcnRpbmdGcmFtZSA9IGlzRXhwb3J0aW5nV2hvbGVDYW52YXMgfHwgIW9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IHVuZGVmaW5lZCA6IGVsZW1lbnRzLmZpbmQoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG4gIGxldCBleHBvcnRpbmdGcmFtZUNsaXBQYXRoID0gXCJcIjtcblxuICBpZiAoZXhwb3J0aW5nRnJhbWUpIHtcbiAgICBjb25zdCBbeDEsIHkxLCB4MiwgeTJdID0gZ2V0RWxlbWVudEFic29sdXRlQ29vcmRzKGV4cG9ydGluZ0ZyYW1lKTtcbiAgICBjb25zdCBjeCA9ICh4MiAtIHgxKSAvIDIgLSAoZXhwb3J0aW5nRnJhbWUueCAtIHgxKTtcbiAgICBjb25zdCBjeSA9ICh5MiAtIHkxKSAvIDIgLSAoZXhwb3J0aW5nRnJhbWUueSAtIHkxKTtcbiAgICBleHBvcnRpbmdGcmFtZUNsaXBQYXRoID0gYDxjbGlwUGF0aCBpZD0ke2V4cG9ydGluZ0ZyYW1lLmlkfT5cbiAgICAgICAgICAgIDxyZWN0IHRyYW5zZm9ybT1cInRyYW5zbGF0ZSgke2V4cG9ydGluZ0ZyYW1lLnggKyBvZmZzZXRYfSAke2V4cG9ydGluZ0ZyYW1lLnkgKyBvZmZzZXRZfSkgcm90YXRlKCR7ZXhwb3J0aW5nRnJhbWUuYW5nbGV9ICR7Y3h9ICR7Y3l9KVwiXG4gICAgICAgICAgd2lkdGg9XCIke2V4cG9ydGluZ0ZyYW1lLndpZHRofVwiXG4gICAgICAgICAgaGVpZ2h0PVwiJHtleHBvcnRpbmdGcmFtZS5oZWlnaHR9XCJcbiAgICAgICAgICA+XG4gICAgICAgICAgPC9yZWN0PlxuICAgICAgICA8L2NsaXBQYXRoPmA7XG4gIH1cblxuICBzdmdSb290LmlubmVySFRNTCA9IGBcbiAgJHtTVkdfRVhQT1JUX1RBR31cbiAgJHttZXRhZGF0YX1cbiAgPGRlZnM+XG4gICAgPHN0eWxlIGNsYXNzPVwic3R5bGUtZm9udHNcIj5cbiAgICAgIEBmb250LWZhY2Uge1xuICAgICAgICBmb250LWZhbWlseTogXCJWaXJnaWxcIjtcbiAgICAgICAgc3JjOiB1cmwoXCIke2Fzc2V0UGF0aH1WaXJnaWwud29mZjJcIik7XG4gICAgICB9XG4gICAgICBAZm9udC1mYWNlIHtcbiAgICAgICAgZm9udC1mYW1pbHk6IFwiQ2FzY2FkaWFcIjtcbiAgICAgICAgc3JjOiB1cmwoXCIke2Fzc2V0UGF0aH1DYXNjYWRpYS53b2ZmMlwiKTtcbiAgICAgIH1cbiAgICA8L3N0eWxlPlxuICAgICR7ZXhwb3J0aW5nRnJhbWVDbGlwUGF0aH1cbiAgPC9kZWZzPlxuICBgOyAvLyByZW5kZXIgYmFja2dyb3VuZCByZWN0XG5cbiAgaWYgKGFwcFN0YXRlLmV4cG9ydEJhY2tncm91bmQgJiYgdmlld0JhY2tncm91bmRDb2xvcikge1xuICAgIGNvbnN0IHJlY3QgPSBzdmdSb290Lm93bmVyRG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgXCJyZWN0XCIpO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwieFwiLCBcIjBcIik7XG4gICAgcmVjdC5zZXRBdHRyaWJ1dGUoXCJ5XCIsIFwiMFwiKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcIndpZHRoXCIsIGAke3dpZHRofWApO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwiaGVpZ2h0XCIsIGAke2hlaWdodH1gKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcImZpbGxcIiwgdmlld0JhY2tncm91bmRDb2xvcik7XG4gICAgc3ZnUm9vdC5hcHBlbmRDaGlsZChyZWN0KTtcbiAgfVxuXG4gIGNvbnN0IHJzdmcgPSByb3VnaC5zdmcoc3ZnUm9vdCk7XG4gIHJlbmRlclNjZW5lVG9TdmcoZWxlbWVudHMsIHJzdmcsIHN2Z1Jvb3QsIGZpbGVzIHx8IHt9LCB7XG4gICAgb2Zmc2V0WCxcbiAgICBvZmZzZXRZLFxuICAgIGV4cG9ydFdpdGhEYXJrTW9kZTogYXBwU3RhdGUuZXhwb3J0V2l0aERhcmtNb2RlLFxuICAgIGV4cG9ydGluZ0ZyYW1lSWQ6IChleHBvcnRpbmdGcmFtZSA9PT0gbnVsbCB8fCBleHBvcnRpbmdGcmFtZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhwb3J0aW5nRnJhbWUuaWQpIHx8IG51bGwsXG4gICAgcmVuZGVyRW1iZWRkYWJsZXM6IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yZW5kZXJFbWJlZGRhYmxlc1xuICB9KTtcbiAgcmV0dXJuIHN2Z1Jvb3Q7XG59KTsgLy8gY2FsY3VsYXRlIHNtYWxsZXN0IGFyZWEgdG8gZml0IHRoZSBjb250ZW50cyBpblxuXG5jb25zdCBnZXRDYW52YXNTaXplID0gKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nKSA9PiB7XG4gIC8vIHdlIHNob3VsZCBkZWNpZGUgaWYgd2UgYXJlIGV4cG9ydGluZyB0aGUgd2hvbGUgY2FudmFzXG4gIC8vIGlmIHNvLCB3ZSBhcmUgbm90IGNsaXBwaW5nIGVsZW1lbnRzIGluIHRoZSBmcmFtZVxuICAvLyBhbmQgdGhlcmVmb3JlLCB3ZSBzaG91bGQgbm90IGRvIGFueXRoaW5nIHNwZWNpYWxcbiAgdmFyIF9hLCBfYjtcblxuICBjb25zdCBpc0V4cG9ydGluZ1dob2xlQ2FudmFzID0gKChfYiA9IChfYSA9IFNjZW5lLmdldFNjZW5lKGVsZW1lbnRzWzBdKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IubGVuZ3RoKSA9PT0gZWxlbWVudHMubGVuZ3RoO1xuICBjb25zdCBvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPSBpc09ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZShlbGVtZW50cyk7XG5cbiAgaWYgKCFpc0V4cG9ydGluZ1dob2xlQ2FudmFzIHx8IG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSkge1xuICAgIGNvbnN0IGZyYW1lcyA9IGVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKTtcbiAgICBjb25zdCBleHBvcnRlZEZyYW1lSWRzID0gZnJhbWVzLnJlZHVjZSgoYWNjLCBmcmFtZSkgPT4ge1xuICAgICAgYWNjW2ZyYW1lLmlkXSA9IHRydWU7XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sIHt9KTsgLy8gZWxlbWVudHMgaW4gYSBmcmFtZSBkbyBub3QgYWZmZWN0IHRoZSBjYW52YXMgc2l6ZSBpZiB3ZSdyZSBub3QgZXhwb3J0aW5nXG4gICAgLy8gdGhlIHdob2xlIGNhbnZhc1xuXG4gICAgZWxlbWVudHMgPSBlbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIHJldHVybiAhZXhwb3J0ZWRGcmFtZUlkc1soX2EgPSBlbGVtZW50LmZyYW1lSWQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IFwiXCJdO1xuICAgIH0pO1xuICB9XG5cbiAgY29uc3QgW21pblgsIG1pblksIG1heFgsIG1heFldID0gZ2V0Q29tbW9uQm91bmRzKGVsZW1lbnRzKTtcbiAgY29uc3Qgd2lkdGggPSBkaXN0YW5jZShtaW5YLCBtYXhYKSArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyAqIDIpO1xuICBjb25zdCBoZWlnaHQgPSBkaXN0YW5jZShtaW5ZLCBtYXhZKSArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyAqIDIpO1xuICByZXR1cm4gW21pblgsIG1pblksIHdpZHRoLCBoZWlnaHRdO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldEV4cG9ydFNpemUgPSAoZWxlbWVudHMsIGV4cG9ydFBhZGRpbmcsIHNjYWxlKSA9PiB7XG4gIGNvbnN0IFssLCB3aWR0aCwgaGVpZ2h0XSA9IGdldENhbnZhc1NpemUoZWxlbWVudHMsIGV4cG9ydFBhZGRpbmcpLm1hcChkaW1lbnNpb24gPT4gTWF0aC50cnVuYyhkaW1lbnNpb24gKiBzY2FsZSkpO1xuICByZXR1cm4gW3dpZHRoLCBoZWlnaHRdO1xufTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../scene/export.ts\n");
4380
+ 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 */ \"getExportSize\": () => (/* binding */ getExportSize)\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 _appState__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../appState */ \"../../appState.ts\");\n/* harmony import */ var _data_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../data/json */ \"../../data/json.ts\");\n/* harmony import */ var _element_image__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../element/image */ \"../../element/image.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 -->`;\nconst exportToCanvas = (elements, appState, files, {\n exportBackground,\n exportPadding = _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_EXPORT_PADDING,\n viewBackgroundColor\n}, createCanvas = (width, height) => {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width * appState.exportScale;\n canvas.height = height * appState.exportScale;\n return {\n canvas,\n scale: appState.exportScale\n };\n}) => __awaiter(void 0, void 0, void 0, function* () {\n const [minX, minY, width, height] = getCanvasSize(elements, exportPadding);\n const {\n canvas,\n scale = 1\n } = createCanvas(width, height);\n const defaultAppState = (0,_appState__WEBPACK_IMPORTED_MODULE_5__.getDefaultAppState)();\n const {\n imageCache\n } = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_7__.updateImageCache)({\n imageCache: new Map(),\n fileIds: (0,_element_image__WEBPACK_IMPORTED_MODULE_7__.getInitializedImageElements)(elements).map(element => element.fileId),\n files\n });\n const onlyExportingSingleFrame = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.isOnlyExportingSingleFrame)(elements);\n (0,_renderer_renderScene__WEBPACK_IMPORTED_MODULE_2__.renderStaticScene)({\n canvas,\n rc: roughjs_bin_rough__WEBPACK_IMPORTED_MODULE_0__[\"default\"].canvas(canvas),\n elements,\n visibleElements: elements,\n scale,\n appState: Object.assign(Object.assign({}, appState), {\n viewBackgroundColor: exportBackground ? viewBackgroundColor : null,\n scrollX: -minX + (onlyExportingSingleFrame ? 0 : exportPadding),\n scrollY: -minY + (onlyExportingSingleFrame ? 0 : exportPadding),\n zoom: defaultAppState.zoom,\n shouldCacheIgnoreZoom: false,\n theme: appState.exportWithDarkMode ? \"dark\" : \"light\"\n }),\n renderConfig: {\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 _a, _b, _c;\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) ? (_a = opts === null || opts === void 0 ? void 0 : opts.serializeAsJSON) === null || _a === void 0 ? void 0 : _a.call(opts) : (0,_data_json__WEBPACK_IMPORTED_MODULE_6__.serializeAsJSON)(elements, appState, files || {}, \"local\")\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n const [minX, minY, width, height] = getCanvasSize(elements, exportPadding); // 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/${\"@excalidraw/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\":\"@excalidraw/excalidraw\",\"VITE_PKG_VERSION\":\"0.16.1-4765f55\",\"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 = ((_c = (_b = _Scene__WEBPACK_IMPORTED_MODULE_8__[\"default\"].getScene(elements[0])) === null || _b === void 0 ? void 0 : _b.getNonDeletedElements()) === null || _c === void 0 ? void 0 : _c.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(\"${assetPath}Virgil.woff2\");\n }\n @font-face {\n font-family: \"Cascadia\";\n src: url(\"${assetPath}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, exportPadding) => {\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) + (onlyExportingSingleFrame ? 0 : exportPadding * 2);\n const height = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.distance)(minY, maxY) + (onlyExportingSingleFrame ? 0 : exportPadding * 2);\n return [minX, minY, width, height];\n};\n\nconst getExportSize = (elements, exportPadding, scale) => {\n const [,, width, height] = getCanvasSize(elements, exportPadding).map(dimension => Math.trunc(dimension * scale));\n return [width, height];\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNBLEtBQUssSUFBSSxHQUFHO0FBQ1o7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDs7QUFFQSxtQ0FBbUMsZ0VBQWU7QUFDbEQsZ0JBQWdCLGdEQUFRO0FBQ3hCLGlCQUFpQixnREFBUTtBQUN6QjtBQUNBOztBQUVPO0FBQ1A7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL3NjZW5lL2V4cG9ydC50cz8zZjRlIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX2F3YWl0ZXIgPSB0aGlzICYmIHRoaXMuX19hd2FpdGVyIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcbiAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkge1xuICAgICAgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7XG4gICAgfVxuXG4gICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xuICB9KTtcbn07XG5cbmltcG9ydCByb3VnaCBmcm9tIFwicm91Z2hqcy9iaW4vcm91Z2hcIjtcbmltcG9ydCB7IGdldENvbW1vbkJvdW5kcywgZ2V0RWxlbWVudEFic29sdXRlQ29vcmRzIH0gZnJvbSBcIi4uL2VsZW1lbnQvYm91bmRzXCI7XG5pbXBvcnQgeyByZW5kZXJTY2VuZVRvU3ZnLCByZW5kZXJTdGF0aWNTY2VuZSB9IGZyb20gXCIuLi9yZW5kZXJlci9yZW5kZXJTY2VuZVwiO1xuaW1wb3J0IHsgZGlzdGFuY2UsIGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgeyBERUZBVUxUX0VYUE9SVF9QQURESU5HLCBTVkdfTlMsIFRIRU1FX0ZJTFRFUiB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGdldERlZmF1bHRBcHBTdGF0ZSB9IGZyb20gXCIuLi9hcHBTdGF0ZVwiO1xuaW1wb3J0IHsgc2VyaWFsaXplQXNKU09OIH0gZnJvbSBcIi4uL2RhdGEvanNvblwiO1xuaW1wb3J0IHsgZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzLCB1cGRhdGVJbWFnZUNhY2hlIH0gZnJvbSBcIi4uL2VsZW1lbnQvaW1hZ2VcIjtcbmltcG9ydCBTY2VuZSBmcm9tIFwiLi9TY2VuZVwiO1xuZXhwb3J0IGNvbnN0IFNWR19FWFBPUlRfVEFHID0gYDwhLS0gc3ZnLXNvdXJjZTpleGNhbGlkcmF3IC0tPmA7XG5leHBvcnQgY29uc3QgZXhwb3J0VG9DYW52YXMgPSAoZWxlbWVudHMsIGFwcFN0YXRlLCBmaWxlcywge1xuICBleHBvcnRCYWNrZ3JvdW5kLFxuICBleHBvcnRQYWRkaW5nID0gREVGQVVMVF9FWFBPUlRfUEFERElORyxcbiAgdmlld0JhY2tncm91bmRDb2xvclxufSwgY3JlYXRlQ2FudmFzID0gKHdpZHRoLCBoZWlnaHQpID0+IHtcbiAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgY2FudmFzLndpZHRoID0gd2lkdGggKiBhcHBTdGF0ZS5leHBvcnRTY2FsZTtcbiAgY2FudmFzLmhlaWdodCA9IGhlaWdodCAqIGFwcFN0YXRlLmV4cG9ydFNjYWxlO1xuICByZXR1cm4ge1xuICAgIGNhbnZhcyxcbiAgICBzY2FsZTogYXBwU3RhdGUuZXhwb3J0U2NhbGVcbiAgfTtcbn0pID0+IF9fYXdhaXRlcih2b2lkIDAsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICBjb25zdCBbbWluWCwgbWluWSwgd2lkdGgsIGhlaWdodF0gPSBnZXRDYW52YXNTaXplKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nKTtcbiAgY29uc3Qge1xuICAgIGNhbnZhcyxcbiAgICBzY2FsZSA9IDFcbiAgfSA9IGNyZWF0ZUNhbnZhcyh3aWR0aCwgaGVpZ2h0KTtcbiAgY29uc3QgZGVmYXVsdEFwcFN0YXRlID0gZ2V0RGVmYXVsdEFwcFN0YXRlKCk7XG4gIGNvbnN0IHtcbiAgICBpbWFnZUNhY2hlXG4gIH0gPSB5aWVsZCB1cGRhdGVJbWFnZUNhY2hlKHtcbiAgICBpbWFnZUNhY2hlOiBuZXcgTWFwKCksXG4gICAgZmlsZUlkczogZ2V0SW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnRzKGVsZW1lbnRzKS5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgZmlsZXNcbiAgfSk7XG4gIGNvbnN0IG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA9IGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKGVsZW1lbnRzKTtcbiAgcmVuZGVyU3RhdGljU2NlbmUoe1xuICAgIGNhbnZhcyxcbiAgICByYzogcm91Z2guY2FudmFzKGNhbnZhcyksXG4gICAgZWxlbWVudHMsXG4gICAgdmlzaWJsZUVsZW1lbnRzOiBlbGVtZW50cyxcbiAgICBzY2FsZSxcbiAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBhcHBTdGF0ZSksIHtcbiAgICAgIHZpZXdCYWNrZ3JvdW5kQ29sb3I6IGV4cG9ydEJhY2tncm91bmQgPyB2aWV3QmFja2dyb3VuZENvbG9yIDogbnVsbCxcbiAgICAgIHNjcm9sbFg6IC1taW5YICsgKG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IDAgOiBleHBvcnRQYWRkaW5nKSxcbiAgICAgIHNjcm9sbFk6IC1taW5ZICsgKG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IDAgOiBleHBvcnRQYWRkaW5nKSxcbiAgICAgIHpvb206IGRlZmF1bHRBcHBTdGF0ZS56b29tLFxuICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiBmYWxzZSxcbiAgICAgIHRoZW1lOiBhcHBTdGF0ZS5leHBvcnRXaXRoRGFya01vZGUgPyBcImRhcmtcIiA6IFwibGlnaHRcIlxuICAgIH0pLFxuICAgIHJlbmRlckNvbmZpZzoge1xuICAgICAgaW1hZ2VDYWNoZSxcbiAgICAgIHJlbmRlckdyaWQ6IGZhbHNlLFxuICAgICAgaXNFeHBvcnRpbmc6IHRydWVcbiAgICB9XG4gIH0pO1xuICByZXR1cm4gY2FudmFzO1xufSk7XG5leHBvcnQgY29uc3QgZXhwb3J0VG9TdmcgPSAoZWxlbWVudHMsIGFwcFN0YXRlLCBmaWxlcywgb3B0cykgPT4gX19hd2FpdGVyKHZvaWQgMCwgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gIHZhciBfYSwgX2IsIF9jO1xuXG4gIGNvbnN0IHtcbiAgICBleHBvcnRQYWRkaW5nID0gREVGQVVMVF9FWFBPUlRfUEFERElORyxcbiAgICB2aWV3QmFja2dyb3VuZENvbG9yLFxuICAgIGV4cG9ydFNjYWxlID0gMSxcbiAgICBleHBvcnRFbWJlZFNjZW5lXG4gIH0gPSBhcHBTdGF0ZTtcbiAgbGV0IG1ldGFkYXRhID0gXCJcIjtcblxuICBpZiAoZXhwb3J0RW1iZWRTY2VuZSkge1xuICAgIHRyeSB7XG4gICAgICBtZXRhZGF0YSA9IHlpZWxkICh5aWVsZCBpbXBvcnQoXG4gICAgICAvKiB3ZWJwYWNrQ2h1bmtOYW1lOiBcImltYWdlXCIgKi9cbiAgICAgIFwiLi4vLi4vc3JjL2RhdGEvaW1hZ2VcIikpLmVuY29kZVN2Z01ldGFkYXRhKHtcbiAgICAgICAgdGV4dDogKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5zZXJpYWxpemVBc0pTT04pID8gKF9hID0gb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnNlcmlhbGl6ZUFzSlNPTikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwob3B0cykgOiBzZXJpYWxpemVBc0pTT04oZWxlbWVudHMsIGFwcFN0YXRlLCBmaWxlcyB8fCB7fSwgXCJsb2NhbFwiKVxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IFttaW5YLCBtaW5ZLCB3aWR0aCwgaGVpZ2h0XSA9IGdldENhbnZhc1NpemUoZWxlbWVudHMsIGV4cG9ydFBhZGRpbmcpOyAvLyBpbml0aWFsaXplIFNWRyByb290XG5cbiAgY29uc3Qgc3ZnUm9vdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsIFwic3ZnXCIpO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcInZlcnNpb25cIiwgXCIxLjFcIik7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwieG1sbnNcIiwgU1ZHX05TKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJ2aWV3Qm94XCIsIGAwIDAgJHt3aWR0aH0gJHtoZWlnaHR9YCk7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwid2lkdGhcIiwgYCR7d2lkdGggKiBleHBvcnRTY2FsZX1gKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJoZWlnaHRcIiwgYCR7aGVpZ2h0ICogZXhwb3J0U2NhbGV9YCk7XG5cbiAgaWYgKGFwcFN0YXRlLmV4cG9ydFdpdGhEYXJrTW9kZSkge1xuICAgIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwiZmlsdGVyXCIsIFRIRU1FX0ZJTFRFUik7XG4gIH1cblxuICBsZXQgYXNzZXRQYXRoID0gXCJodHRwczovL2V4Y2FsaWRyYXcuY29tL1wiOyAvLyBBc3NldCBwYXRoIG5lZWRzIHRvIGJlIGRldGVybWluZWQgb25seSB3aGVuIHVzaW5nIHBhY2thZ2VcblxuICBpZiAocHJvY2Vzcy5lbnYuVklURV9JU19FWENBTElEUkFXX05QTV9QQUNLQUdFKSB7XG4gICAgYXNzZXRQYXRoID0gd2luZG93LkVYQ0FMSURSQVdfQVNTRVRfUEFUSCB8fCBgaHR0cHM6Ly91bnBrZy5jb20vJHtwcm9jZXNzLmVudi5WSVRFX1BLR19OQU1FfUAke3Byb2Nlc3MuZW52LlBLR19WRVJTSU9OfWA7XG5cbiAgICBpZiAoYXNzZXRQYXRoID09PSBudWxsIHx8IGFzc2V0UGF0aCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYXNzZXRQYXRoLnN0YXJ0c1dpdGgoXCIvXCIpKSB7XG4gICAgICBhc3NldFBhdGggPSBhc3NldFBhdGgucmVwbGFjZShcIi9cIiwgYCR7d2luZG93LmxvY2F0aW9uLm9yaWdpbn0vYCk7XG4gICAgfVxuXG4gICAgYXNzZXRQYXRoID0gYCR7YXNzZXRQYXRofS9kaXN0L2V4Y2FsaWRyYXctYXNzZXRzL2A7XG4gIH0gLy8gZG8gbm90IGFwcGx5IGNsaXBwaW5nIHdoZW4gd2UncmUgZXhwb3J0aW5nIHRoZSB3aG9sZSBzY2VuZVxuXG5cbiAgY29uc3QgaXNFeHBvcnRpbmdXaG9sZUNhbnZhcyA9ICgoX2MgPSAoX2IgPSBTY2VuZS5nZXRTY2VuZShlbGVtZW50c1swXSkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5nZXROb25EZWxldGVkRWxlbWVudHMoKSkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmxlbmd0aCkgPT09IGVsZW1lbnRzLmxlbmd0aDtcbiAgY29uc3Qgb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID0gaXNPbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUoZWxlbWVudHMpO1xuICBjb25zdCBvZmZzZXRYID0gLW1pblggKyAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gMCA6IGV4cG9ydFBhZGRpbmcpO1xuICBjb25zdCBvZmZzZXRZID0gLW1pblkgKyAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gMCA6IGV4cG9ydFBhZGRpbmcpO1xuICBjb25zdCBleHBvcnRpbmdGcmFtZSA9IGlzRXhwb3J0aW5nV2hvbGVDYW52YXMgfHwgIW9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IHVuZGVmaW5lZCA6IGVsZW1lbnRzLmZpbmQoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG4gIGxldCBleHBvcnRpbmdGcmFtZUNsaXBQYXRoID0gXCJcIjtcblxuICBpZiAoZXhwb3J0aW5nRnJhbWUpIHtcbiAgICBjb25zdCBbeDEsIHkxLCB4MiwgeTJdID0gZ2V0RWxlbWVudEFic29sdXRlQ29vcmRzKGV4cG9ydGluZ0ZyYW1lKTtcbiAgICBjb25zdCBjeCA9ICh4MiAtIHgxKSAvIDIgLSAoZXhwb3J0aW5nRnJhbWUueCAtIHgxKTtcbiAgICBjb25zdCBjeSA9ICh5MiAtIHkxKSAvIDIgLSAoZXhwb3J0aW5nRnJhbWUueSAtIHkxKTtcbiAgICBleHBvcnRpbmdGcmFtZUNsaXBQYXRoID0gYDxjbGlwUGF0aCBpZD0ke2V4cG9ydGluZ0ZyYW1lLmlkfT5cbiAgICAgICAgICAgIDxyZWN0IHRyYW5zZm9ybT1cInRyYW5zbGF0ZSgke2V4cG9ydGluZ0ZyYW1lLnggKyBvZmZzZXRYfSAke2V4cG9ydGluZ0ZyYW1lLnkgKyBvZmZzZXRZfSkgcm90YXRlKCR7ZXhwb3J0aW5nRnJhbWUuYW5nbGV9ICR7Y3h9ICR7Y3l9KVwiXG4gICAgICAgICAgd2lkdGg9XCIke2V4cG9ydGluZ0ZyYW1lLndpZHRofVwiXG4gICAgICAgICAgaGVpZ2h0PVwiJHtleHBvcnRpbmdGcmFtZS5oZWlnaHR9XCJcbiAgICAgICAgICA+XG4gICAgICAgICAgPC9yZWN0PlxuICAgICAgICA8L2NsaXBQYXRoPmA7XG4gIH1cblxuICBzdmdSb290LmlubmVySFRNTCA9IGBcbiAgJHtTVkdfRVhQT1JUX1RBR31cbiAgJHttZXRhZGF0YX1cbiAgPGRlZnM+XG4gICAgPHN0eWxlIGNsYXNzPVwic3R5bGUtZm9udHNcIj5cbiAgICAgIEBmb250LWZhY2Uge1xuICAgICAgICBmb250LWZhbWlseTogXCJWaXJnaWxcIjtcbiAgICAgICAgc3JjOiB1cmwoXCIke2Fzc2V0UGF0aH1WaXJnaWwud29mZjJcIik7XG4gICAgICB9XG4gICAgICBAZm9udC1mYWNlIHtcbiAgICAgICAgZm9udC1mYW1pbHk6IFwiQ2FzY2FkaWFcIjtcbiAgICAgICAgc3JjOiB1cmwoXCIke2Fzc2V0UGF0aH1DYXNjYWRpYS53b2ZmMlwiKTtcbiAgICAgIH1cbiAgICA8L3N0eWxlPlxuICAgICR7ZXhwb3J0aW5nRnJhbWVDbGlwUGF0aH1cbiAgPC9kZWZzPlxuICBgOyAvLyByZW5kZXIgYmFja2dyb3VuZCByZWN0XG5cbiAgaWYgKGFwcFN0YXRlLmV4cG9ydEJhY2tncm91bmQgJiYgdmlld0JhY2tncm91bmRDb2xvcikge1xuICAgIGNvbnN0IHJlY3QgPSBzdmdSb290Lm93bmVyRG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgXCJyZWN0XCIpO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwieFwiLCBcIjBcIik7XG4gICAgcmVjdC5zZXRBdHRyaWJ1dGUoXCJ5XCIsIFwiMFwiKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcIndpZHRoXCIsIGAke3dpZHRofWApO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwiaGVpZ2h0XCIsIGAke2hlaWdodH1gKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcImZpbGxcIiwgdmlld0JhY2tncm91bmRDb2xvcik7XG4gICAgc3ZnUm9vdC5hcHBlbmRDaGlsZChyZWN0KTtcbiAgfVxuXG4gIGNvbnN0IHJzdmcgPSByb3VnaC5zdmcoc3ZnUm9vdCk7XG4gIHJlbmRlclNjZW5lVG9TdmcoZWxlbWVudHMsIHJzdmcsIHN2Z1Jvb3QsIGZpbGVzIHx8IHt9LCB7XG4gICAgb2Zmc2V0WCxcbiAgICBvZmZzZXRZLFxuICAgIGV4cG9ydFdpdGhEYXJrTW9kZTogYXBwU3RhdGUuZXhwb3J0V2l0aERhcmtNb2RlLFxuICAgIGV4cG9ydGluZ0ZyYW1lSWQ6IChleHBvcnRpbmdGcmFtZSA9PT0gbnVsbCB8fCBleHBvcnRpbmdGcmFtZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhwb3J0aW5nRnJhbWUuaWQpIHx8IG51bGwsXG4gICAgcmVuZGVyRW1iZWRkYWJsZXM6IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5yZW5kZXJFbWJlZGRhYmxlc1xuICB9KTtcbiAgcmV0dXJuIHN2Z1Jvb3Q7XG59KTsgLy8gY2FsY3VsYXRlIHNtYWxsZXN0IGFyZWEgdG8gZml0IHRoZSBjb250ZW50cyBpblxuXG5jb25zdCBnZXRDYW52YXNTaXplID0gKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nKSA9PiB7XG4gIC8vIHdlIHNob3VsZCBkZWNpZGUgaWYgd2UgYXJlIGV4cG9ydGluZyB0aGUgd2hvbGUgY2FudmFzXG4gIC8vIGlmIHNvLCB3ZSBhcmUgbm90IGNsaXBwaW5nIGVsZW1lbnRzIGluIHRoZSBmcmFtZVxuICAvLyBhbmQgdGhlcmVmb3JlLCB3ZSBzaG91bGQgbm90IGRvIGFueXRoaW5nIHNwZWNpYWxcbiAgdmFyIF9hLCBfYjtcblxuICBjb25zdCBpc0V4cG9ydGluZ1dob2xlQ2FudmFzID0gKChfYiA9IChfYSA9IFNjZW5lLmdldFNjZW5lKGVsZW1lbnRzWzBdKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IubGVuZ3RoKSA9PT0gZWxlbWVudHMubGVuZ3RoO1xuICBjb25zdCBvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPSBpc09ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZShlbGVtZW50cyk7XG5cbiAgaWYgKCFpc0V4cG9ydGluZ1dob2xlQ2FudmFzIHx8IG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSkge1xuICAgIGNvbnN0IGZyYW1lcyA9IGVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKTtcbiAgICBjb25zdCBleHBvcnRlZEZyYW1lSWRzID0gZnJhbWVzLnJlZHVjZSgoYWNjLCBmcmFtZSkgPT4ge1xuICAgICAgYWNjW2ZyYW1lLmlkXSA9IHRydWU7XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sIHt9KTsgLy8gZWxlbWVudHMgaW4gYSBmcmFtZSBkbyBub3QgYWZmZWN0IHRoZSBjYW52YXMgc2l6ZSBpZiB3ZSdyZSBub3QgZXhwb3J0aW5nXG4gICAgLy8gdGhlIHdob2xlIGNhbnZhc1xuXG4gICAgZWxlbWVudHMgPSBlbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIHJldHVybiAhZXhwb3J0ZWRGcmFtZUlkc1soX2EgPSBlbGVtZW50LmZyYW1lSWQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IFwiXCJdO1xuICAgIH0pO1xuICB9XG5cbiAgY29uc3QgW21pblgsIG1pblksIG1heFgsIG1heFldID0gZ2V0Q29tbW9uQm91bmRzKGVsZW1lbnRzKTtcbiAgY29uc3Qgd2lkdGggPSBkaXN0YW5jZShtaW5YLCBtYXhYKSArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyAqIDIpO1xuICBjb25zdCBoZWlnaHQgPSBkaXN0YW5jZShtaW5ZLCBtYXhZKSArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyAqIDIpO1xuICByZXR1cm4gW21pblgsIG1pblksIHdpZHRoLCBoZWlnaHRdO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldEV4cG9ydFNpemUgPSAoZWxlbWVudHMsIGV4cG9ydFBhZGRpbmcsIHNjYWxlKSA9PiB7XG4gIGNvbnN0IFssLCB3aWR0aCwgaGVpZ2h0XSA9IGdldENhbnZhc1NpemUoZWxlbWVudHMsIGV4cG9ydFBhZGRpbmcpLm1hcChkaW1lbnNpb24gPT4gTWF0aC50cnVuYyhkaW1lbnNpb24gKiBzY2FsZSkpO1xuICByZXR1cm4gW3dpZHRoLCBoZWlnaHRdO1xufTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../scene/export.ts\n");
4381
4381
 
4382
4382
  /***/ }),
4383
4383