@excalidraw/excalidraw 0.16.1-7251-baadf54 → 0.16.1-7255-5e200e3

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.
@@ -2441,7 +2441,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
2441
2441
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2442
2442
 
2443
2443
  "use strict";
2444
- 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-7251-baadf54\",\"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vYW5hbHl0aWNzLnRzLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QyxvQ0FBb0MsZ0NBQWdDOztBQUVwRSx5Q0FBeUMsbXJDQUFXO0FBQ3BEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2FuYWx5dGljcy50cz81NDIxIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCB0cmFja0V2ZW50ID0gKGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSkgPT4ge1xuICB0cnkge1xuICAgIC8vIHBsYWNlIGhlcmUgY2F0ZWdvcmllcyB0aGF0IHlvdSB3YW50IHRvIHRyYWNrIGFzIGV2ZW50c1xuICAgIC8vIEtFRVAgSU4gTUlORCBUSEUgUFJJQ0lOR1xuICAgIGNvbnN0IEFMTE9XRURfQ0FURUdPUklFU19UT19UUkFDSyA9IFtdOyAvLyBVbmNvbW1lbnQgdGhlIG5leHQgbGluZSB0byB0cmFjayBsb2NhbGx5XG4gICAgLy8gY29uc29sZS5sb2coXCJUcmFjayBFdmVudFwiLCB7IGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSB9KTtcblxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSBcInVuZGVmaW5lZFwiIHx8IHByb2Nlc3MuZW52LlZJVEVfV09SS0VSX0lEKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFBTExPV0VEX0NBVEVHT1JJRVNfVE9fVFJBQ0suaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5zYV9ldmVudCkge1xuICAgICAgd2luZG93LnNhX2V2ZW50KGFjdGlvbiwge1xuICAgICAgICBjYXRlZ29yeSxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIHZhbHVlXG4gICAgICB9KTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcImVycm9yIGR1cmluZyBhbmFseXRpY3NcIiwgZXJyb3IpO1xuICB9XG59OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../analytics.ts\n");
2444
+ 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-7255-5e200e3\",\"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vYW5hbHl0aWNzLnRzLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QyxvQ0FBb0MsZ0NBQWdDOztBQUVwRSx5Q0FBeUMsbXJDQUFXO0FBQ3BEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2FuYWx5dGljcy50cz81NDIxIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCB0cmFja0V2ZW50ID0gKGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSkgPT4ge1xuICB0cnkge1xuICAgIC8vIHBsYWNlIGhlcmUgY2F0ZWdvcmllcyB0aGF0IHlvdSB3YW50IHRvIHRyYWNrIGFzIGV2ZW50c1xuICAgIC8vIEtFRVAgSU4gTUlORCBUSEUgUFJJQ0lOR1xuICAgIGNvbnN0IEFMTE9XRURfQ0FURUdPUklFU19UT19UUkFDSyA9IFtdOyAvLyBVbmNvbW1lbnQgdGhlIG5leHQgbGluZSB0byB0cmFjayBsb2NhbGx5XG4gICAgLy8gY29uc29sZS5sb2coXCJUcmFjayBFdmVudFwiLCB7IGNhdGVnb3J5LCBhY3Rpb24sIGxhYmVsLCB2YWx1ZSB9KTtcblxuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSBcInVuZGVmaW5lZFwiIHx8IHByb2Nlc3MuZW52LlZJVEVfV09SS0VSX0lEKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFBTExPV0VEX0NBVEVHT1JJRVNfVE9fVFJBQ0suaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5zYV9ldmVudCkge1xuICAgICAgd2luZG93LnNhX2V2ZW50KGFjdGlvbiwge1xuICAgICAgICBjYXRlZ29yeSxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIHZhbHVlXG4gICAgICB9KTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcImVycm9yIGR1cmluZyBhbmFseXRpY3NcIiwgZXJyb3IpO1xuICB9XG59OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../analytics.ts\n");
2445
2445
 
2446
2446
  /***/ }),
2447
2447
 
@@ -2529,7 +2529,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
2529
2529
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2530
2530
 
2531
2531
  "use strict";
2532
- 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_71__ = __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 _snapping__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ../snapping */ \"../../snapping.ts\");\n/* harmony import */ var _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(/*! ../actions/actionBoundText */ \"../../actions/actionBoundText.tsx\");\n/* harmony import */ var _BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(/*! ./BraveMeasureTextError */ \"../../components/BraveMeasureTextError.tsx\");\n/* harmony import */ var _EyeDropper__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(/*! ./EyeDropper */ \"../../components/EyeDropper.tsx\");\n/* harmony import */ var _data_transform__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(/*! ../data/transform */ \"../../data/transform.ts\");\n/* harmony import */ var _Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(/*! ./Sidebar/Sidebar */ \"../../components/Sidebar/Sidebar.tsx\");\n/* harmony import */ var _canvases__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(/*! ./canvases */ \"../../components/canvases/index.tsx\");\n/* harmony import */ var _scene_Renderer__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(/*! ../scene/Renderer */ \"../../scene/Renderer.ts\");\n/* harmony import */ var _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(/*! ../scene/ShapeCache */ \"../../scene/ShapeCache.ts\");\n/* harmony import */ var _MermaidToExcalidraw__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(/*! ./MermaidToExcalidraw */ \"../../components/MermaidToExcalidraw.tsx\");\n/* harmony import */ var _LaserTool_LaserTool__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(/*! ./LaserTool/LaserTool */ \"../../components/LaserTool/LaserTool.tsx\");\n/* harmony import */ var _LaserTool_LaserPathManager__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(/*! ./LaserTool/LaserPathManager */ \"../../components/LaserTool/LaserPathManager.ts\");\n/* harmony import */ var _cursor__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(/*! ../cursor */ \"../../cursor.ts\");\n/* harmony import */ var _emitter__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(/*! ../emitter */ \"../../emitter.ts\");\nvar __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {\n function adopt(value) {\n return value instanceof P ? value : new P(function (resolve) {\n resolve(value);\n });\n }\n\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) {\n try {\n step(generator.next(value));\n } catch (e) {\n reject(e);\n }\n }\n\n function rejected(value) {\n try {\n step(generator[\"throw\"](value));\n } catch (e) {\n reject(e);\n }\n }\n\n function step(result) {\n result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n }\n\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst AppContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst AppPropsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst deviceContextInitialValue = {\n viewport: {\n isMobile: false,\n isLandscape: false\n },\n editor: {\n isMobile: false,\n canFitSidebar: false\n },\n isTouchScreen: false\n};\nconst DeviceContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(deviceContextInitialValue);\nDeviceContext.displayName = \"DeviceContext\";\nconst ExcalidrawContainerContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext({\n container: null,\n id: null\n});\nExcalidrawContainerContext.displayName = \"ExcalidrawContainerContext\";\nconst ExcalidrawElementsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext([]);\nExcalidrawElementsContext.displayName = \"ExcalidrawElementsContext\";\nconst ExcalidrawAppStateContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n width: 0,\n height: 0,\n offsetLeft: 0,\n offsetTop: 0\n}));\nExcalidrawAppStateContext.displayName = \"ExcalidrawAppStateContext\";\nconst ExcalidrawSetAppStateContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(() => {\n console.warn(\"unitialized ExcalidrawSetAppStateContext context!\");\n});\nExcalidrawSetAppStateContext.displayName = \"ExcalidrawSetAppStateContext\";\nconst ExcalidrawActionManagerContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nExcalidrawActionManagerContext.displayName = \"ExcalidrawActionManagerContext\";\nconst useApp = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(AppContext);\nconst useAppProps = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(AppPropsContext);\nconst useDevice = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(DeviceContext);\nconst useExcalidrawContainer = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawContainerContext);\nconst useExcalidrawElements = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawElementsContext);\nconst useExcalidrawAppState = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawAppStateContext);\nconst useExcalidrawSetAppState = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawSetAppStateContext);\nconst useExcalidrawActionManager = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawActionManagerContext);\nconst supportsResizeObserver = typeof window !== \"undefined\" && \"ResizeObserver\" in window;\nlet didTapTwice = false;\nlet tappedTwiceTimer = 0;\nlet isHoldingSpace = false;\nlet isPanning = false;\nlet isDraggingScrollBar = false;\nlet currentScrollBars = {\n horizontal: null,\n vertical: null\n};\nlet touchTimeout = 0;\nlet invalidateContextMenu = false;\n/**\n * Map of youtube embed video states\n */\n\nconst YOUTUBE_VIDEO_STATES = new Map();\nlet IS_PLAIN_PASTE = false;\nlet IS_PLAIN_PASTE_TIMER = 0;\nlet PLAIN_PASTE_TOAST_SHOWN = false;\nlet lastPointerUp = null;\nconst gesture = {\n pointers: new Map(),\n lastCenter: null,\n initialDistance: null,\n initialScale: null\n};\n\nclass App extends (react__WEBPACK_IMPORTED_MODULE_1___default().Component) {\n constructor(props) {\n super(props);\n this.interactiveCanvas = null;\n this.unmounted = false;\n this.device = deviceContextInitialValue;\n this.excalidrawContainerRef = react__WEBPACK_IMPORTED_MODULE_1___default().createRef();\n this.files = {};\n this.imageCache = new Map();\n this.iFrameRefs = new Map();\n this.lastPointerDownEvent = null;\n this.lastPointerUpEvent = null;\n this.lastViewportPosition = {\n x: 0,\n y: 0\n };\n this.laserPathManager = new _LaserTool_LaserPathManager__WEBPACK_IMPORTED_MODULE_68__.LaserPathManager(this);\n this.onChangeEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_70__.Emitter();\n this.onPointerDownEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_70__.Emitter();\n this.onPointerUpEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_70__.Emitter();\n\n this.updateEmbeddables = () => {\n const embeddableElements = new Map();\n let updated = false;\n this.scene.getNonDeletedElements().filter(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(element)) {\n embeddableElements.set(element.id, true);\n\n if (element.validated == null) {\n updated = true;\n const validated = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(element.link, this.props.validateEmbeddable);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n validated\n }, false);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__.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_60__.activeEyeDropperAtom, {\n swapPreviewOnAlt: true,\n colorPickerType: type === \"stroke\" ? \"elementStroke\" : \"elementBackground\",\n onSelect: (color, event) => {\n const shouldUpdateStrokeColor = type === \"background\" && event.altKey || type === \"stroke\" && !event.altKey;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (!selectedElements.length || this.state.activeTool.type !== \"selection\") {\n if (shouldUpdateStrokeColor) {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemStrokeColor: color\n }),\n commitToHistory: true\n });\n } else {\n this.syncActionResult({\n appState: Object.assign(Object.assign({}, this.state), {\n currentItemBackgroundColor: color\n }),\n commitToHistory: true\n });\n }\n } else {\n this.updateScene({\n elements: this.scene.getElementsIncludingDeleted().map(el => {\n if (this.state.selectedElementIds[el.id]) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(el, {\n [shouldUpdateStrokeColor ? \"strokeColor\" : \"backgroundColor\"]: color\n });\n }\n\n return el;\n })\n });\n }\n },\n keepOpenOnAlt: false\n });\n };\n\n this.syncActionResult = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(actionResult => {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j;\n\n if (this.unmounted || actionResult === false) {\n return;\n }\n\n let editingElement = null;\n\n if (actionResult.elements) {\n actionResult.elements.forEach(element => {\n var _a;\n\n if (((_a = this.state.editingElement) === null || _a === void 0 ? void 0 : _a.id) === element.id && this.state.editingElement !== element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n editingElement = element;\n }\n });\n this.scene.replaceAllElements(actionResult.elements);\n\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n }\n\n if (actionResult.files) {\n this.files = actionResult.replaceFiles ? actionResult.files : Object.assign(Object.assign({}, this.files), actionResult.files);\n this.addNewImagesToImageCache();\n }\n\n if (actionResult.appState || editingElement || this.state.contextMenu) {\n if (actionResult.commitToHistory) {\n this.history.resumeRecording();\n }\n\n let viewModeEnabled = ((_a = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _a === void 0 ? void 0 : _a.viewModeEnabled) || false;\n let zenModeEnabled = ((_b = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _b === void 0 ? void 0 : _b.zenModeEnabled) || false;\n let gridSize = ((_c = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _c === void 0 ? void 0 : _c.gridSize) || null;\n const theme = ((_d = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _d === void 0 ? void 0 : _d.theme) || this.props.theme || _constants__WEBPACK_IMPORTED_MODULE_12__.THEME.LIGHT;\n let name = (_f = (_e = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : this.state.name;\n const errorMessage = (_h = (_g = actionResult === null || actionResult === void 0 ? void 0 : actionResult.appState) === null || _g === void 0 ? void 0 : _g.errorMessage) !== null && _h !== void 0 ? _h : this.state.errorMessage;\n\n if (typeof this.props.viewModeEnabled !== \"undefined\") {\n viewModeEnabled = this.props.viewModeEnabled;\n }\n\n if (typeof this.props.zenModeEnabled !== \"undefined\") {\n zenModeEnabled = this.props.zenModeEnabled;\n }\n\n if (typeof this.props.gridModeEnabled !== \"undefined\") {\n gridSize = this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null;\n }\n\n if (typeof this.props.name !== \"undefined\") {\n name = this.props.name;\n }\n\n editingElement = editingElement || ((_j = actionResult.appState) === null || _j === void 0 ? void 0 : _j.editingElement) || null;\n\n if (editingElement === null || editingElement === void 0 ? void 0 : editingElement.isDeleted) {\n editingElement = null;\n }\n\n this.setState(state => {\n // using Object.assign instead of spread to fool TS 4.2.2+ into\n // regarding the resulting type as not containing undefined\n // (which the following expression will never contain)\n return Object.assign(actionResult.appState || {}, {\n // NOTE this will prevent opening context menu using an action\n // or programmatically from the host, so it will need to be\n // rewritten later\n contextMenu: null,\n editingElement,\n viewModeEnabled,\n zenModeEnabled,\n gridSize,\n theme,\n name,\n errorMessage\n });\n }, () => {\n if (actionResult.syncHistory) {\n this.history.setCurrentState(this.state, this.scene.getElementsIncludingDeleted());\n }\n });\n }\n }); // Lifecycle\n\n this.onBlur = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isHoldingSpace = false;\n this.setState({\n isBindingEnabled: true\n });\n });\n\n this.onUnload = () => {\n this.onBlur();\n };\n\n this.disableEvent = event => {\n event.preventDefault();\n };\n\n this.resetHistory = () => {\n this.history.clear();\n };\n /**\n * Resets scene & history.\n * ! Do not use to clear scene user action !\n */\n\n\n this.resetScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(opts => {\n this.scene.replaceAllElements([]);\n this.setState(state => Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n isLoading: (opts === null || opts === void 0 ? void 0 : opts.resetLoadingState) ? false : state.isLoading,\n theme: this.state.theme\n }));\n this.resetHistory();\n });\n\n this.initializeScene = () => __awaiter(this, void 0, void 0, function* () {\n var _a;\n\n if (\"launchQueue\" in window && \"LaunchParams\" in window) {\n window.launchQueue.setConsumer(launchParams => __awaiter(this, void 0, void 0, function* () {\n if (!launchParams.files.length) {\n return;\n }\n\n const fileHandle = launchParams.files[0];\n const blob = yield fileHandle.getFile();\n this.loadFileToCanvas(new File([blob], blob.name || \"\", {\n type: blob.type\n }), fileHandle);\n }));\n }\n\n if (this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (!this.state.isLoading) {\n this.setState({\n isLoading: true\n });\n }\n\n let initialData = null;\n\n try {\n initialData = (yield this.props.initialData) || null;\n\n if (initialData === null || initialData === void 0 ? void 0 : initialData.libraryItems) {\n this.library.updateLibrary({\n libraryItems: initialData.libraryItems,\n merge: true\n }).catch(error => {\n console.error(error);\n });\n }\n } catch (error) {\n console.error(error);\n initialData = {\n appState: {\n errorMessage: error.message || \"Encountered an error during importing or restoring scene data\"\n }\n };\n }\n\n const scene = (0,_data_restore__WEBPACK_IMPORTED_MODULE_15__.restore)(initialData, null, null, {\n repairBindings: true\n });\n scene.appState = Object.assign(Object.assign({}, scene.appState), {\n theme: this.props.theme || scene.appState.theme,\n // we're falling back to current (pre-init) state when deciding\n // whether to open the library, to handle a case where we\n // update the state outside of initialData (e.g. when loading the app\n // with a library install link, which should auto-open the library)\n openSidebar: ((_a = scene.appState) === null || _a === void 0 ? void 0 : _a.openSidebar) || this.state.openSidebar,\n activeTool: scene.appState.activeTool.type === \"image\" ? Object.assign(Object.assign({}, scene.appState.activeTool), {\n type: \"selection\"\n }) : scene.appState.activeTool,\n isLoading: false,\n toast: this.state.toast\n });\n\n if (initialData === null || initialData === void 0 ? void 0 : initialData.scrollToContent) {\n scene.appState = Object.assign(Object.assign({}, scene.appState), (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(scene.elements, Object.assign(Object.assign({}, scene.appState), {\n width: this.state.width,\n height: this.state.height,\n offsetTop: this.state.offsetTop,\n offsetLeft: this.state.offsetLeft\n })));\n } // FontFaceSet loadingdone event we listen on may not always fire\n // (looking at you Safari), so on init we manually load fonts for current\n // text elements on canvas, and rerender them once done. This also\n // seems faster even in browsers that do fire the loadingdone event.\n\n\n this.fonts.loadFontsForElements(scene.elements);\n this.resetHistory();\n this.syncActionResult(Object.assign(Object.assign({}, scene), {\n commitToHistory: true\n }));\n });\n\n this.isMobileBreakpoint = (width, height) => {\n return width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_PORTRAIT || height < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_HEIGHT_LANDSCAPE && width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_LANDSCAPE;\n };\n\n this.refreshViewportBreakpoints = () => {\n const container = this.excalidrawContainerRef.current;\n\n if (!container) {\n return;\n }\n\n const {\n clientWidth: viewportWidth,\n clientHeight: viewportHeight\n } = document.body;\n const prevViewportState = this.device.viewport;\n const nextViewportState = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(prevViewportState, {\n isLandscape: viewportWidth > viewportHeight,\n isMobile: this.isMobileBreakpoint(viewportWidth, viewportHeight)\n });\n\n if (prevViewportState !== nextViewportState) {\n this.device = Object.assign(Object.assign({}, this.device), {\n viewport: nextViewportState\n });\n return true;\n }\n\n return false;\n };\n\n this.refreshEditorBreakpoints = () => {\n const container = this.excalidrawContainerRef.current;\n\n if (!container) {\n return;\n }\n\n const {\n width: editorWidth,\n height: editorHeight\n } = container.getBoundingClientRect();\n const sidebarBreakpoint = this.props.UIOptions.dockedSidebarBreakpoint != null ? this.props.UIOptions.dockedSidebarBreakpoint : _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_RIGHT_SIDEBAR_MIN_WIDTH;\n const prevEditorState = this.device.editor;\n const nextEditorState = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(prevEditorState, {\n isMobile: this.isMobileBreakpoint(editorWidth, editorHeight),\n canFitSidebar: editorWidth > sidebarBreakpoint\n });\n\n if (prevEditorState !== nextEditorState) {\n this.device = Object.assign(Object.assign({}, this.device), {\n editor: nextEditorState\n });\n return true;\n }\n\n return false;\n };\n\n this.onResize = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n this.scene.getElementsIncludingDeleted().forEach(element => _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__.ShapeCache[\"delete\"](element));\n this.refreshViewportBreakpoints();\n this.updateDOMRect();\n\n if (!supportsResizeObserver) {\n this.refreshEditorBreakpoints();\n }\n\n this.setState({});\n });\n\n this.renderInteractiveSceneCallback = ({\n atLeastOneVisibleElement,\n scrollBars,\n elements\n }) => {\n if (scrollBars) {\n currentScrollBars = scrollBars;\n }\n\n const scrolledOutside = // hide when editing text\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? false : !atLeastOneVisibleElement && elements.length > 0;\n\n if (this.state.scrolledOutside !== scrolledOutside) {\n this.setState({\n scrolledOutside\n });\n }\n\n this.scheduleImageRefresh();\n };\n\n this.onScroll = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n const {\n offsetTop,\n offsetLeft\n } = this.getCanvasOffsets();\n this.setState(state => {\n if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {\n return null;\n }\n\n return {\n offsetTop,\n offsetLeft\n };\n });\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.SCROLL_TIMEOUT); // Copy/paste\n\n this.onCut = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, \"keyboard\", event);\n event.preventDefault();\n event.stopPropagation();\n });\n this.onCopy = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, \"keyboard\", event);\n event.preventDefault();\n event.stopPropagation();\n });\n\n this.onTouchStart = event => {\n // fix for Apple Pencil Scribble\n // On Android, preventing the event would disable contextMenu on tap-hold\n if (!_constants__WEBPACK_IMPORTED_MODULE_12__.isAndroid) {\n event.preventDefault();\n }\n\n if (!didTapTwice) {\n didTapTwice = true;\n clearTimeout(tappedTwiceTimer);\n tappedTwiceTimer = window.setTimeout(App.resetTapTwice, _constants__WEBPACK_IMPORTED_MODULE_12__.TAP_TWICE_TIMEOUT);\n return;\n } // insert text only if we tapped twice with a single finger\n // event.touches.length === 1 will also prevent inserting text when user's zooming\n\n\n if (didTapTwice && event.touches.length === 1) {\n const touch = event.touches[0]; // @ts-ignore\n\n this.handleCanvasDoubleClick({\n clientX: touch.clientX,\n clientY: touch.clientY\n });\n didTapTwice = false;\n clearTimeout(tappedTwiceTimer);\n }\n\n if (_constants__WEBPACK_IMPORTED_MODULE_12__.isAndroid) {\n event.preventDefault();\n }\n\n if (event.touches.length === 2) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n };\n\n this.onTouchEnd = event => {\n this.resetContextMenuTimer();\n\n if (event.touches.length > 0) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n } else {\n gesture.pointers.clear();\n }\n };\n\n this.pasteFromClipboard = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => __awaiter(this, void 0, void 0, function* () {\n var _b, _c, _d;\n\n const isPlainPaste = !!IS_PLAIN_PASTE; // #686\n\n const target = document.activeElement;\n const isExcalidrawActive = (_b = this.excalidrawContainerRef.current) === null || _b === void 0 ? void 0 : _b.contains(target);\n\n if (event && !isExcalidrawActive) {\n return;\n }\n\n const elementUnderCursor = document.elementFromPoint(this.lastViewportPosition.x, this.lastViewportPosition.y);\n\n if (event && (!(elementUnderCursor instanceof HTMLCanvasElement) || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(target))) {\n return;\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state); // must be called in the same frame (thus before any awaits) as the paste\n // event else some browsers (FF...) will clear the clipboardData\n // (something something security)\n\n let file = (_c = event === null || event === void 0 ? void 0 : event.clipboardData) === null || _c === void 0 ? void 0 : _c.files[0];\n const data = yield (0,_clipboard__WEBPACK_IMPORTED_MODULE_11__.parseClipboard)(event, isPlainPaste);\n\n if (!file && !isPlainPaste) {\n if (data.mixedContent) {\n return this.addElementsFromMixedContentPaste(data.mixedContent, {\n isPlainPaste,\n sceneX,\n sceneY\n });\n } else if (data.text) {\n const string = data.text.trim();\n\n if (string.startsWith(\"<svg\") && string.endsWith(\"</svg>\")) {\n // ignore SVG validation/normalization which will be done during image\n // initialization\n file = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(string);\n }\n }\n } // prefer spreadsheet data over image file (MS Office/Libre Office)\n\n\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(file) && !data.spreadsheet) {\n 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_61__.convertToExcalidrawElements)(data.elements) : data.elements; // TODO remove formatting from elements if isPlainPaste\n\n this.addElementsFromPasteOrLibrary({\n elements,\n files: data.files || null,\n position: \"cursor\",\n retainSeed: isPlainPaste\n });\n } else if (data.text) {\n const maybeUrl = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.extractSrc)(data.text);\n\n if (!isPlainPaste && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(maybeUrl, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(maybeUrl) || ((_d = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(maybeUrl)) === null || _d === void 0 ? void 0 : _d.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(maybeUrl)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n\n return;\n }\n\n this.addTextFromPaste(data.text, isPlainPaste);\n }\n\n this.setActiveTool({\n type: \"selection\"\n });\n event === null || event === void 0 ? void 0 : event.preventDefault();\n }));\n\n this.addElementsFromPasteOrLibrary = opts => {\n const elements = (0,_data_restore__WEBPACK_IMPORTED_MODULE_15__.restoreElements)(opts.elements, null, undefined);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(elements);\n const elementsCenterX = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minX, maxX) / 2;\n const elementsCenterY = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(minY, maxY) / 2;\n const clientX = typeof opts.position === \"object\" ? opts.position.clientX : opts.position === \"cursor\" ? this.lastViewportPosition.x : this.state.width / 2 + this.state.offsetLeft;\n const clientY = typeof opts.position === \"object\" ? opts.position.clientY : opts.position === \"cursor\" ? this.lastViewportPosition.y : this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const dx = x - elementsCenterX;\n const dy = y - elementsCenterY;\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(dx, dy, this.state.gridSize);\n const newElements = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.duplicateElements)(elements.map(element => {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n x: element.x + gridX - minX,\n y: element.y + gridY - minY\n });\n }), {\n randomizeSeed: !opts.retainSeed\n });\n const nextElements = [...this.scene.getElementsIncludingDeleted(), ...newElements];\n this.scene.replaceAllElements(nextElements);\n newElements.forEach(newElement => {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(newElement) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(newElement)) {\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerElement)(newElement);\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.redrawTextBoundingBox)(newElement, container);\n }\n });\n\n if (opts.files) {\n this.files = Object.assign(Object.assign({}, this.files), opts.files);\n }\n\n this.history.resumeRecording();\n const nextElementsToSelect = (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.excludeElementsInFramesFromSelection)(newElements);\n this.setState(Object.assign(Object.assign(Object.assign({}, this.state), {\n // keep sidebar (presumably the library) open if it's docked and\n // can fit.\n //\n // Note, we should close the sidebar only if we're dropping items\n // from library, not when pasting from clipboard. Alas.\n openSidebar: this.state.openSidebar && this.device.editor.canFitSidebar && _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.get(_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_62__.isSidebarDockedAtom) ? this.state.openSidebar : null\n }), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: null,\n selectedElementIds: nextElementsToSelect.reduce((acc, element) => {\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(element)) {\n acc[element.id] = true;\n }\n\n return acc;\n }, {})\n }, this.scene.getNonDeletedElements(), this.state, this)), () => {\n if (opts.files) {\n this.addNewImagesToImageCache();\n }\n });\n this.setActiveTool({\n type: \"selection\"\n });\n\n if (opts.fitToContent) {\n this.scrollToContent(newElements, {\n fitToContent: true\n });\n }\n };\n\n this.setAppState = (state, callback) => {\n this.setState(state, callback);\n };\n\n this.removePointer = event => {\n if (touchTimeout) {\n this.resetContextMenuTimer();\n }\n\n gesture.pointers.delete(event.pointerId);\n };\n\n this.toggleLock = (source = \"ui\") => {\n if (!this.state.activeTool.locked) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", \"toggleLock\", `${source} (${this.device.editor.isMobile ? \"mobile\" : \"desktop\"})`);\n }\n\n this.setState(prevState => {\n return {\n activeTool: Object.assign(Object.assign(Object.assign({}, prevState.activeTool), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, prevState.activeTool.locked ? {\n type: \"selection\"\n } : prevState.activeTool)), {\n locked: !prevState.activeTool.locked\n })\n };\n });\n };\n\n this.updateFrameRendering = opts => {\n this.setState(prevState => {\n var _a, _b, _c, _d;\n\n const next = typeof opts === \"function\" ? opts(prevState.frameRendering) : opts;\n return {\n frameRendering: {\n enabled: (_a = next === null || next === void 0 ? void 0 : next.enabled) !== null && _a !== void 0 ? _a : prevState.frameRendering.enabled,\n clip: (_b = next === null || next === void 0 ? void 0 : next.clip) !== null && _b !== void 0 ? _b : prevState.frameRendering.clip,\n name: (_c = next === null || next === void 0 ? void 0 : next.name) !== null && _c !== void 0 ? _c : prevState.frameRendering.name,\n outline: (_d = next === null || next === void 0 ? void 0 : next.outline) !== null && _d !== void 0 ? _d : prevState.frameRendering.outline\n }\n };\n });\n };\n\n this.togglePenMode = force => {\n this.setState(prevState => {\n return {\n penMode: force !== null && force !== void 0 ? force : !prevState.penMode,\n penDetected: true\n };\n });\n };\n\n this.onHandToolToggle = () => {\n this.actionManager.executeAction(_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.actionToggleHandTool);\n };\n /**\n * Zooms on canvas viewport center\n */\n\n\n this.zoomCanvas = (\n /** decimal fraction between 0.1 (10% zoom) and 30 (3000% zoom) */\n value) => {\n this.setState(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.state.width / 2 + this.state.offsetLeft,\n viewportY: this.state.height / 2 + this.state.offsetTop,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(value)\n }, this.state)));\n };\n\n this.cancelInProgresAnimation = null;\n\n this.scrollToContent = (target = this.scene.getNonDeletedElements(), opts) => {\n var _a, _b;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this); // convert provided target into ExcalidrawElement[] if necessary\n\n const targetElements = Array.isArray(target) ? target : [target];\n let zoom = this.state.zoom;\n let scrollX = this.state.scrollX;\n let scrollY = this.state.scrollY;\n\n if ((opts === null || opts === void 0 ? void 0 : opts.fitToContent) || (opts === null || opts === void 0 ? void 0 : opts.fitToViewport)) {\n const {\n appState\n } = (0,_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.zoomToFit)({\n targetElements,\n appState: this.state,\n fitToViewport: !!(opts === null || opts === void 0 ? void 0 : opts.fitToViewport),\n viewportZoomFactor: opts === null || opts === void 0 ? void 0 : opts.viewportZoomFactor\n });\n zoom = appState.zoom;\n scrollX = appState.scrollX;\n scrollY = appState.scrollY;\n } else {\n // compute only the viewport location, without any zoom adjustment\n const scroll = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(targetElements, this.state);\n scrollX = scroll.scrollX;\n scrollY = scroll.scrollY;\n } // when animating, we use RequestAnimationFrame to prevent the animation\n // from slowing down other processes\n\n\n if (opts === null || opts === void 0 ? void 0 : opts.animate) {\n const origScrollX = this.state.scrollX;\n const origScrollY = this.state.scrollY;\n const origZoom = this.state.zoom.value;\n const cancel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeToValuesRAF)({\n fromValues: {\n scrollX: origScrollX,\n scrollY: origScrollY,\n zoom: origZoom\n },\n toValues: {\n scrollX,\n scrollY,\n zoom: zoom.value\n },\n interpolateValue: (from, to, progress, key) => {\n // for zoom, use different easing\n if (key === \"zoom\") {\n return from * Math.pow(to / from, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeOut)(progress));\n } // handle using default\n\n\n return undefined;\n },\n onStep: ({\n scrollX,\n scrollY,\n zoom\n }) => {\n this.setState({\n scrollX,\n scrollY,\n zoom: {\n value: zoom\n }\n });\n },\n onStart: () => {\n this.setState({\n shouldCacheIgnoreZoom: true\n });\n },\n onEnd: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n onCancel: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n duration: (_b = opts === null || opts === void 0 ? void 0 : opts.duration) !== null && _b !== void 0 ? _b : 500\n });\n\n this.cancelInProgresAnimation = () => {\n cancel();\n this.cancelInProgresAnimation = null;\n };\n } else {\n this.setState({\n scrollX,\n scrollY,\n zoom\n });\n }\n };\n /** use when changing scrollX/scrollY/zoom based on user interaction */\n\n\n this.translateCanvas = state => {\n var _a;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this);\n this.setState(state);\n };\n\n this.setToast = toast => {\n this.setState({\n toast\n });\n };\n\n this.restoreFileFromShare = () => __awaiter(this, void 0, void 0, function* () {\n try {\n const webShareTargetCache = yield caches.open(\"web-share-target\");\n const response = yield webShareTargetCache.match(\"shared-file\");\n\n if (response) {\n const blob = yield response.blob();\n const file = new File([blob], blob.name || \"\", {\n type: blob.type\n });\n this.loadFileToCanvas(file, null);\n yield webShareTargetCache.delete(\"shared-file\");\n window.history.replaceState(null, _constants__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, window.location.pathname);\n }\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n });\n /** adds supplied files to existing files in the appState */\n\n\n this.addFiles = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(files => {\n const filesMap = files.reduce((acc, fileData) => {\n acc.set(fileData.id, fileData);\n return acc;\n }, new Map());\n this.files = Object.assign(Object.assign({}, this.files), Object.fromEntries(filesMap));\n this.scene.getNonDeletedElements().forEach(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && filesMap.has(element.fileId)) {\n this.imageCache.delete(element.fileId);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__.ShapeCache[\"delete\"](element);\n }\n });\n this.scene.informMutation();\n this.addNewImagesToImageCache();\n });\n this.updateScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(sceneData => {\n if (sceneData.commitToHistory) {\n this.history.resumeRecording();\n }\n\n if (sceneData.appState) {\n this.setState(sceneData.appState);\n }\n\n if (sceneData.elements) {\n this.scene.replaceAllElements(sceneData.elements);\n }\n\n if (sceneData.collaborators) {\n this.setState({\n collaborators: sceneData.collaborators\n });\n }\n });\n\n this.onSceneUpdated = () => {\n this.setState({});\n };\n /**\n * @returns whether the menu was toggled on or off\n */\n\n\n this.toggleSidebar = ({\n name,\n tab,\n force\n }) => {\n var _a;\n\n let nextName;\n\n if (force === undefined) {\n nextName = ((_a = this.state.openSidebar) === null || _a === void 0 ? void 0 : _a.name) === name ? null : name;\n } else {\n nextName = force ? name : null;\n }\n\n this.setState({\n openSidebar: nextName ? {\n name: nextName,\n tab\n } : null\n });\n return !!nextName;\n };\n\n this.updateCurrentCursorPosition = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n this.lastViewportPosition.x = event.clientX;\n this.lastViewportPosition.y = event.clientY;\n }); // Input handling\n\n this.onKeyDown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // normalize `event.key` when CapsLock is pressed #2372\n if (\"Proxy\" in window && (!event.shiftKey && /^[A-Z]$/.test(event.key) || event.shiftKey && /^[a-z]$/.test(event.key))) {\n event = new Proxy(event, {\n get(ev, prop) {\n const value = ev[prop];\n\n if (typeof value === \"function\") {\n // fix for Proxies hijacking `this`\n return value.bind(ev);\n }\n\n return prop === \"key\" ? // CapsLock inverts capitalization based on ShiftKey, so invert\n // it back\n event.shiftKey ? ev.key.toUpperCase() : ev.key.toLowerCase() : value;\n }\n\n });\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.V) {\n IS_PLAIN_PASTE = event.shiftKey;\n clearTimeout(IS_PLAIN_PASTE_TIMER); // reset (100ms to be safe that we it runs after the ensuing\n // paste event). Though, technically unnecessary to reset since we\n // (re)set the flag before each paste event.\n\n IS_PLAIN_PASTE_TIMER = window.setTimeout(() => {\n IS_PLAIN_PASTE = false;\n }, 100);\n } // prevent browser zoom in input fields\n\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n if (event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.MINUS || event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.EQUAL) {\n event.preventDefault();\n return;\n }\n } // bail if\n\n\n if ( // inside an input\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target) && // unless pressing escape (finalize action)\n event.key !== _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ESCAPE || // or unless using arrows (to move between buttons)\n (0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key) && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isInputLike)(event.target)) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.QUESTION_MARK) {\n this.setState({\n openDialog: \"help\"\n });\n return;\n } else if (event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.E && event.shiftKey && event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n event.preventDefault();\n this.setState({\n openDialog: \"imageExport\"\n });\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_UP || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n let offset = (event.shiftKey ? this.state.width : this.state.height) / this.state.zoom.value;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n offset = -offset;\n }\n\n if (event.shiftKey) {\n this.translateCanvas(state => ({\n scrollX: state.scrollX + offset\n }));\n } else {\n this.translateCanvas(state => ({\n scrollY: state.scrollY + offset\n }));\n }\n }\n\n if (this.actionManager.handleKeyDown(event)) {\n return;\n }\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: false\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const step = this.state.gridSize && (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize) || (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_SHIFT_TRANSLATE_AMOUNT : _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT);\n let offsetX = 0;\n let offsetY = 0;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_LEFT) {\n offsetX = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_RIGHT) {\n offsetX = step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_UP) {\n offsetY = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_DOWN) {\n offsetY = step;\n }\n\n const selectedElements = this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n });\n selectedElements.forEach(element => {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: element.x + offsetX,\n y: element.y + offsetY\n });\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element, {\n simultaneouslyUpdated: selectedElements\n });\n });\n this.maybeSuggestBindingForAll(selectedElements);\n event.preventDefault();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ENTER) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n const selectedElement = selectedElements[0];\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElement)) {\n if (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElement, this.scene)\n });\n }\n }\n } else if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isValidTextContainer)(selectedElement)) {\n let container;\n\n if (!(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement)) {\n container = selectedElement;\n }\n\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(selectedElement, this.state);\n const sceneX = midPoint.x;\n const sceneY = midPoint.y;\n this.startTextEditing({\n sceneX,\n sceneY,\n container\n });\n event.preventDefault();\n return;\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(selectedElement)) {\n this.setState({\n editingFrame: selectedElement.id\n });\n }\n }\n } else if (!event.ctrlKey && !event.altKey && !event.metaKey && this.state.draggingElement === null) {\n const shape = (0,_shapes__WEBPACK_IMPORTED_MODULE_32__.findShapeByKey)(event.key);\n\n if (shape) {\n if (this.state.activeTool.type !== shape) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", shape, `keyboard (${this.device.editor.isMobile ? \"mobile\" : \"desktop\"})`);\n }\n\n this.setActiveTool({\n type: shape\n });\n event.stopPropagation();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.Q) {\n this.toggleLock(\"keyboard\");\n event.stopPropagation();\n }\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE && gesture.pointers.size === 0) {\n isHoldingSpace = true;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n event.preventDefault();\n }\n\n if ((event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (this.state.activeTool.type === \"selection\" && !selectedElements.length) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && ((0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(this.state.activeTool.type) || selectedElements.some(element => (0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(element.type)))) {\n this.setState({\n openPopup: \"elementBackground\"\n });\n event.stopPropagation();\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) {\n this.setState({\n openPopup: \"elementStroke\"\n });\n event.stopPropagation();\n }\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.K && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if (this.state.activeTool.type === \"laser\") {\n this.setActiveTool({\n type: \"selection\"\n });\n } else {\n this.setActiveTool({\n type: \"laser\"\n });\n }\n\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.BACKSPACE || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.DELETE)) {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__.activeConfirmDialogAtom, \"clearCanvas\");\n } // eye dropper\n // -----------------------------------------------------------------------\n\n\n const lowerCased = event.key.toLocaleLowerCase();\n const isPickingStroke = lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S && event.shiftKey;\n const isPickingBackground = event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.I || lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && event.shiftKey;\n\n if (isPickingStroke || isPickingBackground) {\n this.openEyeDropper({\n type: isPickingStroke ? \"stroke\" : \"background\"\n });\n } // -----------------------------------------------------------------------\n\n });\n this.onWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // prevent browser pinch zoom on DOM elements\n if (!(event.target instanceof HTMLCanvasElement) && event.ctrlKey) {\n event.preventDefault();\n }\n });\n this.onKeyUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE) {\n if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (this.state.activeTool.type === \"selection\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.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 var _a;\n\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, tool);\n\n if (nextActiveTool.type === \"hand\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (!isHoldingSpace) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_33__.isToolIcon)(document.activeElement)) {\n this.focusContainer();\n }\n\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElementType)(nextActiveTool.type)) {\n this.setState({\n suggestedBindings: []\n });\n }\n\n if (nextActiveTool.type === \"image\") {\n this.onImageAction({\n insertOnCanvasDirectly: (_a = tool.type === \"image\" && tool.insertOnCanvasDirectly) !== null && _a !== void 0 ? _a : false\n });\n }\n\n this.setState(prevState => {\n const commonResets = {\n snapLines: prevState.snapLines.length ? [] : prevState.snapLines,\n originSnapOffset: null,\n activeEmbeddable: null\n };\n\n if (nextActiveTool.type !== \"selection\") {\n return Object.assign(Object.assign(Object.assign({}, prevState), {\n activeTool: nextActiveTool,\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n selectedGroupIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n editingGroupId: null,\n multiElement: null\n }), commonResets);\n }\n\n return Object.assign(Object.assign(Object.assign({}, prevState), {\n activeTool: nextActiveTool\n }), commonResets);\n });\n };\n\n this.setOpenDialog = dialogType => {\n this.setState({\n openDialog: dialogType\n });\n };\n\n this.setCursor = cursor => {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, cursor);\n };\n\n this.resetCursor = () => {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n };\n /**\n * returns whether user is making a gesture with >= 2 fingers (points)\n * on o touch screen (not on a trackpad). Currently only relates to Darwin\n * (iOS/iPadOS,MacOS), but may work on other devices in the future if\n * GestureEvent is standardized.\n */\n\n\n this.isTouchScreenMultiTouchGesture = () => {\n // we don't want to deselect when using trackpad, and multi-point gestures\n // only work on touch screens, so checking for >= pointers means we're on a\n // touchscreen\n return gesture.pointers.size >= 2;\n }; // fires only on Safari\n\n\n this.onGestureStart = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // we only want to deselect on touch screens because user may have selected\n // elements by mistake while zooming\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n\n gesture.initialScale = this.state.zoom.value;\n }); // fires only on Safari\n\n this.onGestureChange = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // onGestureChange only has zoom factor but not the center.\n // If we're on iPad or iPhone, then we recognize multi-touch and will\n // zoom in at the right location in the touchmove handler\n // (handleCanvasPointerMove).\n //\n // On Macbook trackpad, we don't have those events so will zoom in at the\n // current location instead.\n //\n // As such, bail from this handler on touch devices.\n\n if (this.isTouchScreenMultiTouchGesture()) {\n return;\n }\n\n const initialScale = gesture.initialScale;\n\n if (initialScale) {\n this.setState(state => Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * event.scale)\n }, state)));\n }\n }); // fires only on Safari\n\n this.onGestureEnd = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // reselect elements only on touch screens (see onGestureStart)\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n }\n\n gesture.initialScale = null;\n });\n\n this.startTextEditing = ({\n sceneX,\n sceneY,\n insertAtParentCenter = true,\n container\n }) => {\n var _a, _b;\n\n let shouldBindToContainer = false;\n let parentCenterPosition = insertAtParentCenter && this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n\n if (container && parentCenterPosition) {\n const boundTextElementToContainer = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(container);\n\n if (!boundTextElementToContainer) {\n shouldBindToContainer = true;\n }\n }\n\n let existingTextElement = null;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElements[0])) {\n existingTextElement = selectedElements[0];\n } else if (container) {\n existingTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(selectedElements[0]);\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n\n const fontFamily = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.fontFamily) || this.state.currentItemFontFamily;\n const lineHeight = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.lineHeight) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(fontFamily);\n const fontSize = this.state.currentItemFontSize;\n\n if (!existingTextElement && shouldBindToContainer && container && !(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isArrowElement)(container)) {\n const fontString = {\n fontSize,\n fontFamily\n };\n const minWidth = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineWidth)((0,_utils__WEBPACK_IMPORTED_MODULE_33__.getFontString)(fontString), lineHeight);\n const minHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineHeight)(fontSize, lineHeight);\n const newHeight = Math.max(container.height, minHeight);\n const newWidth = Math.max(container.width, minWidth);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n height: newHeight,\n width: newWidth\n });\n sceneX = container.x + newWidth / 2;\n sceneY = container.y + newHeight / 2;\n\n if (parentCenterPosition) {\n parentCenterPosition = this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n }\n }\n\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: sceneX,\n y: sceneY\n });\n const element = existingTextElement ? existingTextElement : (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)({\n x: parentCenterPosition ? parentCenterPosition.elementCenterX : sceneX,\n y: parentCenterPosition ? parentCenterPosition.elementCenterY : sceneY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text: \"\",\n fontSize,\n fontFamily,\n textAlign: parentCenterPosition ? \"center\" : this.state.currentItemTextAlign,\n verticalAlign: parentCenterPosition ? _constants__WEBPACK_IMPORTED_MODULE_12__.VERTICAL_ALIGN.MIDDLE : _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n containerId: shouldBindToContainer ? container === null || container === void 0 ? void 0 : container.id : undefined,\n groupIds: (_a = container === null || container === void 0 ? void 0 : container.groupIds) !== null && _a !== void 0 ? _a : [],\n lineHeight,\n angle: (_b = container === null || container === void 0 ? void 0 : container.angle) !== null && _b !== void 0 ? _b : 0,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n\n if (!existingTextElement && shouldBindToContainer && container) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n boundElements: (container.boundElements || []).concat({\n type: \"text\",\n id: element.id\n })\n });\n }\n\n this.setState({\n editingElement: element\n });\n\n if (!existingTextElement) {\n if (container && shouldBindToContainer) {\n const containerIndex = this.scene.getElementIndex(container.id);\n this.scene.insertElementAtIndex(element, containerIndex + 1);\n } else {\n this.scene.addNewElement(element);\n }\n }\n\n this.setState({\n editingElement: element\n });\n this.handleTextWysiwyg(element, {\n isExistingElement: !!existingTextElement\n });\n };\n\n this.handleCanvasDoubleClick = event => {\n // case: double-clicking with arrow/line tool selected would both create\n // text and enter multiElement mode\n if (this.state.multiElement) {\n return;\n } // we should only be able to double click when mode is selection\n\n\n if (this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0])) {\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id)) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElements[0], this.scene)\n });\n return;\n } else if (this.state.editingLinearElement && this.state.editingLinearElement.elementId === selectedElements[0].id) {\n return;\n }\n }\n\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n let {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedGroupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIds)(this.state);\n\n if (selectedGroupIds.length > 0) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n const selectedGroupId = hitElement && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIdForElement)(hitElement, this.state.selectedGroupIds);\n\n if (selectedGroupId) {\n this.setState(prevState => Object.assign(Object.assign({}, prevState), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: selectedGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)));\n return;\n }\n }\n\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.viewModeEnabled) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) {\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"active\"\n }\n });\n return;\n }\n\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if (container) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(container) || !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTransparent)(container.backgroundColor) || (0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY])) {\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, this.state);\n sceneX = midPoint.x;\n sceneY = midPoint.y;\n }\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n }\n };\n\n this.getElementLinkAtPosition = (scenePointer, hitElement) => {\n // Reversing so we traverse the elements in decreasing order\n // of z-index\n const elements = this.scene.getNonDeletedElements().slice().reverse();\n let hitElementIndex = Infinity;\n return elements.find((element, index) => {\n if (hitElement && element.id === hitElement.id) {\n hitElementIndex = index;\n }\n\n return element.link && index <= hitElementIndex && (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(element, this.state, [scenePointer.x, scenePointer.y], this.device.editor.isMobile);\n });\n };\n\n this.redirectToLink = (event, isTouchScreen) => {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDownEvent.clientX, this.lastPointerDownEvent.clientY, this.lastPointerUpEvent.clientX, this.lastPointerUpEvent.clientY);\n\n if (!this.hitLinkElement || // For touch screen allow dragging threshold else strict check\n isTouchScreen && draggedDistance > _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD || !isTouchScreen && draggedDistance !== 0) {\n return;\n }\n\n const lastPointerDownCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerDownEvent, this.state);\n const lastPointerDownHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerDownCoords.x, lastPointerDownCoords.y], this.device.editor.isMobile);\n const lastPointerUpCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerUpEvent, this.state);\n const lastPointerUpHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerUpCoords.x, lastPointerUpCoords.y], this.device.editor.isMobile);\n\n if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {\n let url = this.hitLinkElement.link;\n\n if (url) {\n url = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(url);\n let customEvent;\n\n if (this.props.onLinkOpen) {\n customEvent = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.wrapEvent)(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.EXCALIDRAW_LINK, event.nativeEvent);\n this.props.onLinkOpen(Object.assign(Object.assign({}, this.hitLinkElement), {\n link: url\n }), customEvent);\n }\n\n if (!(customEvent === null || customEvent === void 0 ? void 0 : customEvent.defaultPrevented)) {\n const target = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.isLocalLink)(url) ? \"_self\" : \"_blank\";\n const newWindow = window.open(undefined, target); // https://mathiasbynens.github.io/rel-noopener/\n\n if (newWindow) {\n newWindow.opener = null;\n newWindow.location = url;\n }\n }\n }\n }\n };\n\n this.getTopLayerFrameAtSceneCoords = sceneCoords => {\n const frames = this.scene.getNonDeletedFrames().filter(frame => (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)(sceneCoords, frame));\n return frames.length ? frames[frames.length - 1] : null;\n };\n\n this.handleCanvasPointerMove = event => {\n var _a, _b;\n\n this.savePointer(event.clientX, event.clientY, this.state.cursorButton);\n\n if (gesture.pointers.has(event.pointerId)) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n }\n\n const initialScale = gesture.initialScale;\n\n if (gesture.pointers.size === 2 && gesture.lastCenter && initialScale && gesture.initialDistance) {\n const center = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n const deltaX = center.x - gesture.lastCenter.x;\n const deltaY = center.y - gesture.lastCenter.y;\n gesture.lastCenter = center;\n const distance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n const scaleFactor = this.state.activeTool.type === \"freedraw\" && this.state.penMode ? 1 : distance / gesture.initialDistance;\n const nextZoom = scaleFactor ? (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * scaleFactor) : this.state.zoom.value;\n this.setState(state => {\n const zoomState = (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: center.x,\n viewportY: center.y,\n nextZoom\n }, state);\n this.translateCanvas({\n zoom: zoomState.zoom,\n scrollX: zoomState.scrollX + deltaX / nextZoom,\n scrollY: zoomState.scrollY + deltaY / nextZoom,\n shouldCacheIgnoreZoom: true\n });\n });\n this.resetShouldCacheIgnoreZoomDebounced();\n } else {\n gesture.lastCenter = gesture.initialDistance = gesture.initialScale = null;\n }\n\n if (isHoldingSpace || isPanning || isDraggingScrollBar || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state)) {\n return;\n }\n\n const isPointerOverScrollBars = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop);\n const isOverScrollBar = isPointerOverScrollBars.isOverEither;\n\n if (!this.state.draggingElement && !this.state.multiElement) {\n if (isOverScrollBar) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const {\n x: scenePointerX,\n y: scenePointerY\n } = scenePointer;\n\n if (!this.state.draggingElement && (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.isActiveToolNonLinearSnappable)(this.state.activeTool.type)) {\n const {\n originOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.getSnapLinesAtPointer)(this.scene.getNonDeletedElements(), this.state, {\n x: scenePointerX,\n y: scenePointerY\n }, event);\n this.setState({\n snapLines,\n originSnapOffset: originOffset\n });\n } else if (!this.state.draggingElement) {\n this.setState({\n snapLines: []\n });\n }\n\n if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerMove(event, scenePointerX, scenePointerY, this.state);\n\n if (editingLinearElement && editingLinearElement !== this.state.editingLinearElement) {\n // Since we are reading from previous state which is not possible with\n // automatic batching in React 18 hence using flush sync to synchronously\n // update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n this.setState({\n editingLinearElement\n });\n });\n }\n\n if ((editingLinearElement === null || editingLinearElement === void 0 ? void 0 : editingLinearElement.lastUncommittedPoint) != null) {\n this.maybeSuggestBindingAtCursor(scenePointer);\n } else {\n // causes stack overflow if not sync\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n this.setState({\n suggestedBindings: []\n });\n });\n }\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElementType)(this.state.activeTool.type)) {\n // Hovering with a selected tool or creating new linear element via click\n // and point\n const {\n draggingElement\n } = this.state;\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [scenePointer], this.state.startBoundElement);\n } else {\n this.maybeSuggestBindingAtCursor(scenePointer);\n }\n }\n\n if (this.state.multiElement) {\n const {\n multiElement\n } = this.state;\n const {\n x: rx,\n y: ry\n } = multiElement;\n const {\n points,\n lastCommittedPoint\n } = multiElement;\n const lastPoint = points[points.length - 1];\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n\n if (lastPoint === lastCommittedPoint) {\n // if we haven't yet created a temp point and we're beyond commit-zone\n // threshold, add a point\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(scenePointerX - rx, scenePointerY - ry, lastPoint[0], lastPoint[1]) >= _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: [...points, [scenePointerX - rx, scenePointerY - ry]]\n });\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER); // in this branch, we're inside the commit zone, and no uncommitted\n // point exists. Thus do nothing (don't add/remove points).\n }\n } else if (points.length > 2 && lastCommittedPoint && (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(scenePointerX - rx, scenePointerY - ry, lastCommittedPoint[0], lastCommittedPoint[1]) < _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: points.slice(0, -1)\n });\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(scenePointerX, scenePointerY, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const [lastCommittedX, lastCommittedY] = (_a = multiElement === null || multiElement === void 0 ? void 0 : multiElement.lastCommittedPoint) !== null && _a !== void 0 ? _a : [0, 0];\n let dxFromLastCommitted = gridX - rx - lastCommittedX;\n let dyFromLastCommitted = gridY - ry - lastCommittedY;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event)) {\n ({\n width: dxFromLastCommitted,\n height: dyFromLastCommitted\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)( // actual coordinate of the last committed point\n lastCommittedX + rx, lastCommittedY + ry, // cursor-grid coordinate\n gridX, gridY));\n }\n\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.isPathALoop)(points, this.state.zoom.value)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } // update last uncommitted point\n\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: [...points.slice(0, -1), [lastCommittedX + dxFromLastCommitted, lastCommittedY + dyFromLastCommitted]]\n });\n }\n\n return;\n }\n\n const hasDeselectedButton = Boolean(event.buttons);\n\n if (hasDeselectedButton || this.state.activeTool.type !== \"selection\" && this.state.activeTool.type !== \"text\" && this.state.activeTool.type !== \"eraser\") {\n return;\n }\n\n const elements = this.scene.getNonDeletedElements();\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && !isOverScrollBar && !this.state.editingLinearElement) {\n const elementWithTransformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getElementWithTransformHandleType)(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType);\n\n if (elementWithTransformHandleType && elementWithTransformHandleType.transformHandleType) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCursorForResizingElement)(elementWithTransformHandleType));\n return;\n }\n } else if (selectedElements.length > 1 && !isOverScrollBar) {\n const transformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getTransformHandleTypeFromCoords)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType);\n\n if (transformHandleType) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCursorForResizingElement)({\n transformHandleType\n }));\n return;\n }\n }\n\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n this.hitLinkElement = this.getElementLinkAtPosition(scenePointer, hitElement);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n return;\n }\n\n if (this.hitLinkElement && !this.state.selectedElementIds[this.hitLinkElement.id]) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.showHyperlinkTooltip)(this.hitLinkElement, this.state);\n } else {\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.hideHyperlinkToolip)();\n\n if (hitElement && (hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) && this.state.selectedElementIds[hitElement.id] && !this.state.contextMenu && !this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: \"info\"\n });\n } else if (this.state.activeTool.type === \"text\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(hitElement) ? _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.TEXT : _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.CROSSHAIR);\n } else if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (isOverScrollBar) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n } else if (this.state.selectedLinearElement) {\n this.handleHoverSelectedLinearElement(this.state.selectedLinearElement, scenePointerX, scenePointerY);\n } else if ( // if using cmd/ctrl, we're not dragging\n !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((hitElement || this.isHittingCommonBoundingBoxOfSelectedElements(scenePointer, selectedElements)) && !(hitElement === null || hitElement === void 0 ? void 0 : hitElement.locked)) {\n if (hitElement && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, event, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"hover\"\n }\n });\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n\n if (((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"hover\") {\n this.setState({\n activeEmbeddable: null\n });\n }\n }\n }\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n };\n\n this.handleEraser = (event, pointerDownState, scenePointer) => {\n const updateElementIds = elements => {\n elements.forEach(element => {\n if (element.locked) {\n return;\n }\n\n idsToUpdate.push(element.id);\n\n if (event.altKey) {\n if (pointerDownState.elementIdsToErase[element.id] && pointerDownState.elementIdsToErase[element.id].erase) {\n pointerDownState.elementIdsToErase[element.id].erase = false;\n }\n } else if (!pointerDownState.elementIdsToErase[element.id]) {\n pointerDownState.elementIdsToErase[element.id] = {\n erase: true,\n opacity: element.opacity\n };\n }\n });\n };\n\n const idsToUpdate = [];\n const distance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y, scenePointer.x, scenePointer.y);\n const threshold = 10 / this.state.zoom.value;\n const point = Object.assign({}, pointerDownState.lastCoords);\n let samplingInterval = 0;\n\n while (samplingInterval <= distance) {\n const hitElements = this.getElementsAtPosition(point.x, point.y);\n updateElementIds(hitElements); // Exit since we reached current point\n\n if (samplingInterval === distance) {\n break;\n } // Calculate next point in the line at a distance of sampling interval\n\n\n samplingInterval = Math.min(samplingInterval + threshold, distance);\n const distanceRatio = samplingInterval / distance;\n const nextX = (1 - distanceRatio) * point.x + distanceRatio * scenePointer.x;\n const nextY = (1 - distanceRatio) * point.y + distanceRatio * scenePointer.y;\n point.x = nextX;\n point.y = nextY;\n }\n\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n const id = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && idsToUpdate.includes(ele.containerId) ? ele.containerId : ele.id;\n\n if (idsToUpdate.includes(id)) {\n if (event.altKey) {\n if (pointerDownState.elementIdsToErase[id] && pointerDownState.elementIdsToErase[id].erase === false) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[id].opacity\n });\n }\n } else {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_READY_TO_ERASE_OPACITY\n });\n }\n }\n\n return ele;\n });\n this.scene.replaceAllElements(elements);\n pointerDownState.lastCoords.x = scenePointer.x;\n pointerDownState.lastCoords.y = scenePointer.y;\n }; // set touch moving for mobile context menu\n\n\n this.handleTouchMove = event => {\n invalidateContextMenu = true;\n };\n\n this.handleCanvasPointerDown = event => {\n var _a, _b; // since contextMenu options are potentially evaluated on each render,\n // and an contextMenu action may depend on selection state, we must\n // close the contextMenu before we update the selection on pointerDown\n // (e.g. resetting selection)\n\n\n if (this.state.contextMenu) {\n this.setState({\n contextMenu: null\n });\n }\n\n if (this.state.snapLines) {\n this.setAppState({\n snapLines: []\n });\n }\n\n this.updateGestureOnPointerDown(event); // if dragging element is freedraw and another pointerdown event occurs\n // a second finger is on the screen\n // discard the freedraw element if it is very short because it is likely\n // just a spike, otherwise finalize the freedraw element when the second\n // finger is lifted\n\n if (event.pointerType === \"touch\" && this.state.draggingElement && this.state.draggingElement.type === \"freedraw\") {\n const element = this.state.draggingElement;\n this.updateScene(Object.assign(Object.assign({}, element.points.length < 10 ? {\n elements: this.scene.getElementsIncludingDeleted().filter(el => el.id !== element.id)\n } : {}), {\n appState: {\n draggingElement: null,\n editingElement: null,\n startBoundElement: null,\n suggestedBindings: [],\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.keys(this.state.selectedElementIds).filter(key => key !== element.id).reduce((obj, key) => {\n obj[key] = this.state.selectedElementIds[key];\n return obj;\n }, {}), this.state)\n }\n }));\n return;\n } // remove any active selection when we start to interact with canvas\n // (mainly, we care about removing selection outside the component which\n // would prevent our copy handling otherwise)\n\n\n const selection = document.getSelection();\n\n if (selection === null || selection === void 0 ? void 0 : selection.anchorNode) {\n selection.removeAllRanges();\n }\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices(event);\n this.maybeCleanupAfterMissingPointerUp(event); //fires only once, if pen is detected, penMode is enabled\n //the user can disable this by toggling the penMode button\n\n if (!this.state.penDetected && event.pointerType === \"pen\") {\n this.setState(prevState => {\n return {\n penMode: true,\n penDetected: true\n };\n });\n }\n\n if (!this.device.isTouchScreen && [\"pen\", \"touch\"].includes(event.pointerType)) {\n this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(this.device, {\n isTouchScreen: true\n });\n }\n\n if (isPanning) {\n return;\n }\n\n this.lastPointerDownEvent = event; // we must exit before we set `cursorButton` state and `savePointer`\n // else it will send pointer state & laser pointer events in collab when\n // panning\n\n if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) {\n return;\n }\n\n this.setState({\n lastPointerDownWith: event.pointerType,\n cursorButton: \"down\"\n });\n this.savePointer(event.clientX, event.clientY, \"down\"); // only handle left mouse button or touch\n\n if (event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.TOUCH) {\n return;\n } // don't select while panning\n\n\n if (gesture.pointers.size > 1) {\n return;\n } // State for the duration of a pointer interaction, which starts with a\n // pointerDown event, ends with a pointerUp event (or another pointerDown)\n\n\n const pointerDownState = this.initialPointerDownState(event);\n this.setState({\n selectedElementsAreBeingDragged: false\n });\n\n if (this.handleDraggingScrollBar(event, pointerDownState)) {\n return;\n }\n\n this.clearSelectionIfNotUsingSelection();\n this.updateBindingEnabledOnPointerMove(event);\n\n if (this.handleSelectionOnPointerDown(event, pointerDownState)) {\n return;\n }\n\n const allowOnPointerDown = !this.state.penMode || event.pointerType !== \"touch\" || this.state.activeTool.type === \"selection\" || this.state.activeTool.type === \"text\" || this.state.activeTool.type === \"image\";\n\n if (!allowOnPointerDown) {\n return;\n }\n\n if (this.state.activeTool.type === \"text\") {\n this.handleTextOnPointerDown(event, pointerDownState);\n return;\n } else if (this.state.activeTool.type === \"arrow\" || this.state.activeTool.type === \"line\") {\n this.handleLinearElementOnPointerDown(event, this.state.activeTool.type, pointerDownState);\n } else if (this.state.activeTool.type === \"image\") {\n // reset image preview on pointerdown\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.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,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n } else if (this.state.activeTool.type === \"frame\") {\n this.createFrameElementOnPointerDown(pointerDownState);\n } else if (this.state.activeTool.type === \"laser\") {\n this.laserPathManager.startPath(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y);\n } else if (this.state.activeTool.type !== \"eraser\" && this.state.activeTool.type !== \"hand\") {\n this.createGenericElementOnPointerDown(this.state.activeTool.type, pointerDownState);\n }\n\n (_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.onPointerDown) === null || _b === void 0 ? void 0 : _b.call(_a, this.state.activeTool, pointerDownState);\n this.onPointerDownEmitter.trigger(this.state.activeTool, pointerDownState, event);\n const onPointerMove = this.onPointerMoveFromPointerDownHandler(pointerDownState);\n const onPointerUp = this.onPointerUpFromPointerDownHandler(pointerDownState);\n const onKeyDown = this.onKeyDownFromPointerDownHandler(pointerDownState);\n const onKeyUp = this.onKeyUpFromPointerDownHandler(pointerDownState);\n lastPointerUp = onPointerUp;\n\n if (!this.state.viewModeEnabled || this.state.activeTool.type === \"laser\") {\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, onKeyDown);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, onKeyUp);\n pointerDownState.eventListeners.onMove = onPointerMove;\n pointerDownState.eventListeners.onUp = onPointerUp;\n pointerDownState.eventListeners.onKeyUp = onKeyUp;\n pointerDownState.eventListeners.onKeyDown = onKeyDown;\n }\n };\n\n this.handleCanvasPointerUp = event => {\n var _a, _b;\n\n this.removePointer(event);\n this.lastPointerUpEvent = event;\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: event.clientX,\n clientY: event.clientY\n }, this.state);\n const clicklength = event.timeStamp - ((_b = (_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a.timeStamp) !== null && _b !== void 0 ? _b : 0);\n\n if (this.device.editor.isMobile && clicklength < 300) {\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, event, scenePointer.x, scenePointer.y)) {\n this.handleEmbeddableCenterClick(hitElement);\n return;\n }\n }\n\n if (this.device.isTouchScreen) {\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n this.hitLinkElement = this.getElementLinkAtPosition(scenePointer, hitElement);\n }\n\n if (this.hitLinkElement && !this.state.selectedElementIds[this.hitLinkElement.id]) {\n if (clicklength < 300 && this.hitLinkElement.type === \"embeddable\" && !(0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLinkIcon)(this.hitLinkElement, this.state, [scenePointer.x, scenePointer.y])) {\n this.handleEmbeddableCenterClick(this.hitLinkElement);\n } else {\n this.redirectToLink(event, this.device.isTouchScreen);\n }\n } else if (this.state.viewModeEnabled) {\n this.setState({\n activeEmbeddable: null,\n selectedElementIds: {}\n });\n }\n };\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices = event => {\n // deal with opening context menu on touch devices\n if (event.pointerType === \"touch\") {\n invalidateContextMenu = false;\n\n if (touchTimeout) {\n // If there's already a touchTimeout, this means that there's another\n // touch down and we are doing another touch, so we shouldn't open the\n // context menu.\n invalidateContextMenu = true;\n } else {\n // open the context menu with the first touch's clientX and clientY\n // if the touch is not moving\n touchTimeout = window.setTimeout(() => {\n touchTimeout = 0;\n\n if (!invalidateContextMenu) {\n this.handleCanvasContextMenu(event);\n }\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.TOUCH_CTX_MENU_TIMEOUT);\n }\n }\n };\n\n this.resetContextMenuTimer = () => {\n clearTimeout(touchTimeout);\n touchTimeout = 0;\n invalidateContextMenu = false;\n }; // Returns whether the event is a panning\n\n\n this.handleCanvasPanUsingWheelOrSpaceDrag = event => {\n if (!(gesture.pointers.size <= 1 && (event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.WHEEL || event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && isHoldingSpace || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state) || this.state.viewModeEnabled)) || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement)) {\n return false;\n }\n\n isPanning = true;\n event.preventDefault();\n let nextPastePrevented = false;\n const isLinux = /Linux/.test(window.navigator.platform);\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRABBING);\n let {\n clientX: lastX,\n clientY: lastY\n } = event;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const deltaX = lastX - event.clientX;\n const deltaY = lastY - event.clientY;\n lastX = event.clientX;\n lastY = event.clientY;\n /*\n * Prevent paste event if we move while middle clicking on Linux.\n * See issue #1383.\n */\n\n if (isLinux && !nextPastePrevented && (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1)) {\n nextPastePrevented = true;\n /* Prevent the next paste event */\n\n const preventNextPaste = event => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n event.stopPropagation();\n };\n /*\n * Reenable next paste in case of disabled middle click paste for\n * any reason:\n * - right click paste\n * - empty clipboard\n */\n\n\n const enableNextPaste = () => {\n setTimeout(() => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }, 100);\n };\n\n document.body.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }\n\n this.translateCanvas({\n scrollX: this.state.scrollX - deltaX / this.state.zoom.value,\n scrollY: this.state.scrollY - deltaY / this.state.zoom.value\n });\n });\n const teardown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(lastPointerUp = () => {\n lastPointerUp = null;\n isPanning = false;\n\n if (!isHoldingSpace) {\n if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.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,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n\n if (!this.state.activeTool.locked) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n };\n\n this.handleFreeDrawElementOnPointerDown = (event, elementType, pointerDownState) => {\n // Begin a mark capture. This does not have to update state yet.\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, null);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFreeDrawElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: null,\n simulatePressure: event.pressure === 0.5,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n const pressures = element.simulatePressure ? element.pressures : [...element.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [[0, 0]],\n pressures\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }; //create rectangle element with youtube top left on nearest grid point width / hight 640/360\n\n\n this.insertEmbeddableElement = ({\n sceneX,\n sceneY,\n link\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(link);\n\n if (!embedLink) {\n return;\n }\n\n if (embedLink.warning) {\n this.setToast({\n message: embedLink.warning,\n closable: true\n });\n }\n\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)({\n type: \"embeddable\",\n x: gridX,\n y: gridY,\n strokeColor: \"transparent\",\n backgroundColor: \"transparent\",\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n roundness: this.getCurrentItemRoundness(\"embeddable\"),\n opacity: this.state.currentItemOpacity,\n locked: false,\n width: embedLink.aspectRatio.w,\n height: embedLink.aspectRatio.h,\n link,\n validated: null\n });\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), element]);\n return element;\n };\n\n this.createImageElement = ({\n sceneX,\n sceneY\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const topLayerFrame = 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,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.\n If so, we want it to be null for start and \"arrow\" for end. If the linear item is not\n an arrow, we want it to be null for both. Otherwise, we want it to use the\n values from appState. */\n\n const {\n currentItemStartArrowhead,\n currentItemEndArrowhead\n } = this.state;\n const [startArrowhead, endArrowhead] = elementType === \"arrow\" ? [currentItemStartArrowhead, currentItemEndArrowhead] : [null, null];\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newLinearElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.state.currentItemRoundness === \"round\" ? {\n type: _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null,\n startArrowhead,\n endArrowhead,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [...element.points, [0, 0]]\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }\n };\n\n this.createGenericElementOnPointerDown = (elementType, pointerDownState) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const baseElementAttributes = {\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.getCurrentItemRoundness(elementType),\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n };\n let element;\n\n if (elementType === \"embeddable\") {\n element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)(Object.assign({\n type: \"embeddable\",\n validated: null\n }, baseElementAttributes));\n } else {\n element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newElement)(Object.assign({\n type: elementType\n }, baseElementAttributes));\n }\n\n if (element.type === \"selection\") {\n this.setState({\n selectionElement: element,\n draggingElement: element\n });\n } else {\n this.scene.addNewElement(element);\n this.setState({\n multiElement: null,\n draggingElement: element,\n editingElement: element\n });\n }\n };\n\n this.createFrameElementOnPointerDown = pointerDownState => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const frame = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFrameElement)(Object.assign({\n x: gridX,\n y: gridY,\n opacity: this.state.currentItemOpacity,\n locked: false\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE));\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), frame]);\n this.setState({\n multiElement: null,\n draggingElement: frame,\n editingElement: frame\n });\n };\n\n this.restoreReadyToEraseElements = pointerDownState => {\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n if (pointerDownState.elementIdsToErase[ele.id] && pointerDownState.elementIdsToErase[ele.id].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.id].opacity\n });\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && pointerDownState.elementIdsToErase[ele.containerId] && pointerDownState.elementIdsToErase[ele.containerId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.containerId].opacity\n });\n } else if (ele.frameId && pointerDownState.elementIdsToErase[ele.frameId] && pointerDownState.elementIdsToErase[ele.frameId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.frameId].opacity\n });\n }\n\n return ele;\n });\n this.scene.replaceAllElements(elements);\n };\n\n this.eraseElements = pointerDownState => {\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n if (pointerDownState.elementIdsToErase[ele.id] && pointerDownState.elementIdsToErase[ele.id].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && pointerDownState.elementIdsToErase[ele.containerId] && pointerDownState.elementIdsToErase[ele.containerId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n } else if (ele.frameId && pointerDownState.elementIdsToErase[ele.frameId] && pointerDownState.elementIdsToErase[ele.frameId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n }\n\n return ele;\n });\n this.history.resumeRecording();\n this.scene.replaceAllElements(elements);\n };\n\n this.initializeImage = ({\n imageFile,\n imageElement: _imageElement,\n showCursorImagePreview = false\n }) => __awaiter(this, void 0, void 0, function* () {\n var _e, _f, _g, _h; // at this point this should be guaranteed image file, but we do this check\n // to satisfy TS down the line\n\n\n if (!(0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(imageFile)) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.unsupportedFileType\"));\n }\n\n const mimeType = imageFile.type;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, \"wait\");\n\n if (mimeType === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n try {\n imageFile = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.normalizeSVG)(yield imageFile.text()), imageFile.name);\n } catch (error) {\n console.warn(error);\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.svgImageInsertError\"));\n }\n } // generate image id (by default the file digest) before any\n // resizing/compression takes place to keep it more portable\n\n\n const fileId = yield ((_f = (_e = this.props).generateIdForFile) === null || _f === void 0 ? void 0 : _f.call(_e, imageFile)) || (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.generateIdFromFile)(imageFile);\n\n if (!fileId) {\n console.warn(\"Couldn't generate file id or the supplied `generateIdForFile` didn't resolve to one.\");\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\"));\n }\n\n const existingFileData = this.files[fileId];\n\n if (!(existingFileData === null || existingFileData === void 0 ? void 0 : existingFileData.dataURL)) {\n try {\n imageFile = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT\n });\n } catch (error) {\n console.error(\"error trying to resing image file on insertion\", error);\n }\n\n if (imageFile.size > _constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES) {\n throw new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.fileTooBig\", {\n maxSize: `${Math.trunc(_constants__WEBPACK_IMPORTED_MODULE_12__.MAX_ALLOWED_FILE_BYTES / 1024 / 1024)}MB`\n }));\n }\n }\n\n if (showCursorImagePreview) {\n const dataURL = (_g = this.files[fileId]) === null || _g === void 0 ? void 0 : _g.dataURL; // optimization so that we don't unnecessarily resize the original\n // full-size file for cursor preview\n // (it's much faster to convert the resized dataURL to File)\n\n const resizedFile = dataURL && (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.dataURLToFile)(dataURL);\n this.setImagePreviewCursor(resizedFile || imageFile);\n }\n\n const dataURL = ((_h = this.files[fileId]) === null || _h === void 0 ? void 0 : _h.dataURL) || (yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imageFile));\n const imageElement = (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(_imageElement, {\n fileId\n }, false);\n return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {\n var _j;\n\n try {\n this.files = Object.assign(Object.assign({}, this.files), {\n [fileId]: {\n mimeType,\n id: fileId,\n dataURL,\n created: Date.now(),\n lastRetrieved: Date.now()\n }\n });\n const cachedImageData = this.imageCache.get(fileId);\n\n if (!cachedImageData) {\n this.addNewImagesToImageCache();\n yield this.updateImageCache([imageElement]);\n }\n\n if ((cachedImageData === null || cachedImageData === void 0 ? void 0 : cachedImageData.image) instanceof Promise) {\n yield cachedImageData.image;\n }\n\n if (this.state.pendingImageElementId !== imageElement.id && ((_j = this.state.draggingElement) === null || _j === void 0 ? void 0 : _j.id) !== imageElement.id) {\n this.initializeImageDimensions(imageElement, true);\n }\n\n resolve(imageElement);\n } catch (error) {\n console.error(error);\n reject(new Error((0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\")));\n } finally {\n if (!showCursorImagePreview) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.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 return yield this.initializeImage({\n imageFile,\n imageElement,\n showCursorImagePreview\n });\n } catch (error) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n isDeleted: true\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n this.setState({\n errorMessage: error.message || (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\")\n });\n return null;\n }\n });\n\n this.setImagePreviewCursor = imageFile => __awaiter(this, void 0, void 0, function* () {\n // mustn't be larger than 128 px\n // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Basic_User_Interface/Using_URL_values_for_the_cursor_property\n const cursorImageSizePx = 96;\n const imagePreview = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: cursorImageSizePx\n });\n let previewDataURL = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imagePreview); // SVG cannot be resized via `resizeImageFile` so we resize by rendering to\n // a small canvas\n\n if (imageFile.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n const img = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.loadHTMLImageElement)(previewDataURL);\n let height = Math.min(img.height, cursorImageSizePx);\n let width = height * (img.width / img.height);\n\n if (width > cursorImageSizePx) {\n width = cursorImageSizePx;\n height = width * (img.height / img.width);\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.height = height;\n canvas.width = width;\n const context = canvas.getContext(\"2d\");\n context.drawImage(img, 0, 0, width, height);\n previewDataURL = canvas.toDataURL(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg);\n }\n\n if (this.state.pendingImageElementId) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, `url(${previewDataURL}) 4 4, auto`);\n }\n });\n\n this.onImageAction = ({\n insertOnCanvasDirectly\n }) => __awaiter(this, void 0, void 0, function* () {\n try {\n const clientX = this.state.width / 2 + this.state.offsetLeft;\n const clientY = this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const imageFile = yield (0,_data_filesystem__WEBPACK_IMPORTED_MODULE_42__.fileOpen)({\n description: \"Image\",\n extensions: Object.keys(_constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_MIME_TYPES)\n });\n const imageElement = this.createImageElement({\n sceneX: x,\n sceneY: y\n });\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_65__.ShapeCache[\"delete\"](element);\n }\n }\n }\n\n if (erroredFiles.size) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().map(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && erroredFiles.has(element.fileId)) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(element, {\n status: \"error\"\n });\n }\n\n return element;\n }));\n }\n\n return {\n updatedFiles,\n erroredFiles\n };\n });\n /** adds new images to imageCache and re-renders if needed */\n\n\n this.addNewImagesToImageCache = (imageElements = (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.getInitializedImageElements)(this.scene.getNonDeletedElements()), files = this.files) => __awaiter(this, void 0, void 0, function* () {\n const uncachedImageElements = imageElements.filter(element => !element.isDeleted && !this.imageCache.has(element.fileId));\n\n if (uncachedImageElements.length) {\n const {\n updatedFiles\n } = yield this.updateImageCache(uncachedImageElements, files);\n\n if (updatedFiles.size) {\n this.scene.informMutation();\n }\n }\n });\n /** generally you should use `addNewImagesToImageCache()` directly if you need\n * to render new images. This is just a failsafe */\n\n\n this.scheduleImageRefresh = lodash_throttle__WEBPACK_IMPORTED_MODULE_41___default()(() => {\n this.addNewImagesToImageCache();\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_RENDER_TIMEOUT);\n\n this.updateBindingEnabledOnPointerMove = event => {\n const shouldEnableBinding = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.shouldEnableBindingForPointerEvent)(event);\n\n if (this.state.isBindingEnabled !== shouldEnableBinding) {\n this.setState({\n isBindingEnabled: shouldEnableBinding\n });\n }\n };\n\n this.maybeSuggestBindingAtCursor = pointerCoords => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerCoords, this.scene);\n this.setState({\n suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : []\n });\n };\n\n this.maybeSuggestBindingsForLinearElementAtCoords = (linearElement,\n /** scene coords */\n pointerCoords, // During line creation the start binding hasn't been written yet\n // into `linearElement`\n oppositeBindingBoundElement) => {\n if (!pointerCoords.length) {\n return;\n }\n\n const suggestedBindings = pointerCoords.reduce((acc, coords) => {\n const hoveredBindableElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(coords, this.scene);\n\n if (hoveredBindableElement != null && !(0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isLinearElementSimpleAndAlreadyBound)(linearElement, oppositeBindingBoundElement === null || oppositeBindingBoundElement === void 0 ? void 0 : oppositeBindingBoundElement.id, hoveredBindableElement)) {\n acc.push(hoveredBindableElement);\n }\n\n return acc;\n }, []);\n this.setState({\n suggestedBindings\n });\n };\n\n this.handleInteractiveCanvasRef = canvas => {\n var _a, _b, _c; // canvas is null when unmounting\n\n\n if (canvas !== null) {\n this.interactiveCanvas = canvas; // -----------------------------------------------------------------------\n // NOTE wheel, touchstart, touchend events must be registered outside\n // of react because react binds them them passively (so we can't prevent\n // default on them)\n\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n this.interactiveCanvas.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd); // -----------------------------------------------------------------------\n } else {\n (_a = this.interactiveCanvas) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.handleWheel);\n (_b = this.interactiveCanvas) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_START, this.onTouchStart);\n (_c = this.interactiveCanvas) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.TOUCH_END, this.onTouchEnd);\n }\n };\n\n this.handleAppOnDrop = event => __awaiter(this, void 0, void 0, function* () {\n var _k, _l, _m, _o; // must be retrieved first, in the same frame\n\n\n const {\n file,\n fileHandle\n } = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getFileFromEvent)(event);\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n try {\n if ((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 ((_l = (_k = event.dataTransfer) === null || _k === void 0 ? void 0 : _k.types) === null || _l === void 0 ? void 0 : _l.includes(\"text/plain\")) {\n const text = (_m = event.dataTransfer) === null || _m === void 0 ? void 0 : _m.getData(\"text\");\n\n if (text && (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(text, this.props.validateEmbeddable) && (/^(http|https):\\/\\/[^\\s/$.?#].[^\\s]*$/.test(text) || ((_o = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(text)) === null || _o === void 0 ? void 0 : _o.type) === \"video\")) {\n const embeddable = this.insertEmbeddableElement({\n sceneX,\n sceneY,\n link: (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(text)\n });\n\n if (embeddable) {\n this.setState({\n selectedElementIds: {\n [embeddable.id]: true\n }\n });\n }\n }\n }\n });\n\n this.loadFileToCanvas = (file, fileHandle) => __awaiter(this, void 0, void 0, function* () {\n file = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.normalizeFile)(file);\n\n try {\n const ret = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.loadSceneOrLibraryFromBlob)(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);\n\n if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidraw) {\n this.setState({\n isLoading: true\n });\n this.syncActionResult(Object.assign(Object.assign({}, ret.data), {\n appState: Object.assign(Object.assign({}, ret.data.appState || this.state), {\n isLoading: false\n }),\n replaceFiles: true,\n commitToHistory: true\n }));\n } else if (ret.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.excalidrawlib) {\n yield this.library.updateLibrary({\n libraryItems: file,\n merge: true,\n openLibraryMenu: true\n }).catch(error => {\n console.error(error);\n this.setState({\n errorMessage: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.importLibraryError\")\n });\n });\n }\n } catch (error) {\n this.setState({\n isLoading: false,\n errorMessage: error.message\n });\n }\n });\n\n this.handleCanvasContextMenu = event => {\n event.preventDefault();\n\n if ((\"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"touch\" || \"pointerType\" in event.nativeEvent && event.nativeEvent.pointerType === \"pen\" && // always allow if user uses a pen secondary button\n event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.SECONDARY) && this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const element = this.getElementAtPosition(x, y, {\n preferSelected: true,\n includeLockedElements: true\n });\n const selectedElements = this.scene.getSelectedElements(this.state);\n const isHittignCommonBoundBox = this.isHittingCommonBoundingBoxOfSelectedElements({\n x,\n y\n }, selectedElements);\n const type = element || isHittignCommonBoundBox ? \"element\" : \"canvas\";\n const container = this.excalidrawContainerRef.current;\n const {\n top: offsetTop,\n left: offsetLeft\n } = container.getBoundingClientRect();\n const left = event.clientX - offsetLeft;\n const top = event.clientY - offsetTop;\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"contextMenu\", \"openContextMenu\", type);\n this.setState(Object.assign(Object.assign({}, element && !this.state.selectedElementIds[element.id] ? Object.assign(Object.assign(Object.assign({}, this.state), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: this.state.editingGroupId,\n selectedElementIds: {\n [element.id]: true\n }\n }, this.scene.getNonDeletedElements(), this.state, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(element) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(element, this.scene) : null\n }) : this.state), {\n showHyperlinkPopup: false\n }), () => {\n this.setState({\n contextMenu: {\n top,\n left,\n items: this.getContextMenuItems(type)\n }\n });\n });\n };\n\n this.maybeDragNewGenericElement = (pointerDownState, event) => {\n var _a, _b, _c, _d, _e;\n\n const draggingElement = this.state.draggingElement;\n const pointerCoords = pointerDownState.lastCoords;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"selection\" && this.state.activeTool.type !== \"eraser\") {\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.origin.x, pointerDownState.origin.y, pointerCoords.x, pointerCoords.y, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.x, pointerCoords.x), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.y, pointerCoords.y), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event));\n } else {\n let [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const image = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(draggingElement) && ((_a = this.imageCache.get(draggingElement.fileId)) === null || _a === void 0 ? void 0 : _a.image);\n const aspectRatio = image && !(image instanceof Promise) ? image.width / image.height : null;\n this.maybeCacheReferenceSnapPoints(event, [draggingElement]);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.snapNewElement)(draggingElement, this.state, event, {\n x: pointerDownState.originInGrid.x + ((_c = (_b = this.state.originSnapOffset) === null || _b === void 0 ? void 0 : _b.x) !== null && _c !== void 0 ? _c : 0),\n y: pointerDownState.originInGrid.y + ((_e = (_d = this.state.originSnapOffset) === null || _d === void 0 ? void 0 : _d.y) !== null && _e !== void 0 ? _e : 0)\n }, {\n x: gridX - pointerDownState.originInGrid.x,\n y: gridY - pointerDownState.originInGrid.y\n });\n gridX += snapOffset.x;\n gridY += snapOffset.y;\n this.setState({\n snapLines\n });\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.originInGrid.x, pointerDownState.originInGrid.y, gridX, gridY, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.x, gridX), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.y, gridY), (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), aspectRatio, this.state.originSnapOffset);\n this.maybeSuggestBindingForAll([draggingElement]); // highlight elements that are to be added to frames on frames creation\n\n if (this.state.activeTool.type === \"frame\") {\n this.setState({\n elementsToHighlight: (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), draggingElement, this.state)\n });\n }\n }\n };\n\n this.maybeHandleResize = (pointerDownState, event) => {\n const selectedElements = this.scene.getSelectedElements(this.state);\n const selectedFrames = selectedElements.filter(element => element.type === \"frame\");\n const transformHandleType = pointerDownState.resize.handleType;\n\n if (selectedFrames.length > 0 && transformHandleType === \"rotation\") {\n return false;\n }\n\n this.setState({\n // TODO: rename this state field to \"isScaling\" to distinguish\n // it from the generic \"isResizing\" which includes scaling and\n // rotating\n isResizing: transformHandleType && transformHandleType !== \"rotation\",\n isRotating: transformHandleType === \"rotation\",\n activeEmbeddable: null\n });\n const pointerCoords = pointerDownState.lastCoords;\n let [resizeX, resizeY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x - pointerDownState.resize.offset.x, pointerCoords.y - pointerDownState.resize.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const frameElementsOffsetsMap = new Map();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getFrameElements)(this.scene.getNonDeletedElements(), frame.id);\n elementsInFrame.forEach(element => {\n frameElementsOffsetsMap.set(frame.id + element.id, {\n x: element.x - frame.x,\n y: element.y - frame.y\n });\n });\n }); // check needed for avoiding flickering when a key gets pressed\n // during dragging\n\n if (!this.state.selectedElementsAreBeingDragged) {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const dragOffset = {\n x: gridX - pointerDownState.originInGrid.x,\n y: gridY - pointerDownState.originInGrid.y\n };\n const originalElements = [...pointerDownState.originalElements.values()];\n this.maybeCacheReferenceSnapPoints(event, selectedElements);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.snapResizingElements)(selectedElements, (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(originalElements, this.state), this.state, event, dragOffset, transformHandleType);\n resizeX += snapOffset.x;\n resizeY += snapOffset.y;\n this.setState({\n snapLines\n });\n }\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.transformElements)(pointerDownState, transformHandleType, selectedElements, pointerDownState.resize.arrowDirection, (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(selectedElements[0]) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y, this.state)) {\n this.maybeSuggestBindingForAll(selectedElements);\n const elementsToHighlight = new Set();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.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__.actionToggleObjectsSnapMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n } // element contextMenu\n // -------------------------------------------------------------------------\n\n\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.copyText);\n\n if (this.state.viewModeEnabled) {\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, ...options];\n }\n\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionSelectAllElementsInFrame, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionRemoveAllElementsFromFrame, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, ...options, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyStyles, _actions__WEBPACK_IMPORTED_MODULE_5__.actionPasteStyles, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionGroup, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUnbindText, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBindText, _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_58__.actionWrapTextInContainer, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUngroup, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionAddToLibrary, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendBackward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringForward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendToBack, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringToFront, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipHorizontal, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipVertical, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleLinearEditor, _actions__WEBPACK_IMPORTED_MODULE_5__.actionLink, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDuplicateSelection, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleElementLock, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDeleteSelected];\n };\n\n this.handleWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault();\n\n if (isPanning) {\n return;\n }\n\n const {\n deltaX,\n deltaY\n } = event; // note that event.ctrlKey is necessary to handle pinch zooming\n\n if (event.metaKey || event.ctrlKey) {\n const sign = Math.sign(deltaY);\n const MAX_STEP = _constants__WEBPACK_IMPORTED_MODULE_12__.ZOOM_STEP * 100;\n const absDelta = Math.abs(deltaY);\n let delta = deltaY;\n\n if (absDelta > MAX_STEP) {\n delta = MAX_STEP * sign;\n }\n\n let newZoom = this.state.zoom.value - delta / 100; // increase zoom steps the more zoomed-in we are (applies to >100% only)\n\n newZoom += Math.log10(Math.max(1, this.state.zoom.value)) * -sign * // reduced amplification for small deltas (small movements on a trackpad)\n Math.min(1, absDelta / 20);\n this.translateCanvas(state => Object.assign(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(newZoom)\n }, state)), {\n shouldCacheIgnoreZoom: true\n }));\n this.resetShouldCacheIgnoreZoomDebounced();\n return;\n } // scroll horizontally when shift pressed\n\n\n if (event.shiftKey) {\n this.translateCanvas(({\n zoom,\n scrollX\n }) => ({\n // on Mac, shift+wheel tends to result in deltaX\n scrollX: scrollX - (deltaY || deltaX) / zoom.value\n }));\n return;\n }\n\n this.translateCanvas(({\n zoom,\n scrollX,\n scrollY\n }) => ({\n scrollX: scrollX - deltaX / zoom.value,\n scrollY: scrollY - deltaY / zoom.value\n }));\n });\n\n this.savePointer = (x, y, button) => {\n var _a, _b;\n\n if (!x || !y) {\n return;\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: x,\n clientY: y\n }, this.state);\n\n if (isNaN(sceneX) || isNaN(sceneY)) {// sometimes the pointer goes off screen\n }\n\n const pointer = {\n x: sceneX,\n y: sceneY,\n tool: this.state.activeTool.type === \"laser\" ? \"laser\" : \"pointer\"\n };\n (_b = (_a = this.props).onPointerUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, {\n pointer,\n button,\n pointersMap: gesture.pointers\n });\n };\n\n this.resetShouldCacheIgnoreZoomDebounced = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n if (!this.unmounted) {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n }\n }, 300);\n\n this.updateDOMRect = cb => {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n width,\n height,\n left: offsetLeft,\n top: offsetTop\n } = excalidrawContainer.getBoundingClientRect();\n const {\n width: currentWidth,\n height: currentHeight,\n offsetTop: currentOffsetTop,\n offsetLeft: currentOffsetLeft\n } = this.state;\n\n if (width === currentWidth && height === currentHeight && offsetLeft === currentOffsetLeft && offsetTop === currentOffsetTop) {\n if (cb) {\n cb();\n }\n\n return;\n }\n\n this.setState({\n width,\n height,\n offsetLeft,\n offsetTop\n }, () => {\n cb && cb();\n });\n }\n };\n\n this.refresh = () => {\n this.setState(Object.assign({}, this.getCanvasOffsets()));\n };\n\n const defaultAppState = (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)();\n const {\n excalidrawAPI,\n viewModeEnabled = false,\n zenModeEnabled = false,\n gridModeEnabled = false,\n objectsSnapModeEnabled = false,\n theme = defaultAppState.theme,\n name = defaultAppState.name\n } = props;\n this.state = Object.assign(Object.assign(Object.assign(Object.assign({}, defaultAppState), {\n theme,\n isLoading: true\n }), this.getCanvasOffsets()), {\n viewModeEnabled,\n zenModeEnabled,\n objectsSnapModeEnabled,\n gridSize: gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null,\n name,\n width: window.innerWidth,\n height: window.innerHeight\n });\n this.id = (0,nanoid__WEBPACK_IMPORTED_MODULE_71__.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_64__.Renderer(this.scene);\n\n if (excalidrawAPI) {\n const 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 onChange: cb => this.onChangeEmitter.on(cb),\n onPointerDown: cb => this.onPointerDownEmitter.on(cb),\n onPointerUp: cb => this.onPointerUpEmitter.on(cb)\n };\n\n if (typeof excalidrawAPI === \"function\") {\n excalidrawAPI(api);\n } else {\n console.error(\"excalidrawAPI should be a function!\");\n }\n\n 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.editor.isMobile\n }),\n style: {\n [\"--ui-pointerEvents\"]: this.state.selectionElement || this.state.draggingElement || this.state.resizingElement || this.state.activeTool.type === \"laser\" && // technically we can just test on this once we make it more safe\n this.state.cursorButton === \"down\" || this.state.editingElement && !(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled\n },\n ref: this.excalidrawContainerRef,\n onDrop: this.handleAppOnDrop,\n tabIndex: 0,\n onKeyDown: this.props.handleKeyboardGlobally ? undefined : this.onKeyDown\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AppContext.Provider, Object.assign({\n value: this\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AppPropsContext.Provider, Object.assign({\n value: this.props\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawContainerContext.Provider, Object.assign({\n value: this.excalidrawContainerValue\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(DeviceContext.Provider, Object.assign({\n value: this.device\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawSetAppStateContext.Provider, Object.assign({\n value: this.setAppState\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawAppStateContext.Provider, Object.assign({\n value: this.state\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(ExcalidrawElementsContext.Provider, Object.assign({\n value: this.scene.getNonDeletedElements()\n }, {\n children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(ExcalidrawActionManagerContext.Provider, Object.assign({\n value: this.actionManager\n }, {\n children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_LayerUI__WEBPACK_IMPORTED_MODULE_36__[\"default\"], Object.assign({\n canvas: this.canvas,\n appState: this.state,\n files: this.files,\n setAppState: this.setAppState,\n actionManager: this.actionManager,\n elements: this.scene.getNonDeletedElements(),\n onLockToggle: this.toggleLock,\n onPenModeToggle: this.togglePenMode,\n onHandToolToggle: this.onHandToolToggle,\n langCode: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.getLanguage)().code,\n renderTopRightUI: renderTopRightUI,\n renderCustomStats: renderCustomStats,\n showExitZenModeBtn: typeof ((_a = this.props) === null || _a === void 0 ? void 0 : _a.zenModeEnabled) === \"undefined\" && this.state.zenModeEnabled,\n UIOptions: this.props.UIOptions,\n onExportImage: this.onExportImage,\n renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === \"selection\" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,\n app: this,\n isCollaborating: this.props.isCollaborating\n }, {\n children: [this.props.children, this.state.openDialog === \"mermaid\" && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_MermaidToExcalidraw__WEBPACK_IMPORTED_MODULE_66__[\"default\"], {})]\n })), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-textEditorContainer\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-contextMenuContainer\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-eye-dropper-container\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_LaserTool_LaserTool__WEBPACK_IMPORTED_MODULE_67__.LaserToolOverlay, {\n manager: this.laserPathManager\n }), selectedElements.length === 1 && !this.state.contextMenu && this.state.showHyperlinkPopup && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.Hyperlink, {\n element: selectedElements[0],\n setAppState: this.setAppState,\n onLinkOpen: this.props.onLinkOpen,\n setToast: this.setToast\n }, selectedElements[0].id), this.state.toast !== null && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_Toast__WEBPACK_IMPORTED_MODULE_37__.Toast, {\n message: this.state.toast.message,\n onClose: () => this.setToast(null),\n duration: this.state.toast.duration,\n closable: this.state.toast.closable\n }), this.state.contextMenu && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_ContextMenu__WEBPACK_IMPORTED_MODULE_35__.ContextMenu, {\n items: this.state.contextMenu.items,\n top: this.state.contextMenu.top,\n left: this.state.contextMenu.left,\n actionManager: this.actionManager,\n onClose: callback => {\n this.setState({\n contextMenu: null\n }, () => {\n this.focusContainer();\n callback === null || callback === void 0 ? void 0 : callback();\n });\n }\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_63__.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_63__.InteractiveCanvas, {\n containerRef: this.excalidrawContainerRef,\n canvas: this.interactiveCanvas,\n elements: canvasElements,\n visibleElements: visibleElements,\n selectedElements: selectedElements,\n versionNonce: versionNonce,\n selectionNonce: (_c = this.state.selectionElement) === null || _c === void 0 ? void 0 : _c.versionNonce,\n scale: window.devicePixelRatio,\n appState: this.state,\n renderInteractiveSceneCallback: this.renderInteractiveSceneCallback,\n handleCanvasRef: this.handleInteractiveCanvasRef,\n onContextMenu: this.handleCanvasContextMenu,\n onPointerMove: this.handleCanvasPointerMove,\n onPointerUp: this.handleCanvasPointerUp,\n onPointerCancel: this.removePointer,\n onTouchMove: this.handleTouchMove,\n onPointerDown: this.handleCanvasPointerDown,\n onDoubleClick: this.handleCanvasDoubleClick\n }), this.renderFrameNames()]\n })), this.renderEmbeddables()]\n }))\n }))\n }))\n }))\n }))\n }))\n }))\n }));\n }\n\n componentDidMount() {\n var _a;\n\n return __awaiter(this, void 0, void 0, function* () {\n this.unmounted = false;\n this.excalidrawContainerValue.container = this.excalidrawContainerRef.current;\n\n if (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n const setState = this.setState.bind(this);\n Object.defineProperties(window.h, {\n state: {\n configurable: true,\n get: () => {\n return this.state;\n }\n },\n setState: {\n configurable: true,\n value: (...args) => {\n return this.setState(...args);\n }\n },\n app: {\n configurable: true,\n value: this\n },\n history: {\n configurable: true,\n value: this.history\n }\n });\n }\n\n this.scene.addCallback(this.onSceneUpdated);\n this.addEventListeners();\n\n if (this.props.autoFocus && this.excalidrawContainerRef.current) {\n this.focusContainer();\n }\n\n if ( // bounding rects don't work in tests so updating\n // the state on init would result in making the test enviro run\n // in mobile breakpoint (0 width/height), making everything fail\n !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTestEnv)()) {\n this.refreshViewportBreakpoints();\n this.refreshEditorBreakpoints();\n }\n\n if (supportsResizeObserver && this.excalidrawContainerRef.current) {\n this.resizeObserver = new ResizeObserver(() => {\n this.refreshEditorBreakpoints();\n this.updateDOMRect();\n });\n (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(this.excalidrawContainerRef.current);\n }\n\n const searchParams = new URLSearchParams(window.location.search.slice(1));\n\n if (searchParams.has(\"web-share-target\")) {\n // Obtain a file that was shared via the Web Share Target API.\n this.restoreFileFromShare();\n } else {\n this.updateDOMRect(this.initializeScene);\n } // note that this check seems to always pass in localhost\n\n\n if ((0,_constants__WEBPACK_IMPORTED_MODULE_12__.isBrave)() && !(0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isMeasureTextSupported)()) {\n this.setState({\n errorMessage: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_59__[\"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_64__.Renderer(this.scene);\n this.files = {};\n this.imageCache.clear();\n (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();\n this.unmounted = true;\n this.removeEventListeners();\n this.scene.destroy();\n this.library.destroy();\n this.laserPathManager.destroy();\n this.onChangeEmitter.destroy();\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__.ShapeCache.destroy();\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.destroy();\n clearTimeout(touchTimeout);\n _scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected.clearCache();\n _groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements.clearCache();\n touchTimeout = 0;\n }\n\n removeEventListeners() {\n var _a, _b, _c, _d;\n\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel);\n (_b = this.nearestScrollableContainer) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MESSAGE, this.onWindowMessage, false);\n }\n\n addEventListeners() {\n var _a, _b, _c, _d, _e;\n\n this.removeEventListeners();\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MESSAGE, this.onWindowMessage, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer); // #3553\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel, {\n passive: false\n });\n\n if (this.props.handleKeyboardGlobally) {\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp, {\n passive: true\n });\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition); // rerender text elements on font load to fix #637 && #1553\n\n (_c = (_b = document.fonts) === null || _b === void 0 ? void 0 : _b.addEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, \"loadingdone\", event => {\n const loadedFontFaces = event.fontfaces;\n this.fonts.onFontsLoaded(loadedFontFaces);\n }); // Safari-only desktop pinch zoom\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n\n if (this.props.detectScroll) {\n this.nearestScrollableContainer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getNearestScrollableContainer)(this.excalidrawContainerRef.current);\n this.nearestScrollableContainer.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n }\n\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_e = this.excalidrawContainerRef.current) === null || _e === void 0 ? void 0 : _e.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n }\n\n componentDidUpdate(prevProps, prevState) {\n var _a, _b, _c, _d, _e, _f;\n\n this.updateEmbeddables();\n\n if (!this.state.showWelcomeScreen && !this.scene.getElementsIncludingDeleted().length) {\n this.setState({\n showWelcomeScreen: true\n });\n }\n\n if (prevProps.UIOptions.dockedSidebarBreakpoint !== this.props.UIOptions.dockedSidebarBreakpoint) {\n this.refreshEditorBreakpoints();\n }\n\n if (prevState.scrollX !== this.state.scrollX || prevState.scrollY !== this.state.scrollY) {\n (_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.onScrollChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.state.scrollX, this.state.scrollY);\n }\n\n if (Object.keys(this.state.selectedElementIds).length && (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n\n if (this.state.activeTool.type === \"eraser\" && prevState.theme !== this.state.theme) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setEraserCursor)(this.interactiveCanvas, this.state.theme);\n } // Hide hyperlink popup if shown when element type is not selection\n\n\n if (prevState.activeTool.type === \"selection\" && this.state.activeTool.type !== \"selection\" && this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: false\n });\n }\n\n if (prevProps.langCode !== this.props.langCode) {\n this.updateLanguage();\n }\n\n if (prevProps.viewModeEnabled !== this.props.viewModeEnabled) {\n this.setState({\n viewModeEnabled: !!this.props.viewModeEnabled\n });\n }\n\n if (prevState.viewModeEnabled !== this.state.viewModeEnabled) {\n this.addEventListeners();\n this.deselectElements();\n }\n\n if (prevProps.zenModeEnabled !== this.props.zenModeEnabled) {\n this.setState({\n zenModeEnabled: !!this.props.zenModeEnabled\n });\n }\n\n if (prevProps.theme !== this.props.theme && this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {\n this.setState({\n gridSize: this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null\n });\n }\n\n if (this.props.name && prevProps.name !== this.props.name) {\n this.setState({\n name: this.props.name\n });\n }\n\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.classList.toggle(\"theme--dark\", this.state.theme === \"dark\");\n\n if (this.state.editingLinearElement && !this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {\n // defer so that the commitToHistory flag isn't reset via current update\n setTimeout(() => {\n // execute only if the condition still holds when the deferred callback\n // executes (it can be scheduled multiple times depending on how\n // many times the component renders)\n this.state.editingLinearElement && this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } // failsafe in case the state is being updated in incorrect order resulting\n // in the editingElement being now a deleted element\n\n\n if ((_d = this.state.editingElement) === null || _d === void 0 ? void 0 : _d.isDeleted) {\n this.setState({\n editingElement: null\n });\n }\n\n if (this.state.selectedLinearElement && !this.state.selectedElementIds[this.state.selectedLinearElement.elementId]) {\n // To make sure `selectedLinearElement` is in sync with `selectedElementIds`, however this shouldn't be needed once\n // we have a single API to update `selectedElementIds`\n this.setState({\n selectedLinearElement: null\n });\n }\n\n const {\n multiElement\n } = prevState;\n\n if (prevState.activeTool !== this.state.activeTool && multiElement != null && (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(multiElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(multiElement, this.state, this.scene, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)(_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1)));\n }\n\n this.history.record(this.state, this.scene.getElementsIncludingDeleted()); // Do not notify consumers if we're still loading the scene. Among other\n // potential issues, this fixes a case where the tab isn't focused during\n // init, which would trigger onChange with empty elements, which would then\n // override whatever is in localStorage currently.\n\n if (!this.state.isLoading) {\n (_f = (_e = this.props).onChange) === null || _f === void 0 ? void 0 : _f.call(_e, this.scene.getElementsIncludingDeleted(), this.state, this.files);\n this.onChangeEmitter.trigger(this.scene.getElementsIncludingDeleted(), this.state, this.files);\n }\n }\n\n static resetTapTwice() {\n didTapTwice = false;\n } // TODO rewrite this to paste both text & images at the same time if\n // pasted data contains both\n\n\n addElementsFromMixedContentPaste(mixedContent, {\n isPlainPaste,\n sceneX,\n sceneY\n }) {\n return __awaiter(this, void 0, void 0, function* () {\n if (!isPlainPaste && mixedContent.some(node => node.type === \"imageUrl\")) {\n const imageURLs = mixedContent.filter(node => node.type === \"imageUrl\").map(node => node.value);\n const responses = yield Promise.all(imageURLs.map(url => __awaiter(this, void 0, void 0, function* () {\n try {\n return {\n file: yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.ImageURLToFile)(url)\n };\n } catch (error) {\n return {\n errorMessage: error.message\n };\n }\n })));\n let y = sceneY;\n let firstImageYOffsetDone = false;\n const nextSelectedIds = {};\n\n for (const response of responses) {\n if (response.file) {\n const imageElement = this.createImageElement({\n sceneX,\n sceneY: y\n });\n const initializedImageElement = yield this.insertImageElement(imageElement, response.file);\n\n if (initializedImageElement) {\n // vertically center first image in the batch\n if (!firstImageYOffsetDone) {\n firstImageYOffsetDone = true;\n y -= initializedImageElement.height / 2;\n } // hack to reset the `y` coord because we vertically center during\n // insertImageElement\n\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(initializedImageElement, {\n y\n }, false);\n y = imageElement.y + imageElement.height + 25;\n nextSelectedIds[imageElement.id] = true;\n }\n }\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedIds, this.state)\n });\n const error = responses.find(response => !!response.errorMessage);\n\n if (error && error.errorMessage) {\n this.setState({\n errorMessage: error.errorMessage\n });\n }\n } else {\n const textNodes = mixedContent.filter(node => node.type === \"text\");\n\n if (textNodes.length) {\n this.addTextFromPaste(textNodes.map(node => node.value).join(\"\\n\\n\"), isPlainPaste);\n }\n }\n });\n }\n\n addTextFromPaste(text, isPlainPaste = false) {\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state);\n const textElementProps = {\n x,\n y,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roundness: null,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text,\n fontSize: this.state.currentItemFontSize,\n fontFamily: this.state.currentItemFontFamily,\n textAlign: this.state.currentItemTextAlign,\n verticalAlign: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n locked: false\n };\n const LINE_GAP = 10;\n let currentY = y;\n const lines = isPlainPaste ? [text] : text.split(\"\\n\");\n const textElements = lines.reduce((acc, line, idx) => {\n var _a;\n\n const text = line.trim();\n const lineHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(textElementProps.fontFamily);\n\n if (text.length) {\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x,\n y: currentY\n });\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)(Object.assign(Object.assign({}, textElementProps), {\n x,\n y: currentY,\n text,\n lineHeight,\n frameId: topLayerFrame ? topLayerFrame.id : null\n }));\n acc.push(element);\n currentY += element.height + LINE_GAP;\n } else {\n const prevLine = (_a = lines[idx - 1]) === null || _a === void 0 ? void 0 : _a.trim(); // add paragraph only if previous line was not empty, IOW don't add\n // more than one empty line\n\n if (prevLine) {\n currentY += (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getLineHeightInPx)(textElementProps.fontSize, lineHeight) + LINE_GAP;\n }\n }\n\n return acc;\n }, []);\n\n if (textElements.length === 0) {\n return;\n }\n\n const frameId = textElements[0].frameId;\n\n if (frameId) {\n this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));\n } else {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), ...textElements]);\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.fromEntries(textElements.map(el => [el.id, true])), this.state)\n });\n\n if (!isPlainPaste && textElements.length > 1 && PLAIN_PASTE_TOAST_SHOWN === false && !this.device.editor.isMobile) {\n this.setToast({\n message: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"toast.pasteAsSingleElement\", {\n shortcut: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getShortcutKey)(\"CtrlOrCmd+Shift+V\")\n }),\n duration: 5000\n });\n PLAIN_PASTE_TOAST_SHOWN = true;\n }\n\n this.history.resumeRecording();\n }\n\n handleTextWysiwyg(element, {\n isExistingElement = false\n }) {\n const updateElement = (text, originalText, isDeleted) => {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted().map(_element => {\n if (_element.id === element.id && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(_element)) {\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.updateTextElement)(_element, {\n text,\n isDeleted,\n originalText\n });\n }\n\n return _element;\n })]);\n };\n\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.textWysiwyg)({\n id: element.id,\n canvas: this.canvas,\n getViewportCoords: (x, y) => {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: x,\n sceneY: y\n }, this.state);\n return [viewportX - this.state.offsetLeft, viewportY - this.state.offsetTop];\n },\n onChange: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(text => {\n updateElement(text, text, false);\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element);\n }\n }),\n onSubmit: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(({\n text,\n viaKeyboard,\n originalText\n }) => {\n const isDeleted = !text.trim();\n updateElement(text, originalText, isDeleted); // select the created text element only if submitting via keyboard\n // (when submitting via click it should act as signal to deselect)\n\n if (!isDeleted && viaKeyboard) {\n const elementIdToSelect = element.containerId ? element.containerId : element.id;\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [elementIdToSelect]: true\n }), prevState)\n }));\n }\n\n if (isDeleted) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDeletion)(this.scene.getNonDeletedElements(), [element]);\n }\n\n if (!isDeleted || isExistingElement) {\n this.history.resumeRecording();\n }\n\n this.setState({\n draggingElement: null,\n editingElement: null\n });\n\n if (this.state.activeTool.locked) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n this.focusContainer();\n }),\n element,\n excalidrawContainer: this.excalidrawContainerRef.current,\n app: this\n }); // deselect all other elements when inserting text\n\n this.deselectElements(); // do an initial update to re-initialize element position since we were\n // modifying element's x/y for sake of editor (case: syncing to remote)\n\n updateElement(element.text, element.originalText, false);\n }\n\n deselectElements() {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n getTextElementAtPosition(x, y) {\n const element = this.getElementAtPosition(x, y, {\n includeBoundTextElement: true\n });\n\n if (element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && !element.isDeleted) {\n return element;\n }\n\n return null;\n }\n\n getElementAtPosition(x, y, opts) {\n const allHitElements = this.getElementsAtPosition(x, y, opts === null || opts === void 0 ? void 0 : opts.includeBoundTextElement, opts === null || opts === void 0 ? void 0 : opts.includeLockedElements);\n\n if (allHitElements.length > 1) {\n if (opts === null || opts === void 0 ? void 0 : opts.preferSelected) {\n for (let index = allHitElements.length - 1; index > -1; index--) {\n if (this.state.selectedElementIds[allHitElements[index].id]) {\n return allHitElements[index];\n }\n }\n }\n\n const elementWithHighestZIndex = allHitElements[allHitElements.length - 1]; // If we're hitting element with highest z-index only on its bounding box\n // while also hitting other element figure, the latter should be considered.\n\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(elementWithHighestZIndex, this.state, this.frameNameBoundsCache, x, y) ? allHitElements[allHitElements.length - 2] : elementWithHighestZIndex;\n }\n\n if (allHitElements.length === 1) {\n return allHitElements[0];\n }\n\n return null;\n }\n\n getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {\n const elements = includeBoundTextElement && includeLockedElements ? this.scene.getNonDeletedElements() : this.scene.getNonDeletedElements().filter(element => (includeLockedElements || !element.locked) && (includeBoundTextElement || !((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && element.containerId)));\n return (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsAtPosition)(elements, element => (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(element, this.state, this.frameNameBoundsCache, x, y)).filter(element => {\n // hitting a frame's element from outside the frame is not considered a hit\n const containingFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(element);\n return containingFrame && this.state.frameRendering.enabled && this.state.frameRendering.clip ? (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)({\n x,\n y\n }, containingFrame) : true;\n });\n }\n\n handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {\n const element = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getElement(linearElementEditor.elementId);\n const boundTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(element);\n\n if (!element) {\n return;\n }\n\n if (this.state.selectedLinearElement) {\n let hoverPointIndex = -1;\n let segmentMidPointHoveredCoords = null;\n\n if ((0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(element, this.state, this.frameNameBoundsCache, [scenePointerX, scenePointerY])) {\n hoverPointIndex = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointIndexUnderCursor(element, this.state.zoom, scenePointerX, scenePointerY);\n segmentMidPointHoveredCoords = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, {\n x: scenePointerX,\n y: scenePointerY\n }, this.state);\n\n if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n } else if ((0,_element_transformHandles__WEBPACK_IMPORTED_MODULE_47__.shouldShowBoundingBox)([element], this.state) && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n } else if (boundTextElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(boundTextElement, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n\n if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n hoverPointIndex\n })\n });\n }\n\n if (!_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.arePointsEqual(this.state.selectedLinearElement.segmentMidPointHoveredCoords, segmentMidPointHoveredCoords)) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n segmentMidPointHoveredCoords\n })\n });\n }\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n\n maybeCleanupAfterMissingPointerUp(event) {\n if (lastPointerUp !== null) {\n // Unfortunately, sometimes we don't get a pointerup after a pointerdown,\n // this can happen when a contextual menu or alert is triggered. In order to avoid\n // being in a weird state, we clean up on the next pointerdown\n lastPointerUp(event);\n }\n }\n\n updateGestureOnPointerDown(event) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n\n if (gesture.pointers.size === 2) {\n gesture.lastCenter = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n gesture.initialScale = this.state.zoom.value;\n gesture.initialDistance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n }\n }\n\n initialPointerDownState(event) {\n const origin = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedElements = this.scene.getSelectedElements(this.state);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return {\n origin,\n withCmdOrCtrl: event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD],\n originInGrid: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(origin.x, origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize)),\n scrollbars: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop),\n // we need to duplicate because we'll be updating this state\n lastCoords: Object.assign({}, origin),\n originalElements: this.scene.getNonDeletedElements().reduce((acc, element) => {\n acc.set(element.id, (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.deepCopyElement)(element));\n return acc;\n }, new Map()),\n resize: {\n handleType: false,\n isResizing: false,\n offset: {\n x: 0,\n y: 0\n },\n arrowDirection: \"origin\",\n center: {\n x: (maxX + minX) / 2,\n y: (maxY + minY) / 2\n }\n },\n hit: {\n element: null,\n allHitElements: [],\n wasAddedToSelection: false,\n hasBeenDuplicated: false,\n hasHitCommonBoundingBoxOfSelectedElements: this.isHittingCommonBoundingBoxOfSelectedElements(origin, selectedElements)\n },\n drag: {\n hasOccurred: false,\n offset: null\n },\n eventListeners: {\n onMove: null,\n onUp: null,\n onKeyUp: null,\n onKeyDown: null\n },\n boxSelection: {\n hasOccurred: false\n },\n elementIdsToErase: {}\n };\n } // Returns whether the event is a dragging a scrollbar\n\n\n handleDraggingScrollBar(event, pointerDownState) {\n if (!(pointerDownState.scrollbars.isOverEither && !this.state.multiElement)) {\n return false;\n }\n\n isDraggingScrollBar = true;\n pointerDownState.lastCoords.x = event.clientX;\n pointerDownState.lastCoords.y = event.clientY;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n this.handlePointerMoveOverScrollbars(event, pointerDownState);\n });\n const onPointerUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isDraggingScrollBar = false;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n lastPointerUp = null;\n this.setState({\n cursorButton: \"up\"\n });\n this.savePointer(event.clientX, event.clientY, \"up\");\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n onPointerMove.flush();\n });\n lastPointerUp = onPointerUp;\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n return true;\n }\n\n isASelectedElement(hitElement) {\n return hitElement != null && this.state.selectedElementIds[hitElement.id];\n }\n\n isHittingCommonBoundingBoxOfSelectedElements(point, selectedElements) {\n if (selectedElements.length < 2) {\n return false;\n } // How many pixels off the shape boundary we still consider a hit\n\n\n const threshold = 10 / this.state.zoom.value;\n const [x1, y1, x2, y2] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return point.x > x1 - threshold && point.x < x2 + threshold && point.y > y1 - threshold && point.y < y2 + threshold;\n }\n\n getCurrentItemRoundness(elementType) {\n return this.state.currentItemRoundness === \"round\" ? {\n type: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isUsingAdaptiveRadius)(elementType) ? _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.ADAPTIVE_RADIUS : _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null;\n }\n\n maybeCacheReferenceSnapPoints(event, selectedElements, recomputeAnyways = false) {\n if ((0,_snapping__WEBPACK_IMPORTED_MODULE_57__.isSnappingEnabled)({\n event,\n appState: this.state,\n selectedElements\n }) && (recomputeAnyways || !_snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.getReferenceSnapPoints())) {\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.setReferenceSnapPoints((0,_snapping__WEBPACK_IMPORTED_MODULE_57__.getReferenceSnapPoints)(this.scene.getNonDeletedElements(), selectedElements, this.state));\n }\n }\n\n maybeCacheVisibleGaps(event, selectedElements, recomputeAnyways = false) {\n if ((0,_snapping__WEBPACK_IMPORTED_MODULE_57__.isSnappingEnabled)({\n event,\n appState: this.state,\n selectedElements\n }) && (recomputeAnyways || !_snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.getVisibleGaps())) {\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.setVisibleGaps((0,_snapping__WEBPACK_IMPORTED_MODULE_57__.getVisibleGaps)(this.scene.getNonDeletedElements(), selectedElements, this.state));\n }\n }\n\n onKeyDownFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onKeyUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // Prevents focus from escaping excalidraw tab\n event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ALT && event.preventDefault();\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onPointerMoveFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n var _a, _b; // We need to initialize dragOffsetXY only after we've updated\n // `state.selectedElementIds` on pointerDown. Doing it here in pointerMove\n // event handler should hopefully ensure we're already working with\n // the updated state.\n\n\n if (pointerDownState.drag.offset === null) {\n pointerDownState.drag.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getDragOffsetXY)(this.scene.getSelectedElements(this.state), pointerDownState.origin.x, pointerDownState.origin.y));\n }\n\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n if (this.handlePointerMoveOverScrollbars(event, pointerDownState)) {\n return;\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.handleEraser(event, pointerDownState, pointerCoords);\n return;\n }\n\n if (this.state.activeTool.type === \"laser\") {\n this.laserPathManager.addPointToPath(pointerCoords.x, pointerCoords.y);\n }\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize); // for arrows/lines, don't start dragging until a given threshold\n // to ensure we don't create a 2-point arrow by mistake when\n // user clicks mouse in a way that it moves a tiny bit (thus\n // triggering pointermove)\n\n if (!pointerDownState.drag.hasOccurred && (this.state.activeTool.type === \"arrow\" || this.state.activeTool.type === \"line\")) {\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerCoords.x, pointerCoords.y, pointerDownState.origin.x, pointerDownState.origin.y) < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD) {\n return;\n }\n }\n\n if (pointerDownState.resize.isResizing) {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return true;\n }\n }\n\n if (this.state.selectedLinearElement) {\n const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;\n\n if (_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.shouldAddMidpoint(this.state.selectedLinearElement, pointerCoords, this.state)) {\n const ret = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.addMidpoint(this.state.selectedLinearElement, pointerCoords, this.state, !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]);\n\n if (!ret) {\n return;\n } // Since we are reading from previous state which is not possible with\n // automatic batching in React 18 hence using flush sync to synchronously\n // update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.\n\n\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n if (this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n pointerDownState: ret.pointerDownState,\n selectedPointsIndices: ret.selectedPointsIndices\n })\n });\n }\n\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: Object.assign(Object.assign({}, this.state.editingLinearElement), {\n pointerDownState: ret.pointerDownState,\n selectedPointsIndices: ret.selectedPointsIndices\n })\n });\n }\n });\n return;\n } else if (linearElementEditor.pointerDownState.segmentMidpoint.value !== null && !linearElementEditor.pointerDownState.segmentMidpoint.added) {\n return;\n }\n\n const didDrag = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointDragging(event, this.state, pointerCoords.x, pointerCoords.y, (element, pointsSceneCoords) => {\n this.maybeSuggestBindingsForLinearElementAtCoords(element, pointsSceneCoords);\n }, linearElementEditor);\n\n if (didDrag) {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n pointerDownState.drag.hasOccurred = true;\n\n if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {\n this.setState({\n editingLinearElement: Object.assign(Object.assign({}, this.state.editingLinearElement), {\n isDragging: true\n })\n });\n }\n\n if (!this.state.selectedLinearElement.isDragging) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n isDragging: true\n })\n });\n }\n\n return;\n }\n }\n\n const hasHitASelectedElement = pointerDownState.hit.allHitElements.some(element => this.isASelectedElement(element));\n const isSelectingPointsInLineEditor = this.state.editingLinearElement && event.shiftKey && this.state.editingLinearElement.elementId === ((_a = pointerDownState.hit.element) === null || _a === void 0 ? void 0 : _a.id);\n\n if ((hasHitASelectedElement || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) && !isSelectingPointsInLineEditor) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.every(element => element.locked)) {\n return;\n }\n\n const selectedElementsHasAFrame = selectedElements.find(e => (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(e));\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(pointerCoords);\n this.setState({\n frameToHighlight: topLayerFrame && !selectedElementsHasAFrame ? topLayerFrame : null\n }); // Marking that click was used for dragging to check\n // if elements should be deselected on pointerup\n\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n }); // prevent dragging even if we're no longer holding cmd/ctrl otherwise\n // it would have weird results (stuff jumping all over the screen)\n // Checking for editingElement to avoid jump while editing on mobile #6503\n\n if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl && !this.state.editingElement && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) !== \"active\") {\n const dragOffset = {\n x: pointerCoords.x - pointerDownState.origin.x,\n y: pointerCoords.y - pointerDownState.origin.y\n };\n const originalElements = [...pointerDownState.originalElements.values()]; // We only drag in one direction if shift is pressed\n\n const lockDirection = event.shiftKey;\n\n if (lockDirection) {\n const distanceX = Math.abs(dragOffset.x);\n const distanceY = Math.abs(dragOffset.y);\n const lockX = lockDirection && distanceX < distanceY;\n const lockY = lockDirection && distanceX > distanceY;\n\n if (lockX) {\n dragOffset.x = 0;\n }\n\n if (lockY) {\n dragOffset.y = 0;\n }\n } // Snap cache *must* be synchronously popuplated before initial drag,\n // otherwise the first drag even will not snap, causing a jump before\n // it snaps to its position if previously snapped already.\n\n\n this.maybeCacheVisibleGaps(event, selectedElements);\n this.maybeCacheReferenceSnapPoints(event, selectedElements);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.snapDraggedElements)((0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(originalElements, this.state), dragOffset, this.state, event);\n this.setState({\n snapLines\n }); // when we're editing the name of a frame, we want the user to be\n // able to select and interact with the text input\n\n !this.state.editingFrame && (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragSelectedElements)(pointerDownState, selectedElements, dragOffset, this.state, this.scene, snapOffset, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n this.maybeSuggestBindingForAll(selectedElements); // We duplicate the selected element if alt is pressed on pointer move\n\n if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {\n // Move the currently selected elements to the top of the z index stack, and\n // put the duplicates where the selected elements used to be.\n // (the origin point where the dragging started)\n pointerDownState.hit.hasBeenDuplicated = true;\n const nextElements = [];\n const elementsToAppend = [];\n const groupIdMap = new Map();\n const oldIdToDuplicatedId = new Map();\n const hitElement = pointerDownState.hit.element;\n const selectedElementIds = new Set(this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n }).map(element => element.id));\n const elements = this.scene.getElementsIncludingDeleted();\n\n for (const element of elements) {\n if (selectedElementIds.has(element.id) || // case: the state.selectedElementIds might not have been\n // updated yet by the time this mousemove event is fired\n element.id === (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && pointerDownState.hit.wasAddedToSelection) {\n const duplicatedElement = (0,_element__WEBPACK_IMPORTED_MODULE_16__.duplicateElement)(this.state.editingGroupId, groupIdMap, element);\n const origElement = pointerDownState.originalElements.get(element.id);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(duplicatedElement, {\n x: origElement.x,\n y: origElement.y\n }); // put duplicated element to pointerDownState.originalElements\n // so that we can snap to the duplicated element without releasing\n\n pointerDownState.originalElements.set(duplicatedElement.id, duplicatedElement);\n nextElements.push(duplicatedElement);\n elementsToAppend.push(element);\n oldIdToDuplicatedId.set(element.id, duplicatedElement.id);\n } else {\n nextElements.push(element);\n }\n }\n\n const nextSceneElements = [...nextElements, ...elementsToAppend];\n (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.bindTextToShapeAfterDuplication)(nextElements, elementsToAppend, oldIdToDuplicatedId);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, \"duplicatesServeAsOld\");\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.bindElementsToFramesAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);\n this.scene.replaceAllElements(nextSceneElements);\n this.maybeCacheVisibleGaps(event, selectedElements, true);\n this.maybeCacheReferenceSnapPoints(event, selectedElements, true);\n }\n\n return;\n }\n } // It is very important to read this.state within each move event,\n // otherwise we would read a stale one!\n\n\n const draggingElement = this.state.draggingElement;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"freedraw\") {\n const points = draggingElement.points;\n const dx = pointerCoords.x - draggingElement.x;\n const dy = pointerCoords.y - draggingElement.y;\n const lastPoint = points.length > 0 && points[points.length - 1];\n const discardPoint = lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;\n\n if (!discardPoint) {\n const pressures = draggingElement.simulatePressure ? draggingElement.pressures : [...draggingElement.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures\n });\n }\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n });\n const points = draggingElement.points;\n let dx = gridX - draggingElement.x;\n let dy = gridY - draggingElement.y;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event) && points.length === 2) {\n ({\n width: dx,\n height: dy\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)(draggingElement.x, draggingElement.y, pointerCoords.x, pointerCoords.y));\n }\n\n if (points.length === 1) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]]\n });\n } else if (points.length === 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points.slice(0, -1), [dx, dy]]\n });\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n // When creating a linear element by dragging\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [pointerCoords], this.state.startBoundElement);\n }\n } else {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n this.maybeDragNewGenericElement(pointerDownState, event);\n }\n\n if (this.state.activeTool.type === \"selection\") {\n pointerDownState.boxSelection.hasOccurred = true;\n const elements = this.scene.getNonDeletedElements(); // box-select line editor points\n\n if (this.state.editingLinearElement) {\n _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handleBoxSelection(event, this.state, this.setState.bind(this)); // regular box-select\n } else {\n let shouldReuseSelection = true;\n\n if (!event.shiftKey && (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(elements, this.state)) {\n if (pointerDownState.withCmdOrCtrl && pointerDownState.hit.element) {\n this.setState(prevState => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)(Object.assign(Object.assign({}, prevState), {\n selectedElementIds: {\n [pointerDownState.hit.element.id]: true\n }\n }), this.scene.getNonDeletedElements(), prevState, this));\n } else {\n shouldReuseSelection = false;\n }\n }\n\n const elementsWithinSelection = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsWithinSelection)(elements, draggingElement);\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, shouldReuseSelection && prevState.selectedElementIds), elementsWithinSelection.reduce((acc, element) => {\n acc[element.id] = true;\n return acc;\n }, {}));\n\n if (pointerDownState.hit.element) {\n // if using ctrl/cmd, select the hitElement only if we\n // haven't box-selected anything else\n if (!elementsWithinSelection.length) {\n nextSelectedElementIds[pointerDownState.hit.element.id] = true;\n } else {\n delete nextSelectedElementIds[pointerDownState.hit.element.id];\n }\n }\n\n prevState = !shouldReuseSelection ? Object.assign(Object.assign({}, prevState), {\n selectedGroupIds: {},\n editingGroupId: null\n }) : prevState;\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // select linear element only when we haven't box-selected anything else\n selectedLinearElement: elementsWithinSelection.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(elementsWithinSelection[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(elementsWithinSelection[0], this.scene) : null,\n showHyperlinkPopup: elementsWithinSelection.length === 1 && (elementsWithinSelection[0].link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(elementsWithinSelection[0])) ? \"info\" : false\n });\n });\n }\n }\n });\n } // Returns whether the pointer move happened over either scrollbar\n\n\n handlePointerMoveOverScrollbars(event, pointerDownState) {\n if (pointerDownState.scrollbars.isOverHorizontal) {\n const x = event.clientX;\n const dx = x - pointerDownState.lastCoords.x;\n this.translateCanvas({\n scrollX: this.state.scrollX - dx / this.state.zoom.value\n });\n pointerDownState.lastCoords.x = x;\n return true;\n }\n\n if (pointerDownState.scrollbars.isOverVertical) {\n const y = event.clientY;\n const dy = y - pointerDownState.lastCoords.y;\n this.translateCanvas({\n scrollY: this.state.scrollY - dy / this.state.zoom.value\n });\n pointerDownState.lastCoords.y = y;\n return true;\n }\n\n return false;\n }\n\n onPointerUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(childEvent => {\n var _a, _b, _c, _d, _e, _f;\n\n if (pointerDownState.eventListeners.onMove) {\n pointerDownState.eventListeners.onMove.flush();\n }\n\n const {\n draggingElement,\n resizingElement,\n multiElement,\n activeTool,\n isResizing,\n isRotating\n } = this.state;\n this.setState({\n isResizing: false,\n isRotating: false,\n resizingElement: null,\n selectionElement: null,\n frameToHighlight: null,\n elementsToHighlight: null,\n cursorButton: \"up\",\n // text elements are reset on finalize, and resetting on pointerup\n // may cause issues with double taps\n editingElement: multiElement || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? this.state.editingElement : null,\n snapLines: [],\n originSnapOffset: null\n });\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.setReferenceSnapPoints(null);\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.setVisibleGaps(null);\n this.savePointer(childEvent.clientX, childEvent.clientY, \"up\");\n this.setState({\n selectedElementsAreBeingDragged: false\n }); // Handle end of dragging a point of a linear element, might close a loop\n // and sets binding element\n\n if (this.state.editingLinearElement) {\n if (!pointerDownState.boxSelection.hasOccurred && ((_b = (_a = pointerDownState.hit) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.id) !== this.state.editingLinearElement.elementId) {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n } else {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state);\n\n if (editingLinearElement !== this.state.editingLinearElement) {\n this.setState({\n editingLinearElement,\n suggestedBindings: []\n });\n }\n }\n } else if (this.state.selectedLinearElement) {\n if (((_d = (_c = pointerDownState.hit) === null || _c === void 0 ? void 0 : _c.element) === null || _d === void 0 ? void 0 : _d.id) !== this.state.selectedLinearElement.elementId) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement to null if there is more than one element selected since we don't want to show linear element handles\n\n if (selectedELements.length > 1) {\n this.setState({\n selectedLinearElement: null\n });\n }\n } else {\n const linearElementEditor = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state);\n const {\n startBindingElement,\n endBindingElement\n } = linearElementEditor;\n const element = this.scene.getElement(linearElementEditor.elementId);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindLinearElement)(element, startBindingElement, endBindingElement);\n }\n\n if (linearElementEditor !== this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, linearElementEditor), {\n selectedPointsIndices: null\n }),\n suggestedBindings: []\n });\n }\n }\n }\n\n lastPointerUp = null;\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, pointerDownState.eventListeners.onMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, pointerDownState.eventListeners.onUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, pointerDownState.eventListeners.onKeyDown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, pointerDownState.eventListeners.onKeyUp);\n\n if (this.state.pendingImageElementId) {\n this.setState({\n pendingImageElementId: null\n });\n }\n\n this.onPointerUpEmitter.trigger(this.state.activeTool, pointerDownState, childEvent);\n\n if ((draggingElement === null || draggingElement === void 0 ? void 0 : draggingElement.type) === \"freedraw\") {\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n const points = draggingElement.points;\n let dx = pointerCoords.x - draggingElement.x;\n let dy = pointerCoords.y - draggingElement.y; // Allows dots to avoid being flagged as infinitely small\n\n if (dx === points[0][0] && dy === points[0][1]) {\n dy += 0.0001;\n dx += 0.0001;\n }\n\n const pressures = draggingElement.simulatePressure ? [] : [...draggingElement.pressures, childEvent.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures,\n lastCommittedPoint: [dx, dy]\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement)) {\n const imageElement = draggingElement;\n\n try {\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } catch (error) {\n console.error(error);\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== imageElement.id));\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n }\n\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n if (draggingElement.points.length > 1) {\n this.history.resumeRecording();\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n\n if (!pointerDownState.drag.hasOccurred && draggingElement && !multiElement) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...draggingElement.points, [pointerCoords.x - draggingElement.x, pointerCoords.y - draggingElement.y]]\n });\n this.setState({\n multiElement: draggingElement,\n editingElement: this.state.draggingElement\n });\n } else if (pointerDownState.drag.hasOccurred && !multiElement) {\n if ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(draggingElement, this.state, this.scene, pointerCoords);\n }\n\n this.setState({\n suggestedBindings: [],\n startBoundElement: null\n });\n\n if (!activeTool.locked) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n this.setState(prevState => ({\n draggingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n }),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(draggingElement, this.scene)\n }));\n } else {\n this.setState(prevState => ({\n draggingElement: null\n }));\n }\n }\n\n return;\n }\n\n if (activeTool.type !== \"selection\" && draggingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(draggingElement)) {\n // remove invisible element which was added in onPointerDown\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== draggingElement.id));\n this.setState({\n draggingElement: null\n });\n return;\n }\n\n if (draggingElement) {\n if (pointerDownState.drag.hasOccurred) {\n const sceneCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state); // when editing the points of a linear element, we check if the\n // linear element still is in the frame afterwards\n // if not, the linear element will be removed from its frame (if any)\n\n if (this.state.selectedLinearElement && this.state.selectedLinearElement.isDragging) {\n const linearElement = this.scene.getElement(this.state.selectedLinearElement.elementId);\n\n if (linearElement === null || linearElement === void 0 ? void 0 : linearElement.frameId) {\n const frame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(linearElement);\n\n if (frame && linearElement) {\n if (!(0,_frame__WEBPACK_IMPORTED_MODULE_50__.elementOverlapsWithFrame)(linearElement, frame)) {\n // remove the linear element from all groups\n // before removing it from the frame as well\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(linearElement, {\n groupIds: []\n });\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.removeElementsFromFrame)(this.scene.getElementsIncludingDeleted(), [linearElement], this.state));\n }\n }\n }\n } else {\n // update the relationships between selected elements and frames\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(sceneCoords);\n const selectedElements = this.scene.getSelectedElements(this.state);\n let nextElements = this.scene.getElementsIncludingDeleted();\n\n const updateGroupIdsAfterEditingGroup = elements => {\n if (elements.length > 0) {\n for (const element of elements) {\n const index = element.groupIds.indexOf(this.state.editingGroupId);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: element.groupIds.slice(0, index)\n }, false);\n }\n\n nextElements.forEach(element => {\n if (element.groupIds.length && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(nextElements, element.groupIds[element.groupIds.length - 1]).length < 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: []\n }, false);\n }\n });\n this.setState({\n editingGroupId: null\n });\n }\n };\n\n if (topLayerFrame && !this.state.selectedElementIds[topLayerFrame.id]) {\n const elementsToAdd = selectedElements.filter(element => element.frameId !== topLayerFrame.id && (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n\n if (this.state.editingGroupId) {\n updateGroupIdsAfterEditingGroup(elementsToAdd);\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(nextElements, elementsToAdd, topLayerFrame);\n } else if (!topLayerFrame) {\n if (this.state.editingGroupId) {\n const elementsToRemove = selectedElements.filter(element => element.frameId && !(0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n updateGroupIdsAfterEditingGroup(elementsToRemove);\n }\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(nextElements, this.state, this);\n this.scene.replaceAllElements(nextElements);\n }\n }\n\n if (draggingElement.type === \"frame\") {\n const elementsInsideFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInNewFrame)(this.scene.getElementsIncludingDeleted(), draggingElement);\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(this.scene.getElementsIncludingDeleted(), elementsInsideFrame, draggingElement));\n }\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getNormalizedDimensions)(draggingElement));\n }\n\n if (resizingElement) {\n this.history.resumeRecording();\n }\n\n if (resizingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(resizingElement)) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== resizingElement.id));\n } // handle frame membership for resizing frames and/or selected elements\n\n\n if (pointerDownState.resize.isResizing) {\n let nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(this.scene.getElementsIncludingDeleted(), this.state, this);\n const selectedFrames = this.scene.getSelectedElements(this.state).filter(element => element.type === \"frame\");\n\n for (const frame of selectedFrames) {\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.replaceAllElementsInFrame)(nextElements, (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getElementsIncludingDeleted(), frame, this.state), frame, this.state);\n }\n\n this.scene.replaceAllElements(nextElements);\n } // Code below handles selection when element(s) weren't\n // drag or added to selection on pointer down phase.\n\n\n const hitElement = pointerDownState.hit.element;\n\n if (((_e = this.state.selectedLinearElement) === null || _e === void 0 ? void 0 : _e.elementId) !== (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement)) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement when no other element selected except\n // the one we've hit\n\n if (selectedELements.length === 1) {\n this.setState({\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene)\n });\n }\n }\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDownEvent.clientX, this.lastPointerDownEvent.clientY, this.lastPointerUpEvent.clientX, this.lastPointerUpEvent.clientY);\n\n if (draggedDistance === 0) {\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastPointerUpEvent.clientX,\n clientY: this.lastPointerUpEvent.clientY\n }, this.state);\n const hitElements = this.getElementsAtPosition(scenePointer.x, scenePointer.y);\n hitElements.forEach(hitElement => pointerDownState.elementIdsToErase[hitElement.id] = {\n erase: true,\n opacity: hitElement.opacity\n });\n }\n\n this.eraseElements(pointerDownState);\n return;\n } else if (Object.keys(pointerDownState.elementIdsToErase).length) {\n this.restoreReadyToEraseElements(pointerDownState);\n }\n\n if (hitElement && !pointerDownState.drag.hasOccurred && !pointerDownState.hit.wasAddedToSelection && ( // if we're editing a line, pointerup shouldn't switch selection if\n // box selected\n !this.state.editingLinearElement || !pointerDownState.boxSelection.hasOccurred)) {\n // when inside line editor, shift selects points instead\n if (childEvent.shiftKey && !this.state.editingLinearElement) {\n if (this.state.selectedElementIds[hitElement.id]) {\n if ((0,_groups__WEBPACK_IMPORTED_MODULE_23__.isSelectedViaGroup)(this.state, hitElement)) {\n this.setState(_prevState => {\n const nextSelectedElementIds = Object.assign({}, _prevState.selectedElementIds); // We want to unselect all groups hitElement is part of\n // as well as all elements that are part of the groups\n // hitElement is part of\n\n for (const groupedElement of hitElement.groupIds.flatMap(groupId => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), groupId))) {\n delete nextSelectedElementIds[groupedElement.id];\n }\n\n return {\n selectedGroupIds: Object.assign(Object.assign({}, _prevState.selectedElementIds), hitElement.groupIds.map(gId => ({\n [gId]: false\n })).reduce((prev, acc) => Object.assign(Object.assign({}, prev), acc), {})),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, _prevState)\n };\n }); // if not gragging a linear element point (outside editor)\n } else if (!((_f = this.state.selectedLinearElement) === null || _f === void 0 ? void 0 : _f.isDragging)) {\n // remove element from selection while\n // keeping prev elements selected\n this.setState(prevState => {\n const newSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete newSelectedElementIds[hitElement.id];\n const newSelectedElements = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(this.scene.getNonDeletedElements(), {\n selectedElementIds: newSelectedElementIds\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: newSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // set selectedLinearElement only if thats the only element selected\n selectedLinearElement: newSelectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(newSelectedElements[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(newSelectedElements[0], this.scene) : prevState.selectedLinearElement\n });\n });\n }\n } else if (hitElement.frameId && this.state.selectedElementIds[hitElement.frameId]) {\n // when hitElement is part of a selected frame, deselect the frame\n // to avoid frame and containing elements selected simultaneously\n this.setState(prevState => {\n var _a, _b;\n\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n }); // deselect the frame\n\n delete nextSelectedElementIds[hitElement.frameId]; // deselect groups containing the frame\n\n ((_b = (_a = this.scene.getElement(hitElement.frameId)) === null || _a === void 0 ? void 0 : _a.groupIds) !== null && _b !== void 0 ? _b : []).flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n showHyperlinkPopup: hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) ? \"info\" : false\n });\n });\n } else {\n // add element to selection while keeping prev elements selected\n this.setState(_prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, _prevState.selectedElementIds), {\n [hitElement.id]: true\n }), _prevState)\n }));\n }\n } else {\n this.setState(prevState => {\n var _a;\n\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement) && // Don't set `selectedLinearElement` if its same as the hitElement, this is mainly to prevent resetting the `hoverPointIndex` to -1.\n // Future we should update the API to take care of setting the correct `hoverPointIndex` when initialized\n ((_a = prevState.selectedLinearElement) === null || _a === void 0 ? void 0 : _a.elementId) !== hitElement.id ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene) : prevState.selectedLinearElement\n });\n });\n }\n }\n\n if (!pointerDownState.drag.hasOccurred && !this.state.isResizing && (hitElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(hitElement, this.state, this.frameNameBoundsCache, pointerDownState.origin.x, pointerDownState.origin.y) || !hitElement && pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements)) {\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: null\n });\n } else {\n // Deselect selected elements\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\" && draggingElement && draggingElement.type !== \"selection\") {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n showHyperlinkPopup: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(draggingElement) && !draggingElement.link ? \"editor\" : prevState.showHyperlinkPopup\n }));\n }\n\n if (activeTool.type !== \"selection\" || (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(this.scene.getNonDeletedElements(), this.state)) {\n this.history.resumeRecording();\n }\n\n if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {\n ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? _element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements : _element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(this.scene.getSelectedElements(this.state));\n }\n\n if (activeTool.type === \"laser\") {\n this.laserPathManager.endPath();\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n this.setState({\n draggingElement: null,\n suggestedBindings: [],\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n } else {\n this.setState({\n draggingElement: null,\n suggestedBindings: []\n });\n }\n\n if (hitElement && this.lastPointerUpEvent && this.lastPointerDownEvent && this.lastPointerUpEvent.timeStamp - this.lastPointerDownEvent.timeStamp < 300 && gesture.pointers.size <= 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, this.lastPointerUpEvent, pointerDownState.origin.x, pointerDownState.origin.y)) {\n this.handleEmbeddableCenterClick(hitElement);\n }\n });\n }\n\n maybeSuggestBindingForAll(selectedElements) {\n if (selectedElements.length > 50) {\n return;\n }\n\n const suggestedBindings = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getEligibleElementsForBinding)(selectedElements);\n this.setState({\n suggestedBindings\n });\n }\n\n clearSelection(hitElement) {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n activeEmbeddable: null,\n selectedGroupIds: {},\n // Continue editing the same group if the user selected a different\n // element from it\n editingGroupId: prevState.editingGroupId && hitElement != null && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, prevState.editingGroupId) ? prevState.editingGroupId : null\n }));\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null,\n previousSelectedElementIds: this.state.selectedElementIds\n });\n }\n\n getTextWysiwygSnappedToCenterPosition(x, y, appState, container) {\n if (container) {\n let elementCenterX = container.x + container.width / 2;\n let elementCenterY = container.y + container.height / 2;\n const elementCenter = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, appState);\n\n if (elementCenter) {\n elementCenterX = elementCenter.x;\n elementCenterY = elementCenter.y;\n }\n\n const distanceToCenter = Math.hypot(x - elementCenterX, y - elementCenterY);\n const isSnappedToCenter = distanceToCenter < _constants__WEBPACK_IMPORTED_MODULE_12__.TEXT_TO_CENTER_SNAP_THRESHOLD;\n\n if (isSnappedToCenter) {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: elementCenterX,\n sceneY: elementCenterY\n }, appState);\n return {\n viewportX,\n viewportY,\n elementCenterX,\n elementCenterY\n };\n }\n }\n }\n\n getCanvasOffsets() {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n left,\n top\n } = excalidrawContainer.getBoundingClientRect();\n return {\n offsetLeft: left,\n offsetTop: top\n };\n }\n\n return {\n offsetLeft: 0,\n offsetTop: 0\n };\n }\n\n updateLanguage() {\n return __awaiter(this, void 0, void 0, function* () {\n const currentLang = _i18n__WEBPACK_IMPORTED_MODULE_25__.languages.find(lang => lang.code === this.props.langCode) || _i18n__WEBPACK_IMPORTED_MODULE_25__.defaultLang;\n yield (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.setLanguage)(currentLang);\n this.setAppState({});\n });\n }\n\n}\n\nApp.defaultProps = {\n // needed for tests to pass since we directly render App in many tests\n UIOptions: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_UI_OPTIONS\n};\n\nif (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n window.h = window.h || {};\n Object.defineProperties(window.h, {\n elements: {\n configurable: true,\n\n get() {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.getElementsIncludingDeleted();\n },\n\n set(elements) {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.replaceAllElements(elements);\n }\n\n }\n });\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vLi4vY29tcG9uZW50cy9BcHAudHN4LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxnQkFBZ0IsU0FBSSxJQUFJLFNBQUk7QUFDNUI7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDs7QUFFc0Y7QUFDNUM7QUFDSjtBQUNBO0FBQ2Q7QUFDUTtBQUN5aEI7QUFDM2U7QUFDM0I7QUFDTDtBQUNKO0FBQ3lDO0FBQ3JDO0FBQ3lvQjtBQUNsb0I7QUFDeUI7QUFDbkI7QUFDbWdCO0FBQy9NO0FBQzFTO0FBQ0k7QUFDNkQ7QUFDK0k7QUFDak87QUFDa0o7QUFDcks7QUFDNkM7QUFDc0Q7QUFDdkU7QUFDb0I7QUFDbUg7QUFDaks7QUFDYTtBQUNMO0FBQzBXO0FBQzVUO0FBQ3JCO0FBQ3BDO0FBQ0E7QUFDdUM7QUFDZ0w7QUFDN0c7QUFDbkc7QUFDTztBQUNtUTtBQUNoTztBQUN1RDtBQUNuRTtBQUNEO0FBQ0c7QUFDaEM7QUFDZ1M7QUFDak87QUFDN0M7QUFDaUQ7QUFDaEM7QUFDcEM7QUFDMEI7QUFDcUo7QUFDOUk7QUFDWDtBQUNSO0FBQ1k7QUFDUjtBQUNLO0FBQ2hCO0FBQ0k7QUFDTztBQUNDO0FBQ087QUFDdUI7QUFDbEQ7QUFDckMsbUJBQW1CLDBEQUFtQjtBQUN0Qyx3QkFBd0IsMERBQW1CO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0Esc0JBQXNCLDBEQUFtQjtBQUN6QztBQUNPLG1DQUFtQywwREFBbUI7QUFDN0Q7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBLGtDQUFrQywwREFBbUI7QUFDckQ7QUFDQSxrQ0FBa0MsMERBQW1CLCtCQUErQixFQUFFLDhEQUFrQjtBQUN4RztBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBLHFDQUFxQywwREFBbUI7QUFDeEQ7QUFDQSxDQUFDO0FBQ0Q7QUFDQSx1Q0FBdUMsMERBQW1CO0FBQzFEO0FBQ08scUJBQXFCLGlEQUFVO0FBQy9CLDBCQUEwQixpREFBVTtBQUNwQyx3QkFBd0IsaURBQVU7QUFDbEMscUNBQXFDLGlEQUFVO0FBQy9DLG9DQUFvQyxpREFBVTtBQUM5QyxvQ0FBb0MsaURBQVU7QUFDOUMsdUNBQXVDLGlEQUFVO0FBQ2pELHlDQUF5QyxpREFBVTtBQUMxRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxrQkFBa0Isd0RBQWU7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxzREFBZTtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsMEVBQWdCO0FBQ2hELCtCQUErQiw4Q0FBTztBQUN0QyxvQ0FBb0MsOENBQU87QUFDM0Msa0NBQWtDLDhDQUFPOztBQUV6QztBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVkseUVBQW1CO0FBQy9COztBQUVBO0FBQ0E7QUFDQSw4QkFBOEIsNEVBQXNCO0FBQ3BELFlBQVksc0VBQWE7QUFDekI7QUFDQSxhQUFhO0FBQ2IsWUFBWSxvRUFBaUI7QUFDN0I7QUFDQTs7QUFFQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0EsZ0JBQWdCLFFBQVEsY0FBYyxnQkFBZ0I7QUFDdEQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLG9DQUFvQyxvRUFBMkI7QUFDL0Q7QUFDQTtBQUNBLGFBQWE7QUFDYix3Q0FBd0Msb0VBQTJCO0FBQ25FO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsYUFBYSwwRUFBbUI7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLG9FQUEyQjtBQUN2QztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxVQUFVLEVBQUUsb0VBQTJCO0FBQ3ZDO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsWUFBWSxzRUFBYTtBQUN6QjtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBOztBQUVBO0FBQ0EsNERBQTRELFVBQVU7QUFDdEUseUJBQXlCLHNEQUFJO0FBQzdCO0FBQ0E7QUFDQTtBQUNBLGNBQWMsc0VBQWE7QUFDM0I7QUFDQSxlQUFlO0FBQ2YsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsK0NBQVcsa0JBQWtCLDhDQUFVO0FBQ3ZFO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBLG9DQUFvQyxxREFBWTtBQUNoRDtBQUNBO0FBQ0E7QUFDQSwwQkFBMEIsd0JBQXdCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0NBQXdDLHdCQUF3QjtBQUNoRTtBQUNBO0FBQ0EsMkJBQTJCLHNHQUFzRztBQUNqSSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1YsMkVBQTJFLFVBQVU7QUFDckY7O0FBRUEsZUFBZSxzREFBSTtBQUNuQjtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IsMkNBQTJDO0FBQy9ELHFCQUFxQiw4RkFBOEY7QUFDbkg7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIsc0NBQXNDO0FBQy9EO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQix5REFBZ0I7QUFDcEMsd0RBQXdELGdFQUF1QixHQUFHLCtEQUFzQjtBQUN4RyxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0EsU0FBUztBQUNUO0FBQ0EsU0FBUztBQUNULE9BQU87QUFDUDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0EsTUFBTSxzREFBVTtBQUNoQiwrQkFBK0Isb0RBQVk7QUFDM0M7QUFDQTtBQUNBO0FBQ0EsT0FBTyxRQUFRLHFEQUFnQjtBQUMvQjtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTzs7QUFFUCx1REFBdUQsOERBQWlCO0FBQ3hFO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsTUFBTSxtREFBYyxDQUFDLDhEQUFvQjtBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHdEQUF3RDtBQUN4RDtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBLGVBQWU7QUFDZixjQUFjO0FBQ2Q7QUFDQSx3REFBd0Q7QUFDeEQ7QUFDQSxpQkFBaUI7QUFDakI7QUFDQSxlQUFlO0FBQ2Y7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHVFQUFjO0FBQ3ZDO0FBQ0EsbUJBQW1CO0FBQ25COztBQUVBO0FBQ0EsZUFBZTtBQUNmLGFBQWE7QUFDYjtBQUNBLFNBQVM7QUFDVDtBQUNBLE9BQU87QUFDUDs7QUFFQSw0QkFBNEIsMkRBQWtCO0FBQzlDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsdUpBQXVKLDhEQUFtQjtBQUMxSztBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esb0dBQW9HO0FBQ3BHO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esc0xBQXNMLG9EQUFXO0FBQ2pNO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGtEQUFrRCxrREFBUztBQUMzRDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMERBQTBEO0FBQzFEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUssR0FBRzs7QUFFUixrQkFBa0IsMkRBQWtCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBLHNCQUFzQiwyREFBa0I7QUFDeEM7QUFDQSwyREFBMkQsRUFBRSw4REFBa0I7QUFDL0U7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQSxXQUFXO0FBQ1g7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLHVEQUFPO0FBQzNCO0FBQ0EsT0FBTztBQUNQLHFEQUFxRDtBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrRkFBK0Y7QUFDL0Y7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQSx1REFBdUQsbUJBQW1CLDhEQUFxQiwrQ0FBK0M7QUFDOUk7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBLDBEQUEwRDtBQUMxRDtBQUNBLE9BQU87QUFDUCxLQUFLOztBQUVMO0FBQ0EscUJBQXFCLDhEQUFxQixhQUFhLGdFQUF1QixZQUFZLCtEQUFzQjtBQUNoSDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQSxnQ0FBZ0MscURBQVk7QUFDNUM7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQSxvREFBb0Q7QUFDcEQ7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUixzSUFBc0ksbUVBQTBCO0FBQ2hLO0FBQ0EsOEJBQThCLHFEQUFZO0FBQzFDO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0Esb0RBQW9EO0FBQ3BEO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsMkRBQWtCO0FBQ3RDLGtFQUFrRSxvRUFBaUI7QUFDbkY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsc0JBQXNCO0FBQ3RCLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0EsTUFBTSx3REFBYTs7QUFFbkI7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CLGlEQUFRO0FBQzVCO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCxLQUFLLEVBQUUsdURBQWMsR0FBRzs7QUFFeEIsaUJBQWlCLDJEQUFrQjtBQUNuQzs7QUFFQTs7QUFFQSxpQ0FBaUMsMERBQWlCO0FBQ2xEO0FBQ0E7O0FBRUEsdUNBQXVDLCtDQUFTO0FBQ2hEO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsa0JBQWtCLDJEQUFrQjtBQUNwQzs7QUFFQTs7QUFFQSxpQ0FBaUMsMERBQWlCO0FBQ2xEO0FBQ0E7O0FBRUEsdUNBQXVDLGdEQUFVO0FBQ2pEO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBLFdBQVcsa0RBQVM7QUFDcEI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnRUFBZ0UsMERBQWlCO0FBQ2pGO0FBQ0EsUUFBUTtBQUNSOzs7QUFHQTtBQUNBLHdDQUF3Qzs7QUFFeEM7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQSxVQUFVLGtEQUFTO0FBQ25CO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDhCQUE4Qiw2RUFBMEIsR0FBRztBQUMzRDtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHdDQUF3QztBQUN4Qyw4QkFBOEIsNkVBQTBCO0FBQ3hELFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBLDhCQUE4QiwyREFBa0I7QUFDaEQ7O0FBRUEsNkNBQTZDOztBQUU3QztBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSwwRUFBMEUsMERBQWlCO0FBQzNGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUSxFQUFFLG9FQUEyQjtBQUNyQztBQUNBO0FBQ0EsT0FBTyxlQUFlO0FBQ3RCO0FBQ0E7O0FBRUE7QUFDQSx5QkFBeUIsMkRBQWM7O0FBRXZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLDREQUFlO0FBQ2xDO0FBQ0E7QUFDQSxRQUFROzs7QUFHUixVQUFVLGlFQUFvQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsOEJBQThCLDZFQUEwQjtBQUN4RDtBQUNBLFdBQVc7QUFDWCxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTtBQUNSLGdEQUFnRCw2RUFBMkIsaUNBQWlDOztBQUU1RztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULFFBQVE7QUFDUix5QkFBeUIsZ0VBQVU7O0FBRW5DLDZCQUE2Qiw0RUFBc0IsOEdBQThHLGtFQUFZO0FBQzdLO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQix5REFBYTtBQUMvQixXQUFXOztBQUVYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxLQUFLOztBQUVMO0FBQ0EsdUJBQXVCLCtEQUFlO0FBQ3RDLHVDQUF1QywwREFBZTtBQUN0RCw4QkFBOEIsaURBQVE7QUFDdEMsOEJBQThCLGlEQUFRO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLEVBQUUsb0VBQTJCO0FBQ3JDO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLDZCQUE2QixvREFBWTtBQUN6QywwQkFBMEIsdUVBQWlCO0FBQzNDLGVBQWUsdUVBQWM7QUFDN0I7QUFDQTtBQUNBLFNBQVM7QUFDVCxPQUFPO0FBQ1A7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsWUFBWSx3REFBYSxnQkFBZ0Isd0VBQWtCO0FBQzNELDRCQUE0QiwwRUFBbUI7QUFDL0MsVUFBVSxnRUFBcUI7QUFDL0I7QUFDQSxPQUFPOztBQUVQO0FBQ0EsbURBQW1EO0FBQ25EOztBQUVBO0FBQ0EsbUNBQW1DLHVGQUFvQztBQUN2RSxnRUFBZ0U7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1GQUFtRixtREFBYyxDQUFDLGtFQUFtQjtBQUNySCxPQUFPLEdBQUcseUVBQStCO0FBQ3pDO0FBQ0E7QUFDQSxlQUFlLHdFQUFrQjtBQUNqQztBQUNBOztBQUVBO0FBQ0EsU0FBUyxJQUFJO0FBQ2IsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUSxzREFBVSw2QkFBNkIsUUFBUSxHQUFHLG1EQUFtRDtBQUM3Rzs7QUFFQTtBQUNBO0FBQ0Esa0VBQWtFLHlCQUF5Qix5REFBZ0I7QUFDM0c7QUFDQSxZQUFZO0FBQ1o7QUFDQSxXQUFXO0FBQ1g7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQSx1Q0FBdUMsd0VBQW9CO0FBQzNEO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQSxvQ0FBb0MsRUFBRSw2REFBZTtBQUNyRDtBQUNBO0FBQ0Esa0JBQWtCLDBEQUFpQjtBQUNuQyxPQUFPO0FBQ1A7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSwrRkFBK0Y7O0FBRS9GO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsRUFBRSxpRUFBUztBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQSx1QkFBdUIsOERBQXFCO0FBQzVDO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLHdEQUFlO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLGdEQUFnRCxnREFBTztBQUN2RCxjQUFjOzs7QUFHZDtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0EsNENBQTRDLGlEQUFRO0FBQ3BEO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLO0FBQ0w7OztBQUdBLG9CQUFvQiwyREFBa0I7QUFDdEM7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLGlEQUFpRDtBQUNqRDtBQUNBLFlBQVksK0VBQXlCO0FBQ3JDO0FBQ0EsVUFBVSxvRUFBaUI7QUFDM0I7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLEtBQUs7QUFDTCx1QkFBdUIsMkRBQWtCO0FBQ3pDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7O0FBRUw7QUFDQSxzQkFBc0I7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVixPQUFPO0FBQ1A7QUFDQTs7QUFFQSx1Q0FBdUMsMkRBQWtCO0FBQ3pEO0FBQ0E7QUFDQSxLQUFLLEdBQUc7O0FBRVIscUJBQXFCLDJEQUFrQjtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFNBQVM7QUFDVDs7QUFFQSxnQkFBZ0Isb0RBQWdCLGlDQUFpQywwQ0FBTTtBQUN2RTtBQUNBLDRDQUE0QztBQUM1QztBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTs7O0FBR1IsZ0JBQWdCLG9EQUFnQixLQUFLLDBEQUFpQjtBQUN0RCwyQkFBMkIsK0NBQVcsbUJBQW1CLCtDQUFXO0FBQ3BFO0FBQ0E7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0EsTUFBTSwwREFBaUI7QUFDdkIsb0JBQW9CLCtDQUFXO0FBQy9CLE1BQU0sa0RBQVUsZUFBZSxvREFBVztBQUMxQztBQUNBOztBQUVBLHdCQUF3QixzREFBa0I7QUFDMUM7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLFFBQVEscUNBQXFDLDBDQUFNLDRCQUE0QixvREFBZ0I7QUFDL0Y7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUEsd0JBQXdCLGdEQUFZLGtCQUFrQixrREFBYztBQUNwRTs7QUFFQSwwQkFBMEIsa0RBQWM7QUFDeEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsVUFBVTtBQUNWO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLGdCQUFnQixvREFBZ0I7QUFDaEM7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQSxVQUFVLGtEQUFVO0FBQ3BCLDhEQUE4RCxpRUFBd0IsNkNBQTZDLHVFQUE4QixHQUFHLGlFQUF3QjtBQUM1TDtBQUNBOztBQUVBLDBCQUEwQixtREFBZTtBQUN6QztBQUNBLFVBQVUsdUJBQXVCLG9EQUFnQjtBQUNqRDtBQUNBLFVBQVUsdUJBQXVCLGlEQUFhO0FBQzlDO0FBQ0EsVUFBVSx1QkFBdUIsbURBQWU7QUFDaEQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLFVBQVUsc0VBQWE7QUFDdkI7QUFDQTtBQUNBLFdBQVc7QUFDWCxVQUFVLHNFQUFtQjtBQUM3QjtBQUNBLFdBQVc7QUFDWCxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFFBQVEsdUJBQXVCLDhDQUFVO0FBQ3pDOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CLG9EQUFnQjtBQUNwQyxnQkFBZ0IscUVBQWU7QUFDL0I7QUFDQTtBQUNBO0FBQ0EsNENBQTRDLDhFQUFtQjtBQUMvRCxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLFlBQVksU0FBUyx3REFBYSxxQkFBcUIsMkVBQW9CO0FBQzNFOztBQUVBLGlCQUFpQix3REFBYTtBQUM5QjtBQUNBOztBQUVBLDZCQUE2Qix5RUFBa0I7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQSxZQUFZLFNBQVMsb0VBQWM7QUFDbkM7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0EsUUFBUTtBQUNSLHNCQUFzQix3REFBYzs7QUFFcEM7QUFDQTtBQUNBLFlBQVksc0RBQVUsZ0NBQWdDLG1EQUFtRDtBQUN6Rzs7QUFFQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0EsVUFBVSx1QkFBdUIsMENBQU07QUFDdkM7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsd0JBQXdCLDhDQUFVO0FBQ2xDO0FBQ0EsUUFBUSxtREFBUyx5QkFBeUIseURBQWdCO0FBQzFEO0FBQ0E7O0FBRUEseUJBQXlCLDBDQUFNLGtCQUFrQiwwQ0FBTSw2QkFBNkIsb0RBQWdCO0FBQ3BHOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwwQkFBMEIsMENBQU0sS0FBSyxzREFBYSxpRUFBaUUsc0RBQWE7QUFDaEk7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBOztBQUVBLDBCQUEwQiwwQ0FBTTtBQUNoQztBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTs7QUFFQSx3QkFBd0IsMENBQU0sNEJBQTRCLG9EQUFnQjtBQUMxRTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsVUFBVTtBQUNWO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQTs7QUFFQSxnQkFBZ0Isb0RBQWdCLG9CQUFvQixrREFBYyxrQkFBa0IsK0NBQVc7QUFDL0YsUUFBUSxtREFBYyxDQUFDLDBFQUF1QjtBQUM5QyxRQUFRO0FBQ1I7OztBQUdBO0FBQ0EsNkNBQTZDLDBDQUFNO0FBQ25ELGdEQUFnRCwwQ0FBTSxtQkFBbUIsMENBQU07O0FBRS9FO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFROztBQUVSLEtBQUs7QUFDTCxtQkFBbUIsMkRBQWtCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLG1CQUFtQiwyREFBa0I7QUFDckMsd0JBQXdCLDhDQUFVO0FBQ2xDO0FBQ0EsVUFBVSxtREFBUyx5QkFBeUIseURBQWdCO0FBQzVELFVBQVU7QUFDVixVQUFVLHFEQUFXO0FBQ3JCLFVBQVU7QUFDVixVQUFVLDJEQUFpQjtBQUMzQjtBQUNBLGdDQUFnQyw2RUFBMEIsR0FBRztBQUM3RCxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBOztBQUVBLGlCQUFpQixvREFBZ0I7QUFDakM7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQSxVQUFVLGtEQUFVO0FBQ3BCO0FBQ0EsUUFBUSxtRUFBZ0IsZUFBZSwrRUFBNEIscUJBQXFCLHVFQUFvQjtBQUM1RztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBLDZCQUE2Qix5REFBZ0I7O0FBRTdDO0FBQ0EsUUFBUSxtREFBUyx5QkFBeUIseURBQWdCO0FBQzFELFFBQVE7QUFDUixRQUFRLDJEQUFpQjtBQUN6Qjs7QUFFQSxVQUFVLG1EQUFVO0FBQ3BCO0FBQ0E7O0FBRUEsV0FBVyx5RUFBbUI7QUFDOUI7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsNkRBQTZEO0FBQzdEO0FBQ0EsZ0NBQWdDLDZFQUEwQixHQUFHO0FBQzdELDhCQUE4Qiw2RUFBMEIsR0FBRztBQUMzRDtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBLDJEQUEyRDtBQUMzRDtBQUNBLFNBQVM7QUFDVCxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0EsTUFBTSxtREFBUztBQUNmOztBQUVBO0FBQ0EsTUFBTSxxREFBVztBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87OztBQUdQLDBCQUEwQiwyREFBa0I7QUFDNUMsOEJBQThCO0FBQzlCOztBQUVBO0FBQ0E7QUFDQSw4QkFBOEIsNkVBQTBCLEdBQUc7QUFDM0Q7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQSxLQUFLLEdBQUc7O0FBRVIsMkJBQTJCLDJEQUFrQjtBQUM3Qyw4QkFBOEI7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSwrQ0FBK0MsRUFBRSw2REFBZTtBQUNoRTtBQUNBO0FBQ0Esb0JBQW9CLDBEQUFpQjtBQUNyQyxTQUFTO0FBQ1Q7QUFDQSxLQUFLLEdBQUc7O0FBRVIsd0JBQXdCLDJEQUFrQjtBQUMxQyw4QkFBOEI7O0FBRTlCO0FBQ0E7QUFDQSx3Q0FBd0M7QUFDeEMsOEJBQThCLDZFQUEwQjtBQUN4RCxTQUFTO0FBQ1Q7O0FBRUE7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDRDQUE0QywwRUFBbUI7O0FBRS9EO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLHdEQUFhO0FBQ3pCO0FBQ0EsVUFBVTtBQUNWLGdDQUFnQywwRUFBbUI7QUFDbkQsVUFBVTtBQUNWO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBLHVJQUF1SSwyRUFBb0I7QUFDM0o7O0FBRUEseUVBQXlFLG9FQUFjO0FBQ3ZGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLDRFQUFxQixDQUFDLHNEQUFhO0FBQzVELDBCQUEwQiw2RUFBc0I7QUFDaEQ7QUFDQTtBQUNBLFFBQVEsc0VBQWE7QUFDckI7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCxrRUFBa0UseURBQWM7QUFDaEY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsOERBQXFCLEdBQUcsK0RBQXNCO0FBQzVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0EsUUFBUSxzRUFBYTtBQUNyQjtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSwyQ0FBMkMscUVBQWU7QUFDMUQsa0JBQWtCLG9EQUFnQjtBQUNsQztBQUNBO0FBQ0Esc0NBQXNDLDhFQUFtQjtBQUN6RCxXQUFXO0FBQ1g7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBOztBQUVBLE1BQU0scURBQVc7QUFDakI7QUFDQTtBQUNBO0FBQ0EsUUFBUSxFQUFFLG9FQUEyQjtBQUNyQywrQkFBK0IsNkRBQW1COztBQUVsRDtBQUNBO0FBQ0EsOENBQThDLHNFQUE0Qjs7QUFFMUU7QUFDQSxtRUFBbUUsY0FBYyx5RUFBK0I7QUFDaEg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBOztBQUVBLE1BQU0scURBQVc7O0FBRWpCLGlCQUFpQixvREFBZ0I7QUFDakM7O0FBRUEsWUFBWSx5RUFBbUI7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBOztBQUVBLDBCQUEwQix5RkFBa0M7O0FBRTVEO0FBQ0EsY0FBYyx5RUFBbUIsZ0JBQWdCLHNEQUFhLCtCQUErQiw4RkFBeUM7QUFDdEksNkJBQTZCLHlFQUFrQjtBQUMvQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDJEQUEyRCx1RUFBa0I7QUFDN0UsT0FBTztBQUNQOztBQUVBO0FBQ0EsOEJBQThCLGtEQUFVOztBQUV4QztBQUNBLHlDQUF5QywyREFBa0I7QUFDM0Q7QUFDQTs7QUFFQSxvQ0FBb0Msb0VBQTJCO0FBQy9ELDZDQUE2Qyx1RUFBa0I7QUFDL0Qsa0NBQWtDLG9FQUEyQjtBQUM3RCwyQ0FBMkMsdUVBQWtCOztBQUU3RDtBQUNBOztBQUVBO0FBQ0EsZ0JBQWdCLHlEQUFhO0FBQzdCOztBQUVBO0FBQ0EsMEJBQTBCLGtEQUFTLENBQUMsOERBQXFCO0FBQ3pELGdFQUFnRTtBQUNoRTtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBLDJCQUEyQix1REFBVztBQUN0Qyw4REFBOEQ7O0FBRTlEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzRUFBc0Usd0RBQWU7QUFDckY7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBOztBQUVBO0FBQ0EsdUJBQXVCLG9EQUFTO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QixzREFBVztBQUNwQztBQUNBLHVDQUF1QywwREFBaUI7QUFDeEQ7QUFDQSw0QkFBNEIsNkRBQWU7QUFDM0M7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUEsZ0VBQWdFLDREQUFnQjtBQUNoRjtBQUNBOztBQUVBLHNDQUFzQyx5REFBZ0I7QUFDdEQ7O0FBRUE7QUFDQTtBQUNBLFVBQVUscURBQVc7QUFDckIsVUFBVTtBQUNWLFVBQVUsMkRBQWlCO0FBQzNCO0FBQ0E7O0FBRUEsMkJBQTJCLG9FQUEyQjtBQUN0RDtBQUNBO0FBQ0E7QUFDQSxRQUFROztBQUVSLHlDQUF5QywwRUFBOEI7QUFDdkU7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLGlFQUFxQjtBQUNqQztBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBLHFDQUFxQyxnR0FBcUM7O0FBRTFFO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxvREFBUztBQUNuQjtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDs7QUFFQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0EsVUFBVSxvREFBUztBQUNuQjtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBOztBQUVBLFVBQVUsMEVBQW9CO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTs7QUFFVixZQUFZLHNFQUFnQjtBQUM1QjtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxRQUFRLDJEQUFpQjs7QUFFekI7QUFDQTtBQUNBO0FBQ0EsY0FBYyxrREFBVSx3RUFBd0UsK0RBQXNCO0FBQ3RILFlBQVksc0VBQWE7QUFDekI7QUFDQSxhQUFhO0FBQ2IsWUFBWTtBQUNaLFlBQVksbURBQVMseUJBQXlCLDREQUFtQixHQUFHO0FBQ3BFO0FBQ0E7QUFDQSxVQUFVLG9EQUFvRCxrREFBVSx5RkFBeUYsK0RBQXNCO0FBQ3ZMLFVBQVUsbURBQVMseUJBQXlCLDREQUFtQjtBQUMvRCxVQUFVLHNFQUFhO0FBQ3ZCO0FBQ0EsV0FBVztBQUNYLFVBQVU7QUFDVixpQ0FBaUMsb0RBQVkscUNBQXFDLG9EQUFnQjtBQUNsRztBQUNBO0FBQ0E7O0FBRUEsY0FBYyxxRUFBNkI7QUFDM0M7QUFDQTtBQUNBO0FBQ0EsY0FBYyxFQUFFLHlFQUE4QjtBQUM5QztBQUNBO0FBQ0E7O0FBRUEsY0FBYyxtREFBVztBQUN6QixZQUFZLG1EQUFTLHlCQUF5Qiw0REFBbUI7QUFDakUsWUFBWTs7O0FBR1osVUFBVSxzRUFBYTtBQUN2QjtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsK0NBQStDLDRFQUFpQzs7QUFFaEY7QUFDQSxVQUFVLG1EQUFTLHlCQUF5QixzRUFBMkI7QUFDdkU7QUFDQTtBQUNBLFFBQVE7QUFDUixvQ0FBb0MsMkVBQWdDLENBQUMsMERBQWU7O0FBRXBGO0FBQ0EsVUFBVSxtREFBUyx5QkFBeUIsc0VBQTJCO0FBQ3ZFO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLFVBQVUsMERBQWM7QUFDeEI7QUFDQTs7QUFFQTtBQUNBLFFBQVEsbURBQVMseUJBQXlCLDREQUFtQjtBQUM3RCxRQUFRLHlFQUFvQjtBQUM1QixRQUFRO0FBQ1IsUUFBUSx3RUFBbUI7O0FBRTNCLDhDQUE4Qyx5RUFBbUI7QUFDakU7QUFDQTtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1YsVUFBVSxtREFBUyx5QkFBeUIsd0RBQWEsZUFBZSx5REFBZ0IsR0FBRyw4REFBcUI7QUFDaEgsVUFBVTtBQUNWLFVBQVUsbURBQVMseUJBQXlCLHlEQUFnQjtBQUM1RCxVQUFVO0FBQ1YsVUFBVSxtREFBUyx5QkFBeUIseURBQWdCO0FBQzVELFVBQVU7QUFDVjtBQUNBLFVBQVU7QUFDVixlQUFlLG9EQUFnQjtBQUMvQjtBQUNBLDhCQUE4Qix5RUFBbUI7QUFDakQsY0FBYyxtREFBUyx5QkFBeUIsNERBQW1CO0FBQ25FO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlO0FBQ2YsY0FBYztBQUNkLGNBQWMsbURBQVMseUJBQXlCLHlEQUFnQjs7QUFFaEU7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVixVQUFVLG1EQUFTLHlCQUF5Qix5REFBZ0I7QUFDNUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0EsdUJBQXVCLGtEQUFVO0FBQ2pDO0FBQ0Esb0NBQW9DO0FBQ3BDOztBQUVBO0FBQ0E7QUFDQSx1Q0FBdUM7O0FBRXZDO0FBQ0E7QUFDQSxVQUFVOzs7QUFHVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQix3RUFBa0I7O0FBRXJDO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQix1RUFBYztBQUNuQztBQUNBLGVBQWU7QUFDZjtBQUNBLFlBQVk7QUFDWixtQkFBbUIsdUVBQWM7QUFDakMsdUJBQXVCLHVFQUE4QjtBQUNyRCxhQUFhO0FBQ2I7QUFDQTs7QUFFQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPOzs7QUFHUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxrQkFBa0I7QUFDbEI7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBLDhDQUE4QztBQUM5QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsdURBQXVEO0FBQ3ZEO0FBQ0EsVUFBVSxJQUFJO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQyw2RUFBMEI7QUFDMUQ7QUFDQTtBQUNBLGFBQWEsSUFBSTtBQUNqQjtBQUNBLFNBQVM7QUFDVDtBQUNBLFFBQVE7QUFDUjtBQUNBOzs7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxxREFBcUQ7QUFDckQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0Esc0JBQXNCLHFEQUFZO0FBQ2xDO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSx5Q0FBeUM7QUFDekM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLDhEQUE4RDs7QUFFOUQsMkJBQTJCLDREQUFtQixxQkFBcUIsNkRBQW9CO0FBQ3ZGO0FBQ0EsUUFBUTs7O0FBR1I7QUFDQTtBQUNBLFFBQVE7QUFDUjs7O0FBR0E7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBLFFBQVE7QUFDUjtBQUNBLFFBQVEsbURBQVMseUJBQXlCLDhEQUFxQixHQUFHOztBQUVsRTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUUsb0VBQTJCO0FBQ3ZDLFFBQVEsc0VBQWE7QUFDckI7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQSxRQUFRO0FBQ1IsUUFBUSwyREFBaUI7QUFDekIsUUFBUTtBQUNSO0FBQ0EsUUFBUTtBQUNSO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxnQ0FBZ0MsMkRBQWtCO0FBQ2xELGdDQUFnQyx5REFBZ0I7QUFDaEQsZ0NBQWdDLHNEQUFhO0FBQzdDLGdDQUFnQyxvREFBVztBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsMkJBQTJCLG9FQUEyQjtBQUN0RDtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7O0FBRUEsWUFBWSx5RUFBbUI7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSwrRUFBK0UsMkVBQXNCO0FBQ3JHO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUUsK0RBQXNCO0FBQ25DO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87OztBQUdQO0FBQ0EsNERBQTRELDZEQUFvQixxQkFBcUIsNERBQW1CLHNCQUFzQiw0REFBZ0IsZ0RBQWdELHdEQUFhO0FBQzNOO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLG1EQUFTLHlCQUF5Qiw2REFBb0I7QUFDNUQ7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSLDRCQUE0QixvRUFBMkI7QUFDdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw4Q0FBOEMsb0RBQVc7QUFDekQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBLGdEQUFnRCxvREFBVztBQUMzRCx5Q0FBeUMseURBQWdCO0FBQ3pELGFBQWE7QUFDYjs7QUFFQSx5Q0FBeUMsb0RBQVc7QUFDcEQsa0NBQWtDLHlEQUFnQjtBQUNsRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTztBQUNQLHVCQUF1QiwyREFBa0I7QUFDekM7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxtREFBUyx5QkFBeUIseURBQWdCO0FBQzlELFlBQVk7QUFDWixZQUFZLDJEQUFpQjtBQUM3QjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxtQ0FBbUMsMkRBQWtCO0FBQ3JELG1DQUFtQyx5REFBZ0I7QUFDbkQsbUNBQW1DLG1EQUFVO0FBQzdDO0FBQ0EsT0FBTztBQUNQLDhCQUE4QixtREFBVTtBQUN4Qyw4QkFBOEIsMkRBQWtCO0FBQ2hEO0FBQ0EsT0FBTztBQUNQLDhCQUE4Qix5REFBZ0I7QUFDOUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEIsNkVBQTBCLEdBQUc7QUFDM0QsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxpREFBaUQsNEVBQWlDOztBQUVsRjtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBLFVBQVU7QUFDViwrQ0FBK0MsMkVBQWdDLENBQUMsMERBQWU7QUFDL0Y7O0FBRUE7QUFDQTtBQUNBLDJDQUEyQyxxREFBWSxDQUFDLDREQUFpQjs7QUFFekUsK0NBQStDLHFFQUFlO0FBQzlELHFEQUFxRCxrRUFBdUI7QUFDNUU7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBLHdCQUF3QixnR0FBcUM7O0FBRTdEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxlQUFlOztBQUVmO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7OztBQUdaOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhOztBQUViO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjs7O0FBR0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esa0NBQWtDLDZFQUEwQjtBQUM1RDtBQUNBLGVBQWU7QUFDZixhQUFhLEdBQUc7QUFDaEIsWUFBWTtBQUNaO0FBQ0Esc0JBQXNCLG9EQUFnQjtBQUN0QztBQUNBO0FBQ0E7O0FBRUEsdUVBQXVFLEVBQUUscUVBQTJCO0FBQ3BHO0FBQ0EsZUFBZSxJQUFJOztBQUVuQjtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQSxnREFBZ0QsMERBQWdCO0FBQ2hFO0FBQ0Esc0NBQXNDLDZFQUEwQixHQUFHO0FBQ25FLHNDQUFzQztBQUN0QztBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBLCtFQUErRTtBQUMvRTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixHQUFHOztBQUV0QjtBQUNBLG9CQUFvQix5REFBZ0I7QUFDcEM7QUFDQSxxQkFBcUI7QUFDckIsb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0I7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyRUFBMkUsNERBQWtCOztBQUU3RjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMERBQTBELDREQUFrQjtBQUM1RTtBQUNBLDJCQUEyQjtBQUMzQjtBQUNBLHVCQUF1QjtBQUN2QjtBQUNBOztBQUVBLHVEQUF1RCxFQUFFLHlFQUErQjtBQUN4RjtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CLDJEQUEyRCx5RUFBbUI7QUFDOUUsbUJBQW1CO0FBQ25CLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsd0RBQWE7QUFDdkI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sR0FBRzs7QUFFVixzQkFBc0IseUZBQWtDOztBQUV4RCxVQUFVLHlFQUFtQjtBQUM3QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLE1BQU0scURBQVc7O0FBRWpCO0FBQ0E7QUFDQSxzQkFBc0IseURBQWdCO0FBQ3RDO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQSw2QkFBNkIsb0RBQVk7QUFDekM7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLHNCQUFzQix3RUFBa0I7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLHVEQUF1RDtBQUN2RDtBQUNBO0FBQ0EsOEJBQThCLDZFQUEwQjtBQUN4RDtBQUNBLE9BQU87QUFDUDtBQUNBLE1BQU0sc0VBQWE7QUFDbkI7QUFDQTtBQUNBLE9BQU87QUFDUCwyQkFBMkIsOEVBQTJCO0FBQ3REO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCxPQUFPOzs7QUFHUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQSw2QkFBNkIsb0RBQVksMkZBQTJGLG9EQUFnQjtBQUNwSix3QkFBd0Isa0VBQVk7O0FBRXBDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQSxzQkFBc0IsMEVBQW9CO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUEsNkJBQTZCLG9EQUFZLDJGQUEyRixvREFBZ0I7QUFDcEo7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLHNCQUFzQiwwREFBZTtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxjQUFjOztBQUV4Qiw0Q0FBNEMsbURBQVc7QUFDdkQsVUFBVSxzRUFBYTtBQUN2QjtBQUNBLFdBQVc7QUFDWCwyQ0FBMkMsb0RBQWM7QUFDekQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsZ0JBQWdCOztBQUUxQixvRUFBb0Usa0RBQVUsaUhBQWlILCtEQUFzQjtBQUNyTiwyQ0FBMkMsb0RBQWM7QUFDekQ7QUFDQTs7QUFFQTtBQUNBLDhCQUE4Qiw2RUFBMEIsK0JBQStCO0FBQ3ZGO0FBQ0EsV0FBVztBQUNYLFNBQVMsSUFBSTtBQUNiOztBQUVBLFFBQVEsc0VBQWE7QUFDckI7QUFDQSxTQUFTO0FBQ1QsUUFBUSxtREFBUyx5QkFBeUIsNERBQW1CO0FBQzdELFFBQVE7QUFDUiwrQkFBK0Isb0RBQVksNkRBQTZELG9EQUFnQjtBQUN4SDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0Esd0JBQXdCLDJEQUFnQjtBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLHNFQUE2QjtBQUMvQyxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSx5REFBeUQ7QUFDekQ7QUFDQTtBQUNBLGdDQUFnQyw2RUFBMEI7QUFDMUQ7QUFDQSxTQUFTO0FBQ1QsUUFBUSxzRUFBYTtBQUNyQjtBQUNBLFNBQVM7QUFDVCw2QkFBNkIsOEVBQTJCO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsNkJBQTZCLG9EQUFZLGlJQUFpSSxvREFBZ0I7QUFDMUw7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGtCQUFrQiwwRUFBb0I7QUFDdEM7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1Isa0JBQWtCLHFEQUFVO0FBQzVCO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSw2QkFBNkIsb0RBQVksaUlBQWlJLG9EQUFnQjtBQUMxTCxvQkFBb0IscUVBQWU7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPLEVBQUUsb0RBQVc7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsdUVBQWM7QUFDL0I7QUFDQSxXQUFXO0FBQ1gsVUFBVSxTQUFTLHdFQUFrQjtBQUNyQyxpQkFBaUIsdUVBQWM7QUFDL0I7QUFDQSxXQUFXO0FBQ1gsVUFBVTtBQUNWLGlCQUFpQix1RUFBYztBQUMvQjtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQix1RUFBYztBQUMvQjtBQUNBLFdBQVc7QUFDWCxVQUFVLFNBQVMsd0VBQWtCO0FBQ3JDLGlCQUFpQix1RUFBYztBQUMvQjtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1YsaUJBQWlCLHVFQUFjO0FBQy9CO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCwwQkFBMEI7QUFDMUI7OztBQUdBLFdBQVcsaUVBQW9CO0FBQy9CLHdCQUF3Qix5Q0FBQztBQUN6Qjs7QUFFQTtBQUNBLE1BQU0sbURBQVM7O0FBRWYsdUJBQXVCLHVEQUFjO0FBQ3JDO0FBQ0Esc0JBQXNCLDREQUFlLE9BQU8sNkRBQVk7QUFDeEQsVUFBVTtBQUNWO0FBQ0EsMEJBQTBCLHlDQUFDO0FBQzNCO0FBQ0EsUUFBUTtBQUNSOzs7QUFHQSx1SUFBdUksK0RBQWtCOztBQUV6SjtBQUNBO0FBQ0Esd0JBQXdCLHlDQUFDO0FBQ3pCOztBQUVBOztBQUVBO0FBQ0E7QUFDQSw0QkFBNEIsNERBQWU7QUFDM0MsOEJBQThCLDBFQUFpQztBQUMvRCxXQUFXO0FBQ1gsVUFBVTtBQUNWO0FBQ0E7O0FBRUEsNkJBQTZCLCtEQUFzQjtBQUNuRCwwQkFBMEIseUNBQUM7QUFDM0Isd0JBQXdCLFdBQVcsK0RBQXNCLGdCQUFnQjtBQUN6RSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBLG1HQUFtRztBQUNuRztBQUNBOztBQUVBLHVDQUF1QywwREFBYTtBQUNwRDtBQUNBOztBQUVBLDRHQUE0Ryx1REFBVTtBQUN0SCwyQkFBMkIsc0VBQWE7QUFDeEM7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBLHFEQUFxRDtBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsVUFBVTtBQUNWO0FBQ0EsMkJBQTJCLHlDQUFDO0FBQzVCLFVBQVU7QUFDVjtBQUNBLFlBQVkscURBQVc7QUFDdkI7QUFDQTtBQUNBLE9BQU87QUFDUCxLQUFLO0FBQ0w7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTtBQUNSLFFBQVEsc0VBQWE7QUFDckI7QUFDQSxTQUFTO0FBQ1QseUNBQXlDLG9EQUFjO0FBQ3ZEO0FBQ0EseUNBQXlDLHlDQUFDO0FBQzFDLFNBQVM7QUFDVDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQyw0REFBZTtBQUNoRDtBQUNBLE9BQU87QUFDUCxpQ0FBaUMsdURBQVUsZ0JBQWdCO0FBQzNEOztBQUVBLDZCQUE2Qix1REFBYztBQUMzQywwQkFBMEIscUVBQW9CO0FBQzlDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQyx1REFBYztBQUN4RDs7QUFFQTtBQUNBLFFBQVEsbURBQVMsZ0NBQWdDLGVBQWU7QUFDaEU7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLG9FQUEyQjtBQUN2QztBQUNBO0FBQ0EsU0FBUztBQUNULGdDQUFnQywyREFBUTtBQUN4QztBQUNBLGtDQUFrQyx5REFBZ0I7QUFDbEQsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsNkVBQTBCO0FBQzFEO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWCw2Q0FBNkMsb0RBQWM7QUFDM0QsV0FBVztBQUNYLFVBQVU7QUFDVjtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLHlEQUFnQjtBQUN0QztBQUNBLFdBQVc7QUFDWCxTQUFTO0FBQ1QsMkNBQTJDLG9EQUFjO0FBQ3pELFNBQVM7QUFDVDtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQSxvQkFBb0IsK0VBQXlCOztBQUU3QztBQUNBLGlDQUFpQywyREFBa0Isa0RBQWtELDJEQUFrQjtBQUN2SDtBQUNBLFVBQVUsc0VBQWE7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkIsMkRBQWtCLGtEQUFrRCwyREFBa0I7QUFDakgsa0VBQWtFOztBQUVsRTtBQUNBO0FBQ0EsMkVBQTJFO0FBQzNFOztBQUVBO0FBQ0E7QUFDQSxRQUFRLHNFQUFhO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVEsUUFBUSxpRUFBaUI7QUFDakM7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQSxZQUFZLG9FQUFpQjtBQUM3QjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGNBQWMsK0VBQXlCO0FBQ3ZDLG1CQUFtQix1RUFBYztBQUNqQztBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7O0FBR0EscURBQXFELDRFQUEyQjtBQUNoRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxVQUFVOztBQUVWO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7OztBQUdBLGdDQUFnQyx1REFBUTtBQUN4QztBQUNBLEtBQUssRUFBRSw2REFBb0I7O0FBRTNCO0FBQ0Esa0NBQWtDLHFGQUFrQzs7QUFFcEU7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQSxxQ0FBcUMsOEVBQTJCO0FBQ2hFO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHVDQUF1Qyw4RUFBMkI7O0FBRWxFLCtDQUErQyx1RkFBb0M7QUFDbkY7QUFDQTs7QUFFQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0Esc0JBQXNCOzs7QUFHdEI7QUFDQSx5Q0FBeUM7QUFDekM7QUFDQTtBQUNBOztBQUVBLGdEQUFnRCxvREFBVztBQUMzRCxnREFBZ0QsMERBQWlCO0FBQ2pFLGdEQUFnRCx3REFBZSxvQkFBb0I7QUFDbkYsUUFBUTtBQUNSLGtHQUFrRyxvREFBVztBQUM3RyxrR0FBa0csMERBQWlCO0FBQ25ILGtHQUFrRyx3REFBZTtBQUNqSDtBQUNBOztBQUVBO0FBQ0EsMEJBQTBCOzs7QUFHMUI7QUFDQTtBQUNBO0FBQ0EsUUFBUSxRQUFRLDZEQUFnQjtBQUNoQztBQUNBO0FBQ0E7QUFDQSxRQUFRLEVBQUUsb0VBQTJCOztBQUVyQztBQUNBLFlBQVksaUVBQW9CO0FBQ2hDO0FBQ0E7QUFDQSwwRUFBMEUsdURBQWMsZ0VBQWdFLHVEQUFjO0FBQ3RLO0FBQ0Esa0NBQWtDLG9EQUFZO0FBQzlDLGtFQUFrRTtBQUNsRSx3REFBd0Q7QUFDeEQ7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLDZFQUEwQjtBQUMxRDtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUEscURBQXFELGlFQUF3Qjs7QUFFN0U7QUFDQTtBQUNBLCtCQUErQiw2REFBZ0I7QUFDL0M7QUFDQSxzQkFBc0Isa0ZBQWtDO0FBQ3hEO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsVUFBVTtBQUNWO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLG9CQUFvQiw0RUFBc0Isc0dBQXNHLGtFQUFZO0FBQzVKO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQix5REFBYTtBQUMvQixXQUFXOztBQUVYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLG1CQUFtQiwwREFBYTs7QUFFaEM7QUFDQSwwQkFBMEIsdUVBQTBCOztBQUVwRCx5QkFBeUIsOERBQXFCO0FBQzlDO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsOERBQThEO0FBQzlELG9EQUFvRDtBQUNwRDtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0EsV0FBVztBQUNYLFVBQVUsc0JBQXNCLGlFQUF3QjtBQUN4RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0EsNEJBQTRCLHlDQUFDO0FBQzdCLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0EsdUJBQXVCLGlFQUF3QjtBQUMvQztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVEsRUFBRSxvRUFBMkI7QUFDckM7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBLE1BQU0sc0RBQVU7QUFDaEIsa0RBQWtELHNHQUFzRyxlQUFlLHlFQUErQjtBQUN0TTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCwrQkFBK0IscUVBQWUsZ0JBQWdCLDhFQUFtQjtBQUNqRixPQUFPO0FBQ1A7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULE9BQU87QUFDUDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsUUFBUSx5REFBYyxzSUFBc0ksaURBQVEsOENBQThDLGlEQUFRLDhDQUE4QyxpRUFBeUIsU0FBUyw4REFBc0I7QUFDaFUsUUFBUTtBQUNSLDZCQUE2QixvREFBWSx5Q0FBeUMsb0RBQWdCO0FBQ2xHLHNCQUFzQiwrRUFBeUI7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsRUFBRSwwREFBYztBQUMxQjtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUSx5REFBYyw4SEFBOEgsaURBQVEsMENBQTBDLGlEQUFRLDBDQUEwQyxvRUFBYyxxQkFBcUIsaUVBQXlCLFVBQVUsaUVBQXlCLFNBQVMsOERBQXNCO0FBQ3RYLDJEQUEyRDs7QUFFM0Q7QUFDQTtBQUNBLGlDQUFpQyxtRUFBMEI7QUFDM0QsV0FBVztBQUNYO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSwrQkFBK0Isb0RBQVksK0dBQStHLG9EQUFnQjtBQUMxSztBQUNBO0FBQ0EsZ0NBQWdDLHlEQUFnQjtBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxTQUFTO0FBQ1QsT0FBTyxHQUFHO0FBQ1Y7O0FBRUE7QUFDQSwrQkFBK0Isb0RBQVkseUNBQXlDLG9EQUFnQjtBQUNwRztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUUsZ0VBQW9CLG1CQUFtQiw0REFBbUI7QUFDdEU7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUEsVUFBVSw0REFBaUIsa0dBQWtHLHFFQUE2QixTQUFTLDhEQUFzQiwwQ0FBMEMsb0VBQWMseUJBQXlCLGlFQUF5QixVQUFVLGlFQUF5QjtBQUN0VTtBQUNBO0FBQ0E7QUFDQSxrQ0FBa0MseURBQWdCLGdEQUFnRDs7QUFFbEc7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZ0JBQWdCLHNFQUFhO0FBQzdCO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakIsZUFBZTtBQUNmOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxnQkFBZ0Isc0VBQWE7QUFDN0I7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixlQUFlO0FBQ2Y7QUFDQTs7QUFFQSxVQUFVLG1FQUEwQjtBQUNwQyxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLG1CQUFtQixxREFBZSxFQUFFLHFEQUFlLEdBQUc7QUFDdEQ7O0FBRUE7QUFDQTtBQUNBLDhCQUE4QiwwREFBb0IsRUFBRSx5REFBbUIsRUFBRSxnRkFBb0IsRUFBRSx1REFBaUI7QUFDaEg7O0FBRUEsZ0JBQWdCLGtFQUFXLEVBQUUsaUVBQXNCLEVBQUUscURBQWUsRUFBRSxxREFBZSxFQUFFLDhDQUFRLEVBQUUsaUVBQXNCLEVBQUUscURBQWUsRUFBRSxnRkFBdUIsRUFBRSxpRUFBc0IsRUFBRSwwREFBb0IsRUFBRSxpRUFBMkIsRUFBRSx5REFBbUIsRUFBRSxnRkFBb0IsRUFBRSx1REFBaUI7QUFDMVMsUUFBUTtBQUNSOzs7QUFHQSxtQkFBbUIsOENBQVE7O0FBRTNCO0FBQ0EsZ0JBQWdCLGdEQUFVO0FBQzFCOztBQUVBLGNBQWMsK0NBQVMsRUFBRSxnREFBVSxFQUFFLGtFQUFXLEVBQUUsaUZBQThCLEVBQUUsbUZBQWdDLEVBQUUsaUVBQXNCLGNBQWMsaUVBQXNCLEVBQUUsc0RBQWdCLEVBQUUsdURBQWlCLEVBQUUsaUVBQXNCLEVBQUUsaURBQVcsRUFBRSxzREFBZ0IsRUFBRSxvREFBYyxFQUFFLGdGQUF5QixFQUFFLG1EQUFhLEVBQUUsaUVBQXNCLEVBQUUsd0RBQWtCLEVBQUUsaUVBQXNCLEVBQUUsd0RBQWtCLEVBQUUsd0RBQWtCLEVBQUUsc0RBQWdCLEVBQUUsd0RBQWtCLEVBQUUsaUVBQXNCLEVBQUUsMERBQW9CLEVBQUUsd0RBQWtCLEVBQUUsaUVBQXNCLEVBQUUsOERBQXdCLEVBQUUsZ0RBQVUsRUFBRSw4REFBd0IsRUFBRSw2REFBdUIsRUFBRSxpRUFBc0IsRUFBRSwwREFBb0I7QUFDdnJCOztBQUVBLHVCQUF1QiwyREFBa0I7QUFDekM7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVEsU0FBUzs7QUFFakI7QUFDQTtBQUNBLHlCQUF5QixrREFBUztBQUNsQztBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwyREFBMkQ7O0FBRTNEO0FBQ0E7QUFDQSxvRUFBb0UsRUFBRSw2REFBZTtBQUNyRjtBQUNBO0FBQ0Esb0JBQW9CLDBEQUFpQjtBQUNyQyxTQUFTO0FBQ1Q7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUSxFQUFFLG9FQUEyQjtBQUNyQztBQUNBO0FBQ0EsT0FBTzs7QUFFUCwyQ0FBMkM7QUFDM0M7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBLCtDQUErQyxpREFBUTtBQUN2RDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7O0FBRVY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQSxvQ0FBb0M7QUFDcEM7O0FBRUEsNEJBQTRCLDhEQUFrQjtBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOLDJFQUEyRTtBQUMzRTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxrREFBUztBQUMzQztBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsY0FBYywrQ0FBTTtBQUNwQix1QkFBdUIsc0RBQU87QUFDOUIscUJBQXFCLHFEQUFLO0FBQzFCO0FBQ0EsY0FBYyxnRUFBWTtBQUMxQix3QkFBd0Isc0RBQVE7O0FBRWhDO0FBQ0EsMkJBQTJCLDBEQUFpQjtBQUM1QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQixnREFBSztBQUMxQjtBQUNBO0FBQ0EsS0FBSztBQUNMLHVCQUF1QixpREFBTztBQUM5Qiw2QkFBNkIsMkRBQWE7QUFDMUMsbUNBQW1DLHNEQUFPO0FBQzFDLHNDQUFzQyx3RUFBZ0I7QUFDdEQsc0NBQXNDLHdFQUFnQjtBQUN0RDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSw0QkFBNEIsdURBQWM7QUFDMUM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsNkNBQTZDLGlFQUF3QjtBQUNyRTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQSxhQUFhLCtEQUFzQjtBQUNuQyxhQUFhLGlFQUF3QjtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtFQUErRSx5RUFBbUI7QUFDbEcsV0FBVyxzREFBSSxDQUFDLHVEQUFTO0FBQ3pCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFLG9FQUEyQjtBQUN2QztBQUNBO0FBQ0EsU0FBUztBQUNULDBCQUEwQixrRUFBWSxDQUFDLHNEQUFVO0FBQ2pELDBCQUEwQiwwRUFBbUI7QUFDN0M7QUFDQTtBQUNBLGVBQWUsc0RBQUk7QUFDbkIscUJBQXFCLGdEQUFJO0FBQ3pCO0FBQ0EsV0FBVztBQUNYO0FBQ0EsZ0RBQWdELDBCQUEwQixNQUFNLHlCQUF5QixZQUFZLE1BQU07QUFDM0g7QUFDQTtBQUNBLHdDQUF3Qyx1REFBZSxvQ0FBb0M7QUFDM0Y7QUFDQSxTQUFTO0FBQ1Qsb0JBQW9CLHVEQUFLO0FBQ3pCO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNENBQTRDLEdBQUc7QUFDL0M7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0Esb0NBQW9DLFNBQVM7QUFDN0MscUNBQXFDLFVBQVU7QUFDL0MsK0NBQStDLFNBQVM7QUFDeEQsd0NBQXdDLCtEQUFzQixHQUFHLGdFQUF1QjtBQUN4RjtBQUNBLFdBQVc7QUFDWCxvQ0FBb0Msc0RBQUk7QUFDeEM7QUFDQSxhQUFhO0FBQ2Isd0JBQXdCLHlDQUFDO0FBQ3pCLGFBQWEsSUFBSSxzREFBSTtBQUNyQjtBQUNBO0FBQ0EsNEJBQTRCLGVBQWU7QUFDM0M7QUFDQSxhQUFhO0FBQ2IsMktBQTJLLHNEQUFJO0FBQy9LO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsVUFBVSxpQkFBaUIsaUJBQWlCLFdBQVc7QUFDOUY7QUFDQTtBQUNBLGVBQWU7QUFDZixhQUFhO0FBQ2IsV0FBVztBQUNYLFNBQVM7QUFDVCxPQUFPO0FBQ1AsS0FBSztBQUNMOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsV0FBVyxzREFBSTtBQUNmLGlCQUFpQixnREFBSTtBQUNyQjtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSw0RUFBNEUsd0RBQWEsOEJBQThCLGdFQUF1QixHQUFHLCtEQUFzQjtBQUN2SyxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsZ0JBQWdCLHNEQUFJO0FBQ3BCO0FBQ0EsT0FBTztBQUNQLGtCQUFrQixzREFBSTtBQUN0QjtBQUNBLFNBQVM7QUFDVCxvQkFBb0Isc0RBQUk7QUFDeEI7QUFDQSxXQUFXO0FBQ1gsc0JBQXNCLHNEQUFJO0FBQzFCO0FBQ0EsYUFBYTtBQUNiLHdCQUF3QixzREFBSTtBQUM1QjtBQUNBLGVBQWU7QUFDZiwwQkFBMEIsc0RBQUk7QUFDOUI7QUFDQSxpQkFBaUI7QUFDakIsNEJBQTRCLHVEQUFLO0FBQ2pDO0FBQ0EsbUJBQW1CO0FBQ25CLCtCQUErQix1REFBSztBQUNwQztBQUNBLHFCQUFxQjtBQUNyQixpQ0FBaUMsdURBQUssQ0FBQyxpREFBTztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQ0FBa0MsbURBQVc7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QjtBQUN2QiwrRkFBK0Ysc0RBQUksQ0FBQyw2REFBbUIsSUFBSTtBQUMzSCx1QkFBdUIsSUFBSSxzREFBSTtBQUMvQjtBQUNBLHVCQUF1QixHQUFHLHNEQUFJO0FBQzlCO0FBQ0EsdUJBQXVCLEdBQUcsc0RBQUk7QUFDOUI7QUFDQSx1QkFBdUIsR0FBRyxzREFBSSxDQUFDLG1FQUFnQjtBQUMvQztBQUNBLHVCQUF1QixnR0FBZ0csc0RBQUksQ0FBQywwREFBUztBQUNySTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1Qix3REFBd0Qsc0RBQUksQ0FBQywwQ0FBSztBQUN6RjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1Qiw2QkFBNkIsc0RBQUksQ0FBQyxzREFBVztBQUNwRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQjtBQUMzQjtBQUNBO0FBQ0EsMkJBQTJCO0FBQzNCO0FBQ0EsdUJBQXVCLEdBQUcsc0RBQUksQ0FBQyxvREFBWTtBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QixHQUFHLHNEQUFJLENBQUMseURBQWlCO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QjtBQUN2QixxQkFBcUI7QUFDckIsbUJBQW1CO0FBQ25CLGlCQUFpQjtBQUNqQixlQUFlO0FBQ2YsYUFBYTtBQUNiLFdBQVc7QUFDWCxTQUFTO0FBQ1QsT0FBTztBQUNQLEtBQUs7QUFDTDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxVQUFVLGFBQW9CLEtBQUssaURBQVEsSUFBSSxhQUFvQjtBQUNuRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPLGtEQUFTO0FBQ2hCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBLFFBQVE7OztBQUdSLFVBQVUsb0RBQU8sT0FBTyw2RUFBc0I7QUFDOUM7QUFDQSx3QkFBd0Isc0RBQUksQ0FBQywrREFBcUIsSUFBSTtBQUN0RCxTQUFTO0FBQ1Q7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLHFCQUFxQixxREFBSztBQUMxQix3QkFBd0Isc0RBQVE7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSSxrRUFBa0I7QUFDdEIsSUFBSSx5REFBaUI7QUFDckI7QUFDQSxJQUFJLHFFQUFnQztBQUNwQyxJQUFJLGdGQUEwQztBQUM5QztBQUNBOztBQUVBO0FBQ0E7O0FBRUEsaUNBQWlDLHlEQUFnQjtBQUNqRCxpQ0FBaUMsbURBQVU7QUFDM0MsaUNBQWlDLG9EQUFXO0FBQzVDLGlDQUFpQyxrREFBUztBQUMxQywyR0FBMkcsb0RBQVc7QUFDdEgsdUdBQXVHLHFEQUFZO0FBQ25ILGlDQUFpQyxzREFBYTtBQUM5QyxpQ0FBaUMseURBQWdCO0FBQ2pELGlDQUFpQyxvREFBVztBQUM1QywrQkFBK0IscURBQVk7QUFDM0MsK0JBQStCLHFEQUFZO0FBQzNDLCtCQUErQixtREFBVTtBQUN6QywyR0FBMkcsd0RBQWU7QUFDMUgsMkdBQTJHLG1EQUFVO0FBQ3JILGlDQUFpQyw0REFBbUI7QUFDcEQsaUNBQWlDLDZEQUFvQjtBQUNyRCxpQ0FBaUMsMERBQWlCO0FBQ2xELCtCQUErQixzREFBYTtBQUM1Qzs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsNEJBQTRCLHNEQUFhO0FBQ3pDLDhCQUE4Qix5REFBZ0IsdUJBQXVCOztBQUVyRSw4QkFBOEIsbURBQVU7QUFDeEMsd0dBQXdHLG9EQUFXO0FBQ25IO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLGdDQUFnQyxzREFBYTtBQUM3Qzs7QUFFQSw4QkFBOEIsb0RBQVc7QUFDekM7QUFDQSxLQUFLO0FBQ0wsOEJBQThCLHlEQUFnQixxQ0FBcUM7O0FBRW5GO0FBQ0E7QUFDQTtBQUNBLEtBQUssR0FBRzs7QUFFUiw4QkFBOEIsNERBQW1CO0FBQ2pELDhCQUE4Qiw2REFBb0I7QUFDbEQsOEJBQThCLDBEQUFpQjs7QUFFL0M7QUFDQTtBQUNBOztBQUVBLDhCQUE4QixvREFBVztBQUN6Qyw4QkFBOEIsa0RBQVM7O0FBRXZDO0FBQ0Esd0NBQXdDLHNFQUE2QjtBQUNyRSx1REFBdUQscURBQVk7QUFDbkU7O0FBRUEsNEJBQTRCLHFEQUFZO0FBQ3hDLDRCQUE0QixxREFBWTtBQUN4Qyw0QkFBNEIsbURBQVU7QUFDdEMsd0dBQXdHLHdEQUFlO0FBQ3ZILHdHQUF3RyxtREFBVTtBQUNsSDs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDZEQUE2RCwwREFBYztBQUMzRTtBQUNBLG9CQUFvQix5REFBZ0I7QUFDcEM7QUFDQSxTQUFTO0FBQ1QsT0FBTztBQUNQOztBQUVBO0FBQ0EsTUFBTSx5REFBZTtBQUNyQixNQUFNOzs7QUFHTjtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQSwrQ0FBK0Msa0RBQVM7QUFDeEQsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0RUFBNEUsb0RBQWM7QUFDMUYsT0FBTztBQUNQLE1BQU07QUFDTjs7O0FBR0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBLE1BQU07O0FBRU4sa0ZBQWtGLG1FQUFnQixnQkFBZ0Isc0VBQWdCO0FBQ2xJLE1BQU0seUVBQXNCLHVDQUF1QyxxREFBWSxDQUFDLCtHQUFvRDtBQUNwSTs7QUFFQSwrRUFBK0U7QUFDL0U7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLDJEQUFjO0FBQ3hDO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7OztBQUdBLGNBQWMsc0VBQWE7QUFDM0I7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhCQUE4Qiw2RUFBMEI7QUFDeEQsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBLFFBQVE7QUFDUjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU0sRUFBRSxvRUFBMkI7QUFDbkM7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsK0RBQXNCO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EseUJBQXlCLDJFQUFvQjs7QUFFN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Qsd0JBQXdCLHlEQUFjLCtCQUErQjtBQUNyRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxRQUFRO0FBQ1IsK0ZBQStGO0FBQy9GOztBQUVBO0FBQ0Esc0JBQXNCLHdFQUFpQjtBQUN2QztBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0EsMEJBQTBCLDZFQUEwQjtBQUNwRCxLQUFLOztBQUVMO0FBQ0E7QUFDQSxpQkFBaUIseUNBQUM7QUFDbEIsb0JBQW9CLHVEQUFjO0FBQ2xDLFNBQVM7QUFDVDtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsMENBQTBDLHdEQUFhO0FBQ3ZELGlCQUFpQiw0REFBaUI7QUFDbEM7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0EsT0FBTztBQUNQOztBQUVBLElBQUksc0RBQVc7QUFDZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUUsb0VBQTJCO0FBQ3ZDO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxPQUFPO0FBQ1AsZ0JBQWdCLDJEQUFrQjtBQUNsQzs7QUFFQSxZQUFZLDhEQUFtQjtBQUMvQixVQUFVLHNFQUFtQjtBQUM3QjtBQUNBLE9BQU87QUFDUCxnQkFBZ0IsMkRBQWtCO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLHNEQUFzRDtBQUN0RDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsNkVBQTBCLCtCQUErQjtBQUN6RjtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7O0FBRUE7QUFDQSxVQUFVLDJFQUF3QjtBQUNsQzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBLFVBQVUsMkRBQWlCO0FBQzNCOztBQUVBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLEtBQUssR0FBRzs7QUFFUiw2QkFBNkI7QUFDN0I7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsMEJBQTBCLDZFQUEwQixHQUFHO0FBQ3ZELDBCQUEwQjtBQUMxQjtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUwsbUJBQW1CLHdEQUFhO0FBQ2hDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxvREFBb0QsWUFBWTtBQUNoRTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtGQUFrRjtBQUNsRjs7QUFFQSxhQUFhLDJGQUFnRDtBQUM3RDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDhPQUE4Tyx3REFBYTtBQUMzUCxXQUFXLDhEQUFxQixzQkFBc0Isa0RBQU87QUFDN0Q7QUFDQSw4QkFBOEIsMkRBQWtCO0FBQ2hELHNHQUFzRyx3REFBZTtBQUNySDtBQUNBO0FBQ0EsT0FBTztBQUNQLEtBQUs7QUFDTDs7QUFFQTtBQUNBLG9CQUFvQix5RkFBOEI7QUFDbEQsNkJBQTZCLDBFQUFtQjs7QUFFaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxVQUFVLDhGQUF5QztBQUNuRCwwQkFBMEIsdUdBQTRDO0FBQ3RFLHVDQUF1QywwR0FBK0M7QUFDdEY7QUFDQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQSxVQUFVLG1EQUFTLHlCQUF5Qiw0REFBbUI7QUFDL0QsVUFBVTtBQUNWLFVBQVUsbURBQVMseUJBQXlCLHlEQUFnQjtBQUM1RDtBQUNBLFFBQVEsU0FBUyxpRkFBcUIsMkJBQTJCLDJGQUFnRDtBQUNqSCxRQUFRLG1EQUFTLHlCQUF5Qix5REFBZ0I7QUFDMUQsUUFBUSw2QkFBNkIsa0RBQU87QUFDNUMsUUFBUSxtREFBUyx5QkFBeUIseURBQWdCO0FBQzFEOztBQUVBO0FBQ0E7QUFDQSwrREFBK0Q7QUFDL0Q7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUOztBQUVBLFdBQVcsNkZBQWtDO0FBQzdDO0FBQ0EsK0RBQStEO0FBQy9EO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBLE1BQU07QUFDTixNQUFNLG1EQUFTLHlCQUF5Qix5REFBZ0I7QUFDeEQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLDJCQUEyQixvREFBUztBQUNwQztBQUNBLGdDQUFnQyxzREFBVztBQUMzQztBQUNBOztBQUVBO0FBQ0EsbUJBQW1CLG9FQUEyQjtBQUM5QztBQUNBLHFDQUFxQywwREFBZTtBQUNwRDtBQUNBO0FBQ0EsMkJBQTJCLG9EQUFnQjtBQUMzQyxvQkFBb0IscURBQVksQ0FBQyxvREFBWSwyQkFBMkIsb0RBQWdCO0FBQ3hGLGtCQUFrQix5REFBZ0I7QUFDbEM7QUFDQSxrQ0FBa0M7QUFDbEM7QUFDQSw0QkFBNEIscUVBQWU7QUFDM0M7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLElBQUk7OztBQUdKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixvRUFBMkI7QUFDckQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMLHdCQUF3QiwyREFBa0I7QUFDMUM7QUFDQSxNQUFNLDJEQUFpQjtBQUN2QjtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxpQ0FBaUMsMkRBQWtCO0FBQ25ELGlDQUFpQyx5REFBZ0I7QUFDakQ7QUFDQSxLQUFLO0FBQ0w7QUFDQSw0QkFBNEIsMkRBQWtCO0FBQzlDLDRCQUE0Qix5REFBZ0I7QUFDNUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7O0FBR047QUFDQSw2QkFBNkIsMERBQWU7QUFDNUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSwyRUFBcUIsZ0JBQWdCLGtFQUF5QixHQUFHLHNFQUE2QjtBQUMxRyxNQUFNO0FBQ047O0FBRUE7QUFDQSxRQUFRLDZEQUFpQjtBQUN6QjtBQUNBO0FBQ0E7QUFDQSxLQUFLLDJCQUEyQix3RUFBZ0M7QUFDaEUsTUFBTSx3RUFBZ0MsQ0FBQyxrRUFBc0I7QUFDN0Q7QUFDQTs7QUFFQTtBQUNBLFFBQVEsNkRBQWlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBLEtBQUssMkJBQTJCLGdFQUF3QjtBQUN4RCxNQUFNLGdFQUF3QixDQUFDLDBEQUFjO0FBQzdDO0FBQ0E7O0FBRUE7QUFDQSxXQUFXLDJEQUFrQjtBQUM3QjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQSxXQUFXLDJEQUFrQjtBQUM3QjtBQUNBLG9CQUFvQiw0Q0FBUTs7QUFFNUI7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0EsV0FBVyxvRUFBMkI7QUFDdEMsa0JBQWtCO0FBQ2xCO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQSx1Q0FBdUMscURBQVksQ0FBQywwREFBZTtBQUNuRTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDRCQUE0QixvRUFBMkI7O0FBRXZELFVBQVUsMERBQWM7QUFDeEI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSw2QkFBNkIsb0RBQVkseUNBQXlDLG9EQUFnQixpQ0FBaUM7QUFDbkk7QUFDQTtBQUNBOztBQUVBO0FBQ0EsWUFBWSxrREFBVSwyRkFBMkYsMkRBQWtCO0FBQ25JO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxZQUFZLGdHQUFxQztBQUNqRCxzQkFBc0IsMEZBQStCLHFFQUFxRSxvREFBZ0I7O0FBRTFJO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7O0FBR0EsVUFBVSxvREFBUztBQUNuQjtBQUNBO0FBQ0EscUVBQXFFO0FBQ3JFO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakIsZUFBZTtBQUNmOztBQUVBO0FBQ0E7QUFDQSxvRUFBb0U7QUFDcEU7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixlQUFlO0FBQ2Y7QUFDQSxXQUFXO0FBQ1g7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7QUFFQSx3QkFBd0Isa0dBQXVDO0FBQy9EO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esa0VBQWtFO0FBQ2xFO0FBQ0EsZUFBZTtBQUNmLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0EsbUVBQW1FO0FBQ25FO0FBQ0EsZUFBZTtBQUNmLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxxRUFBcUUsb0VBQWM7QUFDbkY7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHO0FBQ1o7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0ZBQW9GOztBQUVwRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksRUFBRSwrREFBbUIsQ0FBQyw0REFBbUI7QUFDckQ7QUFDQTtBQUNBLFdBQVcsR0FBRztBQUNkOztBQUVBLHNDQUFzQywrREFBb0IsMkZBQTJGLG9EQUFnQjtBQUNySyw0REFBNEQ7O0FBRTVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsMkRBQWdCO0FBQzFEO0FBQ0EsZ0JBQWdCLHNFQUFhO0FBQzdCO0FBQ0E7QUFDQSxpQkFBaUIsR0FBRztBQUNwQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLHNGQUErQjtBQUMzQyxZQUFZLDhFQUEyQjtBQUN2QyxZQUFZLDZFQUFvQztBQUNoRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSOzs7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxVQUFVLHNFQUFhO0FBQ3ZCO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQSxRQUFRLFNBQVMscUVBQWU7QUFDaEM7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQSxZQUFZLHFFQUE2QjtBQUN6QztBQUNBO0FBQ0E7QUFDQSxZQUFZLEVBQUUseUVBQThCO0FBQzVDOztBQUVBO0FBQ0EsVUFBVSxzRUFBYTtBQUN2QjtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1YsVUFBVSxzRUFBYTtBQUN2QjtBQUNBLFdBQVc7QUFDWDs7QUFFQSxZQUFZLHNFQUFnQjtBQUM1QjtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDZEQUE2RDs7QUFFN0Q7QUFDQSxVQUFVLGlHQUFzQywrQ0FBK0M7QUFDL0YsVUFBVTtBQUNWOztBQUVBLGlDQUFpQyw4REFBcUI7QUFDdEQ7QUFDQSx5Q0FBeUMseUVBQStCLCtCQUErQjtBQUN2RztBQUNBO0FBQ0E7QUFDQSxlQUFlO0FBQ2YsY0FBYztBQUNkO0FBQ0E7QUFDQTs7QUFFQSwwQ0FBMEMsbUVBQTBCO0FBQ3BFO0FBQ0EseUVBQXlFO0FBQ3pFO0FBQ0E7QUFDQSxhQUFhLElBQUk7O0FBRWpCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBOztBQUVBLDhFQUE4RTtBQUM5RSxrQ0FBa0M7QUFDbEM7QUFDQSxhQUFhO0FBQ2IsaURBQWlELEVBQUUseUVBQStCO0FBQ2xGO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQSw2RUFBNkUscUVBQWUsbUNBQW1DLDhFQUFtQjtBQUNsSiw4R0FBOEcseUVBQW1CO0FBQ2pJLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJOzs7QUFHSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXLDJEQUFrQjtBQUM3Qjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0Msd0RBQWE7QUFDckQ7QUFDQTtBQUNBLE9BQU87QUFDUCxNQUFNLHdFQUFnQztBQUN0QyxNQUFNLGdFQUF3QjtBQUM5QjtBQUNBO0FBQ0E7QUFDQSxPQUFPLEdBQUc7QUFDVjs7QUFFQTtBQUNBO0FBQ0EsMkNBQTJDLG9EQUFjO0FBQ3pELFVBQVU7QUFDVix1Q0FBdUMsOEZBQW1DOztBQUUxRTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0EsK0VBQStFOztBQUUvRTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQSxVQUFVO0FBQ1Ysc0NBQXNDLDhGQUFtQztBQUN6RTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7O0FBRUEsY0FBYyxzRUFBZ0I7QUFDOUIsWUFBWSw0RUFBeUI7QUFDckM7O0FBRUE7QUFDQTtBQUNBLG1FQUFtRTtBQUNuRTtBQUNBLGVBQWU7QUFDZjtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxpQ0FBaUMsMkRBQWtCO0FBQ25ELGlDQUFpQyx5REFBZ0I7QUFDakQsaUNBQWlDLHNEQUFhO0FBQzlDLGlDQUFpQyxvREFBVzs7QUFFNUM7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBOztBQUVBO0FBQ0EsOEJBQThCLG9FQUEyQjtBQUN6RDtBQUNBO0FBQ0Esc0RBQXNEOztBQUV0RDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFFBQVEsc0VBQWE7QUFDckI7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULHlDQUF5QyxvREFBYztBQUN2RDtBQUNBOztBQUVBLFVBQVUsb0VBQWM7QUFDeEI7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLDZFQUEwQjtBQUMxRDtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1gsNkNBQTZDLG9EQUFjO0FBQzNELFdBQVc7QUFDWCxVQUFVO0FBQ1Y7QUFDQTtBQUNBLDJDQUEyQyxvREFBYztBQUN6RDs7QUFFQTtBQUNBOztBQUVBLFVBQVUscUVBQWU7QUFDekI7QUFDQTtBQUNBOztBQUVBLDhCQUE4QixvRUFBMkI7O0FBRXpEO0FBQ0EsVUFBVSxzRUFBYTtBQUN2QjtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsVUFBVTtBQUNWLGNBQWMsbUVBQWdCLGdCQUFnQixzRUFBZ0I7QUFDOUQsWUFBWSx5RUFBc0I7QUFDbEM7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVzs7QUFFWDtBQUNBLFlBQVkscURBQVc7QUFDdkI7QUFDQTtBQUNBLDBCQUEwQix5REFBZ0I7QUFDMUM7QUFDQSxlQUFlO0FBQ2Ysa0NBQWtDLDZFQUEwQiwrQkFBK0I7QUFDM0Y7QUFDQSxlQUFlO0FBQ2YseUNBQXlDLDhFQUFtQjtBQUM1RCxhQUFhO0FBQ2IsWUFBWTtBQUNaO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGdFQUFnRSxrRUFBdUI7QUFDdkY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsOEJBQThCLG9FQUEyQiwwQkFBMEI7QUFDbkY7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsNEJBQTRCLDJEQUFrQjs7QUFFOUM7QUFDQSxxQkFBcUIsaUVBQXdCO0FBQzdDO0FBQ0E7QUFDQSxrQkFBa0Isc0VBQWE7QUFDL0I7QUFDQSxtQkFBbUI7QUFDbkIsZ0RBQWdELGdFQUF1QjtBQUN2RTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isc0VBQWE7QUFDL0I7QUFDQSxtQkFBbUI7QUFDbkI7O0FBRUE7QUFDQSxpREFBaUQsNERBQWtCO0FBQ25FLG9CQUFvQixzRUFBYTtBQUNqQztBQUNBLHFCQUFxQjtBQUNyQjtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7O0FBRUE7QUFDQSwrR0FBK0cseURBQWdCOztBQUUvSDtBQUNBO0FBQ0E7O0FBRUEsNkJBQTZCLDJEQUFrQjtBQUMvQyxjQUFjO0FBQ2Q7QUFDQSxnR0FBZ0cseURBQWdCO0FBQ2hIO0FBQ0E7QUFDQTs7QUFFQSwyQkFBMkIsZ0ZBQXVDO0FBQ2xFO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHNDQUFzQyw4REFBcUI7QUFDM0Qsd0NBQXdDLDJEQUFrQjtBQUMxRDs7QUFFQSxRQUFRLHNFQUFhLGtCQUFrQixrRUFBdUI7QUFDOUQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDZCQUE2QixrRUFBdUI7QUFDcEQ7QUFDQSxRQUFROzs7QUFHUjtBQUNBLDJCQUEyQixnRkFBdUM7QUFDbEU7O0FBRUE7QUFDQSx5QkFBeUIsa0VBQXlCLGVBQWUsbUVBQTBCO0FBQzNGOztBQUVBO0FBQ0EsUUFBUTtBQUNSOzs7QUFHQTs7QUFFQSxxTEFBcUwscUVBQWU7QUFDcE0sNkVBQTZFO0FBQzdFOztBQUVBO0FBQ0E7QUFDQSx1Q0FBdUMsOEVBQW1CO0FBQzFELFdBQVc7QUFDWDtBQUNBOztBQUVBLFVBQVUsMERBQWM7QUFDeEIsZ0NBQWdDLGtEQUFVOztBQUUxQztBQUNBLCtCQUErQixvRUFBMkI7QUFDMUQ7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLDREQUFrQjtBQUNsQztBQUNBLCtEQUErRCxrQ0FBa0M7QUFDakc7QUFDQTs7QUFFQSxvRkFBb0YsNERBQWtCO0FBQ3RHO0FBQ0E7O0FBRUE7QUFDQSxrRUFBa0U7QUFDbEU7QUFDQSxtQkFBbUIsdURBQXVELGlCQUFpQjtBQUMzRixzQ0FBc0MsNkVBQTBCO0FBQ2hFO0FBQ0EsZUFBZSxHQUFHO0FBQ2xCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSw4REFBOEQ7QUFDOUQ7QUFDQSw0Q0FBNEMsNERBQW1CO0FBQy9EO0FBQ0EsaUJBQWlCO0FBQ2pCLHFEQUFxRCxFQUFFLHlFQUErQjtBQUN0RjtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0EsNkVBQTZFLHFFQUFlLCtCQUErQiw4RUFBbUI7QUFDOUksaUJBQWlCO0FBQ2pCLGVBQWU7QUFDZjtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwyRUFBMkU7QUFDM0U7QUFDQSxlQUFlLEdBQUc7O0FBRWxCLGlFQUFpRTs7QUFFakUsNEtBQTRLLDREQUFrQjtBQUM5TDtBQUNBLGVBQWU7QUFDZixtREFBbUQsRUFBRSx5RUFBK0I7QUFDcEY7QUFDQTtBQUNBLGVBQWU7QUFDZix1REFBdUQseUVBQW1CO0FBQzFFLGVBQWU7QUFDZixhQUFhO0FBQ2IsWUFBWTtBQUNaO0FBQ0E7QUFDQSxrQ0FBa0MsNkVBQTBCLCtCQUErQjtBQUMzRjtBQUNBLGVBQWU7QUFDZixhQUFhO0FBQ2I7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7QUFFQSxpREFBaUQsRUFBRSx5RUFBK0I7QUFDbEY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IscUNBQXFDLHFFQUFlO0FBQ3BEO0FBQ0EsaUlBQWlJLDhFQUFtQjtBQUNwSixhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0E7O0FBRUEseUZBQXlGLDJGQUFnRDtBQUN6STtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsVUFBVTtBQUNWO0FBQ0E7QUFDQSxnQ0FBZ0MsNkVBQTBCLEdBQUc7QUFDN0QsZ0NBQWdDO0FBQ2hDO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsOEJBQThCLDZFQUEwQiwrQkFBK0I7QUFDdkY7QUFDQSxXQUFXO0FBQ1gsOEJBQThCLHlFQUFtQjtBQUNqRCxTQUFTO0FBQ1Q7O0FBRUEsNkNBQTZDLDhEQUFxQjtBQUNsRTtBQUNBOztBQUVBO0FBQ0EsU0FBUyxtRUFBZ0IsZUFBZSwyRUFBNEIsR0FBRyxtRUFBb0I7QUFDM0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxRQUFRLHFEQUFXO0FBQ25CO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQix5REFBZ0I7QUFDdEM7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNULFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUEsK0xBQStMLHlFQUFtQjtBQUNsTjtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDhCQUE4QixnRkFBNkI7QUFDM0Q7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0EsMEJBQTBCLDZFQUEwQixHQUFHO0FBQ3ZEO0FBQ0EsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQSx3RUFBd0UsMERBQWdCO0FBQ3hGLEtBQUs7QUFDTDtBQUNBLDBCQUEwQiw2RUFBMEIsR0FBRztBQUN2RDtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLHlFQUFrQjs7QUFFOUM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxtREFBbUQsc0VBQTZCOztBQUVoRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsRUFBRSxvRUFBMkI7QUFDdkM7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsMEJBQTBCLGtEQUFjLCtDQUErQywrQ0FBVztBQUNsRyxZQUFZLG1EQUFXO0FBQ3ZCLHlCQUF5QjtBQUN6QixLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGFBQWEsMkRBQWtCO0FBQy9COztBQUVBLElBQUksYUFBb0IsS0FBSyxpREFBUSxJQUFJLGFBQW9CO0FBQzdEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDs7QUFFQSxpRUFBZSxHQUFHIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2NvbXBvbmVudHMvQXBwLnRzeD82N2FlIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX2F3YWl0ZXIgPSB0aGlzICYmIHRoaXMuX19hd2FpdGVyIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcbiAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkge1xuICAgICAgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7XG4gICAgfVxuXG4gICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xuICB9KTtcbn07XG5cbmltcG9ydCB7IGpzeCBhcyBfanN4LCBqc3hzIGFzIF9qc3hzLCBGcmFnbWVudCBhcyBfRnJhZ21lbnQgfSBmcm9tIFwicmVhY3QvanN4LXJ1bnRpbWVcIjtcbmltcG9ydCBSZWFjdCwgeyB1c2VDb250ZXh0IH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBmbHVzaFN5bmMgfSBmcm9tIFwicmVhY3QtZG9tXCI7XG5pbXBvcnQgcm91Z2ggZnJvbSBcInJvdWdoanMvYmluL3JvdWdoXCI7XG5pbXBvcnQgY2xzeCBmcm9tIFwiY2xzeFwiO1xuaW1wb3J0IHsgbmFub2lkIH0gZnJvbSBcIm5hbm9pZFwiO1xuaW1wb3J0IHsgYWN0aW9uQWRkVG9MaWJyYXJ5LCBhY3Rpb25CcmluZ0ZvcndhcmQsIGFjdGlvbkJyaW5nVG9Gcm9udCwgYWN0aW9uQ29weSwgYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcsIGNvcHlUZXh0LCBhY3Rpb25Db3B5U3R5bGVzLCBhY3Rpb25DdXQsIGFjdGlvbkRlbGV0ZVNlbGVjdGVkLCBhY3Rpb25EdXBsaWNhdGVTZWxlY3Rpb24sIGFjdGlvbkZpbmFsaXplLCBhY3Rpb25GbGlwSG9yaXpvbnRhbCwgYWN0aW9uRmxpcFZlcnRpY2FsLCBhY3Rpb25Hcm91cCwgYWN0aW9uUGFzdGVTdHlsZXMsIGFjdGlvblNlbGVjdEFsbCwgYWN0aW9uU2VuZEJhY2t3YXJkLCBhY3Rpb25TZW5kVG9CYWNrLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHMsIGFjdGlvblRvZ2dsZVplbk1vZGUsIGFjdGlvblVuYmluZFRleHQsIGFjdGlvbkJpbmRUZXh0LCBhY3Rpb25Vbmdyb3VwLCBhY3Rpb25MaW5rLCBhY3Rpb25Ub2dnbGVFbGVtZW50TG9jaywgYWN0aW9uVG9nZ2xlTGluZWFyRWRpdG9yLCBhY3Rpb25Ub2dnbGVPYmplY3RzU25hcE1vZGUgfSBmcm9tIFwiLi4vYWN0aW9uc1wiO1xuaW1wb3J0IHsgY3JlYXRlUmVkb0FjdGlvbiwgY3JlYXRlVW5kb0FjdGlvbiB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkhpc3RvcnlcIjtcbmltcG9ydCB7IEFjdGlvbk1hbmFnZXIgfSBmcm9tIFwiLi4vYWN0aW9ucy9tYW5hZ2VyXCI7XG5pbXBvcnQgeyBhY3Rpb25zIH0gZnJvbSBcIi4uL2FjdGlvbnMvcmVnaXN0ZXJcIjtcbmltcG9ydCB7IHRyYWNrRXZlbnQgfSBmcm9tIFwiLi4vYW5hbHl0aWNzXCI7XG5pbXBvcnQgeyBnZXREZWZhdWx0QXBwU3RhdGUsIGlzRXJhc2VyQWN0aXZlLCBpc0hhbmRUb29sQWN0aXZlIH0gZnJvbSBcIi4uL2FwcFN0YXRlXCI7XG5pbXBvcnQgeyBwYXJzZUNsaXBib2FyZCB9IGZyb20gXCIuLi9jbGlwYm9hcmRcIjtcbmltcG9ydCB7IEFQUF9OQU1FLCBDVVJTT1JfVFlQRSwgREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hULCBERUZBVUxUX1VJX09QVElPTlMsIERFRkFVTFRfVkVSVElDQUxfQUxJR04sIERSQUdHSU5HX1RIUkVTSE9MRCwgRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZLCBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQsIEVMRU1FTlRfVFJBTlNMQVRFX0FNT1VOVCwgRU5WLCBFVkVOVCwgRlJBTUVfU1RZTEUsIEdSSURfU0laRSwgSU1BR0VfTUlNRV9UWVBFUywgSU1BR0VfUkVOREVSX1RJTUVPVVQsIGlzQW5kcm9pZCwgaXNCcmF2ZSwgTElORV9DT05GSVJNX1RIUkVTSE9MRCwgTUFYX0FMTE9XRURfRklMRV9CWVRFUywgTUlNRV9UWVBFUywgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9QT1JUUkFJVCwgTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEgsIFBPSU5URVJfQlVUVE9OLCBST1VORE5FU1MsIFNDUk9MTF9USU1FT1VULCBUQVBfVFdJQ0VfVElNRU9VVCwgVEVYVF9UT19DRU5URVJfU05BUF9USFJFU0hPTEQsIFRIRU1FLCBUSEVNRV9GSUxURVIsIFRPVUNIX0NUWF9NRU5VX1RJTUVPVVQsIFZFUlRJQ0FMX0FMSUdOLCBZT1VUVUJFX1NUQVRFUywgWk9PTV9TVEVQLCBQT0lOVEVSX0VWRU5UUyB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGV4cG9ydENhbnZhcywgbG9hZEZyb21CbG9iIH0gZnJvbSBcIi4uL2RhdGFcIjtcbmltcG9ydCBMaWJyYXJ5LCB7IGRpc3RyaWJ1dGVMaWJyYXJ5SXRlbXNPblNxdWFyZUdyaWQgfSBmcm9tIFwiLi4vZGF0YS9saWJyYXJ5XCI7XG5pbXBvcnQgeyByZXN0b3JlLCByZXN0b3JlRWxlbWVudHMgfSBmcm9tIFwiLi4vZGF0YS9yZXN0b3JlXCI7XG5pbXBvcnQgeyBkcmFnTmV3RWxlbWVudCwgZHJhZ1NlbGVjdGVkRWxlbWVudHMsIGR1cGxpY2F0ZUVsZW1lbnQsIGdldENvbW1vbkJvdW5kcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50LCBnZXREcmFnT2Zmc2V0WFksIGdldEVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSwgZ2V0Tm9ybWFsaXplZERpbWVuc2lvbnMsIGdldFJlc2l6ZUFycm93RGlyZWN0aW9uLCBnZXRSZXNpemVPZmZzZXRYWSwgZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplLCBnZXRUcmFuc2Zvcm1IYW5kbGVUeXBlRnJvbUNvb3JkcywgaGl0VGVzdCwgaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50LCBpc0ludmlzaWJseVNtYWxsRWxlbWVudCwgaXNOb25EZWxldGVkRWxlbWVudCwgaXNUZXh0RWxlbWVudCwgbmV3RWxlbWVudCwgbmV3TGluZWFyRWxlbWVudCwgbmV3VGV4dEVsZW1lbnQsIG5ld0ltYWdlRWxlbWVudCwgdGV4dFd5c2l3eWcsIHRyYW5zZm9ybUVsZW1lbnRzLCB1cGRhdGVUZXh0RWxlbWVudCwgcmVkcmF3VGV4dEJvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnRcIjtcbmltcG9ydCB7IGJpbmRPclVuYmluZExpbmVhckVsZW1lbnQsIGJpbmRPclVuYmluZFNlbGVjdGVkRWxlbWVudHMsIGZpeEJpbmRpbmdzQWZ0ZXJEZWxldGlvbiwgZml4QmluZGluZ3NBZnRlckR1cGxpY2F0aW9uLCBnZXRFbGlnaWJsZUVsZW1lbnRzRm9yQmluZGluZywgZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nLCBpc0JpbmRpbmdFbmFibGVkLCBpc0xpbmVhckVsZW1lbnRTaW1wbGVBbmRBbHJlYWR5Qm91bmQsIG1heWJlQmluZExpbmVhckVsZW1lbnQsIHNob3VsZEVuYWJsZUJpbmRpbmdGb3JQb2ludGVyRXZlbnQsIHVuYmluZExpbmVhckVsZW1lbnRzLCB1cGRhdGVCb3VuZEVsZW1lbnRzIH0gZnJvbSBcIi4uL2VsZW1lbnQvYmluZGluZ1wiO1xuaW1wb3J0IHsgTGluZWFyRWxlbWVudEVkaXRvciB9IGZyb20gXCIuLi9lbGVtZW50L2xpbmVhckVsZW1lbnRFZGl0b3JcIjtcbmltcG9ydCB7IG11dGF0ZUVsZW1lbnQsIG5ld0VsZW1lbnRXaXRoIH0gZnJvbSBcIi4uL2VsZW1lbnQvbXV0YXRlRWxlbWVudFwiO1xuaW1wb3J0IHsgZGVlcENvcHlFbGVtZW50LCBkdXBsaWNhdGVFbGVtZW50cywgbmV3RnJhbWVFbGVtZW50LCBuZXdGcmVlRHJhd0VsZW1lbnQsIG5ld0VtYmVkZGFibGVFbGVtZW50IH0gZnJvbSBcIi4uL2VsZW1lbnQvbmV3RWxlbWVudFwiO1xuaW1wb3J0IHsgaGFzQm91bmRUZXh0RWxlbWVudCwgaXNBcnJvd0VsZW1lbnQsIGlzQmluZGluZ0VsZW1lbnQsIGlzQmluZGluZ0VsZW1lbnRUeXBlLCBpc0JvdW5kVG9Db250YWluZXIsIGlzRnJhbWVFbGVtZW50LCBpc0ltYWdlRWxlbWVudCwgaXNFbWJlZGRhYmxlRWxlbWVudCwgaXNJbml0aWFsaXplZEltYWdlRWxlbWVudCwgaXNMaW5lYXJFbGVtZW50LCBpc0xpbmVhckVsZW1lbnRUeXBlLCBpc1VzaW5nQWRhcHRpdmVSYWRpdXMgfSBmcm9tIFwiLi4vZWxlbWVudC90eXBlQ2hlY2tzXCI7XG5pbXBvcnQgeyBnZXRDZW50ZXIsIGdldERpc3RhbmNlIH0gZnJvbSBcIi4uL2dlc3R1cmVcIjtcbmltcG9ydCB7IGVkaXRHcm91cEZvclNlbGVjdGVkRWxlbWVudCwgZ2V0RWxlbWVudHNJbkdyb3VwLCBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50LCBnZXRTZWxlY3RlZEdyb3VwSWRzLCBpc0VsZW1lbnRJbkdyb3VwLCBpc1NlbGVjdGVkVmlhR3JvdXAsIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMgfSBmcm9tIFwiLi4vZ3JvdXBzXCI7XG5pbXBvcnQgSGlzdG9yeSBmcm9tIFwiLi4vaGlzdG9yeVwiO1xuaW1wb3J0IHsgZGVmYXVsdExhbmcsIGdldExhbmd1YWdlLCBsYW5ndWFnZXMsIHNldExhbmd1YWdlLCB0IH0gZnJvbSBcIi4uL2kxOG5cIjtcbmltcG9ydCB7IENPREVTLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyLCBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvLCBzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZSwgaXNBcnJvd0tleSwgS0VZUyB9IGZyb20gXCIuLi9rZXlzXCI7XG5pbXBvcnQgeyBpc0VsZW1lbnRJblZpZXdwb3J0IH0gZnJvbSBcIi4uL2VsZW1lbnQvc2l6ZUhlbHBlcnNcIjtcbmltcG9ydCB7IGRpc3RhbmNlMmQsIGdldENvcm5lclJhZGl1cywgZ2V0R3JpZFBvaW50LCBpc1BhdGhBTG9vcCB9IGZyb20gXCIuLi9tYXRoXCI7XG5pbXBvcnQgeyBjYWxjdWxhdGVTY3JvbGxDZW50ZXIsIGdldEVsZW1lbnRzQXRQb3NpdGlvbiwgZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24sIGdldE5vcm1hbGl6ZWRab29tLCBnZXRTZWxlY3RlZEVsZW1lbnRzLCBoYXNCYWNrZ3JvdW5kLCBpc092ZXJTY3JvbGxCYXJzLCBpc1NvbWVFbGVtZW50U2VsZWN0ZWQgfSBmcm9tIFwiLi4vc2NlbmVcIjtcbmltcG9ydCBTY2VuZSBmcm9tIFwiLi4vc2NlbmUvU2NlbmVcIjtcbmltcG9ydCB7IGdldFN0YXRlRm9yWm9vbSB9IGZyb20gXCIuLi9zY2VuZS96b29tXCI7XG5pbXBvcnQgeyBmaW5kU2hhcGVCeUtleSB9IGZyb20gXCIuLi9zaGFwZXNcIjtcbmltcG9ydCB7IGRlYm91bmNlLCBkaXN0YW5jZSwgZ2V0Rm9udFN0cmluZywgZ2V0TmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIsIGlzSW5wdXRMaWtlLCBpc1Rvb2xJY29uLCBpc1dyaXRhYmxlRWxlbWVudCwgcmVzb2x2YWJsZVByb21pc2UsIHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3JkcywgdHVwbGVUb0Nvb3JzLCB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMsIHdpdGhCYXRjaGVkVXBkYXRlcywgd3JhcEV2ZW50LCB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQsIHVwZGF0ZU9iamVjdCwgdXBkYXRlQWN0aXZlVG9vbCwgZ2V0U2hvcnRjdXRLZXksIGlzVHJhbnNwYXJlbnQsIGVhc2VUb1ZhbHVlc1JBRiwgbXV0ZUZTQWJvcnRFcnJvciwgaXNUZXN0RW52LCBlYXNlT3V0IH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgeyBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yLCBleHRyYWN0U3JjLCBnZXRFbWJlZExpbmsgfSBmcm9tIFwiLi4vZWxlbWVudC9lbWJlZGRhYmxlXCI7XG5pbXBvcnQgeyBDb250ZXh0TWVudSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiB9IGZyb20gXCIuL0NvbnRleHRNZW51XCI7XG5pbXBvcnQgTGF5ZXJVSSBmcm9tIFwiLi9MYXllclVJXCI7XG5pbXBvcnQgeyBUb2FzdCB9IGZyb20gXCIuL1RvYXN0XCI7XG5pbXBvcnQgeyBhY3Rpb25Ub2dnbGVWaWV3TW9kZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvblRvZ2dsZVZpZXdNb2RlXCI7XG5pbXBvcnQgeyBkYXRhVVJMVG9GaWxlLCBnZW5lcmF0ZUlkRnJvbUZpbGUsIGdldERhdGFVUkwsIGdldEZpbGVGcm9tRXZlbnQsIEltYWdlVVJMVG9GaWxlLCBpc0ltYWdlRmlsZUhhbmRsZSwgaXNTdXBwb3J0ZWRJbWFnZUZpbGUsIGxvYWRTY2VuZU9yTGlicmFyeUZyb21CbG9iLCBub3JtYWxpemVGaWxlLCBwYXJzZUxpYnJhcnlKU09OLCByZXNpemVJbWFnZUZpbGUsIFNWR1N0cmluZ1RvRmlsZSB9IGZyb20gXCIuLi9kYXRhL2Jsb2JcIjtcbmltcG9ydCB7IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cywgbG9hZEhUTUxJbWFnZUVsZW1lbnQsIG5vcm1hbGl6ZVNWRywgdXBkYXRlSW1hZ2VDYWNoZSBhcyBfdXBkYXRlSW1hZ2VDYWNoZSB9IGZyb20gXCIuLi9lbGVtZW50L2ltYWdlXCI7XG5pbXBvcnQgdGhyb3R0bGUgZnJvbSBcImxvZGFzaC50aHJvdHRsZVwiO1xuaW1wb3J0IHsgZmlsZU9wZW4gfSBmcm9tIFwiLi4vZGF0YS9maWxlc3lzdGVtXCI7XG5pbXBvcnQgeyBiaW5kVGV4dFRvU2hhcGVBZnRlckR1cGxpY2F0aW9uLCBnZXRBcHByb3hNaW5MaW5lSGVpZ2h0LCBnZXRBcHByb3hNaW5MaW5lV2lkdGgsIGdldEJvdW5kVGV4dEVsZW1lbnQsIGdldENvbnRhaW5lckNlbnRlciwgZ2V0Q29udGFpbmVyRWxlbWVudCwgZ2V0RGVmYXVsdExpbmVIZWlnaHQsIGdldExpbmVIZWlnaHRJblB4LCBnZXRUZXh0QmluZGFibGVDb250YWluZXJBdFBvc2l0aW9uLCBpc01lYXN1cmVUZXh0U3VwcG9ydGVkLCBpc1ZhbGlkVGV4dENvbnRhaW5lciB9IGZyb20gXCIuLi9lbGVtZW50L3RleHRFbGVtZW50XCI7XG5pbXBvcnQgeyBpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveCB9IGZyb20gXCIuLi9lbGVtZW50L2NvbGxpc2lvblwiO1xuaW1wb3J0IHsgc2hvd0h5cGVybGlua1Rvb2x0aXAsIGhpZGVIeXBlcmxpbmtUb29saXAsIEh5cGVybGluaywgaXNQb2ludEhpdHRpbmdMaW5rLCBpc1BvaW50SGl0dGluZ0xpbmtJY29uIH0gZnJvbSBcIi4uL2VsZW1lbnQvSHlwZXJsaW5rXCI7XG5pbXBvcnQgeyBpc0xvY2FsTGluaywgbm9ybWFsaXplTGluaywgdG9WYWxpZFVSTCB9IGZyb20gXCIuLi9kYXRhL3VybFwiO1xuaW1wb3J0IHsgc2hvdWxkU2hvd0JvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnQvdHJhbnNmb3JtSGFuZGxlc1wiO1xuaW1wb3J0IHsgYWN0aW9uVW5sb2NrQWxsRWxlbWVudHMgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25FbGVtZW50TG9ja1wiO1xuaW1wb3J0IHsgRm9udHMgfSBmcm9tIFwiLi4vc2NlbmUvRm9udHNcIjtcbmltcG9ydCB7IGdldEZyYW1lRWxlbWVudHMsIGlzQ3Vyc29ySW5GcmFtZSwgYmluZEVsZW1lbnRzVG9GcmFtZXNBZnRlckR1cGxpY2F0aW9uLCBhZGRFbGVtZW50c1RvRnJhbWUsIHJlcGxhY2VBbGxFbGVtZW50c0luRnJhbWUsIHJlbW92ZUVsZW1lbnRzRnJvbUZyYW1lLCBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSwgZ2V0RWxlbWVudHNJbk5ld0ZyYW1lLCBnZXRDb250YWluaW5nRnJhbWUsIGVsZW1lbnRPdmVybGFwc1dpdGhGcmFtZSwgdXBkYXRlRnJhbWVNZW1iZXJzaGlwT2ZTZWxlY3RlZEVsZW1lbnRzLCBpc0VsZW1lbnRJbkZyYW1lIH0gZnJvbSBcIi4uL2ZyYW1lXCI7XG5pbXBvcnQgeyBleGNsdWRlRWxlbWVudHNJbkZyYW1lc0Zyb21TZWxlY3Rpb24sIG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzIH0gZnJvbSBcIi4uL3NjZW5lL3NlbGVjdGlvblwiO1xuaW1wb3J0IHsgYWN0aW9uUGFzdGUgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25DbGlwYm9hcmRcIjtcbmltcG9ydCB7IGFjdGlvblJlbW92ZUFsbEVsZW1lbnRzRnJvbUZyYW1lLCBhY3Rpb25TZWxlY3RBbGxFbGVtZW50c0luRnJhbWUgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25GcmFtZVwiO1xuaW1wb3J0IHsgYWN0aW9uVG9nZ2xlSGFuZFRvb2wsIHpvb21Ub0ZpdCB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkNhbnZhc1wiO1xuaW1wb3J0IHsgam90YWlTdG9yZSB9IGZyb20gXCIuLi9qb3RhaVwiO1xuaW1wb3J0IHsgYWN0aXZlQ29uZmlybURpYWxvZ0F0b20gfSBmcm9tIFwiLi9BY3RpdmVDb25maXJtRGlhbG9nXCI7XG5pbXBvcnQgeyBnZXRTbmFwTGluZXNBdFBvaW50ZXIsIHNuYXBEcmFnZ2VkRWxlbWVudHMsIGlzQWN0aXZlVG9vbE5vbkxpbmVhclNuYXBwYWJsZSwgc25hcE5ld0VsZW1lbnQsIHNuYXBSZXNpemluZ0VsZW1lbnRzLCBpc1NuYXBwaW5nRW5hYmxlZCwgZ2V0VmlzaWJsZUdhcHMsIGdldFJlZmVyZW5jZVNuYXBQb2ludHMsIFNuYXBDYWNoZSB9IGZyb20gXCIuLi9zbmFwcGluZ1wiO1xuaW1wb3J0IHsgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkJvdW5kVGV4dFwiO1xuaW1wb3J0IEJyYXZlTWVhc3VyZVRleHRFcnJvciBmcm9tIFwiLi9CcmF2ZU1lYXN1cmVUZXh0RXJyb3JcIjtcbmltcG9ydCB7IGFjdGl2ZUV5ZURyb3BwZXJBdG9tIH0gZnJvbSBcIi4vRXllRHJvcHBlclwiO1xuaW1wb3J0IHsgY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzIH0gZnJvbSBcIi4uL2RhdGEvdHJhbnNmb3JtXCI7XG5pbXBvcnQgeyBpc1NpZGViYXJEb2NrZWRBdG9tIH0gZnJvbSBcIi4vU2lkZWJhci9TaWRlYmFyXCI7XG5pbXBvcnQgeyBTdGF0aWNDYW52YXMsIEludGVyYWN0aXZlQ2FudmFzIH0gZnJvbSBcIi4vY2FudmFzZXNcIjtcbmltcG9ydCB7IFJlbmRlcmVyIH0gZnJvbSBcIi4uL3NjZW5lL1JlbmRlcmVyXCI7XG5pbXBvcnQgeyBTaGFwZUNhY2hlIH0gZnJvbSBcIi4uL3NjZW5lL1NoYXBlQ2FjaGVcIjtcbmltcG9ydCBNZXJtYWlkVG9FeGNhbGlkcmF3IGZyb20gXCIuL01lcm1haWRUb0V4Y2FsaWRyYXdcIjtcbmltcG9ydCB7IExhc2VyVG9vbE92ZXJsYXkgfSBmcm9tIFwiLi9MYXNlclRvb2wvTGFzZXJUb29sXCI7XG5pbXBvcnQgeyBMYXNlclBhdGhNYW5hZ2VyIH0gZnJvbSBcIi4vTGFzZXJUb29sL0xhc2VyUGF0aE1hbmFnZXJcIjtcbmltcG9ydCB7IHNldEVyYXNlckN1cnNvciwgc2V0Q3Vyc29yLCByZXNldEN1cnNvciwgc2V0Q3Vyc29yRm9yU2hhcGUgfSBmcm9tIFwiLi4vY3Vyc29yXCI7XG5pbXBvcnQgeyBFbWl0dGVyIH0gZnJvbSBcIi4uL2VtaXR0ZXJcIjtcbmNvbnN0IEFwcENvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuY29uc3QgQXBwUHJvcHNDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChudWxsKTtcbmNvbnN0IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWUgPSB7XG4gIHZpZXdwb3J0OiB7XG4gICAgaXNNb2JpbGU6IGZhbHNlLFxuICAgIGlzTGFuZHNjYXBlOiBmYWxzZVxuICB9LFxuICBlZGl0b3I6IHtcbiAgICBpc01vYmlsZTogZmFsc2UsXG4gICAgY2FuRml0U2lkZWJhcjogZmFsc2VcbiAgfSxcbiAgaXNUb3VjaFNjcmVlbjogZmFsc2Vcbn07XG5jb25zdCBEZXZpY2VDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChkZXZpY2VDb250ZXh0SW5pdGlhbFZhbHVlKTtcbkRldmljZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkRldmljZUNvbnRleHRcIjtcbmV4cG9ydCBjb25zdCBFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoe1xuICBjb250YWluZXI6IG51bGwsXG4gIGlkOiBudWxsXG59KTtcbkV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoW10pO1xuRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXREZWZhdWx0QXBwU3RhdGUoKSksIHtcbiAgd2lkdGg6IDAsXG4gIGhlaWdodDogMCxcbiAgb2Zmc2V0TGVmdDogMCxcbiAgb2Zmc2V0VG9wOiAwXG59KSk7XG5FeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dCgoKSA9PiB7XG4gIGNvbnNvbGUud2FybihcInVuaXRpYWxpemVkIEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQgY29udGV4dCFcIik7XG59KTtcbkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQobnVsbCk7XG5FeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dFwiO1xuZXhwb3J0IGNvbnN0IHVzZUFwcCA9ICgpID0+IHVzZUNvbnRleHQoQXBwQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlQXBwUHJvcHMgPSAoKSA9PiB1c2VDb250ZXh0KEFwcFByb3BzQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRGV2aWNlID0gKCkgPT4gdXNlQ29udGV4dChEZXZpY2VDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3Q29udGFpbmVyID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0VsZW1lbnRzID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3QXBwU3RhdGUgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdTZXRBcHBTdGF0ZSA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXIgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCk7XG5jb25zdCBzdXBwb3J0c1Jlc2l6ZU9ic2VydmVyID0gdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiAmJiBcIlJlc2l6ZU9ic2VydmVyXCIgaW4gd2luZG93O1xubGV0IGRpZFRhcFR3aWNlID0gZmFsc2U7XG5sZXQgdGFwcGVkVHdpY2VUaW1lciA9IDA7XG5sZXQgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbmxldCBpc1Bhbm5pbmcgPSBmYWxzZTtcbmxldCBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gZmFsc2U7XG5sZXQgY3VycmVudFNjcm9sbEJhcnMgPSB7XG4gIGhvcml6b250YWw6IG51bGwsXG4gIHZlcnRpY2FsOiBudWxsXG59O1xubGV0IHRvdWNoVGltZW91dCA9IDA7XG5sZXQgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG4vKipcbiAqIE1hcCBvZiB5b3V0dWJlIGVtYmVkIHZpZGVvIHN0YXRlc1xuICovXG5cbmNvbnN0IFlPVVRVQkVfVklERU9fU1RBVEVTID0gbmV3IE1hcCgpO1xubGV0IElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG5sZXQgSVNfUExBSU5fUEFTVEVfVElNRVIgPSAwO1xubGV0IFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gZmFsc2U7XG5sZXQgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG5jb25zdCBnZXN0dXJlID0ge1xuICBwb2ludGVyczogbmV3IE1hcCgpLFxuICBsYXN0Q2VudGVyOiBudWxsLFxuICBpbml0aWFsRGlzdGFuY2U6IG51bGwsXG4gIGluaXRpYWxTY2FsZTogbnVsbFxufTtcblxuY2xhc3MgQXBwIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyA9IG51bGw7XG4gICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICB0aGlzLmRldmljZSA9IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWU7XG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmID0gUmVhY3QuY3JlYXRlUmVmKCk7XG4gICAgdGhpcy5maWxlcyA9IHt9O1xuICAgIHRoaXMuaW1hZ2VDYWNoZSA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmlGcmFtZVJlZnMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCA9IG51bGw7XG4gICAgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQgPSBudWxsO1xuICAgIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24gPSB7XG4gICAgICB4OiAwLFxuICAgICAgeTogMFxuICAgIH07XG4gICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyID0gbmV3IExhc2VyUGF0aE1hbmFnZXIodGhpcyk7XG4gICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyVXBFbWl0dGVyID0gbmV3IEVtaXR0ZXIoKTtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBlbWJlZGRhYmxlRWxlbWVudHMgPSBuZXcgTWFwKCk7XG4gICAgICBsZXQgdXBkYXRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgZW1iZWRkYWJsZUVsZW1lbnRzLnNldChlbGVtZW50LmlkLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50LnZhbGlkYXRlZCA9PSBudWxsKSB7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlZCA9IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IoZWxlbWVudC5saW5rLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSk7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgdmFsaWRhdGVkXG4gICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWQpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgfSAvLyBHQ1xuXG5cbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5mb3JFYWNoKChyZWYsIGlkKSA9PiB7XG4gICAgICAgIGlmICghZW1iZWRkYWJsZUVsZW1lbnRzLmhhcyhpZCkpIHtcbiAgICAgICAgICB0aGlzLmlGcmFtZVJlZnMuZGVsZXRlKGlkKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQgPSBmcmFtZUVsZW1lbnQgPT4ge1xuICAgICAgcmV0dXJuIGAke3RoaXMuaWR9LWZyYW1lLW5hbWUtJHtmcmFtZUVsZW1lbnQuaWR9YDtcbiAgICB9O1xuXG4gICAgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSA9IHtcbiAgICAgIGdldDogZnJhbWVFbGVtZW50ID0+IHtcbiAgICAgICAgbGV0IGJvdW5kcyA9IHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLmdldChmcmFtZUVsZW1lbnQuaWQpO1xuXG4gICAgICAgIGlmICghYm91bmRzIHx8IGJvdW5kcy56b29tICE9PSB0aGlzLnN0YXRlLnpvb20udmFsdWUgfHwgYm91bmRzLnZlcnNpb25Ob25jZSAhPT0gZnJhbWVFbGVtZW50LnZlcnNpb25Ob25jZSkge1xuICAgICAgICAgIGNvbnN0IGZyYW1lTmFtZURpdiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQoZnJhbWVFbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoZnJhbWVOYW1lRGl2KSB7XG4gICAgICAgICAgICBjb25zdCBib3ggPSBmcmFtZU5hbWVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBjb25zdCBib3hTY2VuZVRvcExlZnQgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgICBjbGllbnRYOiBib3gueCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LnlcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3QgYm94U2NlbmVCb3R0b21SaWdodCA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICAgIGNsaWVudFg6IGJveC5yaWdodCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LmJvdHRvbVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBib3VuZHMgPSB7XG4gICAgICAgICAgICAgIHg6IGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICB5OiBib3hTY2VuZVRvcExlZnQueSxcbiAgICAgICAgICAgICAgd2lkdGg6IGJveFNjZW5lQm90dG9tUmlnaHQueCAtIGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICBoZWlnaHQ6IGJveFNjZW5lQm90dG9tUmlnaHQueSAtIGJveFNjZW5lVG9wTGVmdC55LFxuICAgICAgICAgICAgICBhbmdsZTogMCxcbiAgICAgICAgICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLnZhbHVlLFxuICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IGZyYW1lRWxlbWVudC52ZXJzaW9uTm9uY2VcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLnNldChmcmFtZUVsZW1lbnQuaWQsIGJvdW5kcyk7XG5cbiAgICAgICAgICAgIHJldHVybiBib3VuZHM7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYm91bmRzO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICovXG4gICAgICBfY2FjaGU6IG5ldyBNYXAoKVxuICAgIH07XG5cbiAgICB0aGlzLnJlbmRlckZyYW1lTmFtZXMgPSAoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCB8fCAhdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc0RhcmtUaGVtZSA9IHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiO1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLm1hcCgoZiwgaW5kZXgpID0+IHtcbiAgICAgICAgaWYgKCFpc0VsZW1lbnRJblZpZXdwb3J0KGYsIHRoaXMuY2FudmFzLndpZHRoIC8gd2luZG93LmRldmljZVBpeGVsUmF0aW8sIHRoaXMuY2FudmFzLmhlaWdodCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLCB7XG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb21cbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAvLyBpZiBmcmFtZSBub3QgdmlzaWJsZSwgZG9uJ3QgcmVuZGVyIGl0cyBuYW1lXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogeDEsXG4gICAgICAgICAgeTogeTFcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBmLngsXG4gICAgICAgICAgc2NlbmVZOiBmLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB4MlxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IGYueCArIGYud2lkdGgsXG4gICAgICAgICAgc2NlbmVZOiBmLnkgKyBmLmhlaWdodFxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9HQVAgPSAyMDtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgPSA2O1xuXG4gICAgICAgIGNvbnN0IHJlc2V0ID0gKCkgPT4ge1xuICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgIGlmICgoKF9hID0gZi5uYW1lKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudHJpbSgpKSA9PT0gXCJcIikge1xuICAgICAgICAgICAgbXV0YXRlRWxlbWVudChmLCB7XG4gICAgICAgICAgICAgIG5hbWU6IG51bGxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0ZyYW1lOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbGV0IGZyYW1lTmFtZUpTWDtcblxuICAgICAgICBpZiAoZi5pZCA9PT0gdGhpcy5zdGF0ZS5lZGl0aW5nRnJhbWUpIHtcbiAgICAgICAgICBjb25zdCBmcmFtZU5hbWVJbkVkaXQgPSBmLm5hbWUgPT0gbnVsbCA/IGBGcmFtZSAke2luZGV4ICsgMX1gIDogZi5uYW1lO1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IF9qc3goXCJpbnB1dFwiLCB7XG4gICAgICAgICAgICBhdXRvRm9jdXM6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogZnJhbWVOYW1lSW5FZGl0LFxuICAgICAgICAgICAgb25DaGFuZ2U6IGUgPT4ge1xuICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGYsIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBlLnRhcmdldC52YWx1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkJsdXI6ICgpID0+IHJlc2V0KCksXG4gICAgICAgICAgICBvbktleURvd246IGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgLy8gZm9yIHNvbWUgaW5leHBsaWNhYmxlIHJlYXNvbiwgYG9uQmx1cmAgdHJpZ2dlcmVkIG9uIEVTQ1xuICAgICAgICAgICAgICAvLyBkb2VzIG5vdCByZXNldCBgc3RhdGUuZWRpdGluZ0ZyYW1lYCBkZXNwaXRlIGJlaW5nIGNhbGxlZCxcbiAgICAgICAgICAgICAgLy8gYW5kIHdlIG5lZWQgdG8gcmVzZXQgaXQgaGVyZSBhcyB3ZWxsXG4gICAgICAgICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuRVNDQVBFIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5FTlRFUikge1xuICAgICAgICAgICAgICAgIHJlc2V0KCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLnZpZXdCYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgICAgIGZpbHRlcjogaXNEYXJrVGhlbWUgPyBUSEVNRV9GSUxURVIgOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgekluZGV4OiAyLFxuICAgICAgICAgICAgICBib3JkZXI6IFwibm9uZVwiLFxuICAgICAgICAgICAgICBkaXNwbGF5OiBcImJsb2NrXCIsXG4gICAgICAgICAgICAgIHBhZGRpbmc6IGAke0ZSQU1FX05BTUVfRURJVF9QQURESU5HfXB4YCxcbiAgICAgICAgICAgICAgYm9yZGVyUmFkaXVzOiA0LFxuICAgICAgICAgICAgICBib3hTaGFkb3c6IFwiaW5zZXQgMCAwIDAgMXB4IHZhcigtLWNvbG9yLXByaW1hcnkpXCIsXG4gICAgICAgICAgICAgIGZvbnRGYW1pbHk6IFwiQXNzaXN0YW50XCIsXG4gICAgICAgICAgICAgIGZvbnRTaXplOiBcIjE0cHhcIixcbiAgICAgICAgICAgICAgdHJhbnNmb3JtOiBgdHJhbnNsYXRlWSgtJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weClgLFxuICAgICAgICAgICAgICBjb2xvcjogXCJ2YXIoLS1jb2xvci1ncmF5LTgwKVwiLFxuICAgICAgICAgICAgICBvdmVyZmxvdzogXCJoaWRkZW5cIixcbiAgICAgICAgICAgICAgbWF4V2lkdGg6IGAke01hdGgubWluKHgyIC0geDEgLSBGUkFNRV9OQU1FX0VESVRfUEFERElORywgZG9jdW1lbnQuYm9keS5jbGllbnRXaWR0aCAtIHgxIC0gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcpfXB4YFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNpemU6IGZyYW1lTmFtZUluRWRpdC5sZW5ndGggKyAxIHx8IDEsXG4gICAgICAgICAgICBkaXI6IFwiYXV0b1wiLFxuICAgICAgICAgICAgYXV0b0NvbXBsZXRlOiBcIm9mZlwiLFxuICAgICAgICAgICAgYXV0b0NhcGl0YWxpemU6IFwib2ZmXCIsXG4gICAgICAgICAgICBhdXRvQ29ycmVjdDogXCJvZmZcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IGYubmFtZSA9PSBudWxsIHx8IGYubmFtZS50cmltKCkgPT09IFwiXCIgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZS50cmltKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBpZDogdGhpcy5nZXRGcmFtZU5hbWVET01JZChmKSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgcG9zaXRpb246IFwiYWJzb2x1dGVcIixcbiAgICAgICAgICAgIHRvcDogYCR7eTEgLSBGUkFNRV9OQU1FX0dBUCAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wfXB4YCxcbiAgICAgICAgICAgIGxlZnQ6IGAke3gxIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0IC0gKHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID09PSBmLmlkID8gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgOiAwKX1weGAsXG4gICAgICAgICAgICB6SW5kZXg6IDIsXG4gICAgICAgICAgICBmb250U2l6ZTogXCIxNHB4XCIsXG4gICAgICAgICAgICBjb2xvcjogaXNEYXJrVGhlbWUgPyBcInZhcigtLWNvbG9yLWdyYXktNjApXCIgOiBcInZhcigtLWNvbG9yLWdyYXktNTApXCIsXG4gICAgICAgICAgICB3aWR0aDogXCJtYXgtY29udGVudFwiLFxuICAgICAgICAgICAgbWF4V2lkdGg6IGAke3gyIC0geDEgKyBGUkFNRV9OQU1FX0VESVRfUEFERElORyAqIDJ9cHhgLFxuICAgICAgICAgICAgb3ZlcmZsb3c6IGYuaWQgPT09IHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID8gXCJ2aXNpYmxlXCIgOiBcImhpZGRlblwiLFxuICAgICAgICAgICAgd2hpdGVTcGFjZTogXCJub3dyYXBcIixcbiAgICAgICAgICAgIHRleHRPdmVyZmxvdzogXCJlbGxpcHNpc1wiLFxuICAgICAgICAgICAgY3Vyc29yOiBDVVJTT1JfVFlQRS5NT1ZFLFxuICAgICAgICAgICAgcG9pbnRlckV2ZW50czogdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQgPyBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZCA6IFBPSU5URVJfRVZFTlRTLmVuYWJsZWRcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uUG9pbnRlckRvd246IGV2ZW50ID0+IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24oZXZlbnQpLFxuICAgICAgICAgIG9uV2hlZWw6IGV2ZW50ID0+IHRoaXMuaGFuZGxlV2hlZWwoZXZlbnQpLFxuICAgICAgICAgIG9uQ29udGV4dE1lbnU6IHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUsXG4gICAgICAgICAgb25Eb3VibGVDbGljazogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogZi5pZFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IGZyYW1lTmFtZUpTWFxuICAgICAgICB9KSwgZi5pZCk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5mb2N1c0NvbnRhaW5lciA9ICgpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5mb2N1cygpO1xuICAgIH07XG5cbiAgICB0aGlzLmdldFNjZW5lRWxlbWVudHNJbmNsdWRpbmdEZWxldGVkID0gKCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0U2NlbmVFbGVtZW50cyA9ICgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgIH07XG5cbiAgICB0aGlzLm9uSW5zZXJ0RWxlbWVudHMgPSBlbGVtZW50cyA9PiB7XG4gICAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5KHtcbiAgICAgICAgZWxlbWVudHMsXG4gICAgICAgIHBvc2l0aW9uOiBcImNlbnRlclwiLFxuICAgICAgICBmaWxlczogbnVsbFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMub25FeHBvcnRJbWFnZSA9ICh0eXBlLCBlbGVtZW50cykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdHJhY2tFdmVudChcImV4cG9ydFwiLCB0eXBlLCBcInVpXCIpO1xuICAgICAgY29uc3QgZmlsZUhhbmRsZSA9IHlpZWxkIGV4cG9ydENhbnZhcyh0eXBlLCBlbGVtZW50cywgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcywge1xuICAgICAgICBleHBvcnRCYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLmV4cG9ydEJhY2tncm91bmQsXG4gICAgICAgIG5hbWU6IHRoaXMuc3RhdGUubmFtZSxcbiAgICAgICAgdmlld0JhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yXG4gICAgICB9KS5jYXRjaChtdXRlRlNBYm9ydEVycm9yKS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZXhwb3J0RW1iZWRTY2VuZSAmJiBmaWxlSGFuZGxlICYmIGlzSW1hZ2VGaWxlSGFuZGxlKGZpbGVIYW5kbGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGZpbGVIYW5kbGVcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLm9wZW5FeWVEcm9wcGVyID0gKHtcbiAgICAgIHR5cGVcbiAgICB9KSA9PiB7XG4gICAgICBqb3RhaVN0b3JlLnNldChhY3RpdmVFeWVEcm9wcGVyQXRvbSwge1xuICAgICAgICBzd2FwUHJldmlld09uQWx0OiB0cnVlLFxuICAgICAgICBjb2xvclBpY2tlclR5cGU6IHR5cGUgPT09IFwic3Ryb2tlXCIgPyBcImVsZW1lbnRTdHJva2VcIiA6IFwiZWxlbWVudEJhY2tncm91bmRcIixcbiAgICAgICAgb25TZWxlY3Q6IChjb2xvciwgZXZlbnQpID0+IHtcbiAgICAgICAgICBjb25zdCBzaG91bGRVcGRhdGVTdHJva2VDb2xvciA9IHR5cGUgPT09IFwiYmFja2dyb3VuZFwiICYmIGV2ZW50LmFsdEtleSB8fCB0eXBlID09PSBcInN0cm9rZVwiICYmICFldmVudC5hbHRLZXk7XG4gICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICAgIGlmICghc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICAgIGlmIChzaG91bGRVcGRhdGVTdHJva2VDb2xvcikge1xuICAgICAgICAgICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoe1xuICAgICAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgICBjdXJyZW50SXRlbVN0cm9rZUNvbG9yOiBjb2xvclxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCh7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yOiBjb2xvclxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVTY2VuZSh7XG4gICAgICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbCA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2VsLmlkXSkge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsLCB7XG4gICAgICAgICAgICAgICAgICAgIFtzaG91bGRVcGRhdGVTdHJva2VDb2xvciA/IFwic3Ryb2tlQ29sb3JcIiA6IFwiYmFja2dyb3VuZENvbG9yXCJdOiBjb2xvclxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGVsO1xuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBrZWVwT3Blbk9uQWx0OiBmYWxzZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhhY3Rpb25SZXN1bHQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaCwgX2o7XG5cbiAgICAgIGlmICh0aGlzLnVubW91bnRlZCB8fCBhY3Rpb25SZXN1bHQgPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgbGV0IGVkaXRpbmdFbGVtZW50ID0gbnVsbDtcblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5lbGVtZW50cykge1xuICAgICAgICBhY3Rpb25SZXN1bHQuZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pZCkgPT09IGVsZW1lbnQuaWQgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAhPT0gZWxlbWVudCAmJiBpc05vbkRlbGV0ZWRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoYWN0aW9uUmVzdWx0LmVsZW1lbnRzKTtcblxuICAgICAgICBpZiAoYWN0aW9uUmVzdWx0LmNvbW1pdFRvSGlzdG9yeSkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmZpbGVzKSB7XG4gICAgICAgIHRoaXMuZmlsZXMgPSBhY3Rpb25SZXN1bHQucmVwbGFjZUZpbGVzID8gYWN0aW9uUmVzdWx0LmZpbGVzIDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgYWN0aW9uUmVzdWx0LmZpbGVzKTtcbiAgICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5hcHBTdGF0ZSB8fCBlZGl0aW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIGlmIChhY3Rpb25SZXN1bHQuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHZpZXdNb2RlRW5hYmxlZCA9ICgoX2EgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS52aWV3TW9kZUVuYWJsZWQpIHx8IGZhbHNlO1xuICAgICAgICBsZXQgemVuTW9kZUVuYWJsZWQgPSAoKF9iID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuemVuTW9kZUVuYWJsZWQpIHx8IGZhbHNlO1xuICAgICAgICBsZXQgZ3JpZFNpemUgPSAoKF9jID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZ3JpZFNpemUpIHx8IG51bGw7XG4gICAgICAgIGNvbnN0IHRoZW1lID0gKChfZCA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnRoZW1lKSB8fCB0aGlzLnByb3BzLnRoZW1lIHx8IFRIRU1FLkxJR0hUO1xuICAgICAgICBsZXQgbmFtZSA9IChfZiA9IChfZSA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLm5hbWUpICE9PSBudWxsICYmIF9mICE9PSB2b2lkIDAgPyBfZiA6IHRoaXMuc3RhdGUubmFtZTtcbiAgICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gKF9oID0gKF9nID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2cuZXJyb3JNZXNzYWdlKSAhPT0gbnVsbCAmJiBfaCAhPT0gdm9pZCAwID8gX2ggOiB0aGlzLnN0YXRlLmVycm9yTWVzc2FnZTtcblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMudmlld01vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgdmlld01vZGVFbmFibGVkID0gdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICB6ZW5Nb2RlRW5hYmxlZCA9IHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgZ3JpZFNpemUgPSB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMubmFtZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIG5hbWUgPSB0aGlzLnByb3BzLm5hbWU7XG4gICAgICAgIH1cblxuICAgICAgICBlZGl0aW5nRWxlbWVudCA9IGVkaXRpbmdFbGVtZW50IHx8ICgoX2ogPSBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9qID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfai5lZGl0aW5nRWxlbWVudCkgfHwgbnVsbDtcblxuICAgICAgICBpZiAoZWRpdGluZ0VsZW1lbnQgPT09IG51bGwgfHwgZWRpdGluZ0VsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVkaXRpbmdFbGVtZW50LmlzRGVsZXRlZCkge1xuICAgICAgICAgIGVkaXRpbmdFbGVtZW50ID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIC8vIHVzaW5nIE9iamVjdC5hc3NpZ24gaW5zdGVhZCBvZiBzcHJlYWQgdG8gZm9vbCBUUyA0LjIuMisgaW50b1xuICAgICAgICAgIC8vIHJlZ2FyZGluZyB0aGUgcmVzdWx0aW5nIHR5cGUgYXMgbm90IGNvbnRhaW5pbmcgdW5kZWZpbmVkXG4gICAgICAgICAgLy8gKHdoaWNoIHRoZSBmb2xsb3dpbmcgZXhwcmVzc2lvbiB3aWxsIG5ldmVyIGNvbnRhaW4pXG4gICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oYWN0aW9uUmVzdWx0LmFwcFN0YXRlIHx8IHt9LCB7XG4gICAgICAgICAgICAvLyBOT1RFIHRoaXMgd2lsbCBwcmV2ZW50IG9wZW5pbmcgY29udGV4dCBtZW51IHVzaW5nIGFuIGFjdGlvblxuICAgICAgICAgICAgLy8gb3IgcHJvZ3JhbW1hdGljYWxseSBmcm9tIHRoZSBob3N0LCBzbyBpdCB3aWxsIG5lZWQgdG8gYmVcbiAgICAgICAgICAgIC8vIHJld3JpdHRlbiBsYXRlclxuICAgICAgICAgICAgY29udGV4dE1lbnU6IG51bGwsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudCxcbiAgICAgICAgICAgIHZpZXdNb2RlRW5hYmxlZCxcbiAgICAgICAgICAgIHplbk1vZGVFbmFibGVkLFxuICAgICAgICAgICAgZ3JpZFNpemUsXG4gICAgICAgICAgICB0aGVtZSxcbiAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2VcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIGlmIChhY3Rpb25SZXN1bHQuc3luY0hpc3RvcnkpIHtcbiAgICAgICAgICAgIHRoaXMuaGlzdG9yeS5zZXRDdXJyZW50U3RhdGUodGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTsgLy8gTGlmZWN5Y2xlXG5cbiAgICB0aGlzLm9uQmx1ciA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICBpc0hvbGRpbmdTcGFjZSA9IGZhbHNlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQ6IHRydWVcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGhpcy5vblVubG9hZCA9ICgpID0+IHtcbiAgICAgIHRoaXMub25CbHVyKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZGlzYWJsZUV2ZW50ID0gZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldEhpc3RvcnkgPSAoKSA9PiB7XG4gICAgICB0aGlzLmhpc3RvcnkuY2xlYXIoKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJlc2V0cyBzY2VuZSAmIGhpc3RvcnkuXG4gICAgICogISBEbyBub3QgdXNlIHRvIGNsZWFyIHNjZW5lIHVzZXIgYWN0aW9uICFcbiAgICAgKi9cblxuXG4gICAgdGhpcy5yZXNldFNjZW5lID0gd2l0aEJhdGNoZWRVcGRhdGVzKG9wdHMgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldERlZmF1bHRBcHBTdGF0ZSgpKSwge1xuICAgICAgICBpc0xvYWRpbmc6IChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucmVzZXRMb2FkaW5nU3RhdGUpID8gZmFsc2UgOiBzdGF0ZS5pc0xvYWRpbmcsXG4gICAgICAgIHRoZW1lOiB0aGlzLnN0YXRlLnRoZW1lXG4gICAgICB9KSk7XG4gICAgICB0aGlzLnJlc2V0SGlzdG9yeSgpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5pbml0aWFsaXplU2NlbmUgPSAoKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGlmIChcImxhdW5jaFF1ZXVlXCIgaW4gd2luZG93ICYmIFwiTGF1bmNoUGFyYW1zXCIgaW4gd2luZG93KSB7XG4gICAgICAgIHdpbmRvdy5sYXVuY2hRdWV1ZS5zZXRDb25zdW1lcihsYXVuY2hQYXJhbXMgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgICAgIGlmICghbGF1bmNoUGFyYW1zLmZpbGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGZpbGVIYW5kbGUgPSBsYXVuY2hQYXJhbXMuZmlsZXNbMF07XG4gICAgICAgICAgY29uc3QgYmxvYiA9IHlpZWxkIGZpbGVIYW5kbGUuZ2V0RmlsZSgpO1xuICAgICAgICAgIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhuZXcgRmlsZShbYmxvYl0sIGJsb2IubmFtZSB8fCBcIlwiLCB7XG4gICAgICAgICAgICB0eXBlOiBibG9iLnR5cGVcbiAgICAgICAgICB9KSwgZmlsZUhhbmRsZSk7XG4gICAgICAgIH0pKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMucHJvcHMudGhlbWUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5pc0xvYWRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBsZXQgaW5pdGlhbERhdGEgPSBudWxsO1xuXG4gICAgICB0cnkge1xuICAgICAgICBpbml0aWFsRGF0YSA9ICh5aWVsZCB0aGlzLnByb3BzLmluaXRpYWxEYXRhKSB8fCBudWxsO1xuXG4gICAgICAgIGlmIChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEubGlicmFyeUl0ZW1zKSB7XG4gICAgICAgICAgdGhpcy5saWJyYXJ5LnVwZGF0ZUxpYnJhcnkoe1xuICAgICAgICAgICAgbGlicmFyeUl0ZW1zOiBpbml0aWFsRGF0YS5saWJyYXJ5SXRlbXMsXG4gICAgICAgICAgICBtZXJnZTogdHJ1ZVxuICAgICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgaW5pdGlhbERhdGEgPSB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZSB8fCBcIkVuY291bnRlcmVkIGFuIGVycm9yIGR1cmluZyBpbXBvcnRpbmcgb3IgcmVzdG9yaW5nIHNjZW5lIGRhdGFcIlxuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2NlbmUgPSByZXN0b3JlKGluaXRpYWxEYXRhLCBudWxsLCBudWxsLCB7XG4gICAgICAgIHJlcGFpckJpbmRpbmdzOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIHNjZW5lLmFwcFN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIHtcbiAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWUgfHwgc2NlbmUuYXBwU3RhdGUudGhlbWUsXG4gICAgICAgIC8vIHdlJ3JlIGZhbGxpbmcgYmFjayB0byBjdXJyZW50IChwcmUtaW5pdCkgc3RhdGUgd2hlbiBkZWNpZGluZ1xuICAgICAgICAvLyB3aGV0aGVyIHRvIG9wZW4gdGhlIGxpYnJhcnksIHRvIGhhbmRsZSBhIGNhc2Ugd2hlcmUgd2VcbiAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZSBvdXRzaWRlIG9mIGluaXRpYWxEYXRhIChlLmcuIHdoZW4gbG9hZGluZyB0aGUgYXBwXG4gICAgICAgIC8vIHdpdGggYSBsaWJyYXJ5IGluc3RhbGwgbGluaywgd2hpY2ggc2hvdWxkIGF1dG8tb3BlbiB0aGUgbGlicmFyeSlcbiAgICAgICAgb3BlblNpZGViYXI6ICgoX2EgPSBzY2VuZS5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm9wZW5TaWRlYmFyKSB8fCB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyLFxuICAgICAgICBhY3RpdmVUb29sOiBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbCksIHtcbiAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgIH0pIDogc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbCxcbiAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgdG9hc3Q6IHRoaXMuc3RhdGUudG9hc3RcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaW5pdGlhbERhdGEgPT09IG51bGwgfHwgaW5pdGlhbERhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGluaXRpYWxEYXRhLnNjcm9sbFRvQ29udGVudCkge1xuICAgICAgICBzY2VuZS5hcHBTdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCBjYWxjdWxhdGVTY3JvbGxDZW50ZXIoc2NlbmUuZWxlbWVudHMsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCB7XG4gICAgICAgICAgd2lkdGg6IHRoaXMuc3RhdGUud2lkdGgsXG4gICAgICAgICAgaGVpZ2h0OiB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgICAgICBvZmZzZXRUb3A6IHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnQ6IHRoaXMuc3RhdGUub2Zmc2V0TGVmdFxuICAgICAgICB9KSkpO1xuICAgICAgfSAvLyBGb250RmFjZVNldCBsb2FkaW5nZG9uZSBldmVudCB3ZSBsaXN0ZW4gb24gbWF5IG5vdCBhbHdheXMgZmlyZVxuICAgICAgLy8gKGxvb2tpbmcgYXQgeW91IFNhZmFyaSksIHNvIG9uIGluaXQgd2UgbWFudWFsbHkgbG9hZCBmb250cyBmb3IgY3VycmVudFxuICAgICAgLy8gdGV4dCBlbGVtZW50cyBvbiBjYW52YXMsIGFuZCByZXJlbmRlciB0aGVtIG9uY2UgZG9uZS4gVGhpcyBhbHNvXG4gICAgICAvLyBzZWVtcyBmYXN0ZXIgZXZlbiBpbiBicm93c2VycyB0aGF0IGRvIGZpcmUgdGhlIGxvYWRpbmdkb25lIGV2ZW50LlxuXG5cbiAgICAgIHRoaXMuZm9udHMubG9hZEZvbnRzRm9yRWxlbWVudHMoc2NlbmUuZWxlbWVudHMpO1xuICAgICAgdGhpcy5yZXNldEhpc3RvcnkoKTtcbiAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lKSwge1xuICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRoaXMuaXNNb2JpbGVCcmVha3BvaW50ID0gKHdpZHRoLCBoZWlnaHQpID0+IHtcbiAgICAgIHJldHVybiB3aWR0aCA8IE1RX01BWF9XSURUSF9QT1JUUkFJVCB8fCBoZWlnaHQgPCBNUV9NQVhfSEVJR0hUX0xBTkRTQ0FQRSAmJiB3aWR0aCA8IE1RX01BWF9XSURUSF9MQU5EU0NBUEU7XG4gICAgfTtcblxuICAgIHRoaXMucmVmcmVzaFZpZXdwb3J0QnJlYWtwb2ludHMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcblxuICAgICAgaWYgKCFjb250YWluZXIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIGNsaWVudFdpZHRoOiB2aWV3cG9ydFdpZHRoLFxuICAgICAgICBjbGllbnRIZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0XG4gICAgICB9ID0gZG9jdW1lbnQuYm9keTtcbiAgICAgIGNvbnN0IHByZXZWaWV3cG9ydFN0YXRlID0gdGhpcy5kZXZpY2Uudmlld3BvcnQ7XG4gICAgICBjb25zdCBuZXh0Vmlld3BvcnRTdGF0ZSA9IHVwZGF0ZU9iamVjdChwcmV2Vmlld3BvcnRTdGF0ZSwge1xuICAgICAgICBpc0xhbmRzY2FwZTogdmlld3BvcnRXaWR0aCA+IHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgICBpc01vYmlsZTogdGhpcy5pc01vYmlsZUJyZWFrcG9pbnQodmlld3BvcnRXaWR0aCwgdmlld3BvcnRIZWlnaHQpXG4gICAgICB9KTtcblxuICAgICAgaWYgKHByZXZWaWV3cG9ydFN0YXRlICE9PSBuZXh0Vmlld3BvcnRTdGF0ZSkge1xuICAgICAgICB0aGlzLmRldmljZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5kZXZpY2UpLCB7XG4gICAgICAgICAgdmlld3BvcnQ6IG5leHRWaWV3cG9ydFN0YXRlXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cyA9ICgpID0+IHtcbiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAoIWNvbnRhaW5lcikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgd2lkdGg6IGVkaXRvcldpZHRoLFxuICAgICAgICBoZWlnaHQ6IGVkaXRvckhlaWdodFxuICAgICAgfSA9IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGNvbnN0IHNpZGViYXJCcmVha3BvaW50ID0gdGhpcy5wcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT0gbnVsbCA/IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50IDogTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEg7XG4gICAgICBjb25zdCBwcmV2RWRpdG9yU3RhdGUgPSB0aGlzLmRldmljZS5lZGl0b3I7XG4gICAgICBjb25zdCBuZXh0RWRpdG9yU3RhdGUgPSB1cGRhdGVPYmplY3QocHJldkVkaXRvclN0YXRlLCB7XG4gICAgICAgIGlzTW9iaWxlOiB0aGlzLmlzTW9iaWxlQnJlYWtwb2ludChlZGl0b3JXaWR0aCwgZWRpdG9ySGVpZ2h0KSxcbiAgICAgICAgY2FuRml0U2lkZWJhcjogZWRpdG9yV2lkdGggPiBzaWRlYmFyQnJlYWtwb2ludFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChwcmV2RWRpdG9yU3RhdGUgIT09IG5leHRFZGl0b3JTdGF0ZSkge1xuICAgICAgICB0aGlzLmRldmljZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5kZXZpY2UpLCB7XG4gICAgICAgICAgZWRpdG9yOiBuZXh0RWRpdG9yU3RhdGVcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMub25SZXNpemUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoKCkgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5mb3JFYWNoKGVsZW1lbnQgPT4gU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCkpO1xuICAgICAgdGhpcy5yZWZyZXNoVmlld3BvcnRCcmVha3BvaW50cygpO1xuICAgICAgdGhpcy51cGRhdGVET01SZWN0KCk7XG5cbiAgICAgIGlmICghc3VwcG9ydHNSZXNpemVPYnNlcnZlcikge1xuICAgICAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cygpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHt9KTtcbiAgICB9KTtcblxuICAgIHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrID0gKHtcbiAgICAgIGF0TGVhc3RPbmVWaXNpYmxlRWxlbWVudCxcbiAgICAgIHNjcm9sbEJhcnMsXG4gICAgICBlbGVtZW50c1xuICAgIH0pID0+IHtcbiAgICAgIGlmIChzY3JvbGxCYXJzKSB7XG4gICAgICAgIGN1cnJlbnRTY3JvbGxCYXJzID0gc2Nyb2xsQmFycztcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2Nyb2xsZWRPdXRzaWRlID0gLy8gaGlkZSB3aGVuIGVkaXRpbmcgdGV4dFxuICAgICAgaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA/IGZhbHNlIDogIWF0TGVhc3RPbmVWaXNpYmxlRWxlbWVudCAmJiBlbGVtZW50cy5sZW5ndGggPiAwO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zY3JvbGxlZE91dHNpZGUgIT09IHNjcm9sbGVkT3V0c2lkZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzY3JvbGxlZE91dHNpZGVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2NoZWR1bGVJbWFnZVJlZnJlc2goKTtcbiAgICB9O1xuXG4gICAgdGhpcy5vblNjcm9sbCA9IGRlYm91bmNlKCgpID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgb2Zmc2V0VG9wLFxuICAgICAgICBvZmZzZXRMZWZ0XG4gICAgICB9ID0gdGhpcy5nZXRDYW52YXNPZmZzZXRzKCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IHtcbiAgICAgICAgaWYgKHN0YXRlLm9mZnNldExlZnQgPT09IG9mZnNldExlZnQgJiYgc3RhdGUub2Zmc2V0VG9wID09PSBvZmZzZXRUb3ApIHtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgb2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnRcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH0sIFNDUk9MTF9USU1FT1VUKTsgLy8gQ29weS9wYXN0ZVxuXG4gICAgdGhpcy5vbkN1dCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IGlzRXhjYWxpZHJhd0FjdGl2ZSA9IChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY29udGFpbnMoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCk7XG5cbiAgICAgIGlmICghaXNFeGNhbGlkcmF3QWN0aXZlIHx8IGlzV3JpdGFibGVFbGVtZW50KGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25DdXQsIFwia2V5Ym9hcmRcIiwgZXZlbnQpO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH0pO1xuICAgIHRoaXMub25Db3B5ID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaXNFeGNhbGlkcmF3QWN0aXZlID0gKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jb250YWlucyhkb2N1bWVudC5hY3RpdmVFbGVtZW50KTtcblxuICAgICAgaWYgKCFpc0V4Y2FsaWRyYXdBY3RpdmUgfHwgaXNXcml0YWJsZUVsZW1lbnQoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkNvcHksIFwia2V5Ym9hcmRcIiwgZXZlbnQpO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5vblRvdWNoU3RhcnQgPSBldmVudCA9PiB7XG4gICAgICAvLyBmaXggZm9yIEFwcGxlIFBlbmNpbCBTY3JpYmJsZVxuICAgICAgLy8gT24gQW5kcm9pZCwgcHJldmVudGluZyB0aGUgZXZlbnQgd291bGQgZGlzYWJsZSBjb250ZXh0TWVudSBvbiB0YXAtaG9sZFxuICAgICAgaWYgKCFpc0FuZHJvaWQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFkaWRUYXBUd2ljZSkge1xuICAgICAgICBkaWRUYXBUd2ljZSA9IHRydWU7XG4gICAgICAgIGNsZWFyVGltZW91dCh0YXBwZWRUd2ljZVRpbWVyKTtcbiAgICAgICAgdGFwcGVkVHdpY2VUaW1lciA9IHdpbmRvdy5zZXRUaW1lb3V0KEFwcC5yZXNldFRhcFR3aWNlLCBUQVBfVFdJQ0VfVElNRU9VVCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gaW5zZXJ0IHRleHQgb25seSBpZiB3ZSB0YXBwZWQgdHdpY2Ugd2l0aCBhIHNpbmdsZSBmaW5nZXJcbiAgICAgIC8vIGV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSAxIHdpbGwgYWxzbyBwcmV2ZW50IGluc2VydGluZyB0ZXh0IHdoZW4gdXNlcidzIHpvb21pbmdcblxuXG4gICAgICBpZiAoZGlkVGFwVHdpY2UgJiYgZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgY29uc3QgdG91Y2ggPSBldmVudC50b3VjaGVzWzBdOyAvLyBAdHMtaWdub3JlXG5cbiAgICAgICAgdGhpcy5oYW5kbGVDYW52YXNEb3VibGVDbGljayh7XG4gICAgICAgICAgY2xpZW50WDogdG91Y2guY2xpZW50WCxcbiAgICAgICAgICBjbGllbnRZOiB0b3VjaC5jbGllbnRZXG4gICAgICAgIH0pO1xuICAgICAgICBkaWRUYXBUd2ljZSA9IGZhbHNlO1xuICAgICAgICBjbGVhclRpbWVvdXQodGFwcGVkVHdpY2VUaW1lcik7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0FuZHJvaWQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMub25Ub3VjaEVuZCA9IGV2ZW50ID0+IHtcbiAgICAgIHRoaXMucmVzZXRDb250ZXh0TWVudVRpbWVyKCk7XG5cbiAgICAgIGlmIChldmVudC50b3VjaGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHt9LFxuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHModGhpcy5zdGF0ZS5wcmV2aW91c1NlbGVjdGVkRWxlbWVudElkcywgdGhpcy5zdGF0ZSlcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBnZXN0dXJlLnBvaW50ZXJzLmNsZWFyKCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMucGFzdGVGcm9tQ2xpcGJvYXJkID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfYiwgX2MsIF9kO1xuXG4gICAgICBjb25zdCBpc1BsYWluUGFzdGUgPSAhIUlTX1BMQUlOX1BBU1RFOyAvLyAjNjg2XG5cbiAgICAgIGNvbnN0IHRhcmdldCA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG4gICAgICBjb25zdCBpc0V4Y2FsaWRyYXdBY3RpdmUgPSAoX2IgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNvbnRhaW5zKHRhcmdldCk7XG5cbiAgICAgIGlmIChldmVudCAmJiAhaXNFeGNhbGlkcmF3QWN0aXZlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudFVuZGVyQ3Vyc29yID0gZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludCh0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSk7XG5cbiAgICAgIGlmIChldmVudCAmJiAoIShlbGVtZW50VW5kZXJDdXJzb3IgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCkgfHwgaXNXcml0YWJsZUVsZW1lbnQodGFyZ2V0KSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgY2xpZW50WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgICBjbGllbnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnlcbiAgICAgIH0sIHRoaXMuc3RhdGUpOyAvLyBtdXN0IGJlIGNhbGxlZCBpbiB0aGUgc2FtZSBmcmFtZSAodGh1cyBiZWZvcmUgYW55IGF3YWl0cykgYXMgdGhlIHBhc3RlXG4gICAgICAvLyBldmVudCBlbHNlIHNvbWUgYnJvd3NlcnMgKEZGLi4uKSB3aWxsIGNsZWFyIHRoZSBjbGlwYm9hcmREYXRhXG4gICAgICAvLyAoc29tZXRoaW5nIHNvbWV0aGluZyBzZWN1cml0eSlcblxuICAgICAgbGV0IGZpbGUgPSAoX2MgPSBldmVudCA9PT0gbnVsbCB8fCBldmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXZlbnQuY2xpcGJvYXJkRGF0YSkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmZpbGVzWzBdO1xuICAgICAgY29uc3QgZGF0YSA9IHlpZWxkIHBhcnNlQ2xpcGJvYXJkKGV2ZW50LCBpc1BsYWluUGFzdGUpO1xuXG4gICAgICBpZiAoIWZpbGUgJiYgIWlzUGxhaW5QYXN0ZSkge1xuICAgICAgICBpZiAoZGF0YS5taXhlZENvbnRlbnQpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5hZGRFbGVtZW50c0Zyb21NaXhlZENvbnRlbnRQYXN0ZShkYXRhLm1peGVkQ29udGVudCwge1xuICAgICAgICAgICAgaXNQbGFpblBhc3RlLFxuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS50ZXh0KSB7XG4gICAgICAgICAgY29uc3Qgc3RyaW5nID0gZGF0YS50ZXh0LnRyaW0oKTtcblxuICAgICAgICAgIGlmIChzdHJpbmcuc3RhcnRzV2l0aChcIjxzdmdcIikgJiYgc3RyaW5nLmVuZHNXaXRoKFwiPC9zdmc+XCIpKSB7XG4gICAgICAgICAgICAvLyBpZ25vcmUgU1ZHIHZhbGlkYXRpb24vbm9ybWFsaXphdGlvbiB3aGljaCB3aWxsIGJlIGRvbmUgZHVyaW5nIGltYWdlXG4gICAgICAgICAgICAvLyBpbml0aWFsaXphdGlvblxuICAgICAgICAgICAgZmlsZSA9IFNWR1N0cmluZ1RvRmlsZShzdHJpbmcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSAvLyBwcmVmZXIgc3ByZWFkc2hlZXQgZGF0YSBvdmVyIGltYWdlIGZpbGUgKE1TIE9mZmljZS9MaWJyZSBPZmZpY2UpXG5cblxuICAgICAgaWYgKGlzU3VwcG9ydGVkSW1hZ2VGaWxlKGZpbGUpICYmICFkYXRhLnNwcmVhZHNoZWV0KSB7XG4gICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50KHtcbiAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgc2NlbmVZXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmluc2VydEltYWdlRWxlbWVudChpbWFnZUVsZW1lbnQsIGZpbGUpO1xuICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnByb3BzLm9uUGFzdGUpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAoKHlpZWxkIHRoaXMucHJvcHMub25QYXN0ZShkYXRhLCBldmVudCkpID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZGF0YS5lcnJvck1lc3NhZ2UpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBkYXRhLmVycm9yTWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5zcHJlYWRzaGVldCAmJiAhaXNQbGFpblBhc3RlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHBhc3RlRGlhbG9nOiB7XG4gICAgICAgICAgICBkYXRhOiBkYXRhLnNwcmVhZHNoZWV0LFxuICAgICAgICAgICAgc2hvd246IHRydWVcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmVsZW1lbnRzKSB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzID0gZGF0YS5wcm9ncmFtbWF0aWNBUEkgPyBjb252ZXJ0VG9FeGNhbGlkcmF3RWxlbWVudHMoZGF0YS5lbGVtZW50cykgOiBkYXRhLmVsZW1lbnRzOyAvLyBUT0RPIHJlbW92ZSBmb3JtYXR0aW5nIGZyb20gZWxlbWVudHMgaWYgaXNQbGFpblBhc3RlXG5cbiAgICAgICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSh7XG4gICAgICAgICAgZWxlbWVudHMsXG4gICAgICAgICAgZmlsZXM6IGRhdGEuZmlsZXMgfHwgbnVsbCxcbiAgICAgICAgICBwb3NpdGlvbjogXCJjdXJzb3JcIixcbiAgICAgICAgICByZXRhaW5TZWVkOiBpc1BsYWluUGFzdGVcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEudGV4dCkge1xuICAgICAgICBjb25zdCBtYXliZVVybCA9IGV4dHJhY3RTcmMoZGF0YS50ZXh0KTtcblxuICAgICAgICBpZiAoIWlzUGxhaW5QYXN0ZSAmJiBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yKG1heWJlVXJsLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSkgJiYgKC9eKGh0dHB8aHR0cHMpOlxcL1xcL1teXFxzLyQuPyNdLlteXFxzXSokLy50ZXN0KG1heWJlVXJsKSB8fCAoKF9kID0gZ2V0RW1iZWRMaW5rKG1heWJlVXJsKSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnR5cGUpID09PSBcInZpZGVvXCIpKSB7XG4gICAgICAgICAgY29uc3QgZW1iZWRkYWJsZSA9IHRoaXMuaW5zZXJ0RW1iZWRkYWJsZUVsZW1lbnQoe1xuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZLFxuICAgICAgICAgICAgbGluazogbm9ybWFsaXplTGluayhtYXliZVVybClcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmIChlbWJlZGRhYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgW2VtYmVkZGFibGUuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuYWRkVGV4dEZyb21QYXN0ZShkYXRhLnRleHQsIGlzUGxhaW5QYXN0ZSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgIH0pO1xuICAgICAgZXZlbnQgPT09IG51bGwgfHwgZXZlbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSkpO1xuXG4gICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSA9IG9wdHMgPT4ge1xuICAgICAgY29uc3QgZWxlbWVudHMgPSByZXN0b3JlRWxlbWVudHMob3B0cy5lbGVtZW50cywgbnVsbCwgdW5kZWZpbmVkKTtcbiAgICAgIGNvbnN0IFttaW5YLCBtaW5ZLCBtYXhYLCBtYXhZXSA9IGdldENvbW1vbkJvdW5kcyhlbGVtZW50cyk7XG4gICAgICBjb25zdCBlbGVtZW50c0NlbnRlclggPSBkaXN0YW5jZShtaW5YLCBtYXhYKSAvIDI7XG4gICAgICBjb25zdCBlbGVtZW50c0NlbnRlclkgPSBkaXN0YW5jZShtaW5ZLCBtYXhZKSAvIDI7XG4gICAgICBjb25zdCBjbGllbnRYID0gdHlwZW9mIG9wdHMucG9zaXRpb24gPT09IFwib2JqZWN0XCIgPyBvcHRzLnBvc2l0aW9uLmNsaWVudFggOiBvcHRzLnBvc2l0aW9uID09PSBcImN1cnNvclwiID8gdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54IDogdGhpcy5zdGF0ZS53aWR0aCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldExlZnQ7XG4gICAgICBjb25zdCBjbGllbnRZID0gdHlwZW9mIG9wdHMucG9zaXRpb24gPT09IFwib2JqZWN0XCIgPyBvcHRzLnBvc2l0aW9uLmNsaWVudFkgOiBvcHRzLnBvc2l0aW9uID09PSBcImN1cnNvclwiID8gdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55IDogdGhpcy5zdGF0ZS5oZWlnaHQgLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRUb3A7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYLFxuICAgICAgICBjbGllbnRZXG4gICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGR4ID0geCAtIGVsZW1lbnRzQ2VudGVyWDtcbiAgICAgIGNvbnN0IGR5ID0geSAtIGVsZW1lbnRzQ2VudGVyWTtcbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KGR4LCBkeSwgdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBuZXdFbGVtZW50cyA9IGR1cGxpY2F0ZUVsZW1lbnRzKGVsZW1lbnRzLm1hcChlbGVtZW50ID0+IHtcbiAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZW1lbnQsIHtcbiAgICAgICAgICB4OiBlbGVtZW50LnggKyBncmlkWCAtIG1pblgsXG4gICAgICAgICAgeTogZWxlbWVudC55ICsgZ3JpZFkgLSBtaW5ZXG4gICAgICAgIH0pO1xuICAgICAgfSksIHtcbiAgICAgICAgcmFuZG9taXplU2VlZDogIW9wdHMucmV0YWluU2VlZFxuICAgICAgfSk7XG4gICAgICBjb25zdCBuZXh0RWxlbWVudHMgPSBbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgLi4ubmV3RWxlbWVudHNdO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dEVsZW1lbnRzKTtcbiAgICAgIG5ld0VsZW1lbnRzLmZvckVhY2gobmV3RWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc1RleHRFbGVtZW50KG5ld0VsZW1lbnQpICYmIGlzQm91bmRUb0NvbnRhaW5lcihuZXdFbGVtZW50KSkge1xuICAgICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IGdldENvbnRhaW5lckVsZW1lbnQobmV3RWxlbWVudCk7XG4gICAgICAgICAgcmVkcmF3VGV4dEJvdW5kaW5nQm94KG5ld0VsZW1lbnQsIGNvbnRhaW5lcik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpZiAob3B0cy5maWxlcykge1xuICAgICAgICB0aGlzLmZpbGVzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgb3B0cy5maWxlcyk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIGNvbnN0IG5leHRFbGVtZW50c1RvU2VsZWN0ID0gZXhjbHVkZUVsZW1lbnRzSW5GcmFtZXNGcm9tU2VsZWN0aW9uKG5ld0VsZW1lbnRzKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCB7XG4gICAgICAgIC8vIGtlZXAgc2lkZWJhciAocHJlc3VtYWJseSB0aGUgbGlicmFyeSkgb3BlbiBpZiBpdCdzIGRvY2tlZCBhbmRcbiAgICAgICAgLy8gY2FuIGZpdC5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gTm90ZSwgd2Ugc2hvdWxkIGNsb3NlIHRoZSBzaWRlYmFyIG9ubHkgaWYgd2UncmUgZHJvcHBpbmcgaXRlbXNcbiAgICAgICAgLy8gZnJvbSBsaWJyYXJ5LCBub3Qgd2hlbiBwYXN0aW5nIGZyb20gY2xpcGJvYXJkLiBBbGFzLlxuICAgICAgICBvcGVuU2lkZWJhcjogdGhpcy5zdGF0ZS5vcGVuU2lkZWJhciAmJiB0aGlzLmRldmljZS5lZGl0b3IuY2FuRml0U2lkZWJhciAmJiBqb3RhaVN0b3JlLmdldChpc1NpZGViYXJEb2NrZWRBdG9tKSA/IHRoaXMuc3RhdGUub3BlblNpZGViYXIgOiBudWxsXG4gICAgICB9KSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRFbGVtZW50c1RvU2VsZWN0LnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgaWYgKCFpc0JvdW5kVG9Db250YWluZXIoZWxlbWVudCkpIHtcbiAgICAgICAgICAgIGFjY1tlbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgfSwge30pXG4gICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCB0aGlzKSksICgpID0+IHtcbiAgICAgICAgaWYgKG9wdHMuZmlsZXMpIHtcbiAgICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgIH0pO1xuXG4gICAgICBpZiAob3B0cy5maXRUb0NvbnRlbnQpIHtcbiAgICAgICAgdGhpcy5zY3JvbGxUb0NvbnRlbnQobmV3RWxlbWVudHMsIHtcbiAgICAgICAgICBmaXRUb0NvbnRlbnQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuc2V0QXBwU3RhdGUgPSAoc3RhdGUsIGNhbGxiYWNrKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlLCBjYWxsYmFjayk7XG4gICAgfTtcblxuICAgIHRoaXMucmVtb3ZlUG9pbnRlciA9IGV2ZW50ID0+IHtcbiAgICAgIGlmICh0b3VjaFRpbWVvdXQpIHtcbiAgICAgICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIoKTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5wb2ludGVycy5kZWxldGUoZXZlbnQucG9pbnRlcklkKTtcbiAgICB9O1xuXG4gICAgdGhpcy50b2dnbGVMb2NrID0gKHNvdXJjZSA9IFwidWlcIikgPT4ge1xuICAgICAgaWYgKCF0aGlzLnN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgIHRyYWNrRXZlbnQoXCJ0b29sYmFyXCIsIFwidG9nZ2xlTG9ja1wiLCBgJHtzb3VyY2V9ICgke3RoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSA/IFwibW9iaWxlXCIgOiBcImRlc2t0b3BcIn0pYCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhY3RpdmVUb29sOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLmFjdGl2ZVRvb2wpLCB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHByZXZTdGF0ZS5hY3RpdmVUb29sLmxvY2tlZCA/IHtcbiAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgICB9IDogcHJldlN0YXRlLmFjdGl2ZVRvb2wpKSwge1xuICAgICAgICAgICAgbG9ja2VkOiAhcHJldlN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkXG4gICAgICAgICAgfSlcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnVwZGF0ZUZyYW1lUmVuZGVyaW5nID0gb3B0cyA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIHZhciBfYSwgX2IsIF9jLCBfZDtcblxuICAgICAgICBjb25zdCBuZXh0ID0gdHlwZW9mIG9wdHMgPT09IFwiZnVuY3Rpb25cIiA/IG9wdHMocHJldlN0YXRlLmZyYW1lUmVuZGVyaW5nKSA6IG9wdHM7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZnJhbWVSZW5kZXJpbmc6IHtcbiAgICAgICAgICAgIGVuYWJsZWQ6IChfYSA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5lbmFibGVkKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCxcbiAgICAgICAgICAgIGNsaXA6IChfYiA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5jbGlwKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcuY2xpcCxcbiAgICAgICAgICAgIG5hbWU6IChfYyA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5uYW1lKSAhPT0gbnVsbCAmJiBfYyAhPT0gdm9pZCAwID8gX2MgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcubmFtZSxcbiAgICAgICAgICAgIG91dGxpbmU6IChfZCA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5vdXRsaW5lKSAhPT0gbnVsbCAmJiBfZCAhPT0gdm9pZCAwID8gX2QgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcub3V0bGluZVxuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnRvZ2dsZVBlbk1vZGUgPSBmb3JjZSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgcGVuTW9kZTogZm9yY2UgIT09IG51bGwgJiYgZm9yY2UgIT09IHZvaWQgMCA/IGZvcmNlIDogIXByZXZTdGF0ZS5wZW5Nb2RlLFxuICAgICAgICAgIHBlbkRldGVjdGVkOiB0cnVlXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5vbkhhbmRUb29sVG9nZ2xlID0gKCkgPT4ge1xuICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uVG9nZ2xlSGFuZFRvb2wpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogWm9vbXMgb24gY2FudmFzIHZpZXdwb3J0IGNlbnRlclxuICAgICAqL1xuXG5cbiAgICB0aGlzLnpvb21DYW52YXMgPSAoXG4gICAgLyoqIGRlY2ltYWwgZnJhY3Rpb24gYmV0d2VlbiAwLjEgKDEwJSB6b29tKSBhbmQgMzAgKDMwMDAlIHpvb20pICovXG4gICAgdmFsdWUpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgdmlld3BvcnRYOiB0aGlzLnN0YXRlLndpZHRoIC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCxcbiAgICAgICAgdmlld3BvcnRZOiB0aGlzLnN0YXRlLmhlaWdodCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldFRvcCxcbiAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKHZhbHVlKVxuICAgICAgfSwgdGhpcy5zdGF0ZSkpKTtcbiAgICB9O1xuXG4gICAgdGhpcy5jYW5jZWxJblByb2dyZXNBbmltYXRpb24gPSBudWxsO1xuXG4gICAgdGhpcy5zY3JvbGxUb0NvbnRlbnQgPSAodGFyZ2V0ID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgb3B0cykgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgKF9hID0gdGhpcy5jYW5jZWxJblByb2dyZXNBbmltYXRpb24pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jYWxsKHRoaXMpOyAvLyBjb252ZXJ0IHByb3ZpZGVkIHRhcmdldCBpbnRvIEV4Y2FsaWRyYXdFbGVtZW50W10gaWYgbmVjZXNzYXJ5XG5cbiAgICAgIGNvbnN0IHRhcmdldEVsZW1lbnRzID0gQXJyYXkuaXNBcnJheSh0YXJnZXQpID8gdGFyZ2V0IDogW3RhcmdldF07XG4gICAgICBsZXQgem9vbSA9IHRoaXMuc3RhdGUuem9vbTtcbiAgICAgIGxldCBzY3JvbGxYID0gdGhpcy5zdGF0ZS5zY3JvbGxYO1xuICAgICAgbGV0IHNjcm9sbFkgPSB0aGlzLnN0YXRlLnNjcm9sbFk7XG5cbiAgICAgIGlmICgob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvQ29udGVudCkgfHwgKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5maXRUb1ZpZXdwb3J0KSkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgYXBwU3RhdGVcbiAgICAgICAgfSA9IHpvb21Ub0ZpdCh7XG4gICAgICAgICAgdGFyZ2V0RWxlbWVudHMsXG4gICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgZml0VG9WaWV3cG9ydDogISEob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvVmlld3BvcnQpLFxuICAgICAgICAgIHZpZXdwb3J0Wm9vbUZhY3Rvcjogb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnZpZXdwb3J0Wm9vbUZhY3RvclxuICAgICAgICB9KTtcbiAgICAgICAgem9vbSA9IGFwcFN0YXRlLnpvb207XG4gICAgICAgIHNjcm9sbFggPSBhcHBTdGF0ZS5zY3JvbGxYO1xuICAgICAgICBzY3JvbGxZID0gYXBwU3RhdGUuc2Nyb2xsWTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGNvbXB1dGUgb25seSB0aGUgdmlld3BvcnQgbG9jYXRpb24sIHdpdGhvdXQgYW55IHpvb20gYWRqdXN0bWVudFxuICAgICAgICBjb25zdCBzY3JvbGwgPSBjYWxjdWxhdGVTY3JvbGxDZW50ZXIodGFyZ2V0RWxlbWVudHMsIHRoaXMuc3RhdGUpO1xuICAgICAgICBzY3JvbGxYID0gc2Nyb2xsLnNjcm9sbFg7XG4gICAgICAgIHNjcm9sbFkgPSBzY3JvbGwuc2Nyb2xsWTtcbiAgICAgIH0gLy8gd2hlbiBhbmltYXRpbmcsIHdlIHVzZSBSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgdG8gcHJldmVudCB0aGUgYW5pbWF0aW9uXG4gICAgICAvLyBmcm9tIHNsb3dpbmcgZG93biBvdGhlciBwcm9jZXNzZXNcblxuXG4gICAgICBpZiAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmFuaW1hdGUpIHtcbiAgICAgICAgY29uc3Qgb3JpZ1Njcm9sbFggPSB0aGlzLnN0YXRlLnNjcm9sbFg7XG4gICAgICAgIGNvbnN0IG9yaWdTY3JvbGxZID0gdGhpcy5zdGF0ZS5zY3JvbGxZO1xuICAgICAgICBjb25zdCBvcmlnWm9vbSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgICAgY29uc3QgY2FuY2VsID0gZWFzZVRvVmFsdWVzUkFGKHtcbiAgICAgICAgICBmcm9tVmFsdWVzOiB7XG4gICAgICAgICAgICBzY3JvbGxYOiBvcmlnU2Nyb2xsWCxcbiAgICAgICAgICAgIHNjcm9sbFk6IG9yaWdTY3JvbGxZLFxuICAgICAgICAgICAgem9vbTogb3JpZ1pvb21cbiAgICAgICAgICB9LFxuICAgICAgICAgIHRvVmFsdWVzOiB7XG4gICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgIHpvb206IHpvb20udmFsdWVcbiAgICAgICAgICB9LFxuICAgICAgICAgIGludGVycG9sYXRlVmFsdWU6IChmcm9tLCB0bywgcHJvZ3Jlc3MsIGtleSkgPT4ge1xuICAgICAgICAgICAgLy8gZm9yIHpvb20sIHVzZSBkaWZmZXJlbnQgZWFzaW5nXG4gICAgICAgICAgICBpZiAoa2V5ID09PSBcInpvb21cIikge1xuICAgICAgICAgICAgICByZXR1cm4gZnJvbSAqIE1hdGgucG93KHRvIC8gZnJvbSwgZWFzZU91dChwcm9ncmVzcykpO1xuICAgICAgICAgICAgfSAvLyBoYW5kbGUgdXNpbmcgZGVmYXVsdFxuXG5cbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblN0ZXA6ICh7XG4gICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgIHpvb21cbiAgICAgICAgICB9KSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2Nyb2xsWCxcbiAgICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgICAgem9vbToge1xuICAgICAgICAgICAgICAgIHZhbHVlOiB6b29tXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgb25TdGFydDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogdHJ1ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvbkVuZDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgb25DYW5jZWw6ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIGR1cmF0aW9uOiAoX2IgPSBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZHVyYXRpb24pICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDUwMFxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9ICgpID0+IHtcbiAgICAgICAgICBjYW5jZWwoKTtcbiAgICAgICAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9IG51bGw7XG4gICAgICAgIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFksXG4gICAgICAgICAgem9vbVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICAgIC8qKiB1c2Ugd2hlbiBjaGFuZ2luZyBzY3JvbGxYL3Njcm9sbFkvem9vbSBiYXNlZCBvbiB1c2VyIGludGVyYWN0aW9uICovXG5cblxuICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzID0gc3RhdGUgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICAoX2EgPSB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwodGhpcyk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlKTtcbiAgICB9O1xuXG4gICAgdGhpcy5zZXRUb2FzdCA9IHRvYXN0ID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB0b2FzdFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzdG9yZUZpbGVGcm9tU2hhcmUgPSAoKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB3ZWJTaGFyZVRhcmdldENhY2hlID0geWllbGQgY2FjaGVzLm9wZW4oXCJ3ZWItc2hhcmUtdGFyZ2V0XCIpO1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IHlpZWxkIHdlYlNoYXJlVGFyZ2V0Q2FjaGUubWF0Y2goXCJzaGFyZWQtZmlsZVwiKTtcblxuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICBjb25zdCBibG9iID0geWllbGQgcmVzcG9uc2UuYmxvYigpO1xuICAgICAgICAgIGNvbnN0IGZpbGUgPSBuZXcgRmlsZShbYmxvYl0sIGJsb2IubmFtZSB8fCBcIlwiLCB7XG4gICAgICAgICAgICB0eXBlOiBibG9iLnR5cGVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLmxvYWRGaWxlVG9DYW52YXMoZmlsZSwgbnVsbCk7XG4gICAgICAgICAgeWllbGQgd2ViU2hhcmVUYXJnZXRDYWNoZS5kZWxldGUoXCJzaGFyZWQtZmlsZVwiKTtcbiAgICAgICAgICB3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUobnVsbCwgQVBQX05BTUUsIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICAvKiogYWRkcyBzdXBwbGllZCBmaWxlcyB0byBleGlzdGluZyBmaWxlcyBpbiB0aGUgYXBwU3RhdGUgKi9cblxuXG4gICAgdGhpcy5hZGRGaWxlcyA9IHdpdGhCYXRjaGVkVXBkYXRlcyhmaWxlcyA9PiB7XG4gICAgICBjb25zdCBmaWxlc01hcCA9IGZpbGVzLnJlZHVjZSgoYWNjLCBmaWxlRGF0YSkgPT4ge1xuICAgICAgICBhY2Muc2V0KGZpbGVEYXRhLmlkLCBmaWxlRGF0YSk7XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCBuZXcgTWFwKCkpO1xuICAgICAgdGhpcy5maWxlcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5maWxlcyksIE9iamVjdC5mcm9tRW50cmllcyhmaWxlc01hcCkpO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICBpZiAoaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChlbGVtZW50KSAmJiBmaWxlc01hcC5oYXMoZWxlbWVudC5maWxlSWQpKSB7XG4gICAgICAgICAgdGhpcy5pbWFnZUNhY2hlLmRlbGV0ZShlbGVtZW50LmZpbGVJZCk7XG4gICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICB9KTtcbiAgICB0aGlzLnVwZGF0ZVNjZW5lID0gd2l0aEJhdGNoZWRVcGRhdGVzKHNjZW5lRGF0YSA9PiB7XG4gICAgICBpZiAoc2NlbmVEYXRhLmNvbW1pdFRvSGlzdG9yeSkge1xuICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuYXBwU3RhdGUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShzY2VuZURhdGEuYXBwU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc2NlbmVEYXRhLmVsZW1lbnRzKSB7XG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHNjZW5lRGF0YS5lbGVtZW50cyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuY29sbGFib3JhdG9ycykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBjb2xsYWJvcmF0b3JzOiBzY2VuZURhdGEuY29sbGFib3JhdG9yc1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub25TY2VuZVVwZGF0ZWQgPSAoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHt9KTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHdoZXRoZXIgdGhlIG1lbnUgd2FzIHRvZ2dsZWQgb24gb3Igb2ZmXG4gICAgICovXG5cblxuICAgIHRoaXMudG9nZ2xlU2lkZWJhciA9ICh7XG4gICAgICBuYW1lLFxuICAgICAgdGFiLFxuICAgICAgZm9yY2VcbiAgICB9KSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGxldCBuZXh0TmFtZTtcblxuICAgICAgaWYgKGZvcmNlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbmV4dE5hbWUgPSAoKF9hID0gdGhpcy5zdGF0ZS5vcGVuU2lkZWJhcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm5hbWUpID09PSBuYW1lID8gbnVsbCA6IG5hbWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuZXh0TmFtZSA9IGZvcmNlID8gbmFtZSA6IG51bGw7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBvcGVuU2lkZWJhcjogbmV4dE5hbWUgPyB7XG4gICAgICAgICAgbmFtZTogbmV4dE5hbWUsXG4gICAgICAgICAgdGFiXG4gICAgICAgIH0gOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiAhIW5leHROYW1lO1xuICAgIH07XG5cbiAgICB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbiA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnggPSBldmVudC5jbGllbnRYO1xuICAgICAgdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55ID0gZXZlbnQuY2xpZW50WTtcbiAgICB9KTsgLy8gSW5wdXQgaGFuZGxpbmdcblxuICAgIHRoaXMub25LZXlEb3duID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIG5vcm1hbGl6ZSBgZXZlbnQua2V5YCB3aGVuIENhcHNMb2NrIGlzIHByZXNzZWQgIzIzNzJcbiAgICAgIGlmIChcIlByb3h5XCIgaW4gd2luZG93ICYmICghZXZlbnQuc2hpZnRLZXkgJiYgL15bQS1aXSQvLnRlc3QoZXZlbnQua2V5KSB8fCBldmVudC5zaGlmdEtleSAmJiAvXlthLXpdJC8udGVzdChldmVudC5rZXkpKSkge1xuICAgICAgICBldmVudCA9IG5ldyBQcm94eShldmVudCwge1xuICAgICAgICAgIGdldChldiwgcHJvcCkge1xuICAgICAgICAgICAgY29uc3QgdmFsdWUgPSBldltwcm9wXTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgIC8vIGZpeCBmb3IgUHJveGllcyBoaWphY2tpbmcgYHRoaXNgXG4gICAgICAgICAgICAgIHJldHVybiB2YWx1ZS5iaW5kKGV2KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHByb3AgPT09IFwia2V5XCIgPyAvLyBDYXBzTG9jayBpbnZlcnRzIGNhcGl0YWxpemF0aW9uIGJhc2VkIG9uIFNoaWZ0S2V5LCBzbyBpbnZlcnRcbiAgICAgICAgICAgIC8vIGl0IGJhY2tcbiAgICAgICAgICAgIGV2ZW50LnNoaWZ0S2V5ID8gZXYua2V5LnRvVXBwZXJDYXNlKCkgOiBldi5rZXkudG9Mb3dlckNhc2UoKSA6IHZhbHVlO1xuICAgICAgICAgIH1cblxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIGV2ZW50LmtleS50b0xvd2VyQ2FzZSgpID09PSBLRVlTLlYpIHtcbiAgICAgICAgSVNfUExBSU5fUEFTVEUgPSBldmVudC5zaGlmdEtleTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KElTX1BMQUlOX1BBU1RFX1RJTUVSKTsgLy8gcmVzZXQgKDEwMG1zIHRvIGJlIHNhZmUgdGhhdCB3ZSBpdCBydW5zIGFmdGVyIHRoZSBlbnN1aW5nXG4gICAgICAgIC8vIHBhc3RlIGV2ZW50KS4gVGhvdWdoLCB0ZWNobmljYWxseSB1bm5lY2Vzc2FyeSB0byByZXNldCBzaW5jZSB3ZVxuICAgICAgICAvLyAocmUpc2V0IHRoZSBmbGFnIGJlZm9yZSBlYWNoIHBhc3RlIGV2ZW50LlxuXG4gICAgICAgIElTX1BMQUlOX1BBU1RFX1RJTUVSID0gd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG4gICAgICAgIH0sIDEwMCk7XG4gICAgICB9IC8vIHByZXZlbnQgYnJvd3NlciB6b29tIGluIGlucHV0IGZpZWxkc1xuXG5cbiAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpKSB7XG4gICAgICAgIGlmIChldmVudC5jb2RlID09PSBDT0RFUy5NSU5VUyB8fCBldmVudC5jb2RlID09PSBDT0RFUy5FUVVBTCkge1xuICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IC8vIGJhaWwgaWZcblxuXG4gICAgICBpZiAoIC8vIGluc2lkZSBhbiBpbnB1dFxuICAgICAgaXNXcml0YWJsZUVsZW1lbnQoZXZlbnQudGFyZ2V0KSAmJiAvLyB1bmxlc3MgcHJlc3NpbmcgZXNjYXBlIChmaW5hbGl6ZSBhY3Rpb24pXG4gICAgICBldmVudC5rZXkgIT09IEtFWVMuRVNDQVBFIHx8IC8vIG9yIHVubGVzcyB1c2luZyBhcnJvd3MgKHRvIG1vdmUgYmV0d2VlbiBidXR0b25zKVxuICAgICAgaXNBcnJvd0tleShldmVudC5rZXkpICYmIGlzSW5wdXRMaWtlKGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlFVRVNUSU9OX01BUkspIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgb3BlbkRpYWxvZzogXCJoZWxwXCJcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5LnRvTG93ZXJDYXNlKCkgPT09IEtFWVMuRSAmJiBldmVudC5zaGlmdEtleSAmJiBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBvcGVuRGlhbG9nOiBcImltYWdlRXhwb3J0XCJcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX1VQIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX0RPV04pIHtcbiAgICAgICAgbGV0IG9mZnNldCA9IChldmVudC5zaGlmdEtleSA/IHRoaXMuc3RhdGUud2lkdGggOiB0aGlzLnN0YXRlLmhlaWdodCkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX0RPV04pIHtcbiAgICAgICAgICBvZmZzZXQgPSAtb2Zmc2V0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LnNoaWZ0S2V5KSB7XG4gICAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gKHtcbiAgICAgICAgICAgIHNjcm9sbFg6IHN0YXRlLnNjcm9sbFggKyBvZmZzZXRcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gKHtcbiAgICAgICAgICAgIHNjcm9sbFk6IHN0YXRlLnNjcm9sbFkgKyBvZmZzZXRcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuYWN0aW9uTWFuYWdlci5oYW5kbGVLZXlEb3duKGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiB0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0Fycm93S2V5KGV2ZW50LmtleSkpIHtcbiAgICAgICAgY29uc3Qgc3RlcCA9IHRoaXMuc3RhdGUuZ3JpZFNpemUgJiYgKGV2ZW50LnNoaWZ0S2V5ID8gRUxFTUVOVF9UUkFOU0xBVEVfQU1PVU5UIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSkgfHwgKGV2ZW50LnNoaWZ0S2V5ID8gRUxFTUVOVF9TSElGVF9UUkFOU0xBVEVfQU1PVU5UIDogRUxFTUVOVF9UUkFOU0xBVEVfQU1PVU5UKTtcbiAgICAgICAgbGV0IG9mZnNldFggPSAwO1xuICAgICAgICBsZXQgb2Zmc2V0WSA9IDA7XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19MRUZUKSB7XG4gICAgICAgICAgb2Zmc2V0WCA9IC1zdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19SSUdIVCkge1xuICAgICAgICAgIG9mZnNldFggPSBzdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19VUCkge1xuICAgICAgICAgIG9mZnNldFkgPSAtc3RlcDtcbiAgICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkgPT09IEtFWVMuQVJST1dfRE9XTikge1xuICAgICAgICAgIG9mZnNldFkgPSBzdGVwO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyxcbiAgICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZSxcbiAgICAgICAgICBpbmNsdWRlRWxlbWVudHNJbkZyYW1lczogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgeDogZWxlbWVudC54ICsgb2Zmc2V0WCxcbiAgICAgICAgICAgIHk6IGVsZW1lbnQueSArIG9mZnNldFlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB1cGRhdGVCb3VuZEVsZW1lbnRzKGVsZW1lbnQsIHtcbiAgICAgICAgICAgIHNpbXVsdGFuZW91c2x5VXBkYXRlZDogc2VsZWN0ZWRFbGVtZW50c1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkgPT09IEtFWVMuRU5URVIpIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnQgPSBzZWxlY3RlZEVsZW1lbnRzWzBdO1xuXG4gICAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgICAgICBpZiAoaXNMaW5lYXJFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkICE9PSBzZWxlY3RlZEVsZW1lbnRzWzBdLmlkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKHNlbGVjdGVkRWxlbWVudCwgdGhpcy5zY2VuZSlcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSBpZiAoaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnQpIHx8IGlzVmFsaWRUZXh0Q29udGFpbmVyKHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgIGxldCBjb250YWluZXI7XG5cbiAgICAgICAgICAgIGlmICghaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnQpKSB7XG4gICAgICAgICAgICAgIGNvbnRhaW5lciA9IHNlbGVjdGVkRWxlbWVudDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbWlkUG9pbnQgPSBnZXRDb250YWluZXJDZW50ZXIoc2VsZWN0ZWRFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICAgIGNvbnN0IHNjZW5lWCA9IG1pZFBvaW50Lng7XG4gICAgICAgICAgICBjb25zdCBzY2VuZVkgPSBtaWRQb2ludC55O1xuICAgICAgICAgICAgdGhpcy5zdGFydFRleHRFZGl0aW5nKHtcbiAgICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgICAgIGNvbnRhaW5lclxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaXNGcmFtZUVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogc2VsZWN0ZWRFbGVtZW50LmlkXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoIWV2ZW50LmN0cmxLZXkgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQubWV0YUtleSAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCA9PT0gbnVsbCkge1xuICAgICAgICBjb25zdCBzaGFwZSA9IGZpbmRTaGFwZUJ5S2V5KGV2ZW50LmtleSk7XG5cbiAgICAgICAgaWYgKHNoYXBlKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBzaGFwZSkge1xuICAgICAgICAgICAgdHJhY2tFdmVudChcInRvb2xiYXJcIiwgc2hhcGUsIGBrZXlib2FyZCAoJHt0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGUgPyBcIm1vYmlsZVwiIDogXCJkZXNrdG9wXCJ9KWApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgICAgICB0eXBlOiBzaGFwZVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5RKSB7XG4gICAgICAgICAgdGhpcy50b2dnbGVMb2NrKFwia2V5Ym9hcmRcIik7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5TUEFDRSAmJiBnZXN0dXJlLnBvaW50ZXJzLnNpemUgPT09IDApIHtcbiAgICAgICAgaXNIb2xkaW5nU3BhY2UgPSB0cnVlO1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9XG5cbiAgICAgIGlmICgoZXZlbnQua2V5ID09PSBLRVlTLkcgfHwgZXZlbnQua2V5ID09PSBLRVlTLlMpICYmICFldmVudC5hbHRLZXkgJiYgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiICYmICFzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuRyAmJiAoaGFzQmFja2dyb3VuZCh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkgfHwgc2VsZWN0ZWRFbGVtZW50cy5zb21lKGVsZW1lbnQgPT4gaGFzQmFja2dyb3VuZChlbGVtZW50LnR5cGUpKSkpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIG9wZW5Qb3B1cDogXCJlbGVtZW50QmFja2dyb3VuZFwiXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlMpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIG9wZW5Qb3B1cDogXCJlbGVtZW50U3Ryb2tlXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLksgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgICB0aGlzLnNldEFjdGl2ZVRvb2woe1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgICAgICB0eXBlOiBcImxhc2VyXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIChldmVudC5rZXkgPT09IEtFWVMuQkFDS1NQQUNFIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5ERUxFVEUpKSB7XG4gICAgICAgIGpvdGFpU3RvcmUuc2V0KGFjdGl2ZUNvbmZpcm1EaWFsb2dBdG9tLCBcImNsZWFyQ2FudmFzXCIpO1xuICAgICAgfSAvLyBleWUgZHJvcHBlclxuICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gICAgICBjb25zdCBsb3dlckNhc2VkID0gZXZlbnQua2V5LnRvTG9jYWxlTG93ZXJDYXNlKCk7XG4gICAgICBjb25zdCBpc1BpY2tpbmdTdHJva2UgPSBsb3dlckNhc2VkID09PSBLRVlTLlMgJiYgZXZlbnQuc2hpZnRLZXk7XG4gICAgICBjb25zdCBpc1BpY2tpbmdCYWNrZ3JvdW5kID0gZXZlbnQua2V5ID09PSBLRVlTLkkgfHwgbG93ZXJDYXNlZCA9PT0gS0VZUy5HICYmIGV2ZW50LnNoaWZ0S2V5O1xuXG4gICAgICBpZiAoaXNQaWNraW5nU3Ryb2tlIHx8IGlzUGlja2luZ0JhY2tncm91bmQpIHtcbiAgICAgICAgdGhpcy5vcGVuRXllRHJvcHBlcih7XG4gICAgICAgICAgdHlwZTogaXNQaWNraW5nU3Ryb2tlID8gXCJzdHJva2VcIiA6IFwiYmFja2dyb3VuZFwiXG4gICAgICAgIH0pO1xuICAgICAgfSAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgfSk7XG4gICAgdGhpcy5vbldoZWVsID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIHByZXZlbnQgYnJvd3NlciBwaW5jaCB6b29tIG9uIERPTSBlbGVtZW50c1xuICAgICAgaWYgKCEoZXZlbnQudGFyZ2V0IGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQpICYmIGV2ZW50LmN0cmxLZXkpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLm9uS2V5VXAgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5TUEFDRSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUuaXNCaW5kaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNBcnJvd0tleShldmVudC5rZXkpKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgPyBiaW5kT3JVbmJpbmRTZWxlY3RlZEVsZW1lbnRzKHNlbGVjdGVkRWxlbWVudHMpIDogdW5iaW5kTGluZWFyRWxlbWVudHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuc2V0QWN0aXZlVG9vbCA9IHRvb2wgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBuZXh0QWN0aXZlVG9vbCA9IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwgdG9vbCk7XG5cbiAgICAgIGlmIChuZXh0QWN0aXZlVG9vbC50eXBlID09PSBcImhhbmRcIikge1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICB9IGVsc2UgaWYgKCFpc0hvbGRpbmdTcGFjZSkge1xuICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzVG9vbEljb24oZG9jdW1lbnQuYWN0aXZlRWxlbWVudCkpIHtcbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzTGluZWFyRWxlbWVudFR5cGUobmV4dEFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiKSB7XG4gICAgICAgIHRoaXMub25JbWFnZUFjdGlvbih7XG4gICAgICAgICAgaW5zZXJ0T25DYW52YXNEaXJlY3RseTogKF9hID0gdG9vbC50eXBlID09PSBcImltYWdlXCIgJiYgdG9vbC5pbnNlcnRPbkNhbnZhc0RpcmVjdGx5KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICBjb25zdCBjb21tb25SZXNldHMgPSB7XG4gICAgICAgICAgc25hcExpbmVzOiBwcmV2U3RhdGUuc25hcExpbmVzLmxlbmd0aCA/IFtdIDogcHJldlN0YXRlLnNuYXBMaW5lcyxcbiAgICAgICAgICBvcmlnaW5TbmFwT2Zmc2V0OiBudWxsLFxuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2wsXG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCBwcmV2U3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHByZXZTdGF0ZSksXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIG11bHRpRWxlbWVudDogbnVsbFxuICAgICAgICAgIH0pLCBjb21tb25SZXNldHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUpLCB7XG4gICAgICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2xcbiAgICAgICAgfSksIGNvbW1vblJlc2V0cyk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5zZXRPcGVuRGlhbG9nID0gZGlhbG9nVHlwZSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgb3BlbkRpYWxvZzogZGlhbG9nVHlwZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc2V0Q3Vyc29yID0gY3Vyc29yID0+IHtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBjdXJzb3IpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0Q3Vyc29yID0gKCkgPT4ge1xuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiByZXR1cm5zIHdoZXRoZXIgdXNlciBpcyBtYWtpbmcgYSBnZXN0dXJlIHdpdGggPj0gMiBmaW5nZXJzIChwb2ludHMpXG4gICAgICogb24gbyB0b3VjaCBzY3JlZW4gKG5vdCBvbiBhIHRyYWNrcGFkKS4gQ3VycmVudGx5IG9ubHkgcmVsYXRlcyB0byBEYXJ3aW5cbiAgICAgKiAoaU9TL2lQYWRPUyxNYWNPUyksIGJ1dCBtYXkgd29yayBvbiBvdGhlciBkZXZpY2VzIGluIHRoZSBmdXR1cmUgaWZcbiAgICAgKiBHZXN0dXJlRXZlbnQgaXMgc3RhbmRhcmRpemVkLlxuICAgICAqL1xuXG5cbiAgICB0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSA9ICgpID0+IHtcbiAgICAgIC8vIHdlIGRvbid0IHdhbnQgdG8gZGVzZWxlY3Qgd2hlbiB1c2luZyB0cmFja3BhZCwgYW5kIG11bHRpLXBvaW50IGdlc3R1cmVzXG4gICAgICAvLyBvbmx5IHdvcmsgb24gdG91Y2ggc2NyZWVucywgc28gY2hlY2tpbmcgZm9yID49IHBvaW50ZXJzIG1lYW5zIHdlJ3JlIG9uIGFcbiAgICAgIC8vIHRvdWNoc2NyZWVuXG4gICAgICByZXR1cm4gZ2VzdHVyZS5wb2ludGVycy5zaXplID49IDI7XG4gICAgfTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuXG4gICAgdGhpcy5vbkdlc3R1cmVTdGFydCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyB3ZSBvbmx5IHdhbnQgdG8gZGVzZWxlY3Qgb24gdG91Y2ggc2NyZWVucyBiZWNhdXNlIHVzZXIgbWF5IGhhdmUgc2VsZWN0ZWRcbiAgICAgIC8vIGVsZW1lbnRzIGJ5IG1pc3Rha2Ugd2hpbGUgem9vbWluZ1xuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICB9KTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuICAgIHRoaXMub25HZXN0dXJlQ2hhbmdlID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIG9uR2VzdHVyZUNoYW5nZSBvbmx5IGhhcyB6b29tIGZhY3RvciBidXQgbm90IHRoZSBjZW50ZXIuXG4gICAgICAvLyBJZiB3ZSdyZSBvbiBpUGFkIG9yIGlQaG9uZSwgdGhlbiB3ZSByZWNvZ25pemUgbXVsdGktdG91Y2ggYW5kIHdpbGxcbiAgICAgIC8vIHpvb20gaW4gYXQgdGhlIHJpZ2h0IGxvY2F0aW9uIGluIHRoZSB0b3VjaG1vdmUgaGFuZGxlclxuICAgICAgLy8gKGhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlKS5cbiAgICAgIC8vXG4gICAgICAvLyBPbiBNYWNib29rIHRyYWNrcGFkLCB3ZSBkb24ndCBoYXZlIHRob3NlIGV2ZW50cyBzbyB3aWxsIHpvb20gaW4gYXQgdGhlXG4gICAgICAvLyBjdXJyZW50IGxvY2F0aW9uIGluc3RlYWQuXG4gICAgICAvL1xuICAgICAgLy8gQXMgc3VjaCwgYmFpbCBmcm9tIHRoaXMgaGFuZGxlciBvbiB0b3VjaCBkZXZpY2VzLlxuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGluaXRpYWxTY2FsZSA9IGdlc3R1cmUuaW5pdGlhbFNjYWxlO1xuXG4gICAgICBpZiAoaW5pdGlhbFNjYWxlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgICB2aWV3cG9ydFg6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCxcbiAgICAgICAgICB2aWV3cG9ydFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSxcbiAgICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20oaW5pdGlhbFNjYWxlICogZXZlbnQuc2NhbGUpXG4gICAgICAgIH0sIHN0YXRlKSkpO1xuICAgICAgfVxuICAgIH0pOyAvLyBmaXJlcyBvbmx5IG9uIFNhZmFyaVxuXG4gICAgdGhpcy5vbkdlc3R1cmVFbmQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gcmVzZWxlY3QgZWxlbWVudHMgb25seSBvbiB0b3VjaCBzY3JlZW5zIChzZWUgb25HZXN0dXJlU3RhcnQpXG5cbiAgICAgIGlmICh0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSgpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB7fSxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHRoaXMuc3RhdGUucHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHMsIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IG51bGw7XG4gICAgfSk7XG5cbiAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZLFxuICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXIgPSB0cnVlLFxuICAgICAgY29udGFpbmVyXG4gICAgfSkgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgbGV0IHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IGZhbHNlO1xuICAgICAgbGV0IHBhcmVudENlbnRlclBvc2l0aW9uID0gaW5zZXJ0QXRQYXJlbnRDZW50ZXIgJiYgdGhpcy5nZXRUZXh0V3lzaXd5Z1NuYXBwZWRUb0NlbnRlclBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZLCB0aGlzLnN0YXRlLCBjb250YWluZXIpO1xuXG4gICAgICBpZiAoY29udGFpbmVyICYmIHBhcmVudENlbnRlclBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lciA9IGdldEJvdW5kVGV4dEVsZW1lbnQoY29udGFpbmVyKTtcblxuICAgICAgICBpZiAoIWJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lcikge1xuICAgICAgICAgIHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgbGV0IGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBudWxsO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIGlmIChpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHNlbGVjdGVkRWxlbWVudHNbMF07XG4gICAgICAgIH0gZWxzZSBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IGdldEJvdW5kVGV4dEVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZm9udEZhbWlseSA9IChleGlzdGluZ1RleHRFbGVtZW50ID09PSBudWxsIHx8IGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nVGV4dEVsZW1lbnQuZm9udEZhbWlseSkgfHwgdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRGYW1pbHk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gKGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IG51bGwgfHwgZXhpc3RpbmdUZXh0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhpc3RpbmdUZXh0RWxlbWVudC5saW5lSGVpZ2h0KSB8fCBnZXREZWZhdWx0TGluZUhlaWdodChmb250RmFtaWx5KTtcbiAgICAgIGNvbnN0IGZvbnRTaXplID0gdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRTaXplO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyICYmIGNvbnRhaW5lciAmJiAhaXNBcnJvd0VsZW1lbnQoY29udGFpbmVyKSkge1xuICAgICAgICBjb25zdCBmb250U3RyaW5nID0ge1xuICAgICAgICAgIGZvbnRTaXplLFxuICAgICAgICAgIGZvbnRGYW1pbHlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgbWluV2lkdGggPSBnZXRBcHByb3hNaW5MaW5lV2lkdGgoZ2V0Rm9udFN0cmluZyhmb250U3RyaW5nKSwgbGluZUhlaWdodCk7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IGdldEFwcHJveE1pbkxpbmVIZWlnaHQoZm9udFNpemUsIGxpbmVIZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdIZWlnaHQgPSBNYXRoLm1heChjb250YWluZXIuaGVpZ2h0LCBtaW5IZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdXaWR0aCA9IE1hdGgubWF4KGNvbnRhaW5lci53aWR0aCwgbWluV2lkdGgpO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGNvbnRhaW5lciwge1xuICAgICAgICAgIGhlaWdodDogbmV3SGVpZ2h0LFxuICAgICAgICAgIHdpZHRoOiBuZXdXaWR0aFxuICAgICAgICB9KTtcbiAgICAgICAgc2NlbmVYID0gY29udGFpbmVyLnggKyBuZXdXaWR0aCAvIDI7XG4gICAgICAgIHNjZW5lWSA9IGNvbnRhaW5lci55ICsgbmV3SGVpZ2h0IC8gMjtcblxuICAgICAgICBpZiAocGFyZW50Q2VudGVyUG9zaXRpb24pIHtcbiAgICAgICAgICBwYXJlbnRDZW50ZXJQb3NpdGlvbiA9IHRoaXMuZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwgdGhpcy5zdGF0ZSwgY29udGFpbmVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBleGlzdGluZ1RleHRFbGVtZW50ID8gZXhpc3RpbmdUZXh0RWxlbWVudCA6IG5ld1RleHRFbGVtZW50KHtcbiAgICAgICAgeDogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWCA6IHNjZW5lWCxcbiAgICAgICAgeTogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWSA6IHNjZW5lWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIHRleHQ6IFwiXCIsXG4gICAgICAgIGZvbnRTaXplLFxuICAgICAgICBmb250RmFtaWx5LFxuICAgICAgICB0ZXh0QWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gXCJjZW50ZXJcIiA6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1UZXh0QWxpZ24sXG4gICAgICAgIHZlcnRpY2FsQWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gVkVSVElDQUxfQUxJR04uTUlERExFIDogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgICAgY29udGFpbmVySWQ6IHNob3VsZEJpbmRUb0NvbnRhaW5lciA/IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5pZCA6IHVuZGVmaW5lZCxcbiAgICAgICAgZ3JvdXBJZHM6IChfYSA9IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5ncm91cElkcykgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogW10sXG4gICAgICAgIGxpbmVIZWlnaHQsXG4gICAgICAgIGFuZ2xlOiAoX2IgPSBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuYW5nbGUpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDAsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfSk7XG5cbiAgICAgIGlmICghZXhpc3RpbmdUZXh0RWxlbWVudCAmJiBzaG91bGRCaW5kVG9Db250YWluZXIgJiYgY29udGFpbmVyKSB7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoY29udGFpbmVyLCB7XG4gICAgICAgICAgYm91bmRFbGVtZW50czogKGNvbnRhaW5lci5ib3VuZEVsZW1lbnRzIHx8IFtdKS5jb25jYXQoe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGNvbnRhaW5lciAmJiBzaG91bGRCaW5kVG9Db250YWluZXIpIHtcbiAgICAgICAgICBjb25zdCBjb250YWluZXJJbmRleCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudEluZGV4KGNvbnRhaW5lci5pZCk7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50QXRJbmRleChlbGVtZW50LCBjb250YWluZXJJbmRleCArIDEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuICAgICAgdGhpcy5oYW5kbGVUZXh0V3lzaXd5ZyhlbGVtZW50LCB7XG4gICAgICAgIGlzRXhpc3RpbmdFbGVtZW50OiAhIWV4aXN0aW5nVGV4dEVsZW1lbnRcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrID0gZXZlbnQgPT4ge1xuICAgICAgLy8gY2FzZTogZG91YmxlLWNsaWNraW5nIHdpdGggYXJyb3cvbGluZSB0b29sIHNlbGVjdGVkIHdvdWxkIGJvdGggY3JlYXRlXG4gICAgICAvLyB0ZXh0IGFuZCBlbnRlciBtdWx0aUVsZW1lbnQgbW9kZVxuICAgICAgaWYgKHRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gd2Ugc2hvdWxkIG9ubHkgYmUgYWJsZSB0byBkb3VibGUgY2xpY2sgd2hlbiBtb2RlIGlzIHNlbGVjdGlvblxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkpIHtcbiAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICghdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCAhPT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3Ioc2VsZWN0ZWRFbGVtZW50c1swXSwgdGhpcy5zY2VuZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCA9PT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgIGxldCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkR3JvdXBJZHMgPSBnZXRTZWxlY3RlZEdyb3VwSWRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRHcm91cElkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRHcm91cElkID0gaGl0RWxlbWVudCAmJiBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50KGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUuc2VsZWN0ZWRHcm91cElkcyk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkR3JvdXBJZCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogc2VsZWN0ZWRHcm91cElkLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICBlbGVtZW50OiBoaXRFbGVtZW50LFxuICAgICAgICAgICAgICBzdGF0ZTogXCJhY3RpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgc2NlbmVYLCBzY2VuZVkpO1xuXG4gICAgICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgICAgICBpZiAoaGFzQm91bmRUZXh0RWxlbWVudChjb250YWluZXIpIHx8ICFpc1RyYW5zcGFyZW50KGNvbnRhaW5lci5iYWNrZ3JvdW5kQ29sb3IpIHx8IGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94KGNvbnRhaW5lciwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgW3NjZW5lWCwgc2NlbmVZXSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG1pZFBvaW50ID0gZ2V0Q29udGFpbmVyQ2VudGVyKGNvbnRhaW5lciwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBzY2VuZVggPSBtaWRQb2ludC54O1xuICAgICAgICAgICAgc2NlbmVZID0gbWlkUG9pbnQueTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXI6ICFldmVudC5hbHRLZXksXG4gICAgICAgICAgY29udGFpbmVyXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbiA9IChzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpID0+IHtcbiAgICAgIC8vIFJldmVyc2luZyBzbyB3ZSB0cmF2ZXJzZSB0aGUgZWxlbWVudHMgaW4gZGVjcmVhc2luZyBvcmRlclxuICAgICAgLy8gb2Ygei1pbmRleFxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLnNsaWNlKCkucmV2ZXJzZSgpO1xuICAgICAgbGV0IGhpdEVsZW1lbnRJbmRleCA9IEluZmluaXR5O1xuICAgICAgcmV0dXJuIGVsZW1lbnRzLmZpbmQoKGVsZW1lbnQsIGluZGV4KSA9PiB7XG4gICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGVsZW1lbnQuaWQgPT09IGhpdEVsZW1lbnQuaWQpIHtcbiAgICAgICAgICBoaXRFbGVtZW50SW5kZXggPSBpbmRleDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGVtZW50LmxpbmsgJiYgaW5kZXggPD0gaGl0RWxlbWVudEluZGV4ICYmIGlzUG9pbnRIaXR0aW5nTGluayhlbGVtZW50LCB0aGlzLnN0YXRlLCBbc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55XSwgdGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlKTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnJlZGlyZWN0VG9MaW5rID0gKGV2ZW50LCBpc1RvdWNoU2NyZWVuKSA9PiB7XG4gICAgICBjb25zdCBkcmFnZ2VkRGlzdGFuY2UgPSBkaXN0YW5jZTJkKHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQuY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudC5jbGllbnRZLCB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC5jbGllbnRYLCB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC5jbGllbnRZKTtcblxuICAgICAgaWYgKCF0aGlzLmhpdExpbmtFbGVtZW50IHx8IC8vIEZvciB0b3VjaCBzY3JlZW4gYWxsb3cgZHJhZ2dpbmcgdGhyZXNob2xkIGVsc2Ugc3RyaWN0IGNoZWNrXG4gICAgICBpc1RvdWNoU2NyZWVuICYmIGRyYWdnZWREaXN0YW5jZSA+IERSQUdHSU5HX1RIUkVTSE9MRCB8fCAhaXNUb3VjaFNjcmVlbiAmJiBkcmFnZ2VkRGlzdGFuY2UgIT09IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBsYXN0UG9pbnRlckRvd25Db29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHModGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlckRvd25IaXR0aW5nTGlua0ljb24gPSBpc1BvaW50SGl0dGluZ0xpbmsodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSwgW2xhc3RQb2ludGVyRG93bkNvb3Jkcy54LCBsYXN0UG9pbnRlckRvd25Db29yZHMueV0sIHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGxhc3RQb2ludGVyVXBIaXR0aW5nTGlua0ljb24gPSBpc1BvaW50SGl0dGluZ0xpbmsodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSwgW2xhc3RQb2ludGVyVXBDb29yZHMueCwgbGFzdFBvaW50ZXJVcENvb3Jkcy55XSwgdGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlKTtcblxuICAgICAgaWYgKGxhc3RQb2ludGVyRG93bkhpdHRpbmdMaW5rSWNvbiAmJiBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uKSB7XG4gICAgICAgIGxldCB1cmwgPSB0aGlzLmhpdExpbmtFbGVtZW50Lmxpbms7XG5cbiAgICAgICAgaWYgKHVybCkge1xuICAgICAgICAgIHVybCA9IG5vcm1hbGl6ZUxpbmsodXJsKTtcbiAgICAgICAgICBsZXQgY3VzdG9tRXZlbnQ7XG5cbiAgICAgICAgICBpZiAodGhpcy5wcm9wcy5vbkxpbmtPcGVuKSB7XG4gICAgICAgICAgICBjdXN0b21FdmVudCA9IHdyYXBFdmVudChFVkVOVC5FWENBTElEUkFXX0xJTkssIGV2ZW50Lm5hdGl2ZUV2ZW50KTtcbiAgICAgICAgICAgIHRoaXMucHJvcHMub25MaW5rT3BlbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuaGl0TGlua0VsZW1lbnQpLCB7XG4gICAgICAgICAgICAgIGxpbms6IHVybFxuICAgICAgICAgICAgfSksIGN1c3RvbUV2ZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIShjdXN0b21FdmVudCA9PT0gbnVsbCB8fCBjdXN0b21FdmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogY3VzdG9tRXZlbnQuZGVmYXVsdFByZXZlbnRlZCkpIHtcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldCA9IGlzTG9jYWxMaW5rKHVybCkgPyBcIl9zZWxmXCIgOiBcIl9ibGFua1wiO1xuICAgICAgICAgICAgY29uc3QgbmV3V2luZG93ID0gd2luZG93Lm9wZW4odW5kZWZpbmVkLCB0YXJnZXQpOyAvLyBodHRwczovL21hdGhpYXNieW5lbnMuZ2l0aHViLmlvL3JlbC1ub29wZW5lci9cblxuICAgICAgICAgICAgaWYgKG5ld1dpbmRvdykge1xuICAgICAgICAgICAgICBuZXdXaW5kb3cub3BlbmVyID0gbnVsbDtcbiAgICAgICAgICAgICAgbmV3V2luZG93LmxvY2F0aW9uID0gdXJsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzID0gc2NlbmVDb29yZHMgPT4ge1xuICAgICAgY29uc3QgZnJhbWVzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRnJhbWVzKCkuZmlsdGVyKGZyYW1lID0+IGlzQ3Vyc29ySW5GcmFtZShzY2VuZUNvb3JkcywgZnJhbWUpKTtcbiAgICAgIHJldHVybiBmcmFtZXMubGVuZ3RoID8gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXSA6IG51bGw7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIHRoaXMuc3RhdGUuY3Vyc29yQnV0dG9uKTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuaGFzKGV2ZW50LnBvaW50ZXJJZCkpIHtcbiAgICAgICAgZ2VzdHVyZS5wb2ludGVycy5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICAgICAgeDogZXZlbnQuY2xpZW50WCxcbiAgICAgICAgICB5OiBldmVudC5jbGllbnRZXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbml0aWFsU2NhbGUgPSBnZXN0dXJlLmluaXRpYWxTY2FsZTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMiAmJiBnZXN0dXJlLmxhc3RDZW50ZXIgJiYgaW5pdGlhbFNjYWxlICYmIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlKSB7XG4gICAgICAgIGNvbnN0IGNlbnRlciA9IGdldENlbnRlcihnZXN0dXJlLnBvaW50ZXJzKTtcbiAgICAgICAgY29uc3QgZGVsdGFYID0gY2VudGVyLnggLSBnZXN0dXJlLmxhc3RDZW50ZXIueDtcbiAgICAgICAgY29uc3QgZGVsdGFZID0gY2VudGVyLnkgLSBnZXN0dXJlLmxhc3RDZW50ZXIueTtcbiAgICAgICAgZ2VzdHVyZS5sYXN0Q2VudGVyID0gY2VudGVyO1xuICAgICAgICBjb25zdCBkaXN0YW5jZSA9IGdldERpc3RhbmNlKEFycmF5LmZyb20oZ2VzdHVyZS5wb2ludGVycy52YWx1ZXMoKSkpO1xuICAgICAgICBjb25zdCBzY2FsZUZhY3RvciA9IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIgJiYgdGhpcy5zdGF0ZS5wZW5Nb2RlID8gMSA6IGRpc3RhbmNlIC8gZ2VzdHVyZS5pbml0aWFsRGlzdGFuY2U7XG4gICAgICAgIGNvbnN0IG5leHRab29tID0gc2NhbGVGYWN0b3IgPyBnZXROb3JtYWxpemVkWm9vbShpbml0aWFsU2NhbGUgKiBzY2FsZUZhY3RvcikgOiB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIGNvbnN0IHpvb21TdGF0ZSA9IGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgICB2aWV3cG9ydFg6IGNlbnRlci54LFxuICAgICAgICAgICAgdmlld3BvcnRZOiBjZW50ZXIueSxcbiAgICAgICAgICAgIG5leHRab29tXG4gICAgICAgICAgfSwgc3RhdGUpO1xuICAgICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgICAgIHpvb206IHpvb21TdGF0ZS56b29tLFxuICAgICAgICAgICAgc2Nyb2xsWDogem9vbVN0YXRlLnNjcm9sbFggKyBkZWx0YVggLyBuZXh0Wm9vbSxcbiAgICAgICAgICAgIHNjcm9sbFk6IHpvb21TdGF0ZS5zY3JvbGxZICsgZGVsdGFZIC8gbmV4dFpvb20sXG4gICAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlID0gZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNIb2xkaW5nU3BhY2UgfHwgaXNQYW5uaW5nIHx8IGlzRHJhZ2dpbmdTY3JvbGxCYXIgfHwgaXNIYW5kVG9vbEFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzID0gaXNPdmVyU2Nyb2xsQmFycyhjdXJyZW50U2Nyb2xsQmFycywgZXZlbnQuY2xpZW50WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgZXZlbnQuY2xpZW50WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wKTtcbiAgICAgIGNvbnN0IGlzT3ZlclNjcm9sbEJhciA9IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzLmlzT3ZlckVpdGhlcjtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lUG9pbnRlclgsXG4gICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgIH0gPSBzY2VuZVBvaW50ZXI7XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgaXNBY3RpdmVUb29sTm9uTGluZWFyU25hcHBhYmxlKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgb3JpZ2luT2Zmc2V0LFxuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9ID0gZ2V0U25hcExpbmVzQXRQb2ludGVyKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgICAgfSwgZXZlbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXMsXG4gICAgICAgICAgb3JpZ2luU25hcE9mZnNldDogb3JpZ2luT2Zmc2V0XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICBjb25zdCBlZGl0aW5nTGluZWFyRWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlck1vdmUoZXZlbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclksIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChlZGl0aW5nTGluZWFyRWxlbWVudCAmJiBlZGl0aW5nTGluZWFyRWxlbWVudCAhPT0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIC8vIFNpbmNlIHdlIGFyZSByZWFkaW5nIGZyb20gcHJldmlvdXMgc3RhdGUgd2hpY2ggaXMgbm90IHBvc3NpYmxlIHdpdGhcbiAgICAgICAgICAvLyBhdXRvbWF0aWMgYmF0Y2hpbmcgaW4gUmVhY3QgMTggaGVuY2UgdXNpbmcgZmx1c2ggc3luYyB0byBzeW5jaHJvbm91c2x5XG4gICAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZS4gQ2hlY2sgaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzU1MDggZm9yIG1vcmUgZGV0YWlscy5cbiAgICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgoZWRpdGluZ0xpbmVhckVsZW1lbnQgPT09IG51bGwgfHwgZWRpdGluZ0xpbmVhckVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVkaXRpbmdMaW5lYXJFbGVtZW50Lmxhc3RVbmNvbW1pdHRlZFBvaW50KSAhPSBudWxsKSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3Ioc2NlbmVQb2ludGVyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBjYXVzZXMgc3RhY2sgb3ZlcmZsb3cgaWYgbm90IHN5bmNcbiAgICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnRUeXBlKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSkge1xuICAgICAgICAvLyBIb3ZlcmluZyB3aXRoIGEgc2VsZWN0ZWQgdG9vbCBvciBjcmVhdGluZyBuZXcgbGluZWFyIGVsZW1lbnQgdmlhIGNsaWNrXG4gICAgICAgIC8vIGFuZCBwb2ludFxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50XG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuXG4gICAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhkcmFnZ2luZ0VsZW1lbnQsIFtzY2VuZVBvaW50ZXJdLCB0aGlzLnN0YXRlLnN0YXJ0Qm91bmRFbGVtZW50KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdBdEN1cnNvcihzY2VuZVBvaW50ZXIpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgbXVsdGlFbGVtZW50XG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogcngsXG4gICAgICAgICAgeTogcnlcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHBvaW50cyxcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnRcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDtcbiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXTtcbiAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKGxhc3RQb2ludCA9PT0gbGFzdENvbW1pdHRlZFBvaW50KSB7XG4gICAgICAgICAgLy8gaWYgd2UgaGF2ZW4ndCB5ZXQgY3JlYXRlZCBhIHRlbXAgcG9pbnQgYW5kIHdlJ3JlIGJleW9uZCBjb21taXQtem9uZVxuICAgICAgICAgIC8vIHRocmVzaG9sZCwgYWRkIGEgcG9pbnRcbiAgICAgICAgICBpZiAoZGlzdGFuY2UyZChzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeSwgbGFzdFBvaW50WzBdLCBsYXN0UG9pbnRbMV0pID49IExJTkVfQ09ORklSTV9USFJFU0hPTEQpIHtcbiAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW3NjZW5lUG9pbnRlclggLSByeCwgc2NlbmVQb2ludGVyWSAtIHJ5XV1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuUE9JTlRFUik7IC8vIGluIHRoaXMgYnJhbmNoLCB3ZSdyZSBpbnNpZGUgdGhlIGNvbW1pdCB6b25lLCBhbmQgbm8gdW5jb21taXR0ZWRcbiAgICAgICAgICAgIC8vIHBvaW50IGV4aXN0cy4gVGh1cyBkbyBub3RoaW5nIChkb24ndCBhZGQvcmVtb3ZlIHBvaW50cykuXG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHBvaW50cy5sZW5ndGggPiAyICYmIGxhc3RDb21taXR0ZWRQb2ludCAmJiBkaXN0YW5jZTJkKHNjZW5lUG9pbnRlclggLSByeCwgc2NlbmVQb2ludGVyWSAtIHJ5LCBsYXN0Q29tbWl0dGVkUG9pbnRbMF0sIGxhc3RDb21taXR0ZWRQb2ludFsxXSkgPCBMSU5FX0NPTkZJUk1fVEhSRVNIT0xEKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IHBvaW50cy5zbGljZSgwLCAtMSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgICAgICBjb25zdCBbbGFzdENvbW1pdHRlZFgsIGxhc3RDb21taXR0ZWRZXSA9IChfYSA9IG11bHRpRWxlbWVudCA9PT0gbnVsbCB8fCBtdWx0aUVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG11bHRpRWxlbWVudC5sYXN0Q29tbWl0dGVkUG9pbnQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IFswLCAwXTtcbiAgICAgICAgICBsZXQgZHhGcm9tTGFzdENvbW1pdHRlZCA9IGdyaWRYIC0gcnggLSBsYXN0Q29tbWl0dGVkWDtcbiAgICAgICAgICBsZXQgZHlGcm9tTGFzdENvbW1pdHRlZCA9IGdyaWRZIC0gcnkgLSBsYXN0Q29tbWl0dGVkWTtcblxuICAgICAgICAgIGlmIChzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZShldmVudCkpIHtcbiAgICAgICAgICAgICh7XG4gICAgICAgICAgICAgIHdpZHRoOiBkeEZyb21MYXN0Q29tbWl0dGVkLFxuICAgICAgICAgICAgICBoZWlnaHQ6IGR5RnJvbUxhc3RDb21taXR0ZWRcbiAgICAgICAgICAgIH0gPSBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUoIC8vIGFjdHVhbCBjb29yZGluYXRlIG9mIHRoZSBsYXN0IGNvbW1pdHRlZCBwb2ludFxuICAgICAgICAgICAgbGFzdENvbW1pdHRlZFggKyByeCwgbGFzdENvbW1pdHRlZFkgKyByeSwgLy8gY3Vyc29yLWdyaWQgY29vcmRpbmF0ZVxuICAgICAgICAgICAgZ3JpZFgsIGdyaWRZKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGlzUGF0aEFMb29wKHBvaW50cywgdGhpcy5zdGF0ZS56b29tLnZhbHVlKSkge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgIH0gLy8gdXBkYXRlIGxhc3QgdW5jb21taXR0ZWQgcG9pbnRcblxuXG4gICAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cy5zbGljZSgwLCAtMSksIFtsYXN0Q29tbWl0dGVkWCArIGR4RnJvbUxhc3RDb21taXR0ZWQsIGxhc3RDb21taXR0ZWRZICsgZHlGcm9tTGFzdENvbW1pdHRlZF1dXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhhc0Rlc2VsZWN0ZWRCdXR0b24gPSBCb29sZWFuKGV2ZW50LmJ1dHRvbnMpO1xuXG4gICAgICBpZiAoaGFzRGVzZWxlY3RlZEJ1dHRvbiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJ0ZXh0XCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwiZXJhc2VyXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCk7XG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgIWlzT3ZlclNjcm9sbEJhciAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICBjb25zdCBlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgPSBnZXRFbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUoZWxlbWVudHMsIHRoaXMuc3RhdGUsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclksIHRoaXMuc3RhdGUuem9vbSwgZXZlbnQucG9pbnRlclR5cGUpO1xuXG4gICAgICAgIGlmIChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgJiYgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLnRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50KGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSkpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDEgJiYgIWlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICBjb25zdCB0cmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0VHJhbnNmb3JtSGFuZGxlVHlwZUZyb21Db29yZHMoZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZSkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBnZXRDdXJzb3JGb3JSZXNpemluZ0VsZW1lbnQoe1xuICAgICAgICAgICAgdHJhbnNmb3JtSGFuZGxlVHlwZVxuICAgICAgICAgIH0pKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgIHRoaXMuaGl0TGlua0VsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbihzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpO1xuXG4gICAgICBpZiAoaXNFcmFzZXJBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5oaXRMaW5rRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5oaXRMaW5rRWxlbWVudC5pZF0pIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICBzaG93SHlwZXJsaW5rVG9vbHRpcCh0aGlzLmhpdExpbmtFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGhpZGVIeXBlcmxpbmtUb29saXAoKTtcblxuICAgICAgICBpZiAoaGl0RWxlbWVudCAmJiAoaGl0RWxlbWVudC5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkpICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdICYmICF0aGlzLnN0YXRlLmNvbnRleHRNZW51ICYmICF0aGlzLnN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBcImluZm9cIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInRleHRcIikge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBpc1RleHRFbGVtZW50KGhpdEVsZW1lbnQpID8gQ1VSU09SX1RZUEUuVEVYVCA6IENVUlNPUl9UWVBFLkNST1NTSEFJUik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNPdmVyU2Nyb2xsQmFyKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkFVVE8pO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVIb3ZlclNlbGVjdGVkTGluZWFyRWxlbWVudCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSk7XG4gICAgICAgIH0gZWxzZSBpZiAoIC8vIGlmIHVzaW5nIGNtZC9jdHJsLCB3ZSdyZSBub3QgZHJhZ2dpbmdcbiAgICAgICAgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgICAgaWYgKChoaXRFbGVtZW50IHx8IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMoc2NlbmVQb2ludGVyLCBzZWxlY3RlZEVsZW1lbnRzKSkgJiYgIShoaXRFbGVtZW50ID09PSBudWxsIHx8IGhpdEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGhpdEVsZW1lbnQubG9ja2VkKSkge1xuICAgICAgICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSAmJiB0aGlzLmlzRW1iZWRkYWJsZUNlbnRlcihoaXRFbGVtZW50LCBldmVudCwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiB7XG4gICAgICAgICAgICAgICAgICBlbGVtZW50OiBoaXRFbGVtZW50LFxuICAgICAgICAgICAgICAgICAgc3RhdGU6IFwiaG92ZXJcIlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG5cbiAgICAgICAgICAgICAgaWYgKCgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiaG92ZXJcIikge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUVyYXNlciA9IChldmVudCwgcG9pbnRlckRvd25TdGF0ZSwgc2NlbmVQb2ludGVyKSA9PiB7XG4gICAgICBjb25zdCB1cGRhdGVFbGVtZW50SWRzID0gZWxlbWVudHMgPT4ge1xuICAgICAgICBlbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIGlmIChlbGVtZW50LmxvY2tlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlkc1RvVXBkYXRlLnB1c2goZWxlbWVudC5pZCk7XG5cbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlbWVudC5pZF0uZXJhc2UgPSBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKCFwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdKSB7XG4gICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdID0ge1xuICAgICAgICAgICAgICBlcmFzZTogdHJ1ZSxcbiAgICAgICAgICAgICAgb3BhY2l0eTogZWxlbWVudC5vcGFjaXR5XG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9O1xuXG4gICAgICBjb25zdCBpZHNUb1VwZGF0ZSA9IFtdO1xuICAgICAgY29uc3QgZGlzdGFuY2UgPSBkaXN0YW5jZTJkKHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54LCBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSwgc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgIGNvbnN0IHRocmVzaG9sZCA9IDEwIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgY29uc3QgcG9pbnQgPSBPYmplY3QuYXNzaWduKHt9LCBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMpO1xuICAgICAgbGV0IHNhbXBsaW5nSW50ZXJ2YWwgPSAwO1xuXG4gICAgICB3aGlsZSAoc2FtcGxpbmdJbnRlcnZhbCA8PSBkaXN0YW5jZSkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHBvaW50LngsIHBvaW50LnkpO1xuICAgICAgICB1cGRhdGVFbGVtZW50SWRzKGhpdEVsZW1lbnRzKTsgLy8gRXhpdCBzaW5jZSB3ZSByZWFjaGVkIGN1cnJlbnQgcG9pbnRcblxuICAgICAgICBpZiAoc2FtcGxpbmdJbnRlcnZhbCA9PT0gZGlzdGFuY2UpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfSAvLyBDYWxjdWxhdGUgbmV4dCBwb2ludCBpbiB0aGUgbGluZSBhdCBhIGRpc3RhbmNlIG9mIHNhbXBsaW5nIGludGVydmFsXG5cblxuICAgICAgICBzYW1wbGluZ0ludGVydmFsID0gTWF0aC5taW4oc2FtcGxpbmdJbnRlcnZhbCArIHRocmVzaG9sZCwgZGlzdGFuY2UpO1xuICAgICAgICBjb25zdCBkaXN0YW5jZVJhdGlvID0gc2FtcGxpbmdJbnRlcnZhbCAvIGRpc3RhbmNlO1xuICAgICAgICBjb25zdCBuZXh0WCA9ICgxIC0gZGlzdGFuY2VSYXRpbykgKiBwb2ludC54ICsgZGlzdGFuY2VSYXRpbyAqIHNjZW5lUG9pbnRlci54O1xuICAgICAgICBjb25zdCBuZXh0WSA9ICgxIC0gZGlzdGFuY2VSYXRpbykgKiBwb2ludC55ICsgZGlzdGFuY2VSYXRpbyAqIHNjZW5lUG9pbnRlci55O1xuICAgICAgICBwb2ludC54ID0gbmV4dFg7XG4gICAgICAgIHBvaW50LnkgPSBuZXh0WTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGUgPT4ge1xuICAgICAgICBjb25zdCBpZCA9IGlzQm91bmRUb0NvbnRhaW5lcihlbGUpICYmIGlkc1RvVXBkYXRlLmluY2x1ZGVzKGVsZS5jb250YWluZXJJZCkgPyBlbGUuY29udGFpbmVySWQgOiBlbGUuaWQ7XG5cbiAgICAgICAgaWYgKGlkc1RvVXBkYXRlLmluY2x1ZGVzKGlkKSkge1xuICAgICAgICAgIGlmIChldmVudC5hbHRLZXkpIHtcbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXS5lcmFzZSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbaWRdLm9wYWNpdHlcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgICAgb3BhY2l0eTogRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHNjZW5lUG9pbnRlci54O1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBzY2VuZVBvaW50ZXIueTtcbiAgICB9OyAvLyBzZXQgdG91Y2ggbW92aW5nIGZvciBtb2JpbGUgY29udGV4dCBtZW51XG5cblxuICAgIHRoaXMuaGFuZGxlVG91Y2hNb3ZlID0gZXZlbnQgPT4ge1xuICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gdHJ1ZTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyRG93biA9IGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2I7IC8vIHNpbmNlIGNvbnRleHRNZW51IG9wdGlvbnMgYXJlIHBvdGVudGlhbGx5IGV2YWx1YXRlZCBvbiBlYWNoIHJlbmRlcixcbiAgICAgIC8vIGFuZCBhbiBjb250ZXh0TWVudSBhY3Rpb24gbWF5IGRlcGVuZCBvbiBzZWxlY3Rpb24gc3RhdGUsIHdlIG11c3RcbiAgICAgIC8vIGNsb3NlIHRoZSBjb250ZXh0TWVudSBiZWZvcmUgd2UgdXBkYXRlIHRoZSBzZWxlY3Rpb24gb24gcG9pbnRlckRvd25cbiAgICAgIC8vIChlLmcuIHJlc2V0dGluZyBzZWxlY3Rpb24pXG5cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuY29udGV4dE1lbnUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgY29udGV4dE1lbnU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNuYXBMaW5lcykge1xuICAgICAgICB0aGlzLnNldEFwcFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXM6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnVwZGF0ZUdlc3R1cmVPblBvaW50ZXJEb3duKGV2ZW50KTsgLy8gaWYgZHJhZ2dpbmcgZWxlbWVudCBpcyBmcmVlZHJhdyBhbmQgYW5vdGhlciBwb2ludGVyZG93biBldmVudCBvY2N1cnNcbiAgICAgIC8vIGEgc2Vjb25kIGZpbmdlciBpcyBvbiB0aGUgc2NyZWVuXG4gICAgICAvLyBkaXNjYXJkIHRoZSBmcmVlZHJhdyBlbGVtZW50IGlmIGl0IGlzIHZlcnkgc2hvcnQgYmVjYXVzZSBpdCBpcyBsaWtlbHlcbiAgICAgIC8vIGp1c3QgYSBzcGlrZSwgb3RoZXJ3aXNlIGZpbmFsaXplIHRoZSBmcmVlZHJhdyBlbGVtZW50IHdoZW4gdGhlIHNlY29uZFxuICAgICAgLy8gZmluZ2VyIGlzIGxpZnRlZFxuXG4gICAgICBpZiAoZXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIiAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50O1xuICAgICAgICB0aGlzLnVwZGF0ZVNjZW5lKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZWxlbWVudC5wb2ludHMubGVuZ3RoIDwgMTAgPyB7XG4gICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSBlbGVtZW50LmlkKVxuICAgICAgICB9IDoge30pLCB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5rZXlzKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5maWx0ZXIoa2V5ID0+IGtleSAhPT0gZWxlbWVudC5pZCkucmVkdWNlKChvYmosIGtleSkgPT4ge1xuICAgICAgICAgICAgICBvYmpba2V5XSA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2tleV07XG4gICAgICAgICAgICAgIHJldHVybiBvYmo7XG4gICAgICAgICAgICB9LCB7fSksIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gcmVtb3ZlIGFueSBhY3RpdmUgc2VsZWN0aW9uIHdoZW4gd2Ugc3RhcnQgdG8gaW50ZXJhY3Qgd2l0aCBjYW52YXNcbiAgICAgIC8vIChtYWlubHksIHdlIGNhcmUgYWJvdXQgcmVtb3Zpbmcgc2VsZWN0aW9uIG91dHNpZGUgdGhlIGNvbXBvbmVudCB3aGljaFxuICAgICAgLy8gIHdvdWxkIHByZXZlbnQgb3VyIGNvcHkgaGFuZGxpbmcgb3RoZXJ3aXNlKVxuXG5cbiAgICAgIGNvbnN0IHNlbGVjdGlvbiA9IGRvY3VtZW50LmdldFNlbGVjdGlvbigpO1xuXG4gICAgICBpZiAoc2VsZWN0aW9uID09PSBudWxsIHx8IHNlbGVjdGlvbiA9PT0gdm9pZCAwID8gdm9pZCAwIDogc2VsZWN0aW9uLmFuY2hvck5vZGUpIHtcbiAgICAgICAgc2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlT3BlbkNvbnRleHRNZW51QWZ0ZXJQb2ludGVyRG93bk9uVG91Y2hEZXZpY2VzKGV2ZW50KTtcbiAgICAgIHRoaXMubWF5YmVDbGVhbnVwQWZ0ZXJNaXNzaW5nUG9pbnRlclVwKGV2ZW50KTsgLy9maXJlcyBvbmx5IG9uY2UsIGlmIHBlbiBpcyBkZXRlY3RlZCwgcGVuTW9kZSBpcyBlbmFibGVkXG4gICAgICAvL3RoZSB1c2VyIGNhbiBkaXNhYmxlIHRoaXMgYnkgdG9nZ2xpbmcgdGhlIHBlbk1vZGUgYnV0dG9uXG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5wZW5EZXRlY3RlZCAmJiBldmVudC5wb2ludGVyVHlwZSA9PT0gXCJwZW5cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHBlbk1vZGU6IHRydWUsXG4gICAgICAgICAgICBwZW5EZXRlY3RlZDogdHJ1ZVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4gJiYgW1wicGVuXCIsIFwidG91Y2hcIl0uaW5jbHVkZXMoZXZlbnQucG9pbnRlclR5cGUpKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gdXBkYXRlT2JqZWN0KHRoaXMuZGV2aWNlLCB7XG4gICAgICAgICAgaXNUb3VjaFNjcmVlbjogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUGFubmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQgPSBldmVudDsgLy8gd2UgbXVzdCBleGl0IGJlZm9yZSB3ZSBzZXQgYGN1cnNvckJ1dHRvbmAgc3RhdGUgYW5kIGBzYXZlUG9pbnRlcmBcbiAgICAgIC8vIGVsc2UgaXQgd2lsbCBzZW5kIHBvaW50ZXIgc3RhdGUgJiBsYXNlciBwb2ludGVyIGV2ZW50cyBpbiBjb2xsYWIgd2hlblxuICAgICAgLy8gcGFubmluZ1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVDYW52YXNQYW5Vc2luZ1doZWVsT3JTcGFjZURyYWcoZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGxhc3RQb2ludGVyRG93bldpdGg6IGV2ZW50LnBvaW50ZXJUeXBlLFxuICAgICAgICBjdXJzb3JCdXR0b246IFwiZG93blwiXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgXCJkb3duXCIpOyAvLyBvbmx5IGhhbmRsZSBsZWZ0IG1vdXNlIGJ1dHRvbiBvciB0b3VjaFxuXG4gICAgICBpZiAoZXZlbnQuYnV0dG9uICE9PSBQT0lOVEVSX0JVVFRPTi5NQUlOICYmIGV2ZW50LmJ1dHRvbiAhPT0gUE9JTlRFUl9CVVRUT04uVE9VQ0gpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBkb24ndCBzZWxlY3Qgd2hpbGUgcGFubmluZ1xuXG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLnNpemUgPiAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gU3RhdGUgZm9yIHRoZSBkdXJhdGlvbiBvZiBhIHBvaW50ZXIgaW50ZXJhY3Rpb24sIHdoaWNoIHN0YXJ0cyB3aXRoIGFcbiAgICAgIC8vIHBvaW50ZXJEb3duIGV2ZW50LCBlbmRzIHdpdGggYSBwb2ludGVyVXAgZXZlbnQgKG9yIGFub3RoZXIgcG9pbnRlckRvd24pXG5cblxuICAgICAgY29uc3QgcG9pbnRlckRvd25TdGF0ZSA9IHRoaXMuaW5pdGlhbFBvaW50ZXJEb3duU3RhdGUoZXZlbnQpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IGZhbHNlXG4gICAgICB9KTtcblxuICAgICAgaWYgKHRoaXMuaGFuZGxlRHJhZ2dpbmdTY3JvbGxCYXIoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5jbGVhclNlbGVjdGlvbklmTm90VXNpbmdTZWxlY3Rpb24oKTtcbiAgICAgIHRoaXMudXBkYXRlQmluZGluZ0VuYWJsZWRPblBvaW50ZXJNb3ZlKGV2ZW50KTtcblxuICAgICAgaWYgKHRoaXMuaGFuZGxlU2VsZWN0aW9uT25Qb2ludGVyRG93bihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBhbGxvd09uUG9pbnRlckRvd24gPSAhdGhpcy5zdGF0ZS5wZW5Nb2RlIHx8IGV2ZW50LnBvaW50ZXJUeXBlICE9PSBcInRvdWNoXCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwidGV4dFwiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImltYWdlXCI7XG5cbiAgICAgIGlmICghYWxsb3dPblBvaW50ZXJEb3duKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInRleHRcIikge1xuICAgICAgICB0aGlzLmhhbmRsZVRleHRPblBvaW50ZXJEb3duKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJhcnJvd1wiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxpbmVcIikge1xuICAgICAgICB0aGlzLmhhbmRsZUxpbmVhckVsZW1lbnRPblBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImltYWdlXCIpIHtcbiAgICAgICAgLy8gcmVzZXQgaW1hZ2UgcHJldmlldyBvbiBwb2ludGVyZG93blxuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQ1JPU1NIQUlSKTsgLy8gcmV0cmlldmUgdGhlIGxhdGVzdCBlbGVtZW50IGFzIHRoZSBzdGF0ZSBtYXkgYmUgc3RhbGVcblxuICAgICAgICBjb25zdCBwZW5kaW5nSW1hZ2VFbGVtZW50ID0gdGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQgJiYgdGhpcy5zY2VuZS5nZXRFbGVtZW50KHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkKTtcblxuICAgICAgICBpZiAoIXBlbmRpbmdJbWFnZUVsZW1lbnQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IHBlbmRpbmdJbWFnZUVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IHBlbmRpbmdJbWFnZUVsZW1lbnQsXG4gICAgICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiBudWxsLFxuICAgICAgICAgIG11bHRpRWxlbWVudDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgbXV0YXRlRWxlbWVudChwZW5kaW5nSW1hZ2VFbGVtZW50LCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlRnJlZURyYXdFbGVtZW50T25Qb2ludGVyRG93bihldmVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJjdXN0b21cIikge1xuICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUZyYW1lRWxlbWVudE9uUG9pbnRlckRvd24ocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyLnN0YXJ0UGF0aChwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJlcmFzZXJcIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJoYW5kXCIpIHtcbiAgICAgICAgdGhpcy5jcmVhdGVHZW5lcmljRWxlbWVudE9uUG9pbnRlckRvd24odGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eub25Qb2ludGVyRG93bikgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbCwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB0aGlzLm9uUG9pbnRlckRvd25FbWl0dGVyLnRyaWdnZXIodGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgICBjb25zdCBvblBvaW50ZXJNb3ZlID0gdGhpcy5vblBvaW50ZXJNb3ZlRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uUG9pbnRlclVwID0gdGhpcy5vblBvaW50ZXJVcEZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICBjb25zdCBvbktleURvd24gPSB0aGlzLm9uS2V5RG93bkZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICBjb25zdCBvbktleVVwID0gdGhpcy5vbktleVVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGxhc3RQb2ludGVyVXAgPSBvblBvaW50ZXJVcDtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsYXNlclwiKSB7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgb25LZXlEb3duKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIG9uS2V5VXApO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSA9IG9uUG9pbnRlck1vdmU7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25VcCA9IG9uUG9pbnRlclVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5VXAgPSBvbktleVVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5RG93biA9IG9uS2V5RG93bjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnJlbW92ZVBvaW50ZXIoZXZlbnQpO1xuICAgICAgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQgPSBldmVudDtcbiAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgIGNsaWVudFg6IGV2ZW50LmNsaWVudFgsXG4gICAgICAgIGNsaWVudFk6IGV2ZW50LmNsaWVudFlcbiAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgY2xpY2tsZW5ndGggPSBldmVudC50aW1lU3RhbXAgLSAoKF9iID0gKF9hID0gdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRpbWVTdGFtcCkgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogMCk7XG5cbiAgICAgIGlmICh0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGUgJiYgY2xpY2tsZW5ndGggPCAzMDApIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcblxuICAgICAgICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSAmJiB0aGlzLmlzRW1iZWRkYWJsZUNlbnRlcihoaXRFbGVtZW50LCBldmVudCwgc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KSkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKGhpdEVsZW1lbnQpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5kZXZpY2UuaXNUb3VjaFNjcmVlbikge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpO1xuICAgICAgICB0aGlzLmhpdExpbmtFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGl0TGlua0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuaGl0TGlua0VsZW1lbnQuaWRdKSB7XG4gICAgICAgIGlmIChjbGlja2xlbmd0aCA8IDMwMCAmJiB0aGlzLmhpdExpbmtFbGVtZW50LnR5cGUgPT09IFwiZW1iZWRkYWJsZVwiICYmICFpc1BvaW50SGl0dGluZ0xpbmtJY29uKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnldKSkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKHRoaXMuaGl0TGlua0VsZW1lbnQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMucmVkaXJlY3RUb0xpbmsoZXZlbnQsIHRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGwsXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7fVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZU9wZW5Db250ZXh0TWVudUFmdGVyUG9pbnRlckRvd25PblRvdWNoRGV2aWNlcyA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIGRlYWwgd2l0aCBvcGVuaW5nIGNvbnRleHQgbWVudSBvbiB0b3VjaCBkZXZpY2VzXG4gICAgICBpZiAoZXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIikge1xuICAgICAgICBpbnZhbGlkYXRlQ29udGV4dE1lbnUgPSBmYWxzZTtcblxuICAgICAgICBpZiAodG91Y2hUaW1lb3V0KSB7XG4gICAgICAgICAgLy8gSWYgdGhlcmUncyBhbHJlYWR5IGEgdG91Y2hUaW1lb3V0LCB0aGlzIG1lYW5zIHRoYXQgdGhlcmUncyBhbm90aGVyXG4gICAgICAgICAgLy8gdG91Y2ggZG93biBhbmQgd2UgYXJlIGRvaW5nIGFub3RoZXIgdG91Y2gsIHNvIHdlIHNob3VsZG4ndCBvcGVuIHRoZVxuICAgICAgICAgIC8vIGNvbnRleHQgbWVudS5cbiAgICAgICAgICBpbnZhbGlkYXRlQ29udGV4dE1lbnUgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIG9wZW4gdGhlIGNvbnRleHQgbWVudSB3aXRoIHRoZSBmaXJzdCB0b3VjaCdzIGNsaWVudFggYW5kIGNsaWVudFlcbiAgICAgICAgICAvLyBpZiB0aGUgdG91Y2ggaXMgbm90IG1vdmluZ1xuICAgICAgICAgIHRvdWNoVGltZW91dCA9IHdpbmRvdy5zZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHRvdWNoVGltZW91dCA9IDA7XG5cbiAgICAgICAgICAgIGlmICghaW52YWxpZGF0ZUNvbnRleHRNZW51KSB7XG4gICAgICAgICAgICAgIHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUoZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIFRPVUNIX0NUWF9NRU5VX1RJTUVPVVQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMucmVzZXRDb250ZXh0TWVudVRpbWVyID0gKCkgPT4ge1xuICAgICAgY2xlYXJUaW1lb3V0KHRvdWNoVGltZW91dCk7XG4gICAgICB0b3VjaFRpbWVvdXQgPSAwO1xuICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG4gICAgfTsgLy8gUmV0dXJucyB3aGV0aGVyIHRoZSBldmVudCBpcyBhIHBhbm5pbmdcblxuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQYW5Vc2luZ1doZWVsT3JTcGFjZURyYWcgPSBldmVudCA9PiB7XG4gICAgICBpZiAoIShnZXN0dXJlLnBvaW50ZXJzLnNpemUgPD0gMSAmJiAoZXZlbnQuYnV0dG9uID09PSBQT0lOVEVSX0JVVFRPTi5XSEVFTCB8fCBldmVudC5idXR0b24gPT09IFBPSU5URVJfQlVUVE9OLk1BSU4gJiYgaXNIb2xkaW5nU3BhY2UgfHwgaXNIYW5kVG9vbEFjdGl2ZSh0aGlzLnN0YXRlKSB8fCB0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkpIHx8IGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpc1Bhbm5pbmcgPSB0cnVlO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGxldCBuZXh0UGFzdGVQcmV2ZW50ZWQgPSBmYWxzZTtcbiAgICAgIGNvbnN0IGlzTGludXggPSAvTGludXgvLnRlc3Qod2luZG93Lm5hdmlnYXRvci5wbGF0Zm9ybSk7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQkJJTkcpO1xuICAgICAgbGV0IHtcbiAgICAgICAgY2xpZW50WDogbGFzdFgsXG4gICAgICAgIGNsaWVudFk6IGxhc3RZXG4gICAgICB9ID0gZXZlbnQ7XG4gICAgICBjb25zdCBvblBvaW50ZXJNb3ZlID0gd2l0aEJhdGNoZWRVcGRhdGVzVGhyb3R0bGVkKGV2ZW50ID0+IHtcbiAgICAgICAgY29uc3QgZGVsdGFYID0gbGFzdFggLSBldmVudC5jbGllbnRYO1xuICAgICAgICBjb25zdCBkZWx0YVkgPSBsYXN0WSAtIGV2ZW50LmNsaWVudFk7XG4gICAgICAgIGxhc3RYID0gZXZlbnQuY2xpZW50WDtcbiAgICAgICAgbGFzdFkgPSBldmVudC5jbGllbnRZO1xuICAgICAgICAvKlxuICAgICAgICAgKiBQcmV2ZW50IHBhc3RlIGV2ZW50IGlmIHdlIG1vdmUgd2hpbGUgbWlkZGxlIGNsaWNraW5nIG9uIExpbnV4LlxuICAgICAgICAgKiBTZWUgaXNzdWUgIzEzODMuXG4gICAgICAgICAqL1xuXG4gICAgICAgIGlmIChpc0xpbnV4ICYmICFuZXh0UGFzdGVQcmV2ZW50ZWQgJiYgKE1hdGguYWJzKGRlbHRhWCkgPiAxIHx8IE1hdGguYWJzKGRlbHRhWSkgPiAxKSkge1xuICAgICAgICAgIG5leHRQYXN0ZVByZXZlbnRlZCA9IHRydWU7XG4gICAgICAgICAgLyogUHJldmVudCB0aGUgbmV4dCBwYXN0ZSBldmVudCAqL1xuXG4gICAgICAgICAgY29uc3QgcHJldmVudE5leHRQYXN0ZSA9IGV2ZW50ID0+IHtcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QQVNURSwgcHJldmVudE5leHRQYXN0ZSk7XG4gICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICB9O1xuICAgICAgICAgIC8qXG4gICAgICAgICAgICogUmVlbmFibGUgbmV4dCBwYXN0ZSBpbiBjYXNlIG9mIGRpc2FibGVkIG1pZGRsZSBjbGljayBwYXN0ZSBmb3JcbiAgICAgICAgICAgKiBhbnkgcmVhc29uOlxuICAgICAgICAgICAqIC0gcmlnaHQgY2xpY2sgcGFzdGVcbiAgICAgICAgICAgKiAtIGVtcHR5IGNsaXBib2FyZFxuICAgICAgICAgICAqL1xuXG5cbiAgICAgICAgICBjb25zdCBlbmFibGVOZXh0UGFzdGUgPSAoKSA9PiB7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCBwcmV2ZW50TmV4dFBhc3RlKTtcbiAgICAgICAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgZW5hYmxlTmV4dFBhc3RlKTtcbiAgICAgICAgICAgIH0sIDEwMCk7XG4gICAgICAgICAgfTtcblxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QQVNURSwgcHJldmVudE5leHRQYXN0ZSk7XG4gICAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgZW5hYmxlTmV4dFBhc3RlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgICBzY3JvbGxYOiB0aGlzLnN0YXRlLnNjcm9sbFggLSBkZWx0YVggLyB0aGlzLnN0YXRlLnpvb20udmFsdWUsXG4gICAgICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZIC0gZGVsdGFZIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgICBjb25zdCB0ZWFyZG93biA9IHdpdGhCYXRjaGVkVXBkYXRlcyhsYXN0UG9pbnRlclVwID0gKCkgPT4ge1xuICAgICAgICBsYXN0UG9pbnRlclVwID0gbnVsbDtcbiAgICAgICAgaXNQYW5uaW5nID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKCFpc0hvbGRpbmdTcGFjZSkge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIlxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0ZWFyZG93bik7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkJMVVIsIHRlYXJkb3duKTtcbiAgICAgICAgb25Qb2ludGVyTW92ZS5mbHVzaCgpO1xuICAgICAgfSk7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0ZWFyZG93bik7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUsIHtcbiAgICAgICAgcGFzc2l2ZTogdHJ1ZVxuICAgICAgfSk7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0ZWFyZG93bik7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9O1xuXG4gICAgdGhpcy5jbGVhclNlbGVjdGlvbklmTm90VXNpbmdTZWxlY3Rpb24gPSAoKSA9PiB7XG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHdoZXRoZXIgdGhlIHBvaW50ZXIgZXZlbnQgaGFzIGJlZW4gY29tcGxldGVseSBoYW5kbGVkXG4gICAgICovXG5cblxuICAgIHRoaXMuaGFuZGxlU2VsZWN0aW9uT25Qb2ludGVyRG93biA9IChldmVudCwgcG9pbnRlckRvd25TdGF0ZSkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSA9IGdldEVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZShlbGVtZW50cywgdGhpcy5zdGF0ZSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG5cbiAgICAgICAgICBpZiAoZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICByZXNpemluZ0VsZW1lbnQ6IGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS5lbGVtZW50XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUgPSBlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUudHJhbnNmb3JtSGFuZGxlVHlwZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSA9IGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzKGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSkge1xuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmlzUmVzaXppbmcgPSB0cnVlO1xuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldCA9IHR1cGxlVG9Db29ycyhnZXRSZXNpemVPZmZzZXRYWShwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlLCBzZWxlY3RlZEVsZW1lbnRzLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSk7XG5cbiAgICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNMaW5lYXJFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pICYmIHNlbGVjdGVkRWxlbWVudHNbMF0ucG9pbnRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuYXJyb3dEaXJlY3Rpb24gPSBnZXRSZXNpemVBcnJvd0RpcmVjdGlvbihwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlLCBzZWxlY3RlZEVsZW1lbnRzWzBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICBjb25zdCBsaW5lYXJFbGVtZW50RWRpdG9yID0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudDtcbiAgICAgICAgICAgIGNvbnN0IHJldCA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlckRvd24oZXZlbnQsIHRoaXMuc3RhdGUsIHRoaXMuaGlzdG9yeSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4sIGxpbmVhckVsZW1lbnRFZGl0b3IpO1xuXG4gICAgICAgICAgICBpZiAocmV0LmhpdEVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCA9IHJldC5oaXRFbGVtZW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAocmV0LmxpbmVhckVsZW1lbnRFZGl0b3IpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiByZXQubGluZWFyRWxlbWVudEVkaXRvclxuICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IHJldC5saW5lYXJFbGVtZW50RWRpdG9yXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHJldC5kaWRBZGRQb2ludCkge1xuICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIGhpdEVsZW1lbnQgbWF5IGFscmVhZHkgYmUgc2V0IGFib3ZlLCBzbyBjaGVjayBmaXJzdFxuXG5cbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50ID0gKF9hID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KTtcblxuICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSB7XG4gICAgICAgICAgICAvLyBFYXJseSByZXR1cm4gaWYgcG9pbnRlciBpcyBoaXR0aW5nIGxpbmsgaWNvblxuICAgICAgICAgICAgY29uc3QgaGl0TGlua0VsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbih7XG4gICAgICAgICAgICAgIHg6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsXG4gICAgICAgICAgICAgIHk6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnlcbiAgICAgICAgICAgIH0sIHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpO1xuXG4gICAgICAgICAgICBpZiAoaGl0TGlua0VsZW1lbnQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gRm9yIG92ZXJsYXBwZWQgZWxlbWVudHMgb25lIHBvc2l0aW9uIG1heSBoaXRcbiAgICAgICAgICAvLyBtdWx0aXBsZSBlbGVtZW50c1xuXG5cbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC5hbGxIaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpO1xuICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuICAgICAgICAgIGNvbnN0IHNvbWVIaXRFbGVtZW50SXNTZWxlY3RlZCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiB0aGlzLmlzQVNlbGVjdGVkRWxlbWVudChlbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoKGhpdEVsZW1lbnQgPT09IG51bGwgfHwgIXNvbWVIaXRFbGVtZW50SXNTZWxlY3RlZCkgJiYgIWV2ZW50LnNoaWZ0S2V5ICYmICFwb2ludGVyRG93blN0YXRlLmhpdC5oYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cykge1xuICAgICAgICAgICAgdGhpcy5jbGVhclNlbGVjdGlvbihoaXRFbGVtZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICAgIFt0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZF06IHRydWVcbiAgICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICAgIH0pOyAvLyBJZiB3ZSBjbGljayBvbiBzb21ldGhpbmdcbiAgICAgICAgICB9IGVsc2UgaWYgKGhpdEVsZW1lbnQgIT0gbnVsbCkge1xuICAgICAgICAgICAgLy8gb24gQ01EL0NUUkwsIGRyaWxsIGRvd24gdG8gaGl0IGVsZW1lbnQgcmVnYXJkbGVzcyBvZiBncm91cHMgZXRjLlxuICAgICAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF0pIHtcbiAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZWRpdEdyb3VwRm9yU2VsZWN0ZWRFbGVtZW50KHByZXZTdGF0ZSwgaGl0RWxlbWVudCkpLCB7XG4gICAgICAgICAgICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgIH0pKTsgLy8gbWFyayBhcyBub3QgY29tcGxldGVseSBoYW5kbGVkIHNvIGFzIHRvIGFsbG93IGRyYWdnaW5nIGV0Yy5cblxuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9IC8vIGRlc2VsZWN0IGlmIGl0ZW0gaXMgc2VsZWN0ZWRcbiAgICAgICAgICAgIC8vIGlmIHNoaWZ0IGlzIG5vdCBjbGlja2VkLCB0aGlzIHdpbGwgYWx3YXlzIHJldHVybiB0cnVlXG4gICAgICAgICAgICAvLyBvdGhlcndpc2UsIGl0IHdpbGwgdHJpZ2dlciBzZWxlY3Rpb24gYmFzZWQgb24gY3VycmVudFxuICAgICAgICAgICAgLy8gc3RhdGUgb2YgdGhlIGJveFxuXG5cbiAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF0pIHtcbiAgICAgICAgICAgICAgLy8gaWYgd2UgYXJlIGN1cnJlbnRseSBlZGl0aW5nIGEgZ3JvdXAsIGV4aXRpbmcgZWRpdGluZyBtb2RlIGFuZCBkZXNlbGVjdCB0aGUgZ3JvdXAuXG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkICYmICFpc0VsZW1lbnRJbkdyb3VwKGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0gLy8gQWRkIGhpdCBlbGVtZW50IHRvIHNlbGVjdGlvbi4gQXQgdGhpcyBwb2ludCBpZiB3ZSdyZSBub3QgaG9sZGluZ1xuICAgICAgICAgICAgICAvLyBTSElGVCB0aGUgcHJldmlvdXNseSBzZWxlY3RlZCBlbGVtZW50KHMpIHdlcmUgZGVzZWxlY3RlZCBhYm92ZVxuICAgICAgICAgICAgICAvLyAobWFrZSBzdXJlIHlvdSB1c2Ugc2V0U3RhdGUgdXBkYXRlciB0byB1c2UgbGF0ZXN0IHN0YXRlKVxuICAgICAgICAgICAgICAvLyBXaXRoIHNoaWZ0LXNlbGVjdGlvbiwgd2Ugd2FudCB0byBtYWtlIHN1cmUgdGhhdCBmcmFtZXMgYW5kIHRoZWlyIGNvbnRhaW5pbmdcbiAgICAgICAgICAgICAgLy8gZWxlbWVudHMgYXJlIG5vdCBzZWxlY3RlZCBhdCB0aGUgc2FtZSB0aW1lLlxuXG5cbiAgICAgICAgICAgICAgaWYgKCFzb21lSGl0RWxlbWVudElzU2VsZWN0ZWQgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgICAgICAgW2hpdEVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzbHlTZWxlY3RlZEVsZW1lbnRzID0gW107XG4gICAgICAgICAgICAgICAgICBPYmplY3Qua2V5cyhwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5mb3JFYWNoKGlkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudChpZCk7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgJiYgcHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMucHVzaChlbGVtZW50KTtcbiAgICAgICAgICAgICAgICAgIH0pOyAvLyBpZiBoaXRFbGVtZW50IGlzIGZyYW1lLCBkZXNlbGVjdCBhbGwgb2YgaXRzIGVsZW1lbnRzIGlmIHRoZXkgYXJlIHNlbGVjdGVkXG5cbiAgICAgICAgICAgICAgICAgIGlmIChoaXRFbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICAgICAgICAgICAgICBnZXRGcmFtZUVsZW1lbnRzKHByZXZpb3VzbHlTZWxlY3RlZEVsZW1lbnRzLCBoaXRFbGVtZW50LmlkKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaGl0RWxlbWVudC5mcmFtZUlkKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGlmIGhpdEVsZW1lbnQgaXMgaW4gYSBmcmFtZSBhbmQgaXRzIGZyYW1lIGhhcyBiZWVuIHNlbGVjdGVkXG4gICAgICAgICAgICAgICAgICAgIC8vIGRpc2FibGUgc2VsZWN0aW9uIGZvciB0aGUgZ2l2ZW4gZWxlbWVudFxuICAgICAgICAgICAgICAgICAgICBpZiAobmV4dFNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmZyYW1lSWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGhpdEVsZW1lbnQgaXMgbmVpdGhlciBhIGZyYW1lIG5vciBhbiBlbGVtZW50IGluIGEgZnJhbWVcbiAgICAgICAgICAgICAgICAgICAgLy8gYnV0IHNpbmNlIGhpdEVsZW1lbnQgY291bGQgYmUgaW4gYSBncm91cCB3aXRoIHNvbWUgZnJhbWVzXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgbWVhbnMgc2VsZWN0aW5nIGhpdEVsZW1lbnQgd2lsbCBoYXZlIHRoZSBmcmFtZXMgc2VsZWN0ZWQgYXMgd2VsbFxuICAgICAgICAgICAgICAgICAgICAvLyBiZWNhdXNlIHdlIHdhbnQgdG8ga2VlcCB0aGUgaW52YXJpYW50OlxuICAgICAgICAgICAgICAgICAgICAvLyAtIGZyYW1lcyBhbmQgdGhlaXIgZWxlbWVudHMgYXJlIG5vdCBzZWxlY3RlZCBhdCB0aGUgc2FtZSB0aW1lXG4gICAgICAgICAgICAgICAgICAgIC8vIHdlIGRlc2VsZWN0IGVsZW1lbnRzIGluIHRob3NlIGZyYW1lcyB0aGF0IHdlcmUgcHJldmlvdXNseSBzZWxlY3RlZFxuICAgICAgICAgICAgICAgICAgICBjb25zdCBncm91cElkcyA9IGhpdEVsZW1lbnQuZ3JvdXBJZHM7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZyYW1lc0luR3JvdXBzID0gbmV3IFNldChncm91cElkcy5mbGF0TWFwKGdpZCA9PiBnZXRFbGVtZW50c0luR3JvdXAodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZ2lkKSkuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpLm1hcChmcmFtZSA9PiBmcmFtZS5pZCkpO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChmcmFtZXNJbkdyb3Vwcy5zaXplID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgIHByZXZpb3VzbHlTZWxlY3RlZEVsZW1lbnRzLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC5mcmFtZUlkICYmIGZyYW1lc0luR3JvdXBzLmhhcyhlbGVtZW50LmZyYW1lSWQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlc2VsZWN0IGVsZW1lbnQgYW5kIGdyb3VwcyBjb250YWluaW5nIHRoZSBlbGVtZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50Lmdyb3VwSWRzLmZsYXRNYXAoZ2lkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBnaWQpKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpID8gXCJpbmZvXCIgOiBmYWxzZVxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQud2FzQWRkZWRUb1NlbGVjdGlvbiA9IHRydWU7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVUZXh0T25Qb2ludGVyRG93biA9IChldmVudCwgcG9pbnRlckRvd25TdGF0ZSkgPT4ge1xuICAgICAgLy8gaWYgd2UncmUgY3VycmVudGx5IHN0aWxsIGVkaXRpbmcgdGV4dCwgY2xpY2tpbmcgb3V0c2lkZVxuICAgICAgLy8gc2hvdWxkIG9ubHkgZmluYWxpemUgaXQsIG5vdCBjcmVhdGUgYW5vdGhlciAoaXJyZXNwZWN0aXZlXG4gICAgICAvLyBvZiBzdGF0ZS5hY3RpdmVUb29sLmxvY2tlZClcbiAgICAgIGlmIChpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgbGV0IHNjZW5lWCA9IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLng7XG4gICAgICBsZXQgc2NlbmVZID0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZLCB7XG4gICAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlXG4gICAgICB9KTsgLy8gRklYTUVcblxuICAgICAgbGV0IGNvbnRhaW5lciA9IGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgc2NlbmVYLCBzY2VuZVkpO1xuXG4gICAgICBpZiAoaGFzQm91bmRUZXh0RWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICBjb250YWluZXIgPSBlbGVtZW50O1xuICAgICAgICBzY2VuZVggPSBlbGVtZW50LnggKyBlbGVtZW50LndpZHRoIC8gMjtcbiAgICAgICAgc2NlbmVZID0gZWxlbWVudC55ICsgZWxlbWVudC5oZWlnaHQgLyAyO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICBzY2VuZVgsXG4gICAgICAgIHNjZW5lWSxcbiAgICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXI6ICFldmVudC5hbHRLZXksXG4gICAgICAgIGNvbnRhaW5lclxuICAgICAgfSk7XG4gICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUZyZWVEcmF3RWxlbWVudE9uUG9pbnRlckRvd24gPSAoZXZlbnQsIGVsZW1lbnRUeXBlLCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICAvLyBCZWdpbiBhIG1hcmsgY2FwdHVyZS4gVGhpcyBkb2VzIG5vdCBoYXZlIHRvIHVwZGF0ZSBzdGF0ZSB5ZXQuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBudWxsKTtcbiAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdGcmVlRHJhd0VsZW1lbnQoe1xuICAgICAgICB0eXBlOiBlbGVtZW50VHlwZSxcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZUNvbG9yLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgc3Ryb2tlV2lkdGg6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VXaWR0aCxcbiAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgICBzaW11bGF0ZVByZXNzdXJlOiBldmVudC5wcmVzc3VyZSA9PT0gMC41LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7XG4gICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMobmV4dFNlbGVjdGVkRWxlbWVudElkcywgcHJldlN0YXRlKVxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgICBjb25zdCBwcmVzc3VyZXMgPSBlbGVtZW50LnNpbXVsYXRlUHJlc3N1cmUgPyBlbGVtZW50LnByZXNzdXJlcyA6IFsuLi5lbGVtZW50LnByZXNzdXJlcywgZXZlbnQucHJlc3N1cmVdO1xuICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgIHBvaW50czogW1swLCAwXV0sXG4gICAgICAgIHByZXNzdXJlc1xuICAgICAgfSk7XG4gICAgICBjb25zdCBib3VuZEVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4sIHRoaXMuc2NlbmUpO1xuICAgICAgdGhpcy5zY2VuZS5hZGROZXdFbGVtZW50KGVsZW1lbnQpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgIHN0YXJ0Qm91bmRFbGVtZW50OiBib3VuZEVsZW1lbnQsXG4gICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgfSk7XG4gICAgfTsgLy9jcmVhdGUgcmVjdGFuZ2xlIGVsZW1lbnQgd2l0aCB5b3V0dWJlIHRvcCBsZWZ0IG9uIG5lYXJlc3QgZ3JpZCBwb2ludCB3aWR0aCAvIGhpZ2h0IDY0MC8zNjBcblxuXG4gICAgdGhpcy5pbnNlcnRFbWJlZGRhYmxlRWxlbWVudCA9ICh7XG4gICAgICBzY2VuZVgsXG4gICAgICBzY2VuZVksXG4gICAgICBsaW5rXG4gICAgfSkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChzY2VuZVgsIHNjZW5lWSwgKChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVtLRVlTLkNUUkxfT1JfQ01EXSkgPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBlbWJlZExpbmsgPSBnZXRFbWJlZExpbmsobGluayk7XG5cbiAgICAgIGlmICghZW1iZWRMaW5rKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGVtYmVkTGluay53YXJuaW5nKSB7XG4gICAgICAgIHRoaXMuc2V0VG9hc3Qoe1xuICAgICAgICAgIG1lc3NhZ2U6IGVtYmVkTGluay53YXJuaW5nLFxuICAgICAgICAgIGNsb3NhYmxlOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50ID0gbmV3RW1iZWRkYWJsZUVsZW1lbnQoe1xuICAgICAgICB0eXBlOiBcImVtYmVkZGFibGVcIixcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogXCJ0cmFuc3BhcmVudFwiLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IFwidHJhbnNwYXJlbnRcIixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIHJvdW5kbmVzczogdGhpcy5nZXRDdXJyZW50SXRlbVJvdW5kbmVzcyhcImVtYmVkZGFibGVcIiksXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICB3aWR0aDogZW1iZWRMaW5rLmFzcGVjdFJhdGlvLncsXG4gICAgICAgIGhlaWdodDogZW1iZWRMaW5rLmFzcGVjdFJhdGlvLmgsXG4gICAgICAgIGxpbmssXG4gICAgICAgIHZhbGlkYXRlZDogbnVsbFxuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZWxlbWVudF0pO1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50ID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWVxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVYLCBzY2VuZVksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0ltYWdlRWxlbWVudCh7XG4gICAgICAgIHR5cGU6IFwiaW1hZ2VcIixcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZUNvbG9yLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgc3Ryb2tlV2lkdGg6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VXaWR0aCxcbiAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICByb3VuZG5lc3M6IG51bGwsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlTGluZWFyRWxlbWVudE9uUG9pbnRlckRvd24gPSAoZXZlbnQsIGVsZW1lbnRUeXBlLCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG11bHRpRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTsgLy8gZmluYWxpemUgaWYgY29tcGxldGluZyBhIGxvb3BcblxuICAgICAgICBpZiAobXVsdGlFbGVtZW50LnR5cGUgPT09IFwibGluZVwiICYmIGlzUGF0aEFMb29wKG11bHRpRWxlbWVudC5wb2ludHMsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50OiBtdWx0aUVsZW1lbnQucG9pbnRzW211bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoIC0gMV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHJ4LFxuICAgICAgICAgIHk6IHJ5LFxuICAgICAgICAgIGxhc3RDb21taXR0ZWRQb2ludFxuICAgICAgICB9ID0gbXVsdGlFbGVtZW50OyAvLyBjbGlja2luZyBpbnNpZGUgY29tbWl0IHpvbmUg4oaSIGZpbmFsaXplIGFycm93XG5cbiAgICAgICAgaWYgKG11bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoID4gMSAmJiBsYXN0Q29tbWl0dGVkUG9pbnQgJiYgZGlzdGFuY2UyZChwb2ludGVyRG93blN0YXRlLm9yaWdpbi54IC0gcngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkgLSByeSwgbGFzdENvbW1pdHRlZFBvaW50WzBdLCBsYXN0Q29tbWl0dGVkUG9pbnRbMV0pIDwgTElORV9DT05GSVJNX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgW211bHRpRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICB9KSwgcHJldlN0YXRlKVxuICAgICAgICB9KSk7IC8vIGNsaWNraW5nIG91dHNpZGUgY29tbWl0IHpvbmUg4oaSIHVwZGF0ZSByZWZlcmVuY2UgZm9yIGxhc3QgY29tbWl0dGVkXG4gICAgICAgIC8vIHBvaW50XG5cbiAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnQ6IG11bHRpRWxlbWVudC5wb2ludHNbbXVsdGlFbGVtZW50LnBvaW50cy5sZW5ndGggLSAxXVxuICAgICAgICB9KTtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgICB5OiBncmlkWVxuICAgICAgICB9KTtcbiAgICAgICAgLyogSWYgYXJyb3cgaXMgcHJlLWFycm93aGVhZHMsIGl0IHdpbGwgaGF2ZSB1bmRlZmluZWQgZm9yIGJvdGggc3RhcnQgYW5kIGVuZCBhcnJvd2hlYWRzLlxuICAgICAgICBJZiBzbywgd2Ugd2FudCBpdCB0byBiZSBudWxsIGZvciBzdGFydCBhbmQgXCJhcnJvd1wiIGZvciBlbmQuIElmIHRoZSBsaW5lYXIgaXRlbSBpcyBub3RcbiAgICAgICAgYW4gYXJyb3csIHdlIHdhbnQgaXQgdG8gYmUgbnVsbCBmb3IgYm90aC4gT3RoZXJ3aXNlLCB3ZSB3YW50IGl0IHRvIHVzZSB0aGVcbiAgICAgICAgdmFsdWVzIGZyb20gYXBwU3RhdGUuICovXG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGN1cnJlbnRJdGVtU3RhcnRBcnJvd2hlYWQsXG4gICAgICAgICAgY3VycmVudEl0ZW1FbmRBcnJvd2hlYWRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGNvbnN0IFtzdGFydEFycm93aGVhZCwgZW5kQXJyb3doZWFkXSA9IGVsZW1lbnRUeXBlID09PSBcImFycm93XCIgPyBbY3VycmVudEl0ZW1TdGFydEFycm93aGVhZCwgY3VycmVudEl0ZW1FbmRBcnJvd2hlYWRdIDogW251bGwsIG51bGxdO1xuICAgICAgICBjb25zdCBlbGVtZW50ID0gbmV3TGluZWFyRWxlbWVudCh7XG4gICAgICAgICAgdHlwZTogZWxlbWVudFR5cGUsXG4gICAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgICAgeTogZ3JpZFksXG4gICAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgICAgcm91bmRuZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91bmRuZXNzID09PSBcInJvdW5kXCIgPyB7XG4gICAgICAgICAgICB0eXBlOiBST1VORE5FU1MuUFJPUE9SVElPTkFMX1JBRElVU1xuICAgICAgICAgIH0gOiBudWxsLFxuICAgICAgICAgIHN0YXJ0QXJyb3doZWFkLFxuICAgICAgICAgIGVuZEFycm93aGVhZCxcbiAgICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTtcbiAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRFbGVtZW50SWRzLCBwcmV2U3RhdGUpXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgIHBvaW50czogWy4uLmVsZW1lbnQucG9pbnRzLCBbMCwgMF1dXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBib3VuZEVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4sIHRoaXMuc2NlbmUpO1xuICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBzdGFydEJvdW5kRWxlbWVudDogYm91bmRFbGVtZW50LFxuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5jcmVhdGVHZW5lcmljRWxlbWVudE9uUG9pbnRlckRvd24gPSAoZWxlbWVudFR5cGUsIHBvaW50ZXJEb3duU3RhdGUpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgKChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVtLRVlTLkNUUkxfT1JfQ01EXSkgPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWVxuICAgICAgfSk7XG4gICAgICBjb25zdCBiYXNlRWxlbWVudEF0dHJpYnV0ZXMgPSB7XG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIHJvdW5kbmVzczogdGhpcy5nZXRDdXJyZW50SXRlbVJvdW5kbmVzcyhlbGVtZW50VHlwZSksXG4gICAgICAgIGxvY2tlZDogZmFsc2UsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfTtcbiAgICAgIGxldCBlbGVtZW50O1xuXG4gICAgICBpZiAoZWxlbWVudFR5cGUgPT09IFwiZW1iZWRkYWJsZVwiKSB7XG4gICAgICAgIGVsZW1lbnQgPSBuZXdFbWJlZGRhYmxlRWxlbWVudChPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICB0eXBlOiBcImVtYmVkZGFibGVcIixcbiAgICAgICAgICB2YWxpZGF0ZWQ6IG51bGxcbiAgICAgICAgfSwgYmFzZUVsZW1lbnRBdHRyaWJ1dGVzKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbGVtZW50ID0gbmV3RWxlbWVudChPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICB0eXBlOiBlbGVtZW50VHlwZVxuICAgICAgICB9LCBiYXNlRWxlbWVudEF0dHJpYnV0ZXMpKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGVsZW1lbnQudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3Rpb25FbGVtZW50OiBlbGVtZW50LFxuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChlbGVtZW50KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgbXVsdGlFbGVtZW50OiBudWxsLFxuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogZWxlbWVudFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5jcmVhdGVGcmFtZUVsZW1lbnRPblBvaW50ZXJEb3duID0gcG9pbnRlckRvd25TdGF0ZSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgZnJhbWUgPSBuZXdGcmFtZUVsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIGxvY2tlZDogZmFsc2VcbiAgICAgIH0sIEZSQU1FX1NUWUxFKSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZnJhbWVdKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBtdWx0aUVsZW1lbnQ6IG51bGwsXG4gICAgICAgIGRyYWdnaW5nRWxlbWVudDogZnJhbWUsXG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBmcmFtZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzdG9yZVJlYWR5VG9FcmFzZUVsZW1lbnRzID0gcG9pbnRlckRvd25TdGF0ZSA9PiB7XG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsZSA9PiB7XG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgb3BhY2l0eTogcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5jb250YWluZXJJZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgb3BhY2l0eTogcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChlbGUuZnJhbWVJZCAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGU7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGVsZW1lbnRzKTtcbiAgICB9O1xuXG4gICAgdGhpcy5lcmFzZUVsZW1lbnRzID0gcG9pbnRlckRvd25TdGF0ZSA9PiB7XG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsZSA9PiB7XG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNCb3VuZFRvQ29udGFpbmVyKGVsZSkgJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGVsZS5mcmFtZUlkICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgfTtcblxuICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlID0gKHtcbiAgICAgIGltYWdlRmlsZSxcbiAgICAgIGltYWdlRWxlbWVudDogX2ltYWdlRWxlbWVudCxcbiAgICAgIHNob3dDdXJzb3JJbWFnZVByZXZpZXcgPSBmYWxzZVxuICAgIH0pID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfZSwgX2YsIF9nLCBfaDsgLy8gYXQgdGhpcyBwb2ludCB0aGlzIHNob3VsZCBiZSBndWFyYW50ZWVkIGltYWdlIGZpbGUsIGJ1dCB3ZSBkbyB0aGlzIGNoZWNrXG4gICAgICAvLyB0byBzYXRpc2Z5IFRTIGRvd24gdGhlIGxpbmVcblxuXG4gICAgICBpZiAoIWlzU3VwcG9ydGVkSW1hZ2VGaWxlKGltYWdlRmlsZSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMudW5zdXBwb3J0ZWRGaWxlVHlwZVwiKSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1pbWVUeXBlID0gaW1hZ2VGaWxlLnR5cGU7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgXCJ3YWl0XCIpO1xuXG4gICAgICBpZiAobWltZVR5cGUgPT09IE1JTUVfVFlQRVMuc3ZnKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaW1hZ2VGaWxlID0gU1ZHU3RyaW5nVG9GaWxlKHlpZWxkIG5vcm1hbGl6ZVNWRyh5aWVsZCBpbWFnZUZpbGUudGV4dCgpKSwgaW1hZ2VGaWxlLm5hbWUpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMuc3ZnSW1hZ2VJbnNlcnRFcnJvclwiKSk7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gZ2VuZXJhdGUgaW1hZ2UgaWQgKGJ5IGRlZmF1bHQgdGhlIGZpbGUgZGlnZXN0KSBiZWZvcmUgYW55XG4gICAgICAvLyByZXNpemluZy9jb21wcmVzc2lvbiB0YWtlcyBwbGFjZSB0byBrZWVwIGl0IG1vcmUgcG9ydGFibGVcblxuXG4gICAgICBjb25zdCBmaWxlSWQgPSB5aWVsZCAoKF9mID0gKF9lID0gdGhpcy5wcm9wcykuZ2VuZXJhdGVJZEZvckZpbGUpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5jYWxsKF9lLCBpbWFnZUZpbGUpKSB8fCBnZW5lcmF0ZUlkRnJvbUZpbGUoaW1hZ2VGaWxlKTtcblxuICAgICAgaWYgKCFmaWxlSWQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFwiQ291bGRuJ3QgZ2VuZXJhdGUgZmlsZSBpZCBvciB0aGUgc3VwcGxpZWQgYGdlbmVyYXRlSWRGb3JGaWxlYCBkaWRuJ3QgcmVzb2x2ZSB0byBvbmUuXCIpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IodChcImVycm9ycy5pbWFnZUluc2VydEVycm9yXCIpKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXhpc3RpbmdGaWxlRGF0YSA9IHRoaXMuZmlsZXNbZmlsZUlkXTtcblxuICAgICAgaWYgKCEoZXhpc3RpbmdGaWxlRGF0YSA9PT0gbnVsbCB8fCBleGlzdGluZ0ZpbGVEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBleGlzdGluZ0ZpbGVEYXRhLmRhdGFVUkwpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaW1hZ2VGaWxlID0geWllbGQgcmVzaXplSW1hZ2VGaWxlKGltYWdlRmlsZSwge1xuICAgICAgICAgICAgbWF4V2lkdGhPckhlaWdodDogREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hUXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcImVycm9yIHRyeWluZyB0byByZXNpbmcgaW1hZ2UgZmlsZSBvbiBpbnNlcnRpb25cIiwgZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGltYWdlRmlsZS5zaXplID4gTUFYX0FMTE9XRURfRklMRV9CWVRFUykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0KFwiZXJyb3JzLmZpbGVUb29CaWdcIiwge1xuICAgICAgICAgICAgbWF4U2l6ZTogYCR7TWF0aC50cnVuYyhNQVhfQUxMT1dFRF9GSUxFX0JZVEVTIC8gMTAyNCAvIDEwMjQpfU1CYFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoc2hvd0N1cnNvckltYWdlUHJldmlldykge1xuICAgICAgICBjb25zdCBkYXRhVVJMID0gKF9nID0gdGhpcy5maWxlc1tmaWxlSWRdKSA9PT0gbnVsbCB8fCBfZyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2cuZGF0YVVSTDsgLy8gb3B0aW1pemF0aW9uIHNvIHRoYXQgd2UgZG9uJ3QgdW5uZWNlc3NhcmlseSByZXNpemUgdGhlIG9yaWdpbmFsXG4gICAgICAgIC8vIGZ1bGwtc2l6ZSBmaWxlIGZvciBjdXJzb3IgcHJldmlld1xuICAgICAgICAvLyAoaXQncyBtdWNoIGZhc3RlciB0byBjb252ZXJ0IHRoZSByZXNpemVkIGRhdGFVUkwgdG8gRmlsZSlcblxuICAgICAgICBjb25zdCByZXNpemVkRmlsZSA9IGRhdGFVUkwgJiYgZGF0YVVSTFRvRmlsZShkYXRhVVJMKTtcbiAgICAgICAgdGhpcy5zZXRJbWFnZVByZXZpZXdDdXJzb3IocmVzaXplZEZpbGUgfHwgaW1hZ2VGaWxlKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YVVSTCA9ICgoX2ggPSB0aGlzLmZpbGVzW2ZpbGVJZF0pID09PSBudWxsIHx8IF9oID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfaC5kYXRhVVJMKSB8fCAoeWllbGQgZ2V0RGF0YVVSTChpbWFnZUZpbGUpKTtcbiAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IG11dGF0ZUVsZW1lbnQoX2ltYWdlRWxlbWVudCwge1xuICAgICAgICBmaWxlSWRcbiAgICAgIH0sIGZhbHNlKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgIHZhciBfajtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIHRoaXMuZmlsZXMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZmlsZXMpLCB7XG4gICAgICAgICAgICBbZmlsZUlkXToge1xuICAgICAgICAgICAgICBtaW1lVHlwZSxcbiAgICAgICAgICAgICAgaWQ6IGZpbGVJZCxcbiAgICAgICAgICAgICAgZGF0YVVSTCxcbiAgICAgICAgICAgICAgY3JlYXRlZDogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgbGFzdFJldHJpZXZlZDogRGF0ZS5ub3coKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGNvbnN0IGNhY2hlZEltYWdlRGF0YSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoZmlsZUlkKTtcblxuICAgICAgICAgIGlmICghY2FjaGVkSW1hZ2VEYXRhKSB7XG4gICAgICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgICAgICAgeWllbGQgdGhpcy51cGRhdGVJbWFnZUNhY2hlKFtpbWFnZUVsZW1lbnRdKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoKGNhY2hlZEltYWdlRGF0YSA9PT0gbnVsbCB8fCBjYWNoZWRJbWFnZURhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNhY2hlZEltYWdlRGF0YS5pbWFnZSkgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgICAgICB5aWVsZCBjYWNoZWRJbWFnZURhdGEuaW1hZ2U7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkICE9PSBpbWFnZUVsZW1lbnQuaWQgJiYgKChfaiA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50KSA9PT0gbnVsbCB8fCBfaiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2ouaWQpICE9PSBpbWFnZUVsZW1lbnQuaWQpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlRGltZW5zaW9ucyhpbWFnZUVsZW1lbnQsIHRydWUpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlc29sdmUoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKHQoXCJlcnJvcnMuaW1hZ2VJbnNlcnRFcnJvclwiKSkpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIGlmICghc2hvd0N1cnNvckltYWdlUHJldmlldykge1xuICAgICAgICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KSk7XG4gICAgfSk7XG4gICAgLyoqXG4gICAgICogaW5zZXJ0cyBpbWFnZSBpbnRvIGVsZW1lbnRzIGFycmF5IGFuZCByZXJlbmRlcnNcbiAgICAgKi9cblxuXG4gICAgdGhpcy5pbnNlcnRJbWFnZUVsZW1lbnQgPSAoaW1hZ2VFbGVtZW50LCBpbWFnZUZpbGUsIHNob3dDdXJzb3JJbWFnZVByZXZpZXcpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChpbWFnZUVsZW1lbnQpO1xuXG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4geWllbGQgdGhpcy5pbml0aWFsaXplSW1hZ2Uoe1xuICAgICAgICAgIGltYWdlRmlsZSxcbiAgICAgICAgICBpbWFnZUVsZW1lbnQsXG4gICAgICAgICAgc2hvd0N1cnNvckltYWdlUHJldmlld1xuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoaW1hZ2VFbGVtZW50LCB7XG4gICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZSB8fCB0KFwiZXJyb3JzLmltYWdlSW5zZXJ0RXJyb3JcIilcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5zZXRJbWFnZVByZXZpZXdDdXJzb3IgPSBpbWFnZUZpbGUgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgLy8gbXVzdG4ndCBiZSBsYXJnZXIgdGhhbiAxMjggcHhcbiAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0NTUy9DU1NfQmFzaWNfVXNlcl9JbnRlcmZhY2UvVXNpbmdfVVJMX3ZhbHVlc19mb3JfdGhlX2N1cnNvcl9wcm9wZXJ0eVxuICAgICAgY29uc3QgY3Vyc29ySW1hZ2VTaXplUHggPSA5NjtcbiAgICAgIGNvbnN0IGltYWdlUHJldmlldyA9IHlpZWxkIHJlc2l6ZUltYWdlRmlsZShpbWFnZUZpbGUsIHtcbiAgICAgICAgbWF4V2lkdGhPckhlaWdodDogY3Vyc29ySW1hZ2VTaXplUHhcbiAgICAgIH0pO1xuICAgICAgbGV0IHByZXZpZXdEYXRhVVJMID0geWllbGQgZ2V0RGF0YVVSTChpbWFnZVByZXZpZXcpOyAvLyBTVkcgY2Fubm90IGJlIHJlc2l6ZWQgdmlhIGByZXNpemVJbWFnZUZpbGVgIHNvIHdlIHJlc2l6ZSBieSByZW5kZXJpbmcgdG9cbiAgICAgIC8vIGEgc21hbGwgY2FudmFzXG5cbiAgICAgIGlmIChpbWFnZUZpbGUudHlwZSA9PT0gTUlNRV9UWVBFUy5zdmcpIHtcbiAgICAgICAgY29uc3QgaW1nID0geWllbGQgbG9hZEhUTUxJbWFnZUVsZW1lbnQocHJldmlld0RhdGFVUkwpO1xuICAgICAgICBsZXQgaGVpZ2h0ID0gTWF0aC5taW4oaW1nLmhlaWdodCwgY3Vyc29ySW1hZ2VTaXplUHgpO1xuICAgICAgICBsZXQgd2lkdGggPSBoZWlnaHQgKiAoaW1nLndpZHRoIC8gaW1nLmhlaWdodCk7XG5cbiAgICAgICAgaWYgKHdpZHRoID4gY3Vyc29ySW1hZ2VTaXplUHgpIHtcbiAgICAgICAgICB3aWR0aCA9IGN1cnNvckltYWdlU2l6ZVB4O1xuICAgICAgICAgIGhlaWdodCA9IHdpZHRoICogKGltZy5oZWlnaHQgLyBpbWcud2lkdGgpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodDtcbiAgICAgICAgY2FudmFzLndpZHRoID0gd2lkdGg7XG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xuICAgICAgICBjb250ZXh0LmRyYXdJbWFnZShpbWcsIDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xuICAgICAgICBwcmV2aWV3RGF0YVVSTCA9IGNhbnZhcy50b0RhdGFVUkwoTUlNRV9UWVBFUy5zdmcpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIGB1cmwoJHtwcmV2aWV3RGF0YVVSTH0pIDQgNCwgYXV0b2ApO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5vbkltYWdlQWN0aW9uID0gKHtcbiAgICAgIGluc2VydE9uQ2FudmFzRGlyZWN0bHlcbiAgICB9KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjbGllbnRYID0gdGhpcy5zdGF0ZS53aWR0aCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldExlZnQ7XG4gICAgICAgIGNvbnN0IGNsaWVudFkgPSB0aGlzLnN0YXRlLmhlaWdodCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldFRvcDtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgICBjbGllbnRYLFxuICAgICAgICAgIGNsaWVudFlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGltYWdlRmlsZSA9IHlpZWxkIGZpbGVPcGVuKHtcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJJbWFnZVwiLFxuICAgICAgICAgIGV4dGVuc2lvbnM6IE9iamVjdC5rZXlzKElNQUdFX01JTUVfVFlQRVMpXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSB0aGlzLmNyZWF0ZUltYWdlRWxlbWVudCh7XG4gICAgICAgICAgc2NlbmVYOiB4LFxuICAgICAgICAgIHNjZW5lWTogeVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoaW5zZXJ0T25DYW52YXNEaXJlY3RseSkge1xuICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlKTtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IGltYWdlRWxlbWVudC5pZFxuICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlLFxuICAgICAgICAgICAgLyogc2hvd0N1cnNvckltYWdlUHJldmlldyAqL1xuICAgICAgICAgICAgdHJ1ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmIChlcnJvci5uYW1lICE9PSBcIkFib3J0RXJyb3JcIikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGwsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMgPSAoaW1hZ2VFbGVtZW50LCBmb3JjZU5hdHVyYWxTaXplID0gZmFsc2UpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaW1hZ2UgPSBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCkgJiYgKChfYSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoaW1hZ2VFbGVtZW50LmZpbGVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pbWFnZSk7XG5cbiAgICAgIGlmICghaW1hZ2UgfHwgaW1hZ2UgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgIGlmIChpbWFnZUVsZW1lbnQud2lkdGggPCBEUkFHR0lOR19USFJFU0hPTEQgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUgJiYgaW1hZ2VFbGVtZW50LmhlaWdodCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkge1xuICAgICAgICAgIGNvbnN0IHBsYWNlaG9sZGVyU2l6ZSA9IDEwMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgICAgeDogaW1hZ2VFbGVtZW50LnggLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgeTogaW1hZ2VFbGVtZW50LnkgLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgd2lkdGg6IHBsYWNlaG9sZGVyU2l6ZSxcbiAgICAgICAgICAgIGhlaWdodDogcGxhY2Vob2xkZXJTaXplXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChmb3JjZU5hdHVyYWxTaXplIHx8IC8vIGlmIHVzZXItY3JlYXRlZCBib3VuZGluZyBib3ggaXMgYmVsb3cgdGhyZXNob2xkLCBhc3N1bWUgdGhlXG4gICAgICAvLyBpbnRlbnRpb24gd2FzIHRvIGNsaWNrIGluc3RlYWQgb2YgZHJhZywgYW5kIHVzZSB0aGUgaW1hZ2Unc1xuICAgICAgLy8gaW50cmluc2ljIHNpemVcbiAgICAgIGltYWdlRWxlbWVudC53aWR0aCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSAmJiBpbWFnZUVsZW1lbnQuaGVpZ2h0IDwgRFJBR0dJTkdfVEhSRVNIT0xEIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlKSB7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IE1hdGgubWF4KHRoaXMuc3RhdGUuaGVpZ2h0IC0gMTIwLCAxNjApOyAvLyBtYXggNjUlIG9mIGNhbnZhcyBoZWlnaHQsIGNsYW1wZWQgdG8gPDMwMHB4LCB2aCAtIDEyMHB4PlxuXG4gICAgICAgIGNvbnN0IG1heEhlaWdodCA9IE1hdGgubWluKG1pbkhlaWdodCwgTWF0aC5mbG9vcih0aGlzLnN0YXRlLmhlaWdodCAqIDAuNSkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUpO1xuICAgICAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1pbihpbWFnZS5uYXR1cmFsSGVpZ2h0LCBtYXhIZWlnaHQpO1xuICAgICAgICBjb25zdCB3aWR0aCA9IGhlaWdodCAqIChpbWFnZS5uYXR1cmFsV2lkdGggLyBpbWFnZS5uYXR1cmFsSGVpZ2h0KTsgLy8gYWRkIGN1cnJlbnQgaW1hZ2VFbGVtZW50IHdpZHRoL2hlaWdodCB0byBhY2NvdW50IGZvciBwcmV2aW91cyBjZW50ZXJpbmdcbiAgICAgICAgLy8gb2YgdGhlIHBsYWNlaG9sZGVyIGltYWdlXG5cbiAgICAgICAgY29uc3QgeCA9IGltYWdlRWxlbWVudC54ICsgaW1hZ2VFbGVtZW50LndpZHRoIC8gMiAtIHdpZHRoIC8gMjtcbiAgICAgICAgY29uc3QgeSA9IGltYWdlRWxlbWVudC55ICsgaW1hZ2VFbGVtZW50LmhlaWdodCAvIDIgLSBoZWlnaHQgLyAyO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeSxcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHRcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcbiAgICAvKiogdXBkYXRlcyBpbWFnZSBjYWNoZSwgcmVmcmVzaGluZyB1cGRhdGVkIGVsZW1lbnRzIGFuZC9vciBzZXR0aW5nIHN0YXR1c1xuICAgICAgICB0byBlcnJvciBmb3IgaW1hZ2VzIHRoYXQgZmFpbCBkdXJpbmcgPGltZz4gZWxlbWVudCBjcmVhdGlvbiAqL1xuXG5cbiAgICB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUgPSAoZWxlbWVudHMsIGZpbGVzID0gdGhpcy5maWxlcykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgY29uc3Qge1xuICAgICAgICB1cGRhdGVkRmlsZXMsXG4gICAgICAgIGVycm9yZWRGaWxlc1xuICAgICAgfSA9IHlpZWxkIF91cGRhdGVJbWFnZUNhY2hlKHtcbiAgICAgICAgaW1hZ2VDYWNoZTogdGhpcy5pbWFnZUNhY2hlLFxuICAgICAgICBmaWxlSWRzOiBlbGVtZW50cy5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgICAgIGZpbGVzXG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplIHx8IGVycm9yZWRGaWxlcy5zaXplKSB7XG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgIGlmICh1cGRhdGVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChlcnJvcmVkRmlsZXMuc2l6ZSkge1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChlbGVtZW50KSAmJiBlcnJvcmVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgc3RhdHVzOiBcImVycm9yXCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBlbGVtZW50O1xuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHVwZGF0ZWRGaWxlcyxcbiAgICAgICAgZXJyb3JlZEZpbGVzXG4gICAgICB9O1xuICAgIH0pO1xuICAgIC8qKiBhZGRzIG5ldyBpbWFnZXMgdG8gaW1hZ2VDYWNoZSBhbmQgcmUtcmVuZGVycyBpZiBuZWVkZWQgKi9cblxuXG4gICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUgPSAoaW1hZ2VFbGVtZW50cyA9IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSwgZmlsZXMgPSB0aGlzLmZpbGVzKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCB1bmNhY2hlZEltYWdlRWxlbWVudHMgPSBpbWFnZUVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+ICFlbGVtZW50LmlzRGVsZXRlZCAmJiAhdGhpcy5pbWFnZUNhY2hlLmhhcyhlbGVtZW50LmZpbGVJZCkpO1xuXG4gICAgICBpZiAodW5jYWNoZWRJbWFnZUVsZW1lbnRzLmxlbmd0aCkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgdXBkYXRlZEZpbGVzXG4gICAgICAgIH0gPSB5aWVsZCB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUodW5jYWNoZWRJbWFnZUVsZW1lbnRzLCBmaWxlcyk7XG5cbiAgICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplKSB7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgLyoqIGdlbmVyYWxseSB5b3Ugc2hvdWxkIHVzZSBgYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKClgIGRpcmVjdGx5IGlmIHlvdSBuZWVkXG4gICAgICogIHRvIHJlbmRlciBuZXcgaW1hZ2VzLiBUaGlzIGlzIGp1c3QgYSBmYWlsc2FmZSAgKi9cblxuXG4gICAgdGhpcy5zY2hlZHVsZUltYWdlUmVmcmVzaCA9IHRocm90dGxlKCgpID0+IHtcbiAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgfSwgSU1BR0VfUkVOREVSX1RJTUVPVVQpO1xuXG4gICAgdGhpcy51cGRhdGVCaW5kaW5nRW5hYmxlZE9uUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICBjb25zdCBzaG91bGRFbmFibGVCaW5kaW5nID0gc2hvdWxkRW5hYmxlQmluZGluZ0ZvclBvaW50ZXJFdmVudChldmVudCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQgIT09IHNob3VsZEVuYWJsZUJpbmRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogc2hvdWxkRW5hYmxlQmluZGluZ1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3IgPSBwb2ludGVyQ29vcmRzID0+IHtcbiAgICAgIGNvbnN0IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckNvb3JkcywgdGhpcy5zY2VuZSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgIT0gbnVsbCA/IFtob3ZlcmVkQmluZGFibGVFbGVtZW50XSA6IFtdXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyA9IChsaW5lYXJFbGVtZW50LFxuICAgIC8qKiBzY2VuZSBjb29yZHMgKi9cbiAgICBwb2ludGVyQ29vcmRzLCAvLyBEdXJpbmcgbGluZSBjcmVhdGlvbiB0aGUgc3RhcnQgYmluZGluZyBoYXNuJ3QgYmVlbiB3cml0dGVuIHlldFxuICAgIC8vIGludG8gYGxpbmVhckVsZW1lbnRgXG4gICAgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50KSA9PiB7XG4gICAgICBpZiAoIXBvaW50ZXJDb29yZHMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3VnZ2VzdGVkQmluZGluZ3MgPSBwb2ludGVyQ29vcmRzLnJlZHVjZSgoYWNjLCBjb29yZHMpID0+IHtcbiAgICAgICAgY29uc3QgaG92ZXJlZEJpbmRhYmxlRWxlbWVudCA9IGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZyhjb29yZHMsIHRoaXMuc2NlbmUpO1xuXG4gICAgICAgIGlmIChob3ZlcmVkQmluZGFibGVFbGVtZW50ICE9IG51bGwgJiYgIWlzTGluZWFyRWxlbWVudFNpbXBsZUFuZEFscmVhZHlCb3VuZChsaW5lYXJFbGVtZW50LCBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQgPT09IG51bGwgfHwgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQuaWQsIGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQpKSB7XG4gICAgICAgICAgYWNjLnB1c2goaG92ZXJlZEJpbmRhYmxlRWxlbWVudCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwgW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVJbnRlcmFjdGl2ZUNhbnZhc1JlZiA9IGNhbnZhcyA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYzsgLy8gY2FudmFzIGlzIG51bGwgd2hlbiB1bm1vdW50aW5nXG5cblxuICAgICAgaWYgKGNhbnZhcyAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzID0gY2FudmFzOyAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAvLyBOT1RFIHdoZWVsLCB0b3VjaHN0YXJ0LCB0b3VjaGVuZCBldmVudHMgbXVzdCBiZSByZWdpc3RlcmVkIG91dHNpZGVcbiAgICAgICAgLy8gb2YgcmVhY3QgYmVjYXVzZSByZWFjdCBiaW5kcyB0aGVtIHRoZW0gcGFzc2l2ZWx5IChzbyB3ZSBjYW4ndCBwcmV2ZW50XG4gICAgICAgIC8vIGRlZmF1bHQgb24gdGhlbSlcblxuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuV0hFRUwsIHRoaXMuaGFuZGxlV2hlZWwpO1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlRPVUNIX0VORCwgdGhpcy5vblRvdWNoRW5kKTsgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIChfYSA9IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLmhhbmRsZVdoZWVsKTtcbiAgICAgICAgKF9iID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgKF9jID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfRU5ELCB0aGlzLm9uVG91Y2hFbmQpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUFwcE9uRHJvcCA9IGV2ZW50ID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfaywgX2wsIF9tLCBfbzsgLy8gbXVzdCBiZSByZXRyaWV2ZWQgZmlyc3QsIGluIHRoZSBzYW1lIGZyYW1lXG5cblxuICAgICAgY29uc3Qge1xuICAgICAgICBmaWxlLFxuICAgICAgICBmaWxlSGFuZGxlXG4gICAgICB9ID0geWllbGQgZ2V0RmlsZUZyb21FdmVudChldmVudCk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKGlzU3VwcG9ydGVkSW1hZ2VGaWxlKGZpbGUpKSB7XG4gICAgICAgICAgLy8gZmlyc3QgYXR0ZW1wdCB0byBkZWNvZGUgc2NlbmUgZnJvbSB0aGUgaW1hZ2UgaWYgaXQncyBlbWJlZGRlZFxuICAgICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAgIGlmICgoZmlsZSA9PT0gbnVsbCB8fCBmaWxlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBmaWxlLnR5cGUpID09PSBNSU1FX1RZUEVTLnBuZyB8fCAoZmlsZSA9PT0gbnVsbCB8fCBmaWxlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBmaWxlLnR5cGUpID09PSBNSU1FX1RZUEVTLnN2Zykge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3Qgc2NlbmUgPSB5aWVsZCBsb2FkRnJvbUJsb2IoZmlsZSwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZmlsZUhhbmRsZSk7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lKSwge1xuICAgICAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlIHx8IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgcmVwbGFjZUZpbGVzOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgIGlmIChlcnJvci5uYW1lICE9PSBcIkVuY29kaW5nRXJyb3JcIikge1xuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBpZiBubyBzY2VuZSBpcyBlbWJlZGRlZCBvciB3ZSBmYWlsIGZvciB3aGF0ZXZlciByZWFzb24sIGZhbGwgYmFja1xuICAgICAgICAgIC8vIHRvIGltcG9ydGluZyBhcyByZWd1bGFyIGltYWdlXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuICAgICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50KHtcbiAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgIHNjZW5lWVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgZmlsZSk7XG4gICAgICAgICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zKGltYWdlRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgICAgW2ltYWdlRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGxpYnJhcnlKU09OID0gZXZlbnQuZGF0YVRyYW5zZmVyLmdldERhdGEoTUlNRV9UWVBFUy5leGNhbGlkcmF3bGliKTtcblxuICAgICAgaWYgKGxpYnJhcnlKU09OICYmIHR5cGVvZiBsaWJyYXJ5SlNPTiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGxpYnJhcnlJdGVtcyA9IHBhcnNlTGlicmFyeUpTT04obGlicmFyeUpTT04pO1xuICAgICAgICAgIHRoaXMuYWRkRWxlbWVudHNGcm9tUGFzdGVPckxpYnJhcnkoe1xuICAgICAgICAgICAgZWxlbWVudHM6IGRpc3RyaWJ1dGVMaWJyYXJ5SXRlbXNPblNxdWFyZUdyaWQobGlicmFyeUl0ZW1zKSxcbiAgICAgICAgICAgIHBvc2l0aW9uOiBldmVudCxcbiAgICAgICAgICAgIGZpbGVzOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGZpbGUpIHtcbiAgICAgICAgLy8gYXRldG1wdCB0byBwYXJzZSBhbiBleGNhbGlkcmF3L2V4Y2FsaWRyYXdsaWIgZmlsZVxuICAgICAgICB5aWVsZCB0aGlzLmxvYWRGaWxlVG9DYW52YXMoZmlsZSwgZmlsZUhhbmRsZSk7XG4gICAgICB9XG5cbiAgICAgIGlmICgoX2wgPSAoX2sgPSBldmVudC5kYXRhVHJhbnNmZXIpID09PSBudWxsIHx8IF9rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfay50eXBlcykgPT09IG51bGwgfHwgX2wgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9sLmluY2x1ZGVzKFwidGV4dC9wbGFpblwiKSkge1xuICAgICAgICBjb25zdCB0ZXh0ID0gKF9tID0gZXZlbnQuZGF0YVRyYW5zZmVyKSA9PT0gbnVsbCB8fCBfbSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX20uZ2V0RGF0YShcInRleHRcIik7XG5cbiAgICAgICAgaWYgKHRleHQgJiYgZW1iZWRkYWJsZVVSTFZhbGlkYXRvcih0ZXh0LCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSkgJiYgKC9eKGh0dHB8aHR0cHMpOlxcL1xcL1teXFxzLyQuPyNdLlteXFxzXSokLy50ZXN0KHRleHQpIHx8ICgoX28gPSBnZXRFbWJlZExpbmsodGV4dCkpID09PSBudWxsIHx8IF9vID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfby50eXBlKSA9PT0gXCJ2aWRlb1wiKSkge1xuICAgICAgICAgIGNvbnN0IGVtYmVkZGFibGUgPSB0aGlzLmluc2VydEVtYmVkZGFibGVFbGVtZW50KHtcbiAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgIHNjZW5lWSxcbiAgICAgICAgICAgIGxpbms6IG5vcm1hbGl6ZUxpbmsodGV4dClcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmIChlbWJlZGRhYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgW2VtYmVkZGFibGUuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5sb2FkRmlsZVRvQ2FudmFzID0gKGZpbGUsIGZpbGVIYW5kbGUpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGZpbGUgPSB5aWVsZCBub3JtYWxpemVGaWxlKGZpbGUpO1xuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXQgPSB5aWVsZCBsb2FkU2NlbmVPckxpYnJhcnlGcm9tQmxvYihmaWxlLCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBmaWxlSGFuZGxlKTtcblxuICAgICAgICBpZiAocmV0LnR5cGUgPT09IE1JTUVfVFlQRVMuZXhjYWxpZHJhdykge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcmV0LmRhdGEpLCB7XG4gICAgICAgICAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCByZXQuZGF0YS5hcHBTdGF0ZSB8fCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHJlcGxhY2VGaWxlczogdHJ1ZSxcbiAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfSBlbHNlIGlmIChyZXQudHlwZSA9PT0gTUlNRV9UWVBFUy5leGNhbGlkcmF3bGliKSB7XG4gICAgICAgICAgeWllbGQgdGhpcy5saWJyYXJ5LnVwZGF0ZUxpYnJhcnkoe1xuICAgICAgICAgICAgbGlicmFyeUl0ZW1zOiBmaWxlLFxuICAgICAgICAgICAgbWVyZ2U6IHRydWUsXG4gICAgICAgICAgICBvcGVuTGlicmFyeU1lbnU6IHRydWVcbiAgICAgICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IHQoXCJlcnJvcnMuaW1wb3J0TGlicmFyeUVycm9yXCIpXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51ID0gZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKChcInBvaW50ZXJUeXBlXCIgaW4gZXZlbnQubmF0aXZlRXZlbnQgJiYgZXZlbnQubmF0aXZlRXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIiB8fCBcInBvaW50ZXJUeXBlXCIgaW4gZXZlbnQubmF0aXZlRXZlbnQgJiYgZXZlbnQubmF0aXZlRXZlbnQucG9pbnRlclR5cGUgPT09IFwicGVuXCIgJiYgLy8gYWx3YXlzIGFsbG93IGlmIHVzZXIgdXNlcyBhIHBlbiBzZWNvbmRhcnkgYnV0dG9uXG4gICAgICBldmVudC5idXR0b24gIT09IFBPSU5URVJfQlVUVE9OLlNFQ09OREFSWSkgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oeCwgeSwge1xuICAgICAgICBwcmVmZXJTZWxlY3RlZDogdHJ1ZSxcbiAgICAgICAgaW5jbHVkZUxvY2tlZEVsZW1lbnRzOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBpc0hpdHRpZ25Db21tb25Cb3VuZEJveCA9IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICB4LFxuICAgICAgICB5XG4gICAgICB9LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgIGNvbnN0IHR5cGUgPSBlbGVtZW50IHx8IGlzSGl0dGlnbkNvbW1vbkJvdW5kQm94ID8gXCJlbGVtZW50XCIgOiBcImNhbnZhc1wiO1xuICAgICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHRvcDogb2Zmc2V0VG9wLFxuICAgICAgICBsZWZ0OiBvZmZzZXRMZWZ0XG4gICAgICB9ID0gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgY29uc3QgbGVmdCA9IGV2ZW50LmNsaWVudFggLSBvZmZzZXRMZWZ0O1xuICAgICAgY29uc3QgdG9wID0gZXZlbnQuY2xpZW50WSAtIG9mZnNldFRvcDtcbiAgICAgIHRyYWNrRXZlbnQoXCJjb250ZXh0TWVudVwiLCBcIm9wZW5Db250ZXh0TWVudVwiLCB0eXBlKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBlbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXSA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIGVkaXRpbmdHcm91cElkOiB0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICBbZWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgfVxuICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogaXNMaW5lYXJFbGVtZW50KGVsZW1lbnQpID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZWxlbWVudCwgdGhpcy5zY2VuZSkgOiBudWxsXG4gICAgICB9KSA6IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZmFsc2VcbiAgICAgIH0pLCAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiB7XG4gICAgICAgICAgICB0b3AsXG4gICAgICAgICAgICBsZWZ0LFxuICAgICAgICAgICAgaXRlbXM6IHRoaXMuZ2V0Q29udGV4dE1lbnVJdGVtcyh0eXBlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudCA9IChwb2ludGVyRG93blN0YXRlLCBldmVudCkgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZTtcblxuICAgICAgY29uc3QgZHJhZ2dpbmdFbGVtZW50ID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQ7XG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzO1xuXG4gICAgICBpZiAoIWRyYWdnaW5nRWxlbWVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJlcmFzZXJcIikge1xuICAgICAgICBkcmFnTmV3RWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckNvb3Jkcy54KSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgcG9pbnRlckNvb3Jkcy55KSwgc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCksIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIoZXZlbnQpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgIGNvbnN0IGltYWdlID0gaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpICYmICgoX2EgPSB0aGlzLmltYWdlQ2FjaGUuZ2V0KGRyYWdnaW5nRWxlbWVudC5maWxlSWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaW1hZ2UpO1xuICAgICAgICBjb25zdCBhc3BlY3RSYXRpbyA9IGltYWdlICYmICEoaW1hZ2UgaW5zdGFuY2VvZiBQcm9taXNlKSA/IGltYWdlLndpZHRoIC8gaW1hZ2UuaGVpZ2h0IDogbnVsbDtcbiAgICAgICAgdGhpcy5tYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgW2RyYWdnaW5nRWxlbWVudF0pO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgc25hcE9mZnNldCxcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSA9IHNuYXBOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZSwgZXZlbnQsIHtcbiAgICAgICAgICB4OiBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54ICsgKChfYyA9IChfYiA9IHRoaXMuc3RhdGUub3JpZ2luU25hcE9mZnNldCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLngpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IDApLFxuICAgICAgICAgIHk6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnkgKyAoKF9lID0gKF9kID0gdGhpcy5zdGF0ZS5vcmlnaW5TbmFwT2Zmc2V0KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QueSkgIT09IG51bGwgJiYgX2UgIT09IHZvaWQgMCA/IF9lIDogMClcbiAgICAgICAgfSwge1xuICAgICAgICAgIHg6IGdyaWRYIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCxcbiAgICAgICAgICB5OiBncmlkWSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnlcbiAgICAgICAgfSk7XG4gICAgICAgIGdyaWRYICs9IHNuYXBPZmZzZXQueDtcbiAgICAgICAgZ3JpZFkgKz0gc25hcE9mZnNldC55O1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSk7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnksIGdyaWRYLCBncmlkWSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCwgZ3JpZFgpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55LCBncmlkWSksIGlzSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgPyAhc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCkgOiBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCksIGFzcGVjdFJhdGlvLCB0aGlzLnN0YXRlLm9yaWdpblNuYXBPZmZzZXQpO1xuICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoW2RyYWdnaW5nRWxlbWVudF0pOyAvLyBoaWdobGlnaHQgZWxlbWVudHMgdGhhdCBhcmUgdG8gYmUgYWRkZWQgdG8gZnJhbWVzIG9uIGZyYW1lcyBjcmVhdGlvblxuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZUhhbmRsZVJlc2l6ZSA9IChwb2ludGVyRG93blN0YXRlLCBldmVudCkgPT4ge1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRnJhbWVzID0gc2VsZWN0ZWRFbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG4gICAgICBjb25zdCB0cmFuc2Zvcm1IYW5kbGVUeXBlID0gcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZTtcblxuICAgICAgaWYgKHNlbGVjdGVkRnJhbWVzLmxlbmd0aCA+IDAgJiYgdHJhbnNmb3JtSGFuZGxlVHlwZSA9PT0gXCJyb3RhdGlvblwiKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIC8vIFRPRE86IHJlbmFtZSB0aGlzIHN0YXRlIGZpZWxkIHRvIFwiaXNTY2FsaW5nXCIgdG8gZGlzdGluZ3Vpc2hcbiAgICAgICAgLy8gaXQgZnJvbSB0aGUgZ2VuZXJpYyBcImlzUmVzaXppbmdcIiB3aGljaCBpbmNsdWRlcyBzY2FsaW5nIGFuZFxuICAgICAgICAvLyByb3RhdGluZ1xuICAgICAgICBpc1Jlc2l6aW5nOiB0cmFuc2Zvcm1IYW5kbGVUeXBlICYmIHRyYW5zZm9ybUhhbmRsZVR5cGUgIT09IFwicm90YXRpb25cIixcbiAgICAgICAgaXNSb3RhdGluZzogdHJhbnNmb3JtSGFuZGxlVHlwZSA9PT0gXCJyb3RhdGlvblwiLFxuICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHM7XG4gICAgICBsZXQgW3Jlc2l6ZVgsIHJlc2l6ZVldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCAtIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldC54LCBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5vZmZzZXQueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcCA9IG5ldyBNYXAoKTtcbiAgICAgIHNlbGVjdGVkRnJhbWVzLmZvckVhY2goZnJhbWUgPT4ge1xuICAgICAgICBjb25zdCBlbGVtZW50c0luRnJhbWUgPSBnZXRGcmFtZUVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLmlkKTtcbiAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgZnJhbWVFbGVtZW50c09mZnNldHNNYXAuc2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCwge1xuICAgICAgICAgICAgeDogZWxlbWVudC54IC0gZnJhbWUueCxcbiAgICAgICAgICAgIHk6IGVsZW1lbnQueSAtIGZyYW1lLnlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTsgLy8gY2hlY2sgbmVlZGVkIGZvciBhdm9pZGluZyBmbGlja2VyaW5nIHdoZW4gYSBrZXkgZ2V0cyBwcmVzc2VkXG4gICAgICAvLyBkdXJpbmcgZHJhZ2dpbmdcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQpIHtcbiAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCBkcmFnT2Zmc2V0ID0ge1xuICAgICAgICAgIHg6IGdyaWRYIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCxcbiAgICAgICAgICB5OiBncmlkWSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3Qgb3JpZ2luYWxFbGVtZW50cyA9IFsuLi5wb2ludGVyRG93blN0YXRlLm9yaWdpbmFsRWxlbWVudHMudmFsdWVzKCldO1xuICAgICAgICB0aGlzLm1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHNuYXBPZmZzZXQsXG4gICAgICAgICAgc25hcExpbmVzXG4gICAgICAgIH0gPSBzbmFwUmVzaXppbmdFbGVtZW50cyhzZWxlY3RlZEVsZW1lbnRzLCBnZXRTZWxlY3RlZEVsZW1lbnRzKG9yaWdpbmFsRWxlbWVudHMsIHRoaXMuc3RhdGUpLCB0aGlzLnN0YXRlLCBldmVudCwgZHJhZ09mZnNldCwgdHJhbnNmb3JtSGFuZGxlVHlwZSk7XG4gICAgICAgIHJlc2l6ZVggKz0gc25hcE9mZnNldC54O1xuICAgICAgICByZXNpemVZICs9IHNuYXBPZmZzZXQueTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAodHJhbnNmb3JtRWxlbWVudHMocG9pbnRlckRvd25TdGF0ZSwgdHJhbnNmb3JtSGFuZGxlVHlwZSwgc2VsZWN0ZWRFbGVtZW50cywgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuYXJyb3dEaXJlY3Rpb24sIHNob3VsZFJvdGF0ZVdpdGhEaXNjcmV0ZUFuZ2xlKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCksIHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmIGlzSW1hZ2VFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pID8gIXNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpIDogc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCksIHJlc2l6ZVgsIHJlc2l6ZVksIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmNlbnRlci54LCBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5jZW50ZXIueSwgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICBjb25zdCBlbGVtZW50c1RvSGlnaGxpZ2h0ID0gbmV3IFNldCgpO1xuICAgICAgICBzZWxlY3RlZEZyYW1lcy5mb3JFYWNoKGZyYW1lID0+IHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50c0luRnJhbWUgPSBnZXRGcmFtZUVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLmlkKTsgLy8ga2VlcCBlbGVtZW50cycgcG9zaXRpb25zIHJlbGF0aXZlIHRvIHRoZWlyIGZyYW1lcyBvbiBmcmFtZXMgcmVzaXppbmdcblxuICAgICAgICAgIGlmICh0cmFuc2Zvcm1IYW5kbGVUeXBlKSB7XG4gICAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZS5pbmNsdWRlcyhcIndcIikpIHtcbiAgICAgICAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgeDogZnJhbWUueCArICgoKF9hID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS54KSB8fCAwKSxcbiAgICAgICAgICAgICAgICAgIHk6IGZyYW1lLnkgKyAoKChfYiA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IueSkgfHwgMClcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0cmFuc2Zvcm1IYW5kbGVUeXBlLmluY2x1ZGVzKFwiblwiKSkge1xuICAgICAgICAgICAgICBlbGVtZW50c0luRnJhbWUuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICB4OiBmcmFtZS54ICsgKCgoX2EgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLngpIHx8IDApLFxuICAgICAgICAgICAgICAgICAgeTogZnJhbWUueSArICgoKF9iID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi55KSB8fCAwKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBmcmFtZSwgdGhpcy5zdGF0ZSkuZm9yRWFjaChlbGVtZW50ID0+IGVsZW1lbnRzVG9IaWdobGlnaHQuYWRkKGVsZW1lbnQpKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVsZW1lbnRzVG9IaWdobGlnaHQ6IFsuLi5lbGVtZW50c1RvSGlnaGxpZ2h0XVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgdGhpcy5nZXRDb250ZXh0TWVudUl0ZW1zID0gdHlwZSA9PiB7XG4gICAgICBjb25zdCBvcHRpb25zID0gW107XG4gICAgICBvcHRpb25zLnB1c2goYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcpOyAvLyBjYW52YXMgY29udGV4dE1lbnVcbiAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAgICAgaWYgKHR5cGUgPT09IFwiY2FudmFzXCIpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgcmV0dXJuIFsuLi5vcHRpb25zLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVG9nZ2xlVmlld01vZGUsIGFjdGlvblRvZ2dsZVN0YXRzXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbYWN0aW9uUGFzdGUsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkNvcHlBc1BuZywgYWN0aW9uQ29weUFzU3ZnLCBjb3B5VGV4dCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uU2VsZWN0QWxsLCBhY3Rpb25VbmxvY2tBbGxFbGVtZW50cywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uVG9nZ2xlR3JpZE1vZGUsIGFjdGlvblRvZ2dsZU9iamVjdHNTbmFwTW9kZSwgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVG9nZ2xlVmlld01vZGUsIGFjdGlvblRvZ2dsZVN0YXRzXTtcbiAgICAgIH0gLy8gZWxlbWVudCBjb250ZXh0TWVudVxuICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbiAgICAgIG9wdGlvbnMucHVzaChjb3B5VGV4dCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICByZXR1cm4gW2FjdGlvbkNvcHksIC4uLm9wdGlvbnNdO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gW2FjdGlvbkN1dCwgYWN0aW9uQ29weSwgYWN0aW9uUGFzdGUsIGFjdGlvblNlbGVjdEFsbEVsZW1lbnRzSW5GcmFtZSwgYWN0aW9uUmVtb3ZlQWxsRWxlbWVudHNGcm9tRnJhbWUsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIC4uLm9wdGlvbnMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkNvcHlTdHlsZXMsIGFjdGlvblBhc3RlU3R5bGVzLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Hcm91cCwgYWN0aW9uVW5iaW5kVGV4dCwgYWN0aW9uQmluZFRleHQsIGFjdGlvbldyYXBUZXh0SW5Db250YWluZXIsIGFjdGlvblVuZ3JvdXAsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkFkZFRvTGlicmFyeSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uU2VuZEJhY2t3YXJkLCBhY3Rpb25CcmluZ0ZvcndhcmQsIGFjdGlvblNlbmRUb0JhY2ssIGFjdGlvbkJyaW5nVG9Gcm9udCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uRmxpcEhvcml6b250YWwsIGFjdGlvbkZsaXBWZXJ0aWNhbCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uVG9nZ2xlTGluZWFyRWRpdG9yLCBhY3Rpb25MaW5rLCBhY3Rpb25EdXBsaWNhdGVTZWxlY3Rpb24sIGFjdGlvblRvZ2dsZUVsZW1lbnRMb2NrLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25EZWxldGVTZWxlY3RlZF07XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlV2hlZWwgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKGlzUGFubmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZGVsdGFYLFxuICAgICAgICBkZWx0YVlcbiAgICAgIH0gPSBldmVudDsgLy8gbm90ZSB0aGF0IGV2ZW50LmN0cmxLZXkgaXMgbmVjZXNzYXJ5IHRvIGhhbmRsZSBwaW5jaCB6b29taW5nXG5cbiAgICAgIGlmIChldmVudC5tZXRhS2V5IHx8IGV2ZW50LmN0cmxLZXkpIHtcbiAgICAgICAgY29uc3Qgc2lnbiA9IE1hdGguc2lnbihkZWx0YVkpO1xuICAgICAgICBjb25zdCBNQVhfU1RFUCA9IFpPT01fU1RFUCAqIDEwMDtcbiAgICAgICAgY29uc3QgYWJzRGVsdGEgPSBNYXRoLmFicyhkZWx0YVkpO1xuICAgICAgICBsZXQgZGVsdGEgPSBkZWx0YVk7XG5cbiAgICAgICAgaWYgKGFic0RlbHRhID4gTUFYX1NURVApIHtcbiAgICAgICAgICBkZWx0YSA9IE1BWF9TVEVQICogc2lnbjtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBuZXdab29tID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlIC0gZGVsdGEgLyAxMDA7IC8vIGluY3JlYXNlIHpvb20gc3RlcHMgdGhlIG1vcmUgem9vbWVkLWluIHdlIGFyZSAoYXBwbGllcyB0byA+MTAwJSBvbmx5KVxuXG4gICAgICAgIG5ld1pvb20gKz0gTWF0aC5sb2cxMChNYXRoLm1heCgxLCB0aGlzLnN0YXRlLnpvb20udmFsdWUpKSAqIC1zaWduICogLy8gcmVkdWNlZCBhbXBsaWZpY2F0aW9uIGZvciBzbWFsbCBkZWx0YXMgKHNtYWxsIG1vdmVtZW50cyBvbiBhIHRyYWNrcGFkKVxuICAgICAgICBNYXRoLm1pbigxLCBhYnNEZWx0YSAvIDIwKTtcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICAgIHZpZXdwb3J0WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgICAgIHZpZXdwb3J0WTogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55LFxuICAgICAgICAgIG5leHRab29tOiBnZXROb3JtYWxpemVkWm9vbShuZXdab29tKVxuICAgICAgICB9LCBzdGF0ZSkpLCB7XG4gICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgIH0pKTtcbiAgICAgICAgdGhpcy5yZXNldFNob3VsZENhY2hlSWdub3JlWm9vbURlYm91bmNlZCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHNjcm9sbCBob3Jpem9udGFsbHkgd2hlbiBzaGlmdCBwcmVzc2VkXG5cblxuICAgICAgaWYgKGV2ZW50LnNoaWZ0S2V5KSB7XG4gICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKCh7XG4gICAgICAgICAgem9vbSxcbiAgICAgICAgICBzY3JvbGxYXG4gICAgICAgIH0pID0+ICh7XG4gICAgICAgICAgLy8gb24gTWFjLCBzaGlmdCt3aGVlbCB0ZW5kcyB0byByZXN1bHQgaW4gZGVsdGFYXG4gICAgICAgICAgc2Nyb2xsWDogc2Nyb2xsWCAtIChkZWx0YVkgfHwgZGVsdGFYKSAvIHpvb20udmFsdWVcbiAgICAgICAgfSkpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKCh7XG4gICAgICAgIHpvb20sXG4gICAgICAgIHNjcm9sbFgsXG4gICAgICAgIHNjcm9sbFlcbiAgICAgIH0pID0+ICh7XG4gICAgICAgIHNjcm9sbFg6IHNjcm9sbFggLSBkZWx0YVggLyB6b29tLnZhbHVlLFxuICAgICAgICBzY3JvbGxZOiBzY3JvbGxZIC0gZGVsdGFZIC8gem9vbS52YWx1ZVxuICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5zYXZlUG9pbnRlciA9ICh4LCB5LCBidXR0b24pID0+IHtcbiAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgIGlmICgheCB8fCAheSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeDogc2NlbmVYLFxuICAgICAgICB5OiBzY2VuZVlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiB4LFxuICAgICAgICBjbGllbnRZOiB5XG4gICAgICB9LCB0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKGlzTmFOKHNjZW5lWCkgfHwgaXNOYU4oc2NlbmVZKSkgey8vIHNvbWV0aW1lcyB0aGUgcG9pbnRlciBnb2VzIG9mZiBzY3JlZW5cbiAgICAgIH1cblxuICAgICAgY29uc3QgcG9pbnRlciA9IHtcbiAgICAgICAgeDogc2NlbmVYLFxuICAgICAgICB5OiBzY2VuZVksXG4gICAgICAgIHRvb2w6IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIgPyBcImxhc2VyXCIgOiBcInBvaW50ZXJcIlxuICAgICAgfTtcbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpLm9uUG9pbnRlclVwZGF0ZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHtcbiAgICAgICAgcG9pbnRlcixcbiAgICAgICAgYnV0dG9uLFxuICAgICAgICBwb2ludGVyc01hcDogZ2VzdHVyZS5wb2ludGVyc1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQgPSBkZWJvdW5jZSgoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMudW5tb3VudGVkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSwgMzAwKTtcblxuICAgIHRoaXMudXBkYXRlRE9NUmVjdCA9IGNiID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgaWYgKChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmN1cnJlbnQpIHtcbiAgICAgICAgY29uc3QgZXhjYWxpZHJhd0NvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgIGxlZnQ6IG9mZnNldExlZnQsXG4gICAgICAgICAgdG9wOiBvZmZzZXRUb3BcbiAgICAgICAgfSA9IGV4Y2FsaWRyYXdDb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB3aWR0aDogY3VycmVudFdpZHRoLFxuICAgICAgICAgIGhlaWdodDogY3VycmVudEhlaWdodCxcbiAgICAgICAgICBvZmZzZXRUb3A6IGN1cnJlbnRPZmZzZXRUb3AsXG4gICAgICAgICAgb2Zmc2V0TGVmdDogY3VycmVudE9mZnNldExlZnRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7XG5cbiAgICAgICAgaWYgKHdpZHRoID09PSBjdXJyZW50V2lkdGggJiYgaGVpZ2h0ID09PSBjdXJyZW50SGVpZ2h0ICYmIG9mZnNldExlZnQgPT09IGN1cnJlbnRPZmZzZXRMZWZ0ICYmIG9mZnNldFRvcCA9PT0gY3VycmVudE9mZnNldFRvcCkge1xuICAgICAgICAgIGlmIChjYikge1xuICAgICAgICAgICAgY2IoKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgb2Zmc2V0TGVmdCxcbiAgICAgICAgICBvZmZzZXRUb3BcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIGNiICYmIGNiKCk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLnJlZnJlc2ggPSAoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZ2V0Q2FudmFzT2Zmc2V0cygpKSk7XG4gICAgfTtcblxuICAgIGNvbnN0IGRlZmF1bHRBcHBTdGF0ZSA9IGdldERlZmF1bHRBcHBTdGF0ZSgpO1xuICAgIGNvbnN0IHtcbiAgICAgIGV4Y2FsaWRyYXdBUEksXG4gICAgICB2aWV3TW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIHplbk1vZGVFbmFibGVkID0gZmFsc2UsXG4gICAgICBncmlkTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIG9iamVjdHNTbmFwTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIHRoZW1lID0gZGVmYXVsdEFwcFN0YXRlLnRoZW1lLFxuICAgICAgbmFtZSA9IGRlZmF1bHRBcHBTdGF0ZS5uYW1lXG4gICAgfSA9IHByb3BzO1xuICAgIHRoaXMuc3RhdGUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBkZWZhdWx0QXBwU3RhdGUpLCB7XG4gICAgICB0aGVtZSxcbiAgICAgIGlzTG9hZGluZzogdHJ1ZVxuICAgIH0pLCB0aGlzLmdldENhbnZhc09mZnNldHMoKSksIHtcbiAgICAgIHZpZXdNb2RlRW5hYmxlZCxcbiAgICAgIHplbk1vZGVFbmFibGVkLFxuICAgICAgb2JqZWN0c1NuYXBNb2RlRW5hYmxlZCxcbiAgICAgIGdyaWRTaXplOiBncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsLFxuICAgICAgbmFtZSxcbiAgICAgIHdpZHRoOiB3aW5kb3cuaW5uZXJXaWR0aCxcbiAgICAgIGhlaWdodDogd2luZG93LmlubmVySGVpZ2h0XG4gICAgfSk7XG4gICAgdGhpcy5pZCA9IG5hbm9pZCgpO1xuICAgIHRoaXMubGlicmFyeSA9IG5ldyBMaWJyYXJ5KHRoaXMpO1xuICAgIHRoaXMuc2NlbmUgPSBuZXcgU2NlbmUoKTtcbiAgICB0aGlzLmNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgdGhpcy5yYyA9IHJvdWdoLmNhbnZhcyh0aGlzLmNhbnZhcyk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcblxuICAgIGlmIChleGNhbGlkcmF3QVBJKSB7XG4gICAgICBjb25zdCByZWFkeVByb21pc2UgPSByZXNvbHZhYmxlUHJvbWlzZSgpO1xuICAgICAgY29uc3QgYXBpID0ge1xuICAgICAgICByZWFkeTogdHJ1ZSxcbiAgICAgICAgcmVhZHlQcm9taXNlLFxuICAgICAgICB1cGRhdGVTY2VuZTogdGhpcy51cGRhdGVTY2VuZSxcbiAgICAgICAgdXBkYXRlTGlicmFyeTogdGhpcy5saWJyYXJ5LnVwZGF0ZUxpYnJhcnksXG4gICAgICAgIGFkZEZpbGVzOiB0aGlzLmFkZEZpbGVzLFxuICAgICAgICByZXNldFNjZW5lOiB0aGlzLnJlc2V0U2NlbmUsXG4gICAgICAgIGdldFNjZW5lRWxlbWVudHNJbmNsdWRpbmdEZWxldGVkOiB0aGlzLmdldFNjZW5lRWxlbWVudHNJbmNsdWRpbmdEZWxldGVkLFxuICAgICAgICBoaXN0b3J5OiB7XG4gICAgICAgICAgY2xlYXI6IHRoaXMucmVzZXRIaXN0b3J5XG4gICAgICAgIH0sXG4gICAgICAgIHNjcm9sbFRvQ29udGVudDogdGhpcy5zY3JvbGxUb0NvbnRlbnQsXG4gICAgICAgIGdldFNjZW5lRWxlbWVudHM6IHRoaXMuZ2V0U2NlbmVFbGVtZW50cyxcbiAgICAgICAgZ2V0QXBwU3RhdGU6ICgpID0+IHRoaXMuc3RhdGUsXG4gICAgICAgIGdldEZpbGVzOiAoKSA9PiB0aGlzLmZpbGVzLFxuICAgICAgICByZWZyZXNoOiB0aGlzLnJlZnJlc2gsXG4gICAgICAgIHNldFRvYXN0OiB0aGlzLnNldFRvYXN0LFxuICAgICAgICBpZDogdGhpcy5pZCxcbiAgICAgICAgc2V0QWN0aXZlVG9vbDogdGhpcy5zZXRBY3RpdmVUb29sLFxuICAgICAgICBzZXRDdXJzb3I6IHRoaXMuc2V0Q3Vyc29yLFxuICAgICAgICByZXNldEN1cnNvcjogdGhpcy5yZXNldEN1cnNvcixcbiAgICAgICAgdXBkYXRlRnJhbWVSZW5kZXJpbmc6IHRoaXMudXBkYXRlRnJhbWVSZW5kZXJpbmcsXG4gICAgICAgIHRvZ2dsZVNpZGViYXI6IHRoaXMudG9nZ2xlU2lkZWJhcixcbiAgICAgICAgb25DaGFuZ2U6IGNiID0+IHRoaXMub25DaGFuZ2VFbWl0dGVyLm9uKGNiKSxcbiAgICAgICAgb25Qb2ludGVyRG93bjogY2IgPT4gdGhpcy5vblBvaW50ZXJEb3duRW1pdHRlci5vbihjYiksXG4gICAgICAgIG9uUG9pbnRlclVwOiBjYiA9PiB0aGlzLm9uUG9pbnRlclVwRW1pdHRlci5vbihjYilcbiAgICAgIH07XG5cbiAgICAgIGlmICh0eXBlb2YgZXhjYWxpZHJhd0FQSSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgIGV4Y2FsaWRyYXdBUEkoYXBpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJleGNhbGlkcmF3QVBJIHNob3VsZCBiZSBhIGZ1bmN0aW9uIVwiKTtcbiAgICAgIH1cblxuICAgICAgcmVhZHlQcm9taXNlLnJlc29sdmUoYXBpKTtcbiAgICB9XG5cbiAgICB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJWYWx1ZSA9IHtcbiAgICAgIGNvbnRhaW5lcjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQsXG4gICAgICBpZDogdGhpcy5pZFxuICAgIH07XG4gICAgdGhpcy5mb250cyA9IG5ldyBGb250cyh7XG4gICAgICBzY2VuZTogdGhpcy5zY2VuZSxcbiAgICAgIG9uU2NlbmVVcGRhdGVkOiB0aGlzLm9uU2NlbmVVcGRhdGVkXG4gICAgfSk7XG4gICAgdGhpcy5oaXN0b3J5ID0gbmV3IEhpc3RvcnkoKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIgPSBuZXcgQWN0aW9uTWFuYWdlcih0aGlzLnN5bmNBY3Rpb25SZXN1bHQsICgpID0+IHRoaXMuc3RhdGUsICgpID0+IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMpO1xuICAgIHRoaXMuYWN0aW9uTWFuYWdlci5yZWdpc3RlckFsbChhY3Rpb25zKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBY3Rpb24oY3JlYXRlVW5kb0FjdGlvbih0aGlzLmhpc3RvcnkpKTtcbiAgICB0aGlzLmFjdGlvbk1hbmFnZXIucmVnaXN0ZXJBY3Rpb24oY3JlYXRlUmVkb0FjdGlvbih0aGlzLmhpc3RvcnkpKTtcbiAgfVxuXG4gIG9uV2luZG93TWVzc2FnZShldmVudCkge1xuICAgIGlmIChldmVudC5vcmlnaW4gIT09IFwiaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tXCIgJiYgZXZlbnQub3JpZ2luICE9PSBcImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsZXQgZGF0YSA9IG51bGw7XG5cbiAgICB0cnkge1xuICAgICAgZGF0YSA9IEpTT04ucGFyc2UoZXZlbnQuZGF0YSk7XG4gICAgfSBjYXRjaCAoZSkge31cblxuICAgIGlmICghZGF0YSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHN3aXRjaCAoZXZlbnQub3JpZ2luKSB7XG4gICAgICBjYXNlIFwiaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tXCI6XG4gICAgICAgIC8vQWxsb3dpbmcgZm9yIG11bHRpcGxlIGluc3RhbmNlcyBvZiBFeGNhbGlkcmF3IHJ1bm5pbmcgaW4gdGhlIHdpbmRvd1xuICAgICAgICBpZiAoZGF0YS5tZXRob2QgPT09IFwicGF1c2VkXCIpIHtcbiAgICAgICAgICBsZXQgc291cmNlID0gbnVsbDtcbiAgICAgICAgICBjb25zdCBpZnJhbWVzID0gZG9jdW1lbnQuYm9keS5xdWVyeVNlbGVjdG9yQWxsKFwiaWZyYW1lLmV4Y2FsaWRyYXdfX2VtYmVkZGFibGVcIik7XG5cbiAgICAgICAgICBpZiAoIWlmcmFtZXMpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGZvciAoY29uc3QgaWZyYW1lIG9mIGlmcmFtZXMpIHtcbiAgICAgICAgICAgIGlmIChpZnJhbWUuY29udGVudFdpbmRvdyA9PT0gZXZlbnQuc291cmNlKSB7XG4gICAgICAgICAgICAgIHNvdXJjZSA9IGlmcmFtZS5jb250ZW50V2luZG93O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHNvdXJjZSA9PT0gbnVsbCB8fCBzb3VyY2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHNvdXJjZS5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBtZXRob2Q6IGRhdGEudmFsdWUgPyBcInBsYXlcIiA6IFwicGF1c2VcIixcbiAgICAgICAgICAgIHZhbHVlOiB0cnVlXG4gICAgICAgICAgfSksIFwiKlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlIFwiaHR0cHM6Ly93d3cueW91dHViZS5jb21cIjpcbiAgICAgICAgaWYgKGRhdGEuZXZlbnQgPT09IFwiaW5mb0RlbGl2ZXJ5XCIgJiYgZGF0YS5pbmZvICYmIGRhdGEuaWQgJiYgdHlwZW9mIGRhdGEuaW5mby5wbGF5ZXJTdGF0ZSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAgIGNvbnN0IGlkID0gZGF0YS5pZDtcbiAgICAgICAgICBjb25zdCBwbGF5ZXJTdGF0ZSA9IGRhdGEuaW5mby5wbGF5ZXJTdGF0ZTtcblxuICAgICAgICAgIGlmIChPYmplY3QudmFsdWVzKFlPVVRVQkVfU1RBVEVTKS5pbmNsdWRlcyhwbGF5ZXJTdGF0ZSkpIHtcbiAgICAgICAgICAgIFlPVVRVQkVfVklERU9fU1RBVEVTLnNldChpZCwgcGxheWVyU3RhdGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIHVwZGF0ZUVtYmVkZGFibGVSZWYoaWQsIHJlZikge1xuICAgIGlmIChyZWYpIHtcbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5zZXQoaWQsIHJlZik7XG4gICAgfVxuICB9XG5cbiAgZ2V0SFRNTElGcmFtZUVsZW1lbnQoaWQpIHtcbiAgICByZXR1cm4gdGhpcy5pRnJhbWVSZWZzLmdldChpZCk7XG4gIH1cblxuICBoYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2soZWxlbWVudCkge1xuICAgIHZhciBfYSwgX2IsIF9jLCBfZDtcblxuICAgIGlmICgoKF9hID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgPT09IGVsZW1lbnQgJiYgKChfYiA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnN0YXRlKSA9PT0gXCJhY3RpdmVcIikge1xuICAgICAgcmV0dXJuO1xuICAgIH0gLy8gVGhlIGRlbGF5IHNlcnZlcyB0d28gcHVycG9zZXNcbiAgICAvLyAxLiBUbyBwcmV2ZW50IGZpcnN0IGNsaWNrIHByb3BhZ2F0aW5nIHRvIGlmcmFtZSBvbiBtb2JpbGUsXG4gICAgLy8gICAgZWxzZSB0aGUgY2xpY2sgd2lsbCBpbW1lZGlhdGVseSBzdGFydCBhbmQgc3RvcCB0aGUgdmlkZW9cbiAgICAvLyAyLiBJZiB0aGUgdXNlciBkb3VibGUgY2xpY2tzIHRoZSBmcmFtZSBjZW50ZXIgdG8gYWN0aXZhdGUgaXRcbiAgICAvLyAgICB3aXRob3V0IHRoZSBkZWxheSB5b3V0dWJlIHdpbGwgaW1tZWRpYXRlbHkgb3BlbiB0aGUgdmlkZW9cbiAgICAvLyAgICBpbiBmdWxsc2NyZWVuIG1vZGVcblxuXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgIGVsZW1lbnQsXG4gICAgICAgICAgc3RhdGU6IFwiYWN0aXZlXCJcbiAgICAgICAgfSxcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgW2VsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgIH0sXG4gICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgc2VsZWN0aW9uRWxlbWVudDogbnVsbFxuICAgICAgfSk7XG4gICAgfSwgMTAwKTtcbiAgICBjb25zdCBpZnJhbWUgPSB0aGlzLmdldEhUTUxJRnJhbWVFbGVtZW50KGVsZW1lbnQuaWQpO1xuXG4gICAgaWYgKCEoaWZyYW1lID09PSBudWxsIHx8IGlmcmFtZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaWZyYW1lLmNvbnRlbnRXaW5kb3cpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlmcmFtZS5zcmMuaW5jbHVkZXMoXCJ5b3V0dWJlXCIpKSB7XG4gICAgICBjb25zdCBzdGF0ZSA9IFlPVVRVQkVfVklERU9fU1RBVEVTLmdldChlbGVtZW50LmlkKTtcblxuICAgICAgaWYgKCFzdGF0ZSkge1xuICAgICAgICBZT1VUVUJFX1ZJREVPX1NUQVRFUy5zZXQoZWxlbWVudC5pZCwgWU9VVFVCRV9TVEFURVMuVU5TVEFSVEVEKTtcbiAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIGV2ZW50OiBcImxpc3RlbmluZ1wiLFxuICAgICAgICAgIGlkOiBlbGVtZW50LmlkXG4gICAgICAgIH0pLCBcIipcIik7XG4gICAgICB9XG5cbiAgICAgIHN3aXRjaCAoc3RhdGUpIHtcbiAgICAgICAgY2FzZSBZT1VUVUJFX1NUQVRFUy5QTEFZSU5HOlxuICAgICAgICBjYXNlIFlPVVRVQkVfU1RBVEVTLkJVRkZFUklORzpcbiAgICAgICAgICAoX2MgPSBpZnJhbWUuY29udGVudFdpbmRvdykgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIGV2ZW50OiBcImNvbW1hbmRcIixcbiAgICAgICAgICAgIGZ1bmM6IFwicGF1c2VWaWRlb1wiLFxuICAgICAgICAgICAgYXJnczogXCJcIlxuICAgICAgICAgIH0pLCBcIipcIik7XG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAoX2QgPSBpZnJhbWUuY29udGVudFdpbmRvdykgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIGV2ZW50OiBcImNvbW1hbmRcIixcbiAgICAgICAgICAgIGZ1bmM6IFwicGxheVZpZGVvXCIsXG4gICAgICAgICAgICBhcmdzOiBcIlwiXG4gICAgICAgICAgfSksIFwiKlwiKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaWZyYW1lLnNyYy5pbmNsdWRlcyhcInBsYXllci52aW1lby5jb21cIikpIHtcbiAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgbWV0aG9kOiBcInBhdXNlZFwiIC8vdmlkZW8gcGxheS9wYXVzZSBpbiBvbldpbmRvd01lc3NhZ2UgaGFuZGxlclxuXG4gICAgICB9KSwgXCIqXCIpO1xuICAgIH1cbiAgfVxuXG4gIGlzRW1iZWRkYWJsZUNlbnRlcihlbCwgZXZlbnQsIHNjZW5lWCwgc2NlbmVZKSB7XG4gICAgdmFyIF9hLCBfYjtcblxuICAgIHJldHVybiBlbCAmJiAhZXZlbnQuYWx0S2V5ICYmICFldmVudC5zaGlmdEtleSAmJiAhZXZlbnQubWV0YUtleSAmJiAhZXZlbnQuY3RybEtleSAmJiAoKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpICE9PSBlbCB8fCAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImhvdmVyXCIgfHwgIXRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgJiYgc2NlbmVYID49IGVsLnggKyBlbC53aWR0aCAvIDMgJiYgc2NlbmVYIDw9IGVsLnggKyAyICogZWwud2lkdGggLyAzICYmIHNjZW5lWSA+PSBlbC55ICsgZWwuaGVpZ2h0IC8gMyAmJiBzY2VuZVkgPD0gZWwueSArIDIgKiBlbC5oZWlnaHQgLyAzO1xuICB9XG5cbiAgcmVuZGVyRW1iZWRkYWJsZXMoKSB7XG4gICAgY29uc3Qgc2NhbGUgPSB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgY29uc3Qgbm9ybWFsaXplZFdpZHRoID0gdGhpcy5zdGF0ZS53aWR0aDtcbiAgICBjb25zdCBub3JtYWxpemVkSGVpZ2h0ID0gdGhpcy5zdGF0ZS5oZWlnaHQ7XG4gICAgY29uc3QgZW1iZWRkYWJsZUVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWwgPT4gaXNFbWJlZGRhYmxlRWxlbWVudChlbCkgJiYgISFlbC52YWxpZGF0ZWQpO1xuICAgIHJldHVybiBfanN4KF9GcmFnbWVudCwge1xuICAgICAgY2hpbGRyZW46IGVtYmVkZGFibGVFbGVtZW50cy5tYXAoZWwgPT4ge1xuICAgICAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZiwgX2csIF9oO1xuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBlbC54LFxuICAgICAgICAgIHNjZW5lWTogZWwueVxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgZW1iZWRMaW5rID0gZ2V0RW1iZWRMaW5rKHRvVmFsaWRVUkwoZWwubGluayB8fCBcIlwiKSk7XG4gICAgICAgIGNvbnN0IGlzVmlzaWJsZSA9IGlzRWxlbWVudEluVmlld3BvcnQoZWwsIG5vcm1hbGl6ZWRXaWR0aCwgbm9ybWFsaXplZEhlaWdodCwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGlzQWN0aXZlID0gKChfYSA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmVsZW1lbnQpID09PSBlbCAmJiAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImFjdGl2ZVwiO1xuICAgICAgICBjb25zdCBpc0hvdmVyZWQgPSAoKF9jID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZWxlbWVudCkgPT09IGVsICYmICgoX2QgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5zdGF0ZSkgPT09IFwiaG92ZXJcIjtcbiAgICAgICAgcmV0dXJuIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgY2xhc3NOYW1lOiBjbHN4KFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZS1jb250YWluZXJcIiwge1xuICAgICAgICAgICAgXCJpcy1ob3ZlcmVkXCI6IGlzSG92ZXJlZFxuICAgICAgICAgIH0pLFxuICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICB0cmFuc2Zvcm06IGlzVmlzaWJsZSA/IGB0cmFuc2xhdGUoJHt4IC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0fXB4LCAke3kgLSB0aGlzLnN0YXRlLm9mZnNldFRvcH1weCkgc2NhbGUoJHtzY2FsZX0pYCA6IFwibm9uZVwiLFxuICAgICAgICAgICAgZGlzcGxheTogaXNWaXNpYmxlID8gXCJibG9ja1wiIDogXCJub25lXCIsXG4gICAgICAgICAgICBvcGFjaXR5OiBlbC5vcGFjaXR5IC8gMTAwLFxuICAgICAgICAgICAgW1wiLS1lbWJlZGRhYmxlLXJhZGl1c1wiXTogYCR7Z2V0Q29ybmVyUmFkaXVzKE1hdGgubWluKGVsLndpZHRoLCBlbC5oZWlnaHQpLCBlbCl9cHhgXG4gICAgICAgICAgfVxuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IF9qc3hzKFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgLy90aGlzIGlzIGEgaGFjayB0aGF0IGFkZHJlc3NlcyBpc3NlIHdpdGggZW1iZWRkZWQgZXhjYWxpZHJhdy5jb20gZW1iZWRkYWJsZVxuICAgICAgICAgICAgLy9odHRwczovL2dpdGh1Yi5jb20vZXhjYWxpZHJhdy9leGNhbGlkcmF3L3B1bGwvNjY5MSNpc3N1ZWNvbW1lbnQtMTYwNzM4MzkzOFxuXG4gICAgICAgICAgICAvKnJlZj17KHJlZikgPT4ge1xuICAgICAgICAgICAgICBpZiAoIXRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgICAgICAgICBjb25zdCBzaCA9IGNvbnRhaW5lci5zY3JvbGxIZWlnaHQ7XG4gICAgICAgICAgICAgIGNvbnN0IGNoID0gY29udGFpbmVyLmNsaWVudEhlaWdodDtcbiAgICAgICAgICAgICAgaWYgKHNoICE9PSBjaCkge1xuICAgICAgICAgICAgICAgIGNvbnRhaW5lci5zdHlsZS5oZWlnaHQgPSBgJHtzaH1weGA7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICBjb250YWluZXIuc3R5bGUuaGVpZ2h0ID0gYDEwMCVgO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9fSovXG4gICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZS1jb250YWluZXJfX2lubmVyXCIsXG4gICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICB3aWR0aDogaXNWaXNpYmxlID8gYCR7ZWwud2lkdGh9cHhgIDogMCxcbiAgICAgICAgICAgICAgaGVpZ2h0OiBpc1Zpc2libGUgPyBgJHtlbC5oZWlnaHR9cHhgIDogMCxcbiAgICAgICAgICAgICAgdHJhbnNmb3JtOiBpc1Zpc2libGUgPyBgcm90YXRlKCR7ZWwuYW5nbGV9cmFkKWAgOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgcG9pbnRlckV2ZW50czogaXNBY3RpdmUgPyBQT0lOVEVSX0VWRU5UUy5lbmFibGVkIDogUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCB7XG4gICAgICAgICAgICBjaGlsZHJlbjogW2lzSG92ZXJlZCAmJiBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZS1oaW50XCJcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IHQoXCJidXR0b25zLmVtYmVkZGFibGVJbnRlcmFjdGlvbkJ1dHRvblwiKVxuICAgICAgICAgICAgfSkpLCBfanN4KFwiZGl2XCIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhd19fZW1iZWRkYWJsZV9fb3V0ZXJcIixcbiAgICAgICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgICAgICBwYWRkaW5nOiBgJHtlbC5zdHJva2VXaWR0aH1weGBcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICBjaGlsZHJlbjogKF9nID0gKF9mID0gKF9lID0gdGhpcy5wcm9wcykucmVuZGVyRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2YgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9mLmNhbGwoX2UsIGVsLCB0aGlzLnN0YXRlKSkgIT09IG51bGwgJiYgX2cgIT09IHZvaWQgMCA/IF9nIDogX2pzeChcImlmcmFtZVwiLCB7XG4gICAgICAgICAgICAgICAgcmVmOiByZWYgPT4gdGhpcy51cGRhdGVFbWJlZGRhYmxlUmVmKGVsLmlkLCByZWYpLFxuICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlXCIsXG4gICAgICAgICAgICAgICAgc3JjRG9jOiAoZW1iZWRMaW5rID09PSBudWxsIHx8IGVtYmVkTGluayA9PT0gdm9pZCAwID8gdm9pZCAwIDogZW1iZWRMaW5rLnR5cGUpID09PSBcImRvY3VtZW50XCIgPyBlbWJlZExpbmsuc3JjZG9jKHRoaXMuc3RhdGUudGhlbWUpIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHNyYzogKGVtYmVkTGluayA9PT0gbnVsbCB8fCBlbWJlZExpbmsgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVtYmVkTGluay50eXBlKSAhPT0gXCJkb2N1bWVudFwiID8gKF9oID0gZW1iZWRMaW5rID09PSBudWxsIHx8IGVtYmVkTGluayA9PT0gdm9pZCAwID8gdm9pZCAwIDogZW1iZWRMaW5rLmxpbmspICE9PSBudWxsICYmIF9oICE9PSB2b2lkIDAgPyBfaCA6IFwiXCIgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xLzE4NDcwMDE1XG4gICAgICAgICAgICAgICAgc2Nyb2xsaW5nOiBcIm5vXCIsXG4gICAgICAgICAgICAgICAgcmVmZXJyZXJQb2xpY3k6IFwibm8tcmVmZXJyZXItd2hlbi1kb3duZ3JhZGVcIixcbiAgICAgICAgICAgICAgICB0aXRsZTogXCJFeGNhbGlkcmF3IEVtYmVkZGVkIENvbnRlbnRcIixcbiAgICAgICAgICAgICAgICBhbGxvdzogXCJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlXCIsXG4gICAgICAgICAgICAgICAgYWxsb3dGdWxsU2NyZWVuOiB0cnVlLFxuICAgICAgICAgICAgICAgIHNhbmRib3g6IFwiYWxsb3ctc2FtZS1vcmlnaW4gYWxsb3ctc2NyaXB0cyBhbGxvdy1mb3JtcyBhbGxvdy1wb3B1cHMgYWxsb3ctcG9wdXBzLXRvLWVzY2FwZS1zYW5kYm94IGFsbG93LXByZXNlbnRhdGlvbiBhbGxvdy1kb3dubG9hZHNcIlxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSkpXVxuICAgICAgICAgIH0pKVxuICAgICAgICB9KSwgZWwuaWQpO1xuICAgICAgfSlcbiAgICB9KTtcbiAgfVxuXG4gIHJlbmRlcigpIHtcbiAgICB2YXIgX2EsIF9iLCBfYztcblxuICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgY29uc3Qge1xuICAgICAgcmVuZGVyVG9wUmlnaHRVSSxcbiAgICAgIHJlbmRlckN1c3RvbVN0YXRzXG4gICAgfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3QgdmVyc2lvbk5vbmNlID0gdGhpcy5zY2VuZS5nZXRWZXJzaW9uTm9uY2UoKTtcbiAgICBjb25zdCB7XG4gICAgICBjYW52YXNFbGVtZW50cyxcbiAgICAgIHZpc2libGVFbGVtZW50c1xuICAgIH0gPSB0aGlzLnJlbmRlcmVyLmdldFJlbmRlcmFibGVFbGVtZW50cyh7XG4gICAgICB2ZXJzaW9uTm9uY2UsXG4gICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb20sXG4gICAgICBvZmZzZXRMZWZ0OiB0aGlzLnN0YXRlLm9mZnNldExlZnQsXG4gICAgICBvZmZzZXRUb3A6IHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZLFxuICAgICAgaGVpZ2h0OiB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgIHdpZHRoOiB0aGlzLnN0YXRlLndpZHRoLFxuICAgICAgZWRpdGluZ0VsZW1lbnQ6IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQsXG4gICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkXG4gICAgfSk7XG4gICAgcmV0dXJuIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICBjbGFzc05hbWU6IGNsc3goXCJleGNhbGlkcmF3IGV4Y2FsaWRyYXctY29udGFpbmVyXCIsIHtcbiAgICAgICAgXCJleGNhbGlkcmF3LS12aWV3LW1vZGVcIjogdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQsXG4gICAgICAgIFwiZXhjYWxpZHJhdy0tbW9iaWxlXCI6IHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZVxuICAgICAgfSksXG4gICAgICBzdHlsZToge1xuICAgICAgICBbXCItLXVpLXBvaW50ZXJFdmVudHNcIl06IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCB8fCB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLnJlc2l6aW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsYXNlclwiICYmIC8vIHRlY2huaWNhbGx5IHdlIGNhbiBqdXN0IHRlc3Qgb24gdGhpcyBvbmNlIHdlIG1ha2UgaXQgbW9yZSBzYWZlXG4gICAgICAgIHRoaXMuc3RhdGUuY3Vyc29yQnV0dG9uID09PSBcImRvd25cIiB8fCB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICYmICFpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID8gUE9JTlRFUl9FVkVOVFMuZGlzYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5lbmFibGVkXG4gICAgICB9LFxuICAgICAgcmVmOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYsXG4gICAgICBvbkRyb3A6IHRoaXMuaGFuZGxlQXBwT25Ecm9wLFxuICAgICAgdGFiSW5kZXg6IDAsXG4gICAgICBvbktleURvd246IHRoaXMucHJvcHMuaGFuZGxlS2V5Ym9hcmRHbG9iYWxseSA/IHVuZGVmaW5lZCA6IHRoaXMub25LZXlEb3duXG4gICAgfSwge1xuICAgICAgY2hpbGRyZW46IF9qc3goQXBwQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgIHZhbHVlOiB0aGlzXG4gICAgICB9LCB7XG4gICAgICAgIGNoaWxkcmVuOiBfanN4KEFwcFByb3BzQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgdmFsdWU6IHRoaXMucHJvcHNcbiAgICAgICAgfSwge1xuICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJWYWx1ZVxuICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KERldmljZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5kZXZpY2VcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc2V0QXBwU3RhdGVcbiAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc3RhdGVcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICBjaGlsZHJlbjogX2pzeHMoRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpXG4gICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbX2pzeHMoRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXJDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5hY3Rpb25NYW5hZ2VyXG4gICAgICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW19qc3hzKExheWVyVUksIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmNhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZXM6IHRoaXMuZmlsZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRBcHBTdGF0ZTogdGhpcy5zZXRBcHBTdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGlvbk1hbmFnZXI6IHRoaXMuYWN0aW9uTWFuYWdlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Mb2NrVG9nZ2xlOiB0aGlzLnRvZ2dsZUxvY2ssXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBlbk1vZGVUb2dnbGU6IHRoaXMudG9nZ2xlUGVuTW9kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uSGFuZFRvb2xUb2dnbGU6IHRoaXMub25IYW5kVG9vbFRvZ2dsZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhbmdDb2RlOiBnZXRMYW5ndWFnZSgpLmNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJUb3BSaWdodFVJOiByZW5kZXJUb3BSaWdodFVJLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyQ3VzdG9tU3RhdHM6IHJlbmRlckN1c3RvbVN0YXRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2hvd0V4aXRaZW5Nb2RlQnRuOiB0eXBlb2YgKChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS56ZW5Nb2RlRW5hYmxlZCkgPT09IFwidW5kZWZpbmVkXCIgJiYgdGhpcy5zdGF0ZS56ZW5Nb2RlRW5hYmxlZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIFVJT3B0aW9uczogdGhpcy5wcm9wcy5VSU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkV4cG9ydEltYWdlOiB0aGlzLm9uRXhwb3J0SW1hZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJXZWxjb21lU2NyZWVuOiAhdGhpcy5zdGF0ZS5pc0xvYWRpbmcgJiYgdGhpcy5zdGF0ZS5zaG93V2VsY29tZVNjcmVlbiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiAhdGhpcy5zdGF0ZS56ZW5Nb2RlRW5hYmxlZCAmJiAhdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICBhcHA6IHRoaXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0NvbGxhYm9yYXRpbmc6IHRoaXMucHJvcHMuaXNDb2xsYWJvcmF0aW5nXG4gICAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IFt0aGlzLnByb3BzLmNoaWxkcmVuLCB0aGlzLnN0YXRlLm9wZW5EaWFsb2cgPT09IFwibWVybWFpZFwiICYmIF9qc3goTWVybWFpZFRvRXhjYWxpZHJhdywge30pXVxuICAgICAgICAgICAgICAgICAgICAgIH0pKSwgX2pzeChcImRpdlwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhdy10ZXh0RWRpdG9yQ29udGFpbmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgX2pzeChcImRpdlwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhdy1jb250ZXh0TWVudUNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goXCJkaXZcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXctZXllLWRyb3BwZXItY29udGFpbmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgX2pzeChMYXNlclRvb2xPdmVybGF5LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtYW5hZ2VyOiB0aGlzLmxhc2VyUGF0aE1hbmFnZXJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgIXRoaXMuc3RhdGUuY29udGV4dE1lbnUgJiYgdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXAgJiYgX2pzeChIeXBlcmxpbmssIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHNlbGVjdGVkRWxlbWVudHNbMF0sXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRBcHBTdGF0ZTogdGhpcy5zZXRBcHBTdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uTGlua09wZW46IHRoaXMucHJvcHMub25MaW5rT3BlbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFRvYXN0OiB0aGlzLnNldFRvYXN0XG4gICAgICAgICAgICAgICAgICAgICAgfSwgc2VsZWN0ZWRFbGVtZW50c1swXS5pZCksIHRoaXMuc3RhdGUudG9hc3QgIT09IG51bGwgJiYgX2pzeChUb2FzdCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogdGhpcy5zdGF0ZS50b2FzdC5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25DbG9zZTogKCkgPT4gdGhpcy5zZXRUb2FzdChudWxsKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiB0aGlzLnN0YXRlLnRvYXN0LmR1cmF0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2xvc2FibGU6IHRoaXMuc3RhdGUudG9hc3QuY2xvc2FibGVcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiBfanN4KENvbnRleHRNZW51LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtczogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS5pdGVtcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvcDogdGhpcy5zdGF0ZS5jb250ZXh0TWVudS50b3AsXG4gICAgICAgICAgICAgICAgICAgICAgICBsZWZ0OiB0aGlzLnN0YXRlLmNvbnRleHRNZW51LmxlZnQsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25NYW5hZ2VyOiB0aGlzLmFjdGlvbk1hbmFnZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkNsb3NlOiBjYWxsYmFjayA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRleHRNZW51OiBudWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZvY3VzQ29udGFpbmVyKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sgPT09IG51bGwgfHwgY2FsbGJhY2sgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KFN0YXRpY0NhbnZhcywge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmNhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJjOiB0aGlzLnJjLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IGNhbnZhc0VsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZUVsZW1lbnRzOiB2aXNpYmxlRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IHZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdGlvbk5vbmNlOiAoX2IgPSB0aGlzLnN0YXRlLnNlbGVjdGlvbkVsZW1lbnQpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi52ZXJzaW9uTm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZTogd2luZG93LmRldmljZVBpeGVsUmF0aW8sXG4gICAgICAgICAgICAgICAgICAgICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlckNvbmZpZzoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZUNhY2hlOiB0aGlzLmltYWdlQ2FjaGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlzRXhwb3J0aW5nOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyR3JpZDogdHJ1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KEludGVyYWN0aXZlQ2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250YWluZXJSZWY6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbnZhczogdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzOiBjYW52YXNFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpc2libGVFbGVtZW50czogdmlzaWJsZUVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50czogc2VsZWN0ZWRFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb25Ob25jZTogdmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uTm9uY2U6IChfYyA9IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrOiB0aGlzLnJlbmRlckludGVyYWN0aXZlU2NlbmVDYWxsYmFjayxcbiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZUNhbnZhc1JlZjogdGhpcy5oYW5kbGVJbnRlcmFjdGl2ZUNhbnZhc1JlZixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ29udGV4dE1lbnU6IHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJNb3ZlOiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Qb2ludGVyVXA6IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlclVwLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Qb2ludGVyQ2FuY2VsOiB0aGlzLnJlbW92ZVBvaW50ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblRvdWNoTW92ZTogdGhpcy5oYW5kbGVUb3VjaE1vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJEb3duOiB0aGlzLmhhbmRsZUNhbnZhc1BvaW50ZXJEb3duLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Eb3VibGVDbGljazogdGhpcy5oYW5kbGVDYW52YXNEb3VibGVDbGlja1xuICAgICAgICAgICAgICAgICAgICAgIH0pLCB0aGlzLnJlbmRlckZyYW1lTmFtZXMoKV1cbiAgICAgICAgICAgICAgICAgICAgfSkpLCB0aGlzLnJlbmRlckVtYmVkZGFibGVzKCldXG4gICAgICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgICAgfSkpXG4gICAgICAgICAgICB9KSlcbiAgICAgICAgICB9KSlcbiAgICAgICAgfSkpXG4gICAgICB9KSlcbiAgICB9KSk7XG4gIH1cblxuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICB2YXIgX2E7XG5cbiAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlLmNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IEVOVi5URVNUIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICAgICAgICBjb25zdCBzZXRTdGF0ZSA9IHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMod2luZG93LmgsIHtcbiAgICAgICAgICBzdGF0ZToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZ2V0OiAoKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2V0U3RhdGU6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiAoLi4uYXJncykgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSguLi5hcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIGFwcDoge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHRoaXNcbiAgICAgICAgICB9LFxuICAgICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmhpc3RvcnlcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNjZW5lLmFkZENhbGxiYWNrKHRoaXMub25TY2VuZVVwZGF0ZWQpO1xuICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVycygpO1xuXG4gICAgICBpZiAodGhpcy5wcm9wcy5hdXRvRm9jdXMgJiYgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIC8vIGJvdW5kaW5nIHJlY3RzIGRvbid0IHdvcmsgaW4gdGVzdHMgc28gdXBkYXRpbmdcbiAgICAgIC8vIHRoZSBzdGF0ZSBvbiBpbml0IHdvdWxkIHJlc3VsdCBpbiBtYWtpbmcgdGhlIHRlc3QgZW52aXJvIHJ1blxuICAgICAgLy8gaW4gbW9iaWxlIGJyZWFrcG9pbnQgKDAgd2lkdGgvaGVpZ2h0KSwgbWFraW5nIGV2ZXJ5dGhpbmcgZmFpbFxuICAgICAgIWlzVGVzdEVudigpKSB7XG4gICAgICAgIHRoaXMucmVmcmVzaFZpZXdwb3J0QnJlYWtwb2ludHMoKTtcbiAgICAgICAgdGhpcy5yZWZyZXNoRWRpdG9yQnJlYWtwb2ludHMoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHN1cHBvcnRzUmVzaXplT2JzZXJ2ZXIgJiYgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgdGhpcy5yZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5yZWZyZXNoRWRpdG9yQnJlYWtwb2ludHMoKTtcbiAgICAgICAgICB0aGlzLnVwZGF0ZURPTVJlY3QoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIChfYSA9IHRoaXMucmVzaXplT2JzZXJ2ZXIpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vYnNlcnZlKHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VhcmNoUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoLnNsaWNlKDEpKTtcblxuICAgICAgaWYgKHNlYXJjaFBhcmFtcy5oYXMoXCJ3ZWItc2hhcmUtdGFyZ2V0XCIpKSB7XG4gICAgICAgIC8vIE9idGFpbiBhIGZpbGUgdGhhdCB3YXMgc2hhcmVkIHZpYSB0aGUgV2ViIFNoYXJlIFRhcmdldCBBUEkuXG4gICAgICAgIHRoaXMucmVzdG9yZUZpbGVGcm9tU2hhcmUoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCh0aGlzLmluaXRpYWxpemVTY2VuZSk7XG4gICAgICB9IC8vIG5vdGUgdGhhdCB0aGlzIGNoZWNrIHNlZW1zIHRvIGFsd2F5cyBwYXNzIGluIGxvY2FsaG9zdFxuXG5cbiAgICAgIGlmIChpc0JyYXZlKCkgJiYgIWlzTWVhc3VyZVRleHRTdXBwb3J0ZWQoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IF9qc3goQnJhdmVNZWFzdXJlVGV4dEVycm9yLCB7fSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICB2YXIgX2E7XG5cbiAgICB0aGlzLnJlbmRlcmVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLnNjZW5lID0gbmV3IFNjZW5lKCk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcbiAgICB0aGlzLmZpbGVzID0ge307XG4gICAgdGhpcy5pbWFnZUNhY2hlLmNsZWFyKCk7XG4gICAgKF9hID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmRpc2Nvbm5lY3QoKTtcbiAgICB0aGlzLnVubW91bnRlZCA9IHRydWU7XG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHRoaXMuc2NlbmUuZGVzdHJveSgpO1xuICAgIHRoaXMubGlicmFyeS5kZXN0cm95KCk7XG4gICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyLmRlc3Ryb3koKTtcbiAgICB0aGlzLm9uQ2hhbmdlRW1pdHRlci5kZXN0cm95KCk7XG4gICAgU2hhcGVDYWNoZS5kZXN0cm95KCk7XG4gICAgU25hcENhY2hlLmRlc3Ryb3koKTtcbiAgICBjbGVhclRpbWVvdXQodG91Y2hUaW1lb3V0KTtcbiAgICBpc1NvbWVFbGVtZW50U2VsZWN0ZWQuY2xlYXJDYWNoZSgpO1xuICAgIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMuY2xlYXJDYWNoZSgpO1xuICAgIHRvdWNoVGltZW91dCA9IDA7XG4gIH1cblxuICByZW1vdmVFdmVudExpc3RlbmVycygpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG5cbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIHRoaXMucmVtb3ZlUG9pbnRlcik7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5DT1BZLCB0aGlzLm9uQ29weSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QQVNURSwgdGhpcy5wYXN0ZUZyb21DbGlwYm9hcmQpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuQ1VULCB0aGlzLm9uQ3V0KTtcbiAgICAoX2EgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuV0hFRUwsIHRoaXMub25XaGVlbCk7XG4gICAgKF9iID0gdGhpcy5uZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lcikgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuU0NST0xMLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHRoaXMub25LZXlEb3duLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5NT1VTRV9NT1ZFLCB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbiwgZmFsc2UpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIHRoaXMub25LZXlVcCk7XG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUkVTSVpFLCB0aGlzLm9uUmVzaXplLCBmYWxzZSk7XG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVU5MT0FELCB0aGlzLm9uVW5sb2FkLCBmYWxzZSk7XG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGhpcy5vbkJsdXIsIGZhbHNlKTtcbiAgICAoX2MgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuRFJBR19PVkVSLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICAgIChfZCA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5EUk9QLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9TVEFSVCwgdGhpcy5vbkdlc3R1cmVTdGFydCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9DSEFOR0UsIHRoaXMub25HZXN0dXJlQ2hhbmdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0VORCwgdGhpcy5vbkdlc3R1cmVFbmQsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5NRVNTQUdFLCB0aGlzLm9uV2luZG93TWVzc2FnZSwgZmFsc2UpO1xuICB9XG5cbiAgYWRkRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZTtcblxuICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5NRVNTQUdFLCB0aGlzLm9uV2luZG93TWVzc2FnZSwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGhpcy5yZW1vdmVQb2ludGVyKTsgLy8gIzM1NTNcblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuQ09QWSwgdGhpcy5vbkNvcHkpO1xuICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5XSEVFTCwgdGhpcy5vbldoZWVsLCB7XG4gICAgICBwYXNzaXZlOiBmYWxzZVxuICAgIH0pO1xuXG4gICAgaWYgKHRoaXMucHJvcHMuaGFuZGxlS2V5Ym9hcmRHbG9iYWxseSkge1xuICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlET1dOLCB0aGlzLm9uS2V5RG93biwgZmFsc2UpO1xuICAgIH1cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIHRoaXMub25LZXlVcCwge1xuICAgICAgcGFzc2l2ZTogdHJ1ZVxuICAgIH0pO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuTU9VU0VfTU9WRSwgdGhpcy51cGRhdGVDdXJyZW50Q3Vyc29yUG9zaXRpb24pOyAvLyByZXJlbmRlciB0ZXh0IGVsZW1lbnRzIG9uIGZvbnQgbG9hZCB0byBmaXggIzYzNyAmJiAjMTU1M1xuXG4gICAgKF9jID0gKF9iID0gZG9jdW1lbnQuZm9udHMpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5hZGRFdmVudExpc3RlbmVyKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuY2FsbChfYiwgXCJsb2FkaW5nZG9uZVwiLCBldmVudCA9PiB7XG4gICAgICBjb25zdCBsb2FkZWRGb250RmFjZXMgPSBldmVudC5mb250ZmFjZXM7XG4gICAgICB0aGlzLmZvbnRzLm9uRm9udHNMb2FkZWQobG9hZGVkRm9udEZhY2VzKTtcbiAgICB9KTsgLy8gU2FmYXJpLW9ubHkgZGVza3RvcCBwaW5jaCB6b29tXG5cbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfU1RBUlQsIHRoaXMub25HZXN0dXJlU3RhcnQsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfQ0hBTkdFLCB0aGlzLm9uR2VzdHVyZUNoYW5nZSwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9FTkQsIHRoaXMub25HZXN0dXJlRW5kLCBmYWxzZSk7XG5cbiAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5DVVQsIHRoaXMub25DdXQpO1xuXG4gICAgaWYgKHRoaXMucHJvcHMuZGV0ZWN0U2Nyb2xsKSB7XG4gICAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyID0gZ2V0TmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgdGhpcy5uZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lci5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlNDUk9MTCwgdGhpcy5vblNjcm9sbCk7XG4gICAgfVxuXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUkVTSVpFLCB0aGlzLm9uUmVzaXplLCBmYWxzZSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuVU5MT0FELCB0aGlzLm9uVW5sb2FkLCBmYWxzZSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuQkxVUiwgdGhpcy5vbkJsdXIsIGZhbHNlKTtcbiAgICAoX2QgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuRFJBR19PVkVSLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICAgIChfZSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2UuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5EUk9QLCB0aGlzLmRpc2FibGVFdmVudCwgZmFsc2UpO1xuICB9XG5cbiAgY29tcG9uZW50RGlkVXBkYXRlKHByZXZQcm9wcywgcHJldlN0YXRlKSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2Y7XG5cbiAgICB0aGlzLnVwZGF0ZUVtYmVkZGFibGVzKCk7XG5cbiAgICBpZiAoIXRoaXMuc3RhdGUuc2hvd1dlbGNvbWVTY3JlZW4gJiYgIXRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubGVuZ3RoKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2hvd1dlbGNvbWVTY3JlZW46IHRydWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50ICE9PSB0aGlzLnByb3BzLlVJT3B0aW9ucy5kb2NrZWRTaWRlYmFyQnJlYWtwb2ludCkge1xuICAgICAgdGhpcy5yZWZyZXNoRWRpdG9yQnJlYWtwb2ludHMoKTtcbiAgICB9XG5cbiAgICBpZiAocHJldlN0YXRlLnNjcm9sbFggIT09IHRoaXMuc3RhdGUuc2Nyb2xsWCB8fCBwcmV2U3RhdGUuc2Nyb2xsWSAhPT0gdGhpcy5zdGF0ZS5zY3JvbGxZKSB7XG4gICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eub25TY3JvbGxDaGFuZ2UpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5jYWxsKF9hLCB0aGlzLnN0YXRlLnNjcm9sbFgsIHRoaXMuc3RhdGUuc2Nyb2xsWSk7XG4gICAgfVxuXG4gICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5sZW5ndGggJiYgaXNFcmFzZXJBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBhY3RpdmVUb29sOiB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgIH0pXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZXJhc2VyXCIgJiYgcHJldlN0YXRlLnRoZW1lICE9PSB0aGlzLnN0YXRlLnRoZW1lKSB7XG4gICAgICBzZXRFcmFzZXJDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZS50aGVtZSk7XG4gICAgfSAvLyBIaWRlIGh5cGVybGluayBwb3B1cCBpZiBzaG93biB3aGVuIGVsZW1lbnQgdHlwZSBpcyBub3Qgc2VsZWN0aW9uXG5cblxuICAgIGlmIChwcmV2U3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiICYmIHRoaXMuc3RhdGUuc2hvd0h5cGVybGlua1BvcHVwKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBmYWxzZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy5sYW5nQ29kZSAhPT0gdGhpcy5wcm9wcy5sYW5nQ29kZSkge1xuICAgICAgdGhpcy51cGRhdGVMYW5ndWFnZSgpO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMudmlld01vZGVFbmFibGVkICE9PSB0aGlzLnByb3BzLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHZpZXdNb2RlRW5hYmxlZDogISF0aGlzLnByb3BzLnZpZXdNb2RlRW5hYmxlZFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZTdGF0ZS52aWV3TW9kZUVuYWJsZWQgIT09IHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXJzKCk7XG4gICAgICB0aGlzLmRlc2VsZWN0RWxlbWVudHMoKTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLnplbk1vZGVFbmFibGVkICE9PSB0aGlzLnByb3BzLnplbk1vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgemVuTW9kZUVuYWJsZWQ6ICEhdGhpcy5wcm9wcy56ZW5Nb2RlRW5hYmxlZFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy50aGVtZSAhPT0gdGhpcy5wcm9wcy50aGVtZSAmJiB0aGlzLnByb3BzLnRoZW1lKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMuZ3JpZE1vZGVFbmFibGVkICE9PSB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGdyaWRTaXplOiB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnByb3BzLm5hbWUgJiYgcHJldlByb3BzLm5hbWUgIT09IHRoaXMucHJvcHMubmFtZSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIG5hbWU6IHRoaXMucHJvcHMubmFtZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgKF9jID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5jbGFzc0xpc3QudG9nZ2xlKFwidGhlbWUtLWRhcmtcIiwgdGhpcy5zdGF0ZS50aGVtZSA9PT0gXCJkYXJrXCIpO1xuXG4gICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkXSkge1xuICAgICAgLy8gZGVmZXIgc28gdGhhdCB0aGUgY29tbWl0VG9IaXN0b3J5IGZsYWcgaXNuJ3QgcmVzZXQgdmlhIGN1cnJlbnQgdXBkYXRlXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgLy8gZXhlY3V0ZSBvbmx5IGlmIHRoZSBjb25kaXRpb24gc3RpbGwgaG9sZHMgd2hlbiB0aGUgZGVmZXJyZWQgY2FsbGJhY2tcbiAgICAgICAgLy8gZXhlY3V0ZXMgKGl0IGNhbiBiZSBzY2hlZHVsZWQgbXVsdGlwbGUgdGltZXMgZGVwZW5kaW5nIG9uIGhvd1xuICAgICAgICAvLyBtYW55IHRpbWVzIHRoZSBjb21wb25lbnQgcmVuZGVycylcbiAgICAgICAgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICB9KTtcbiAgICB9IC8vIGZhaWxzYWZlIGluIGNhc2UgdGhlIHN0YXRlIGlzIGJlaW5nIHVwZGF0ZWQgaW4gaW5jb3JyZWN0IG9yZGVyIHJlc3VsdGluZ1xuICAgIC8vIGluIHRoZSBlZGl0aW5nRWxlbWVudCBiZWluZyBub3cgYSBkZWxldGVkIGVsZW1lbnRcblxuXG4gICAgaWYgKChfZCA9IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5pc0RlbGV0ZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBlZGl0aW5nRWxlbWVudDogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1t0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5lbGVtZW50SWRdKSB7XG4gICAgICAvLyBUbyBtYWtlIHN1cmUgYHNlbGVjdGVkTGluZWFyRWxlbWVudGAgaXMgaW4gc3luYyB3aXRoIGBzZWxlY3RlZEVsZW1lbnRJZHNgLCBob3dldmVyIHRoaXMgc2hvdWxkbid0IGJlIG5lZWRlZCBvbmNlXG4gICAgICAvLyB3ZSBoYXZlIGEgc2luZ2xlIEFQSSB0byB1cGRhdGUgYHNlbGVjdGVkRWxlbWVudElkc2BcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG51bGxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IHtcbiAgICAgIG11bHRpRWxlbWVudFxuICAgIH0gPSBwcmV2U3RhdGU7XG5cbiAgICBpZiAocHJldlN0YXRlLmFjdGl2ZVRvb2wgIT09IHRoaXMuc3RhdGUuYWN0aXZlVG9vbCAmJiBtdWx0aUVsZW1lbnQgIT0gbnVsbCAmJiBpc0JpbmRpbmdFbmFibGVkKHRoaXMuc3RhdGUpICYmIGlzQmluZGluZ0VsZW1lbnQobXVsdGlFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgIG1heWJlQmluZExpbmVhckVsZW1lbnQobXVsdGlFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLCB0dXBsZVRvQ29vcnMoTGluZWFyRWxlbWVudEVkaXRvci5nZXRQb2ludEF0SW5kZXhHbG9iYWxDb29yZGluYXRlcyhtdWx0aUVsZW1lbnQsIC0xKSkpO1xuICAgIH1cblxuICAgIHRoaXMuaGlzdG9yeS5yZWNvcmQodGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSk7IC8vIERvIG5vdCBub3RpZnkgY29uc3VtZXJzIGlmIHdlJ3JlIHN0aWxsIGxvYWRpbmcgdGhlIHNjZW5lLiBBbW9uZyBvdGhlclxuICAgIC8vIHBvdGVudGlhbCBpc3N1ZXMsIHRoaXMgZml4ZXMgYSBjYXNlIHdoZXJlIHRoZSB0YWIgaXNuJ3QgZm9jdXNlZCBkdXJpbmdcbiAgICAvLyBpbml0LCB3aGljaCB3b3VsZCB0cmlnZ2VyIG9uQ2hhbmdlIHdpdGggZW1wdHkgZWxlbWVudHMsIHdoaWNoIHdvdWxkIHRoZW5cbiAgICAvLyBvdmVycmlkZSB3aGF0ZXZlciBpcyBpbiBsb2NhbFN0b3JhZ2UgY3VycmVudGx5LlxuXG4gICAgaWYgKCF0aGlzLnN0YXRlLmlzTG9hZGluZykge1xuICAgICAgKF9mID0gKF9lID0gdGhpcy5wcm9wcykub25DaGFuZ2UpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5jYWxsKF9lLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzLnN0YXRlLCB0aGlzLmZpbGVzKTtcbiAgICAgIHRoaXMub25DaGFuZ2VFbWl0dGVyLnRyaWdnZXIodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcyk7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIHJlc2V0VGFwVHdpY2UoKSB7XG4gICAgZGlkVGFwVHdpY2UgPSBmYWxzZTtcbiAgfSAvLyBUT0RPIHJld3JpdGUgdGhpcyB0byBwYXN0ZSBib3RoIHRleHQgJiBpbWFnZXMgYXQgdGhlIHNhbWUgdGltZSBpZlxuICAvLyBwYXN0ZWQgZGF0YSBjb250YWlucyBib3RoXG5cblxuICBhZGRFbGVtZW50c0Zyb21NaXhlZENvbnRlbnRQYXN0ZShtaXhlZENvbnRlbnQsIHtcbiAgICBpc1BsYWluUGFzdGUsXG4gICAgc2NlbmVYLFxuICAgIHNjZW5lWVxuICB9KSB7XG4gICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGlmICghaXNQbGFpblBhc3RlICYmIG1peGVkQ29udGVudC5zb21lKG5vZGUgPT4gbm9kZS50eXBlID09PSBcImltYWdlVXJsXCIpKSB7XG4gICAgICAgIGNvbnN0IGltYWdlVVJMcyA9IG1peGVkQ29udGVudC5maWx0ZXIobm9kZSA9PiBub2RlLnR5cGUgPT09IFwiaW1hZ2VVcmxcIikubWFwKG5vZGUgPT4gbm9kZS52YWx1ZSk7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlcyA9IHlpZWxkIFByb21pc2UuYWxsKGltYWdlVVJMcy5tYXAodXJsID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgZmlsZTogeWllbGQgSW1hZ2VVUkxUb0ZpbGUodXJsKVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5tZXNzYWdlXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgfSkpKTtcbiAgICAgICAgbGV0IHkgPSBzY2VuZVk7XG4gICAgICAgIGxldCBmaXJzdEltYWdlWU9mZnNldERvbmUgPSBmYWxzZTtcbiAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkSWRzID0ge307XG5cbiAgICAgICAgZm9yIChjb25zdCByZXNwb25zZSBvZiByZXNwb25zZXMpIHtcbiAgICAgICAgICBpZiAocmVzcG9uc2UuZmlsZSkge1xuICAgICAgICAgICAgY29uc3QgaW1hZ2VFbGVtZW50ID0gdGhpcy5jcmVhdGVJbWFnZUVsZW1lbnQoe1xuICAgICAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgICAgIHNjZW5lWTogeVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb25zdCBpbml0aWFsaXplZEltYWdlRWxlbWVudCA9IHlpZWxkIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgcmVzcG9uc2UuZmlsZSk7XG5cbiAgICAgICAgICAgIGlmIChpbml0aWFsaXplZEltYWdlRWxlbWVudCkge1xuICAgICAgICAgICAgICAvLyB2ZXJ0aWNhbGx5IGNlbnRlciBmaXJzdCBpbWFnZSBpbiB0aGUgYmF0Y2hcbiAgICAgICAgICAgICAgaWYgKCFmaXJzdEltYWdlWU9mZnNldERvbmUpIHtcbiAgICAgICAgICAgICAgICBmaXJzdEltYWdlWU9mZnNldERvbmUgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHkgLT0gaW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQuaGVpZ2h0IC8gMjtcbiAgICAgICAgICAgICAgfSAvLyBoYWNrIHRvIHJlc2V0IHRoZSBgeWAgY29vcmQgYmVjYXVzZSB3ZSB2ZXJ0aWNhbGx5IGNlbnRlciBkdXJpbmdcbiAgICAgICAgICAgICAgLy8gaW5zZXJ0SW1hZ2VFbGVtZW50XG5cblxuICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGluaXRpYWxpemVkSW1hZ2VFbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgeVxuICAgICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICAgIHkgPSBpbWFnZUVsZW1lbnQueSArIGltYWdlRWxlbWVudC5oZWlnaHQgKyAyNTtcbiAgICAgICAgICAgICAgbmV4dFNlbGVjdGVkSWRzW2ltYWdlRWxlbWVudC5pZF0gPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMobmV4dFNlbGVjdGVkSWRzLCB0aGlzLnN0YXRlKVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgZXJyb3IgPSByZXNwb25zZXMuZmluZChyZXNwb25zZSA9PiAhIXJlc3BvbnNlLmVycm9yTWVzc2FnZSk7XG5cbiAgICAgICAgaWYgKGVycm9yICYmIGVycm9yLmVycm9yTWVzc2FnZSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvci5lcnJvck1lc3NhZ2VcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgdGV4dE5vZGVzID0gbWl4ZWRDb250ZW50LmZpbHRlcihub2RlID0+IG5vZGUudHlwZSA9PT0gXCJ0ZXh0XCIpO1xuXG4gICAgICAgIGlmICh0ZXh0Tm9kZXMubGVuZ3RoKSB7XG4gICAgICAgICAgdGhpcy5hZGRUZXh0RnJvbVBhc3RlKHRleHROb2Rlcy5tYXAobm9kZSA9PiBub2RlLnZhbHVlKS5qb2luKFwiXFxuXFxuXCIpLCBpc1BsYWluUGFzdGUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBhZGRUZXh0RnJvbVBhc3RlKHRleHQsIGlzUGxhaW5QYXN0ZSA9IGZhbHNlKSB7XG4gICAgY29uc3Qge1xuICAgICAgeCxcbiAgICAgIHlcbiAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgIGNsaWVudFg6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCxcbiAgICAgIGNsaWVudFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueVxuICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IHRleHRFbGVtZW50UHJvcHMgPSB7XG4gICAgICB4LFxuICAgICAgeSxcbiAgICAgIHN0cm9rZUNvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlQ29sb3IsXG4gICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgIHJvdW5kbmVzczogbnVsbCxcbiAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgdGV4dCxcbiAgICAgIGZvbnRTaXplOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRm9udFNpemUsXG4gICAgICBmb250RmFtaWx5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRm9udEZhbWlseSxcbiAgICAgIHRleHRBbGlnbjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVRleHRBbGlnbixcbiAgICAgIHZlcnRpY2FsQWxpZ246IERFRkFVTFRfVkVSVElDQUxfQUxJR04sXG4gICAgICBsb2NrZWQ6IGZhbHNlXG4gICAgfTtcbiAgICBjb25zdCBMSU5FX0dBUCA9IDEwO1xuICAgIGxldCBjdXJyZW50WSA9IHk7XG4gICAgY29uc3QgbGluZXMgPSBpc1BsYWluUGFzdGUgPyBbdGV4dF0gOiB0ZXh0LnNwbGl0KFwiXFxuXCIpO1xuICAgIGNvbnN0IHRleHRFbGVtZW50cyA9IGxpbmVzLnJlZHVjZSgoYWNjLCBsaW5lLCBpZHgpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgdGV4dCA9IGxpbmUudHJpbSgpO1xuICAgICAgY29uc3QgbGluZUhlaWdodCA9IGdldERlZmF1bHRMaW5lSGVpZ2h0KHRleHRFbGVtZW50UHJvcHMuZm9udEZhbWlseSk7XG5cbiAgICAgIGlmICh0ZXh0Lmxlbmd0aCkge1xuICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5OiBjdXJyZW50WVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IG5ld1RleHRFbGVtZW50KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGV4dEVsZW1lbnRQcm9wcyksIHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHk6IGN1cnJlbnRZLFxuICAgICAgICAgIHRleHQsXG4gICAgICAgICAgbGluZUhlaWdodCxcbiAgICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgICAgfSkpO1xuICAgICAgICBhY2MucHVzaChlbGVtZW50KTtcbiAgICAgICAgY3VycmVudFkgKz0gZWxlbWVudC5oZWlnaHQgKyBMSU5FX0dBUDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHByZXZMaW5lID0gKF9hID0gbGluZXNbaWR4IC0gMV0pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS50cmltKCk7IC8vIGFkZCBwYXJhZ3JhcGggb25seSBpZiBwcmV2aW91cyBsaW5lIHdhcyBub3QgZW1wdHksIElPVyBkb24ndCBhZGRcbiAgICAgICAgLy8gbW9yZSB0aGFuIG9uZSBlbXB0eSBsaW5lXG5cbiAgICAgICAgaWYgKHByZXZMaW5lKSB7XG4gICAgICAgICAgY3VycmVudFkgKz0gZ2V0TGluZUhlaWdodEluUHgodGV4dEVsZW1lbnRQcm9wcy5mb250U2l6ZSwgbGluZUhlaWdodCkgKyBMSU5FX0dBUDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sIFtdKTtcblxuICAgIGlmICh0ZXh0RWxlbWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgZnJhbWVJZCA9IHRleHRFbGVtZW50c1swXS5mcmFtZUlkO1xuXG4gICAgaWYgKGZyYW1lSWQpIHtcbiAgICAgIHRoaXMuc2NlbmUuaW5zZXJ0RWxlbWVudHNBdEluZGV4KHRleHRFbGVtZW50cywgdGhpcy5zY2VuZS5nZXRFbGVtZW50SW5kZXgoZnJhbWVJZCkpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgLi4udGV4dEVsZW1lbnRzXSk7XG4gICAgfVxuXG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5mcm9tRW50cmllcyh0ZXh0RWxlbWVudHMubWFwKGVsID0+IFtlbC5pZCwgdHJ1ZV0pKSwgdGhpcy5zdGF0ZSlcbiAgICB9KTtcblxuICAgIGlmICghaXNQbGFpblBhc3RlICYmIHRleHRFbGVtZW50cy5sZW5ndGggPiAxICYmIFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID09PSBmYWxzZSAmJiAhdGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlKSB7XG4gICAgICB0aGlzLnNldFRvYXN0KHtcbiAgICAgICAgbWVzc2FnZTogdChcInRvYXN0LnBhc3RlQXNTaW5nbGVFbGVtZW50XCIsIHtcbiAgICAgICAgICBzaG9ydGN1dDogZ2V0U2hvcnRjdXRLZXkoXCJDdHJsT3JDbWQrU2hpZnQrVlwiKVxuICAgICAgICB9KSxcbiAgICAgICAgZHVyYXRpb246IDUwMDBcbiAgICAgIH0pO1xuICAgICAgUExBSU5fUEFTVEVfVE9BU1RfU0hPV04gPSB0cnVlO1xuICAgIH1cblxuICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgfVxuXG4gIGhhbmRsZVRleHRXeXNpd3lnKGVsZW1lbnQsIHtcbiAgICBpc0V4aXN0aW5nRWxlbWVudCA9IGZhbHNlXG4gIH0pIHtcbiAgICBjb25zdCB1cGRhdGVFbGVtZW50ID0gKHRleHQsIG9yaWdpbmFsVGV4dCwgaXNEZWxldGVkKSA9PiB7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5tYXAoX2VsZW1lbnQgPT4ge1xuICAgICAgICBpZiAoX2VsZW1lbnQuaWQgPT09IGVsZW1lbnQuaWQgJiYgaXNUZXh0RWxlbWVudChfZWxlbWVudCkpIHtcbiAgICAgICAgICByZXR1cm4gdXBkYXRlVGV4dEVsZW1lbnQoX2VsZW1lbnQsIHtcbiAgICAgICAgICAgIHRleHQsXG4gICAgICAgICAgICBpc0RlbGV0ZWQsXG4gICAgICAgICAgICBvcmlnaW5hbFRleHRcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBfZWxlbWVudDtcbiAgICAgIH0pXSk7XG4gICAgfTtcblxuICAgIHRleHRXeXNpd3lnKHtcbiAgICAgIGlkOiBlbGVtZW50LmlkLFxuICAgICAgY2FudmFzOiB0aGlzLmNhbnZhcyxcbiAgICAgIGdldFZpZXdwb3J0Q29vcmRzOiAoeCwgeSkgPT4ge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogdmlld3BvcnRYLFxuICAgICAgICAgIHk6IHZpZXdwb3J0WVxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IHgsXG4gICAgICAgICAgc2NlbmVZOiB5XG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICByZXR1cm4gW3ZpZXdwb3J0WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgdmlld3BvcnRZIC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3BdO1xuICAgICAgfSxcbiAgICAgIG9uQ2hhbmdlOiB3aXRoQmF0Y2hlZFVwZGF0ZXModGV4dCA9PiB7XG4gICAgICAgIHVwZGF0ZUVsZW1lbnQodGV4dCwgdGV4dCwgZmFsc2UpO1xuXG4gICAgICAgIGlmIChpc05vbkRlbGV0ZWRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgdXBkYXRlQm91bmRFbGVtZW50cyhlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSksXG4gICAgICBvblN1Ym1pdDogd2l0aEJhdGNoZWRVcGRhdGVzKCh7XG4gICAgICAgIHRleHQsXG4gICAgICAgIHZpYUtleWJvYXJkLFxuICAgICAgICBvcmlnaW5hbFRleHRcbiAgICAgIH0pID0+IHtcbiAgICAgICAgY29uc3QgaXNEZWxldGVkID0gIXRleHQudHJpbSgpO1xuICAgICAgICB1cGRhdGVFbGVtZW50KHRleHQsIG9yaWdpbmFsVGV4dCwgaXNEZWxldGVkKTsgLy8gc2VsZWN0IHRoZSBjcmVhdGVkIHRleHQgZWxlbWVudCBvbmx5IGlmIHN1Ym1pdHRpbmcgdmlhIGtleWJvYXJkXG4gICAgICAgIC8vICh3aGVuIHN1Ym1pdHRpbmcgdmlhIGNsaWNrIGl0IHNob3VsZCBhY3QgYXMgc2lnbmFsIHRvIGRlc2VsZWN0KVxuXG4gICAgICAgIGlmICghaXNEZWxldGVkICYmIHZpYUtleWJvYXJkKSB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudElkVG9TZWxlY3QgPSBlbGVtZW50LmNvbnRhaW5lcklkID8gZWxlbWVudC5jb250YWluZXJJZCA6IGVsZW1lbnQuaWQ7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICBbZWxlbWVudElkVG9TZWxlY3RdOiB0cnVlXG4gICAgICAgICAgICB9KSwgcHJldlN0YXRlKVxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpc0RlbGV0ZWQpIHtcbiAgICAgICAgICBmaXhCaW5kaW5nc0FmdGVyRGVsZXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgW2VsZW1lbnRdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaXNEZWxldGVkIHx8IGlzRXhpc3RpbmdFbGVtZW50KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmZvY3VzQ29udGFpbmVyKCk7XG4gICAgICB9KSxcbiAgICAgIGVsZW1lbnQsXG4gICAgICBleGNhbGlkcmF3Q29udGFpbmVyOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCxcbiAgICAgIGFwcDogdGhpc1xuICAgIH0pOyAvLyBkZXNlbGVjdCBhbGwgb3RoZXIgZWxlbWVudHMgd2hlbiBpbnNlcnRpbmcgdGV4dFxuXG4gICAgdGhpcy5kZXNlbGVjdEVsZW1lbnRzKCk7IC8vIGRvIGFuIGluaXRpYWwgdXBkYXRlIHRvIHJlLWluaXRpYWxpemUgZWxlbWVudCBwb3NpdGlvbiBzaW5jZSB3ZSB3ZXJlXG4gICAgLy8gbW9kaWZ5aW5nIGVsZW1lbnQncyB4L3kgZm9yIHNha2Ugb2YgZWRpdG9yIChjYXNlOiBzeW5jaW5nIHRvIHJlbW90ZSlcblxuICAgIHVwZGF0ZUVsZW1lbnQoZWxlbWVudC50ZXh0LCBlbGVtZW50Lm9yaWdpbmFsVGV4dCwgZmFsc2UpO1xuICB9XG5cbiAgZGVzZWxlY3RFbGVtZW50cygpIHtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICB9KTtcbiAgfVxuXG4gIGdldFRleHRFbGVtZW50QXRQb3NpdGlvbih4LCB5KSB7XG4gICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oeCwgeSwge1xuICAgICAgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQ6IHRydWVcbiAgICB9KTtcblxuICAgIGlmIChlbGVtZW50ICYmIGlzVGV4dEVsZW1lbnQoZWxlbWVudCkgJiYgIWVsZW1lbnQuaXNEZWxldGVkKSB7XG4gICAgICByZXR1cm4gZWxlbWVudDtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGdldEVsZW1lbnRBdFBvc2l0aW9uKHgsIHksIG9wdHMpIHtcbiAgICBjb25zdCBhbGxIaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHgsIHksIG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5pbmNsdWRlQm91bmRUZXh0RWxlbWVudCwgb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmluY2x1ZGVMb2NrZWRFbGVtZW50cyk7XG5cbiAgICBpZiAoYWxsSGl0RWxlbWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgaWYgKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5wcmVmZXJTZWxlY3RlZCkge1xuICAgICAgICBmb3IgKGxldCBpbmRleCA9IGFsbEhpdEVsZW1lbnRzLmxlbmd0aCAtIDE7IGluZGV4ID4gLTE7IGluZGV4LS0pIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbYWxsSGl0RWxlbWVudHNbaW5kZXhdLmlkXSkge1xuICAgICAgICAgICAgcmV0dXJuIGFsbEhpdEVsZW1lbnRzW2luZGV4XTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudFdpdGhIaWdoZXN0WkluZGV4ID0gYWxsSGl0RWxlbWVudHNbYWxsSGl0RWxlbWVudHMubGVuZ3RoIC0gMV07IC8vIElmIHdlJ3JlIGhpdHRpbmcgZWxlbWVudCB3aXRoIGhpZ2hlc3Qgei1pbmRleCBvbmx5IG9uIGl0cyBib3VuZGluZyBib3hcbiAgICAgIC8vIHdoaWxlIGFsc28gaGl0dGluZyBvdGhlciBlbGVtZW50IGZpZ3VyZSwgdGhlIGxhdHRlciBzaG91bGQgYmUgY29uc2lkZXJlZC5cblxuICAgICAgcmV0dXJuIGlzSGl0dGluZ0VsZW1lbnRCb3VuZGluZ0JveFdpdGhvdXRIaXR0aW5nRWxlbWVudChlbGVtZW50V2l0aEhpZ2hlc3RaSW5kZXgsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHgsIHkpID8gYWxsSGl0RWxlbWVudHNbYWxsSGl0RWxlbWVudHMubGVuZ3RoIC0gMl0gOiBlbGVtZW50V2l0aEhpZ2hlc3RaSW5kZXg7XG4gICAgfVxuXG4gICAgaWYgKGFsbEhpdEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcmV0dXJuIGFsbEhpdEVsZW1lbnRzWzBdO1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHgsIHksIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50ID0gZmFsc2UsIGluY2x1ZGVMb2NrZWRFbGVtZW50cyA9IGZhbHNlKSB7XG4gICAgY29uc3QgZWxlbWVudHMgPSBpbmNsdWRlQm91bmRUZXh0RWxlbWVudCAmJiBpbmNsdWRlTG9ja2VkRWxlbWVudHMgPyB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpIDogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiAoaW5jbHVkZUxvY2tlZEVsZW1lbnRzIHx8ICFlbGVtZW50LmxvY2tlZCkgJiYgKGluY2x1ZGVCb3VuZFRleHRFbGVtZW50IHx8ICEoaXNUZXh0RWxlbWVudChlbGVtZW50KSAmJiBlbGVtZW50LmNvbnRhaW5lcklkKSkpO1xuICAgIHJldHVybiBnZXRFbGVtZW50c0F0UG9zaXRpb24oZWxlbWVudHMsIGVsZW1lbnQgPT4gaGl0VGVzdChlbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCB4LCB5KSkuZmlsdGVyKGVsZW1lbnQgPT4ge1xuICAgICAgLy8gaGl0dGluZyBhIGZyYW1lJ3MgZWxlbWVudCBmcm9tIG91dHNpZGUgdGhlIGZyYW1lIGlzIG5vdCBjb25zaWRlcmVkIGEgaGl0XG4gICAgICBjb25zdCBjb250YWluaW5nRnJhbWUgPSBnZXRDb250YWluaW5nRnJhbWUoZWxlbWVudCk7XG4gICAgICByZXR1cm4gY29udGFpbmluZ0ZyYW1lICYmIHRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCAmJiB0aGlzLnN0YXRlLmZyYW1lUmVuZGVyaW5nLmNsaXAgPyBpc0N1cnNvckluRnJhbWUoe1xuICAgICAgICB4LFxuICAgICAgICB5XG4gICAgICB9LCBjb250YWluaW5nRnJhbWUpIDogdHJ1ZTtcbiAgICB9KTtcbiAgfVxuXG4gIGhhbmRsZUhvdmVyU2VsZWN0ZWRMaW5lYXJFbGVtZW50KGxpbmVhckVsZW1lbnRFZGl0b3IsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpIHtcbiAgICBjb25zdCBlbGVtZW50ID0gTGluZWFyRWxlbWVudEVkaXRvci5nZXRFbGVtZW50KGxpbmVhckVsZW1lbnRFZGl0b3IuZWxlbWVudElkKTtcbiAgICBjb25zdCBib3VuZFRleHRFbGVtZW50ID0gZ2V0Qm91bmRUZXh0RWxlbWVudChlbGVtZW50KTtcblxuICAgIGlmICghZWxlbWVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgbGV0IGhvdmVyUG9pbnRJbmRleCA9IC0xO1xuICAgICAgbGV0IHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMgPSBudWxsO1xuXG4gICAgICBpZiAoaXNIaXR0aW5nRWxlbWVudE5vdENvbnNpZGVyaW5nQm91bmRpbmdCb3goZWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgW3NjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclldKSkge1xuICAgICAgICBob3ZlclBvaW50SW5kZXggPSBMaW5lYXJFbGVtZW50RWRpdG9yLmdldFBvaW50SW5kZXhVbmRlckN1cnNvcihlbGVtZW50LCB0aGlzLnN0YXRlLnpvb20sIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpO1xuICAgICAgICBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzID0gTGluZWFyRWxlbWVudEVkaXRvci5nZXRTZWdtZW50TWlkcG9pbnRIaXRDb29yZHMobGluZWFyRWxlbWVudEVkaXRvciwge1xuICAgICAgICAgIHg6IHNjZW5lUG9pbnRlclgsXG4gICAgICAgICAgeTogc2NlbmVQb2ludGVyWVxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoaG92ZXJQb2ludEluZGV4ID49IDAgfHwgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3Jkcykge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5QT0lOVEVSKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc2hvdWxkU2hvd0JvdW5kaW5nQm94KFtlbGVtZW50XSwgdGhpcy5zdGF0ZSkgJiYgaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50KGVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5NT1ZFKTtcbiAgICAgIH0gZWxzZSBpZiAoYm91bmRUZXh0RWxlbWVudCAmJiBoaXRUZXN0KGJvdW5kVGV4dEVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclkpKSB7XG4gICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5NT1ZFKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmhvdmVyUG9pbnRJbmRleCAhPT0gaG92ZXJQb2ludEluZGV4KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgIGhvdmVyUG9pbnRJbmRleFxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoIUxpbmVhckVsZW1lbnRFZGl0b3IuYXJlUG9pbnRzRXF1YWwodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3Jkcywgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3JkcykpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3Jkc1xuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQVVUTyk7XG4gICAgfVxuICB9XG5cbiAgbWF5YmVDbGVhbnVwQWZ0ZXJNaXNzaW5nUG9pbnRlclVwKGV2ZW50KSB7XG4gICAgaWYgKGxhc3RQb2ludGVyVXAgIT09IG51bGwpIHtcbiAgICAgIC8vIFVuZm9ydHVuYXRlbHksIHNvbWV0aW1lcyB3ZSBkb24ndCBnZXQgYSBwb2ludGVydXAgYWZ0ZXIgYSBwb2ludGVyZG93bixcbiAgICAgIC8vIHRoaXMgY2FuIGhhcHBlbiB3aGVuIGEgY29udGV4dHVhbCBtZW51IG9yIGFsZXJ0IGlzIHRyaWdnZXJlZC4gSW4gb3JkZXIgdG8gYXZvaWRcbiAgICAgIC8vIGJlaW5nIGluIGEgd2VpcmQgc3RhdGUsIHdlIGNsZWFuIHVwIG9uIHRoZSBuZXh0IHBvaW50ZXJkb3duXG4gICAgICBsYXN0UG9pbnRlclVwKGV2ZW50KTtcbiAgICB9XG4gIH1cblxuICB1cGRhdGVHZXN0dXJlT25Qb2ludGVyRG93bihldmVudCkge1xuICAgIGdlc3R1cmUucG9pbnRlcnMuc2V0KGV2ZW50LnBvaW50ZXJJZCwge1xuICAgICAgeDogZXZlbnQuY2xpZW50WCxcbiAgICAgIHk6IGV2ZW50LmNsaWVudFlcbiAgICB9KTtcblxuICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLnNpemUgPT09IDIpIHtcbiAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGdldENlbnRlcihnZXN0dXJlLnBvaW50ZXJzKTtcbiAgICAgIGdlc3R1cmUuaW5pdGlhbFNjYWxlID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgZ2VzdHVyZS5pbml0aWFsRGlzdGFuY2UgPSBnZXREaXN0YW5jZShBcnJheS5mcm9tKGdlc3R1cmUucG9pbnRlcnMudmFsdWVzKCkpKTtcbiAgICB9XG4gIH1cblxuICBpbml0aWFsUG9pbnRlckRvd25TdGF0ZShldmVudCkge1xuICAgIGNvbnN0IG9yaWdpbiA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICBjb25zdCBbbWluWCwgbWluWSwgbWF4WCwgbWF4WV0gPSBnZXRDb21tb25Cb3VuZHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgcmV0dXJuIHtcbiAgICAgIG9yaWdpbixcbiAgICAgIHdpdGhDbWRPckN0cmw6IGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdLFxuICAgICAgb3JpZ2luSW5HcmlkOiB0dXBsZVRvQ29vcnMoZ2V0R3JpZFBvaW50KG9yaWdpbi54LCBvcmlnaW4ueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSkpLFxuICAgICAgc2Nyb2xsYmFyczogaXNPdmVyU2Nyb2xsQmFycyhjdXJyZW50U2Nyb2xsQmFycywgZXZlbnQuY2xpZW50WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgZXZlbnQuY2xpZW50WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wKSxcbiAgICAgIC8vIHdlIG5lZWQgdG8gZHVwbGljYXRlIGJlY2F1c2Ugd2UnbGwgYmUgdXBkYXRpbmcgdGhpcyBzdGF0ZVxuICAgICAgbGFzdENvb3JkczogT2JqZWN0LmFzc2lnbih7fSwgb3JpZ2luKSxcbiAgICAgIG9yaWdpbmFsRWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkucmVkdWNlKChhY2MsIGVsZW1lbnQpID0+IHtcbiAgICAgICAgYWNjLnNldChlbGVtZW50LmlkLCBkZWVwQ29weUVsZW1lbnQoZWxlbWVudCkpO1xuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwgbmV3IE1hcCgpKSxcbiAgICAgIHJlc2l6ZToge1xuICAgICAgICBoYW5kbGVUeXBlOiBmYWxzZSxcbiAgICAgICAgaXNSZXNpemluZzogZmFsc2UsXG4gICAgICAgIG9mZnNldDoge1xuICAgICAgICAgIHg6IDAsXG4gICAgICAgICAgeTogMFxuICAgICAgICB9LFxuICAgICAgICBhcnJvd0RpcmVjdGlvbjogXCJvcmlnaW5cIixcbiAgICAgICAgY2VudGVyOiB7XG4gICAgICAgICAgeDogKG1heFggKyBtaW5YKSAvIDIsXG4gICAgICAgICAgeTogKG1heFkgKyBtaW5ZKSAvIDJcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGhpdDoge1xuICAgICAgICBlbGVtZW50OiBudWxsLFxuICAgICAgICBhbGxIaXRFbGVtZW50czogW10sXG4gICAgICAgIHdhc0FkZGVkVG9TZWxlY3Rpb246IGZhbHNlLFxuICAgICAgICBoYXNCZWVuRHVwbGljYXRlZDogZmFsc2UsXG4gICAgICAgIGhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzOiB0aGlzLmlzSGl0dGluZ0NvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKG9yaWdpbiwgc2VsZWN0ZWRFbGVtZW50cylcbiAgICAgIH0sXG4gICAgICBkcmFnOiB7XG4gICAgICAgIGhhc09jY3VycmVkOiBmYWxzZSxcbiAgICAgICAgb2Zmc2V0OiBudWxsXG4gICAgICB9LFxuICAgICAgZXZlbnRMaXN0ZW5lcnM6IHtcbiAgICAgICAgb25Nb3ZlOiBudWxsLFxuICAgICAgICBvblVwOiBudWxsLFxuICAgICAgICBvbktleVVwOiBudWxsLFxuICAgICAgICBvbktleURvd246IG51bGxcbiAgICAgIH0sXG4gICAgICBib3hTZWxlY3Rpb246IHtcbiAgICAgICAgaGFzT2NjdXJyZWQ6IGZhbHNlXG4gICAgICB9LFxuICAgICAgZWxlbWVudElkc1RvRXJhc2U6IHt9XG4gICAgfTtcbiAgfSAvLyBSZXR1cm5zIHdoZXRoZXIgdGhlIGV2ZW50IGlzIGEgZHJhZ2dpbmcgYSBzY3JvbGxiYXJcblxuXG4gIGhhbmRsZURyYWdnaW5nU2Nyb2xsQmFyKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKSB7XG4gICAgaWYgKCEocG9pbnRlckRvd25TdGF0ZS5zY3JvbGxiYXJzLmlzT3ZlckVpdGhlciAmJiAhdGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaXNEcmFnZ2luZ1Njcm9sbEJhciA9IHRydWU7XG4gICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBldmVudC5jbGllbnRYO1xuICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gZXZlbnQuY2xpZW50WTtcbiAgICBjb25zdCBvblBvaW50ZXJNb3ZlID0gd2l0aEJhdGNoZWRVcGRhdGVzVGhyb3R0bGVkKGV2ZW50ID0+IHtcbiAgICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldDtcblxuICAgICAgaWYgKCEodGFyZ2V0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5oYW5kbGVQb2ludGVyTW92ZU92ZXJTY3JvbGxiYXJzKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKTtcbiAgICB9KTtcbiAgICBjb25zdCBvblBvaW50ZXJVcCA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gZmFsc2U7XG4gICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgIGxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGN1cnNvckJ1dHRvbjogXCJ1cFwiXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgXCJ1cFwiKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBvblBvaW50ZXJVcCk7XG4gICAgICBvblBvaW50ZXJNb3ZlLmZsdXNoKCk7XG4gICAgfSk7XG4gICAgbGFzdFBvaW50ZXJVcCA9IG9uUG9pbnRlclVwO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgb25Qb2ludGVyVXApO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgaXNBU2VsZWN0ZWRFbGVtZW50KGhpdEVsZW1lbnQpIHtcbiAgICByZXR1cm4gaGl0RWxlbWVudCAhPSBudWxsICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdO1xuICB9XG5cbiAgaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMocG9pbnQsIHNlbGVjdGVkRWxlbWVudHMpIHtcbiAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPCAyKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSAvLyBIb3cgbWFueSBwaXhlbHMgb2ZmIHRoZSBzaGFwZSBib3VuZGFyeSB3ZSBzdGlsbCBjb25zaWRlciBhIGhpdFxuXG5cbiAgICBjb25zdCB0aHJlc2hvbGQgPSAxMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICBjb25zdCBbeDEsIHkxLCB4MiwgeTJdID0gZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgIHJldHVybiBwb2ludC54ID4geDEgLSB0aHJlc2hvbGQgJiYgcG9pbnQueCA8IHgyICsgdGhyZXNob2xkICYmIHBvaW50LnkgPiB5MSAtIHRocmVzaG9sZCAmJiBwb2ludC55IDwgeTIgKyB0aHJlc2hvbGQ7XG4gIH1cblxuICBnZXRDdXJyZW50SXRlbVJvdW5kbmVzcyhlbGVtZW50VHlwZSkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91bmRuZXNzID09PSBcInJvdW5kXCIgPyB7XG4gICAgICB0eXBlOiBpc1VzaW5nQWRhcHRpdmVSYWRpdXMoZWxlbWVudFR5cGUpID8gUk9VTkRORVNTLkFEQVBUSVZFX1JBRElVUyA6IFJPVU5ETkVTUy5QUk9QT1JUSU9OQUxfUkFESVVTXG4gICAgfSA6IG51bGw7XG4gIH1cblxuICBtYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgcmVjb21wdXRlQW55d2F5cyA9IGZhbHNlKSB7XG4gICAgaWYgKGlzU25hcHBpbmdFbmFibGVkKHtcbiAgICAgIGV2ZW50LFxuICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICBzZWxlY3RlZEVsZW1lbnRzXG4gICAgfSkgJiYgKHJlY29tcHV0ZUFueXdheXMgfHwgIVNuYXBDYWNoZS5nZXRSZWZlcmVuY2VTbmFwUG9pbnRzKCkpKSB7XG4gICAgICBTbmFwQ2FjaGUuc2V0UmVmZXJlbmNlU25hcFBvaW50cyhnZXRSZWZlcmVuY2VTbmFwUG9pbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHNlbGVjdGVkRWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcbiAgICB9XG4gIH1cblxuICBtYXliZUNhY2hlVmlzaWJsZUdhcHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMsIHJlY29tcHV0ZUFueXdheXMgPSBmYWxzZSkge1xuICAgIGlmIChpc1NuYXBwaW5nRW5hYmxlZCh7XG4gICAgICBldmVudCxcbiAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgc2VsZWN0ZWRFbGVtZW50c1xuICAgIH0pICYmIChyZWNvbXB1dGVBbnl3YXlzIHx8ICFTbmFwQ2FjaGUuZ2V0VmlzaWJsZUdhcHMoKSkpIHtcbiAgICAgIFNuYXBDYWNoZS5zZXRWaXNpYmxlR2FwcyhnZXRWaXNpYmxlR2Fwcyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBzZWxlY3RlZEVsZW1lbnRzLCB0aGlzLnN0YXRlKSk7XG4gICAgfVxuICB9XG5cbiAgb25LZXlEb3duRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uS2V5VXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIFByZXZlbnRzIGZvY3VzIGZyb20gZXNjYXBpbmcgZXhjYWxpZHJhdyB0YWJcbiAgICAgIGV2ZW50LmtleSA9PT0gS0VZUy5BTFQgJiYgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKHRoaXMubWF5YmVIYW5kbGVSZXNpemUocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudChwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgfSk7XG4gIH1cblxuICBvblBvaW50ZXJNb3ZlRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlc1Rocm90dGxlZChldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iOyAvLyBXZSBuZWVkIHRvIGluaXRpYWxpemUgZHJhZ09mZnNldFhZIG9ubHkgYWZ0ZXIgd2UndmUgdXBkYXRlZFxuICAgICAgLy8gYHN0YXRlLnNlbGVjdGVkRWxlbWVudElkc2Agb24gcG9pbnRlckRvd24uIERvaW5nIGl0IGhlcmUgaW4gcG9pbnRlck1vdmVcbiAgICAgIC8vIGV2ZW50IGhhbmRsZXIgc2hvdWxkIGhvcGVmdWxseSBlbnN1cmUgd2UncmUgYWxyZWFkeSB3b3JraW5nIHdpdGhcbiAgICAgIC8vIHRoZSB1cGRhdGVkIHN0YXRlLlxuXG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcub2Zmc2V0ID09PSBudWxsKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5vZmZzZXQgPSB0dXBsZVRvQ29vcnMoZ2V0RHJhZ09mZnNldFhZKHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQ7XG5cbiAgICAgIGlmICghKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICB0aGlzLmhhbmRsZUVyYXNlcihldmVudCwgcG9pbnRlckRvd25TdGF0ZSwgcG9pbnRlckNvb3Jkcyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyLmFkZFBvaW50VG9QYXRoKHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpOyAvLyBmb3IgYXJyb3dzL2xpbmVzLCBkb24ndCBzdGFydCBkcmFnZ2luZyB1bnRpbCBhIGdpdmVuIHRocmVzaG9sZFxuICAgICAgLy8gdG8gZW5zdXJlIHdlIGRvbid0IGNyZWF0ZSBhIDItcG9pbnQgYXJyb3cgYnkgbWlzdGFrZSB3aGVuXG4gICAgICAvLyB1c2VyIGNsaWNrcyBtb3VzZSBpbiBhIHdheSB0aGF0IGl0IG1vdmVzIGEgdGlueSBiaXQgKHRodXNcbiAgICAgIC8vIHRyaWdnZXJpbmcgcG9pbnRlcm1vdmUpXG5cbiAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJhcnJvd1wiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxpbmVcIikpIHtcbiAgICAgICAgaWYgKGRpc3RhbmNlMmQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpIDwgRFJBR0dJTkdfVEhSRVNIT0xEKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5pc1Jlc2l6aW5nKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gcG9pbnRlckNvb3Jkcy54O1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcblxuICAgICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudEVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQ7XG5cbiAgICAgICAgaWYgKExpbmVhckVsZW1lbnRFZGl0b3Iuc2hvdWxkQWRkTWlkcG9pbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQsIHBvaW50ZXJDb29yZHMsIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgICAgY29uc3QgcmV0ID0gTGluZWFyRWxlbWVudEVkaXRvci5hZGRNaWRwb2ludCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgcG9pbnRlckNvb3JkcywgdGhpcy5zdGF0ZSwgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKTtcblxuICAgICAgICAgIGlmICghcmV0KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSAvLyBTaW5jZSB3ZSBhcmUgcmVhZGluZyBmcm9tIHByZXZpb3VzIHN0YXRlIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSB3aXRoXG4gICAgICAgICAgLy8gYXV0b21hdGljIGJhdGNoaW5nIGluIFJlYWN0IDE4IGhlbmNlIHVzaW5nIGZsdXNoIHN5bmMgdG8gc3luY2hyb25vdXNseVxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgc3RhdGUuIENoZWNrIGh0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC81NTA4IGZvciBtb3JlIGRldGFpbHMuXG5cblxuICAgICAgICAgIGZsdXNoU3luYygoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZTogcmV0LnBvaW50ZXJEb3duU3RhdGUsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IHJldC5zZWxlY3RlZFBvaW50c0luZGljZXNcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGU6IHJldC5wb2ludGVyRG93blN0YXRlLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRQb2ludHNJbmRpY2VzOiByZXQuc2VsZWN0ZWRQb2ludHNJbmRpY2VzXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2UgaWYgKGxpbmVhckVsZW1lbnRFZGl0b3IucG9pbnRlckRvd25TdGF0ZS5zZWdtZW50TWlkcG9pbnQudmFsdWUgIT09IG51bGwgJiYgIWxpbmVhckVsZW1lbnRFZGl0b3IucG9pbnRlckRvd25TdGF0ZS5zZWdtZW50TWlkcG9pbnQuYWRkZWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBkaWREcmFnID0gTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVQb2ludERyYWdnaW5nKGV2ZW50LCB0aGlzLnN0YXRlLCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgKGVsZW1lbnQsIHBvaW50c1NjZW5lQ29vcmRzKSA9PiB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhlbGVtZW50LCBwb2ludHNTY2VuZUNvb3Jkcyk7XG4gICAgICAgIH0sIGxpbmVhckVsZW1lbnRFZGl0b3IpO1xuXG4gICAgICAgIGlmIChkaWREcmFnKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBwb2ludGVyQ29vcmRzLnk7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcblxuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgIGlzRHJhZ2dpbmc6IHRydWVcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCksIHtcbiAgICAgICAgICAgICAgICBpc0RyYWdnaW5nOiB0cnVlXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgaGFzSGl0QVNlbGVjdGVkRWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiB0aGlzLmlzQVNlbGVjdGVkRWxlbWVudChlbGVtZW50KSk7XG4gICAgICBjb25zdCBpc1NlbGVjdGluZ1BvaW50c0luTGluZUVkaXRvciA9IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgZXZlbnQuc2hpZnRLZXkgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQgPT09ICgoX2EgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaWQpO1xuXG4gICAgICBpZiAoKGhhc0hpdEFTZWxlY3RlZEVsZW1lbnQgfHwgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpICYmICFpc1NlbGVjdGluZ1BvaW50c0luTGluZUVkaXRvcikge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmV2ZXJ5KGVsZW1lbnQgPT4gZWxlbWVudC5sb2NrZWQpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50c0hhc0FGcmFtZSA9IHNlbGVjdGVkRWxlbWVudHMuZmluZChlID0+IGlzRnJhbWVFbGVtZW50KGUpKTtcbiAgICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMocG9pbnRlckNvb3Jkcyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGZyYW1lVG9IaWdobGlnaHQ6IHRvcExheWVyRnJhbWUgJiYgIXNlbGVjdGVkRWxlbWVudHNIYXNBRnJhbWUgPyB0b3BMYXllckZyYW1lIDogbnVsbFxuICAgICAgICB9KTsgLy8gTWFya2luZyB0aGF0IGNsaWNrIHdhcyB1c2VkIGZvciBkcmFnZ2luZyB0byBjaGVja1xuICAgICAgICAvLyBpZiBlbGVtZW50cyBzaG91bGQgYmUgZGVzZWxlY3RlZCBvbiBwb2ludGVydXBcblxuICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzQXJlQmVpbmdEcmFnZ2VkOiB0cnVlXG4gICAgICAgIH0pOyAvLyBwcmV2ZW50IGRyYWdnaW5nIGV2ZW4gaWYgd2UncmUgbm8gbG9uZ2VyIGhvbGRpbmcgY21kL2N0cmwgb3RoZXJ3aXNlXG4gICAgICAgIC8vIGl0IHdvdWxkIGhhdmUgd2VpcmQgcmVzdWx0cyAoc3R1ZmYganVtcGluZyBhbGwgb3ZlciB0aGUgc2NyZWVuKVxuICAgICAgICAvLyBDaGVja2luZyBmb3IgZWRpdGluZ0VsZW1lbnQgdG8gYXZvaWQganVtcCB3aGlsZSBlZGl0aW5nIG9uIG1vYmlsZSAjNjUwM1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDAgJiYgIXBvaW50ZXJEb3duU3RhdGUud2l0aENtZE9yQ3RybCAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAmJiAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpICE9PSBcImFjdGl2ZVwiKSB7XG4gICAgICAgICAgY29uc3QgZHJhZ09mZnNldCA9IHtcbiAgICAgICAgICAgIHg6IHBvaW50ZXJDb29yZHMueCAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsXG4gICAgICAgICAgICB5OiBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55XG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zdCBvcmlnaW5hbEVsZW1lbnRzID0gWy4uLnBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50cy52YWx1ZXMoKV07IC8vIFdlIG9ubHkgZHJhZyBpbiBvbmUgZGlyZWN0aW9uIGlmIHNoaWZ0IGlzIHByZXNzZWRcblxuICAgICAgICAgIGNvbnN0IGxvY2tEaXJlY3Rpb24gPSBldmVudC5zaGlmdEtleTtcblxuICAgICAgICAgIGlmIChsb2NrRGlyZWN0aW9uKSB7XG4gICAgICAgICAgICBjb25zdCBkaXN0YW5jZVggPSBNYXRoLmFicyhkcmFnT2Zmc2V0LngpO1xuICAgICAgICAgICAgY29uc3QgZGlzdGFuY2VZID0gTWF0aC5hYnMoZHJhZ09mZnNldC55KTtcbiAgICAgICAgICAgIGNvbnN0IGxvY2tYID0gbG9ja0RpcmVjdGlvbiAmJiBkaXN0YW5jZVggPCBkaXN0YW5jZVk7XG4gICAgICAgICAgICBjb25zdCBsb2NrWSA9IGxvY2tEaXJlY3Rpb24gJiYgZGlzdGFuY2VYID4gZGlzdGFuY2VZO1xuXG4gICAgICAgICAgICBpZiAobG9ja1gpIHtcbiAgICAgICAgICAgICAgZHJhZ09mZnNldC54ID0gMDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGxvY2tZKSB7XG4gICAgICAgICAgICAgIGRyYWdPZmZzZXQueSA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBTbmFwIGNhY2hlICptdXN0KiBiZSBzeW5jaHJvbm91c2x5IHBvcHVwbGF0ZWQgYmVmb3JlIGluaXRpYWwgZHJhZyxcbiAgICAgICAgICAvLyBvdGhlcndpc2UgdGhlIGZpcnN0IGRyYWcgZXZlbiB3aWxsIG5vdCBzbmFwLCBjYXVzaW5nIGEganVtcCBiZWZvcmVcbiAgICAgICAgICAvLyBpdCBzbmFwcyB0byBpdHMgcG9zaXRpb24gaWYgcHJldmlvdXNseSBzbmFwcGVkIGFscmVhZHkuXG5cblxuICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVZpc2libGVHYXBzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgICB0aGlzLm1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgICBjb25zdCB7XG4gICAgICAgICAgICBzbmFwT2Zmc2V0LFxuICAgICAgICAgICAgc25hcExpbmVzXG4gICAgICAgICAgfSA9IHNuYXBEcmFnZ2VkRWxlbWVudHMoZ2V0U2VsZWN0ZWRFbGVtZW50cyhvcmlnaW5hbEVsZW1lbnRzLCB0aGlzLnN0YXRlKSwgZHJhZ09mZnNldCwgdGhpcy5zdGF0ZSwgZXZlbnQpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc25hcExpbmVzXG4gICAgICAgICAgfSk7IC8vIHdoZW4gd2UncmUgZWRpdGluZyB0aGUgbmFtZSBvZiBhIGZyYW1lLCB3ZSB3YW50IHRoZSB1c2VyIHRvIGJlXG4gICAgICAgICAgLy8gYWJsZSB0byBzZWxlY3QgYW5kIGludGVyYWN0IHdpdGggdGhlIHRleHQgaW5wdXRcblxuICAgICAgICAgICF0aGlzLnN0YXRlLmVkaXRpbmdGcmFtZSAmJiBkcmFnU2VsZWN0ZWRFbGVtZW50cyhwb2ludGVyRG93blN0YXRlLCBzZWxlY3RlZEVsZW1lbnRzLCBkcmFnT2Zmc2V0LCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLCBzbmFwT2Zmc2V0LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cyk7IC8vIFdlIGR1cGxpY2F0ZSB0aGUgc2VsZWN0ZWQgZWxlbWVudCBpZiBhbHQgaXMgcHJlc3NlZCBvbiBwb2ludGVyIG1vdmVcblxuICAgICAgICAgIGlmIChldmVudC5hbHRLZXkgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0JlZW5EdXBsaWNhdGVkKSB7XG4gICAgICAgICAgICAvLyBNb3ZlIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgZWxlbWVudHMgdG8gdGhlIHRvcCBvZiB0aGUgeiBpbmRleCBzdGFjaywgYW5kXG4gICAgICAgICAgICAvLyBwdXQgdGhlIGR1cGxpY2F0ZXMgd2hlcmUgdGhlIHNlbGVjdGVkIGVsZW1lbnRzIHVzZWQgdG8gYmUuXG4gICAgICAgICAgICAvLyAodGhlIG9yaWdpbiBwb2ludCB3aGVyZSB0aGUgZHJhZ2dpbmcgc3RhcnRlZClcbiAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0JlZW5EdXBsaWNhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IG5leHRFbGVtZW50cyA9IFtdO1xuICAgICAgICAgICAgY29uc3QgZWxlbWVudHNUb0FwcGVuZCA9IFtdO1xuICAgICAgICAgICAgY29uc3QgZ3JvdXBJZE1hcCA9IG5ldyBNYXAoKTtcbiAgICAgICAgICAgIGNvbnN0IG9sZElkVG9EdXBsaWNhdGVkSWQgPSBuZXcgTWFwKCk7XG4gICAgICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudDtcbiAgICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudElkcyA9IG5ldyBTZXQodGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyxcbiAgICAgICAgICAgICAgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQ6IHRydWUsXG4gICAgICAgICAgICAgIGluY2x1ZGVFbGVtZW50c0luRnJhbWVzOiB0cnVlXG4gICAgICAgICAgICB9KS5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmlkKSk7XG4gICAgICAgICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG5cbiAgICAgICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50SWRzLmhhcyhlbGVtZW50LmlkKSB8fCAvLyBjYXNlOiB0aGUgc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzIG1pZ2h0IG5vdCBoYXZlIGJlZW5cbiAgICAgICAgICAgICAgLy8gdXBkYXRlZCB5ZXQgYnkgdGhlIHRpbWUgdGhpcyBtb3VzZW1vdmUgZXZlbnQgaXMgZmlyZWRcbiAgICAgICAgICAgICAgZWxlbWVudC5pZCA9PT0gKGhpdEVsZW1lbnQgPT09IG51bGwgfHwgaGl0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogaGl0RWxlbWVudC5pZCkgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQud2FzQWRkZWRUb1NlbGVjdGlvbikge1xuICAgICAgICAgICAgICAgIGNvbnN0IGR1cGxpY2F0ZWRFbGVtZW50ID0gZHVwbGljYXRlRWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkLCBncm91cElkTWFwLCBlbGVtZW50KTtcbiAgICAgICAgICAgICAgICBjb25zdCBvcmlnRWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50cy5nZXQoZWxlbWVudC5pZCk7XG4gICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChkdXBsaWNhdGVkRWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgeDogb3JpZ0VsZW1lbnQueCxcbiAgICAgICAgICAgICAgICAgIHk6IG9yaWdFbGVtZW50LnlcbiAgICAgICAgICAgICAgICB9KTsgLy8gcHV0IGR1cGxpY2F0ZWQgZWxlbWVudCB0byBwb2ludGVyRG93blN0YXRlLm9yaWdpbmFsRWxlbWVudHNcbiAgICAgICAgICAgICAgICAvLyBzbyB0aGF0IHdlIGNhbiBzbmFwIHRvIHRoZSBkdXBsaWNhdGVkIGVsZW1lbnQgd2l0aG91dCByZWxlYXNpbmdcblxuICAgICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50cy5zZXQoZHVwbGljYXRlZEVsZW1lbnQuaWQsIGR1cGxpY2F0ZWRFbGVtZW50KTtcbiAgICAgICAgICAgICAgICBuZXh0RWxlbWVudHMucHVzaChkdXBsaWNhdGVkRWxlbWVudCk7XG4gICAgICAgICAgICAgICAgZWxlbWVudHNUb0FwcGVuZC5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIG9sZElkVG9EdXBsaWNhdGVkSWQuc2V0KGVsZW1lbnQuaWQsIGR1cGxpY2F0ZWRFbGVtZW50LmlkKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZXh0RWxlbWVudHMucHVzaChlbGVtZW50KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBuZXh0U2NlbmVFbGVtZW50cyA9IFsuLi5uZXh0RWxlbWVudHMsIC4uLmVsZW1lbnRzVG9BcHBlbmRdO1xuICAgICAgICAgICAgYmluZFRleHRUb1NoYXBlQWZ0ZXJEdXBsaWNhdGlvbihuZXh0RWxlbWVudHMsIGVsZW1lbnRzVG9BcHBlbmQsIG9sZElkVG9EdXBsaWNhdGVkSWQpO1xuICAgICAgICAgICAgZml4QmluZGluZ3NBZnRlckR1cGxpY2F0aW9uKG5leHRTY2VuZUVsZW1lbnRzLCBlbGVtZW50c1RvQXBwZW5kLCBvbGRJZFRvRHVwbGljYXRlZElkLCBcImR1cGxpY2F0ZXNTZXJ2ZUFzT2xkXCIpO1xuICAgICAgICAgICAgYmluZEVsZW1lbnRzVG9GcmFtZXNBZnRlckR1cGxpY2F0aW9uKG5leHRTY2VuZUVsZW1lbnRzLCBlbGVtZW50c1RvQXBwZW5kLCBvbGRJZFRvRHVwbGljYXRlZElkKTtcbiAgICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKG5leHRTY2VuZUVsZW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVZpc2libGVHYXBzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzLCB0cnVlKTtcbiAgICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMsIHRydWUpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfSAvLyBJdCBpcyB2ZXJ5IGltcG9ydGFudCB0byByZWFkIHRoaXMuc3RhdGUgd2l0aGluIGVhY2ggbW92ZSBldmVudCxcbiAgICAgIC8vIG90aGVyd2lzZSB3ZSB3b3VsZCByZWFkIGEgc3RhbGUgb25lIVxuXG5cbiAgICAgIGNvbnN0IGRyYWdnaW5nRWxlbWVudCA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50O1xuXG4gICAgICBpZiAoIWRyYWdnaW5nRWxlbWVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIGNvbnN0IHBvaW50cyA9IGRyYWdnaW5nRWxlbWVudC5wb2ludHM7XG4gICAgICAgIGNvbnN0IGR4ID0gcG9pbnRlckNvb3Jkcy54IC0gZHJhZ2dpbmdFbGVtZW50Lng7XG4gICAgICAgIGNvbnN0IGR5ID0gcG9pbnRlckNvb3Jkcy55IC0gZHJhZ2dpbmdFbGVtZW50Lnk7XG4gICAgICAgIGNvbnN0IGxhc3RQb2ludCA9IHBvaW50cy5sZW5ndGggPiAwICYmIHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV07XG4gICAgICAgIGNvbnN0IGRpc2NhcmRQb2ludCA9IGxhc3RQb2ludCAmJiBsYXN0UG9pbnRbMF0gPT09IGR4ICYmIGxhc3RQb2ludFsxXSA9PT0gZHk7XG5cbiAgICAgICAgaWYgKCFkaXNjYXJkUG9pbnQpIHtcbiAgICAgICAgICBjb25zdCBwcmVzc3VyZXMgPSBkcmFnZ2luZ0VsZW1lbnQuc2ltdWxhdGVQcmVzc3VyZSA/IGRyYWdnaW5nRWxlbWVudC5wcmVzc3VyZXMgOiBbLi4uZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcywgZXZlbnQucHJlc3N1cmVdO1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtkeCwgZHldXSxcbiAgICAgICAgICAgIHByZXNzdXJlc1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGlzTGluZWFyRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCA9IHRydWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHBvaW50cyA9IGRyYWdnaW5nRWxlbWVudC5wb2ludHM7XG4gICAgICAgIGxldCBkeCA9IGdyaWRYIC0gZHJhZ2dpbmdFbGVtZW50Lng7XG4gICAgICAgIGxldCBkeSA9IGdyaWRZIC0gZHJhZ2dpbmdFbGVtZW50Lnk7XG5cbiAgICAgICAgaWYgKHNob3VsZFJvdGF0ZVdpdGhEaXNjcmV0ZUFuZ2xlKGV2ZW50KSAmJiBwb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgKHtcbiAgICAgICAgICAgIHdpZHRoOiBkeCxcbiAgICAgICAgICAgIGhlaWdodDogZHlcbiAgICAgICAgICB9ID0gZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplKGRyYWdnaW5nRWxlbWVudC54LCBkcmFnZ2luZ0VsZW1lbnQueSwgcG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnkpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwb2ludHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAocG9pbnRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMuc2xpY2UoMCwgLTEpLCBbZHgsIGR5XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICAgICAgLy8gV2hlbiBjcmVhdGluZyBhIGxpbmVhciBlbGVtZW50IGJ5IGRyYWdnaW5nXG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhkcmFnZ2luZ0VsZW1lbnQsIFtwb2ludGVyQ29vcmRzXSwgdGhpcy5zdGF0ZS5zdGFydEJvdW5kRWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0gcG9pbnRlckNvb3Jkcy54O1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcbiAgICAgICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudChwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmJveFNlbGVjdGlvbi5oYXNPY2N1cnJlZCA9IHRydWU7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKTsgLy8gYm94LXNlbGVjdCBsaW5lIGVkaXRvciBwb2ludHNcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlQm94U2VsZWN0aW9uKGV2ZW50LCB0aGlzLnN0YXRlLCB0aGlzLnNldFN0YXRlLmJpbmQodGhpcykpOyAvLyByZWd1bGFyIGJveC1zZWxlY3RcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsZXQgc2hvdWxkUmV1c2VTZWxlY3Rpb24gPSB0cnVlO1xuXG4gICAgICAgICAgaWYgKCFldmVudC5zaGlmdEtleSAmJiBpc1NvbWVFbGVtZW50U2VsZWN0ZWQoZWxlbWVudHMsIHRoaXMuc3RhdGUpKSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS53aXRoQ21kT3JDdHJsICYmIHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICAgICAgICAgIFtwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSksIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc2hvdWxkUmV1c2VTZWxlY3Rpb24gPSBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBlbGVtZW50c1dpdGhpblNlbGVjdGlvbiA9IGdldEVsZW1lbnRzV2l0aGluU2VsZWN0aW9uKGVsZW1lbnRzLCBkcmFnZ2luZ0VsZW1lbnQpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNob3VsZFJldXNlU2VsZWN0aW9uICYmIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCBlbGVtZW50c1dpdGhpblNlbGVjdGlvbi5yZWR1Y2UoKGFjYywgZWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICBhY2NbZWxlbWVudC5pZF0gPSB0cnVlO1xuICAgICAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICAgICAgfSwge30pKTtcblxuICAgICAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgLy8gaWYgdXNpbmcgY3RybC9jbWQsIHNlbGVjdCB0aGUgaGl0RWxlbWVudCBvbmx5IGlmIHdlXG4gICAgICAgICAgICAgIC8vIGhhdmVuJ3QgYm94LXNlbGVjdGVkIGFueXRoaW5nIGVsc2VcbiAgICAgICAgICAgICAgaWYgKCFlbGVtZW50c1dpdGhpblNlbGVjdGlvbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1twb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBwcmV2U3RhdGUgPSAhc2hvdWxkUmV1c2VTZWxlY3Rpb24gPyBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZSksIHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsXG4gICAgICAgICAgICB9KSA6IHByZXZTdGF0ZTtcbiAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgIC8vIHNlbGVjdCBsaW5lYXIgZWxlbWVudCBvbmx5IHdoZW4gd2UgaGF2ZW4ndCBib3gtc2VsZWN0ZWQgYW55dGhpbmcgZWxzZVxuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0pID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0sIHRoaXMuc2NlbmUpIDogbnVsbCxcbiAgICAgICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBlbGVtZW50c1dpdGhpblNlbGVjdGlvbi5sZW5ndGggPT09IDEgJiYgKGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdLmxpbmsgfHwgaXNFbWJlZGRhYmxlRWxlbWVudChlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSkpID8gXCJpbmZvXCIgOiBmYWxzZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfSAvLyBSZXR1cm5zIHdoZXRoZXIgdGhlIHBvaW50ZXIgbW92ZSBoYXBwZW5lZCBvdmVyIGVpdGhlciBzY3JvbGxiYXJcblxuXG4gIGhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5zY3JvbGxiYXJzLmlzT3Zlckhvcml6b250YWwpIHtcbiAgICAgIGNvbnN0IHggPSBldmVudC5jbGllbnRYO1xuICAgICAgY29uc3QgZHggPSB4IC0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLng7XG4gICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyh7XG4gICAgICAgIHNjcm9sbFg6IHRoaXMuc3RhdGUuc2Nyb2xsWCAtIGR4IC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlXG4gICAgICB9KTtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54ID0geDtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGlmIChwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVyVmVydGljYWwpIHtcbiAgICAgIGNvbnN0IHkgPSBldmVudC5jbGllbnRZO1xuICAgICAgY29uc3QgZHkgPSB5IC0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnk7XG4gICAgICB0aGlzLnRyYW5zbGF0ZUNhbnZhcyh7XG4gICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSAtIGR5IC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlXG4gICAgICB9KTtcbiAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0geTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIG9uUG9pbnRlclVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKSB7XG4gICAgcmV0dXJuIHdpdGhCYXRjaGVkVXBkYXRlcyhjaGlsZEV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2IsIF9jLCBfZCwgX2UsIF9mO1xuXG4gICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbk1vdmUpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbk1vdmUuZmx1c2goKTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qge1xuICAgICAgICBkcmFnZ2luZ0VsZW1lbnQsXG4gICAgICAgIHJlc2l6aW5nRWxlbWVudCxcbiAgICAgICAgbXVsdGlFbGVtZW50LFxuICAgICAgICBhY3RpdmVUb29sLFxuICAgICAgICBpc1Jlc2l6aW5nLFxuICAgICAgICBpc1JvdGF0aW5nXG4gICAgICB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBpc1Jlc2l6aW5nOiBmYWxzZSxcbiAgICAgICAgaXNSb3RhdGluZzogZmFsc2UsXG4gICAgICAgIHJlc2l6aW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgc2VsZWN0aW9uRWxlbWVudDogbnVsbCxcbiAgICAgICAgZnJhbWVUb0hpZ2hsaWdodDogbnVsbCxcbiAgICAgICAgZWxlbWVudHNUb0hpZ2hsaWdodDogbnVsbCxcbiAgICAgICAgY3Vyc29yQnV0dG9uOiBcInVwXCIsXG4gICAgICAgIC8vIHRleHQgZWxlbWVudHMgYXJlIHJlc2V0IG9uIGZpbmFsaXplLCBhbmQgcmVzZXR0aW5nIG9uIHBvaW50ZXJ1cFxuICAgICAgICAvLyBtYXkgY2F1c2UgaXNzdWVzIHdpdGggZG91YmxlIHRhcHNcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG11bHRpRWxlbWVudCB8fCBpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID8gdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCA6IG51bGwsXG4gICAgICAgIHNuYXBMaW5lczogW10sXG4gICAgICAgIG9yaWdpblNuYXBPZmZzZXQ6IG51bGxcbiAgICAgIH0pO1xuICAgICAgU25hcENhY2hlLnNldFJlZmVyZW5jZVNuYXBQb2ludHMobnVsbCk7XG4gICAgICBTbmFwQ2FjaGUuc2V0VmlzaWJsZUdhcHMobnVsbCk7XG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGNoaWxkRXZlbnQuY2xpZW50WCwgY2hpbGRFdmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IGZhbHNlXG4gICAgICB9KTsgLy8gSGFuZGxlIGVuZCBvZiBkcmFnZ2luZyBhIHBvaW50IG9mIGEgbGluZWFyIGVsZW1lbnQsIG1pZ2h0IGNsb3NlIGEgbG9vcFxuICAgICAgLy8gYW5kIHNldHMgYmluZGluZyBlbGVtZW50XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5ib3hTZWxlY3Rpb24uaGFzT2NjdXJyZWQgJiYgKChfYiA9IChfYSA9IHBvaW50ZXJEb3duU3RhdGUuaGl0KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmlkKSAhPT0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWQpIHtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgZWRpdGluZ0xpbmVhckVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJVcChjaGlsZEV2ZW50LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgICAgIGlmIChlZGl0aW5nTGluZWFyRWxlbWVudCAhPT0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50LFxuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICBpZiAoKChfZCA9IChfYyA9IHBvaW50ZXJEb3duU3RhdGUuaGl0KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZWxlbWVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmlkKSAhPT0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuZWxlbWVudElkKSB7XG4gICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFTGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTsgLy8gc2V0IHNlbGVjdGVkTGluZWFyRWxlbWVudCB0byBudWxsIGlmIHRoZXJlIGlzIG1vcmUgdGhhbiBvbmUgZWxlbWVudCBzZWxlY3RlZCBzaW5jZSB3ZSBkb24ndCB3YW50IHRvIHNob3cgbGluZWFyIGVsZW1lbnQgaGFuZGxlc1xuXG4gICAgICAgICAgaWYgKHNlbGVjdGVkRUxlbWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbnVsbFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnN0IGxpbmVhckVsZW1lbnRFZGl0b3IgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50ZXJVcChjaGlsZEV2ZW50LCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgY29uc3Qge1xuICAgICAgICAgICAgc3RhcnRCaW5kaW5nRWxlbWVudCxcbiAgICAgICAgICAgIGVuZEJpbmRpbmdFbGVtZW50XG4gICAgICAgICAgfSA9IGxpbmVhckVsZW1lbnRFZGl0b3I7XG4gICAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudChsaW5lYXJFbGVtZW50RWRpdG9yLmVsZW1lbnRJZCk7XG5cbiAgICAgICAgICBpZiAoaXNCaW5kaW5nRWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICAgICAgYmluZE9yVW5iaW5kTGluZWFyRWxlbWVudChlbGVtZW50LCBzdGFydEJpbmRpbmdFbGVtZW50LCBlbmRCaW5kaW5nRWxlbWVudCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGxpbmVhckVsZW1lbnRFZGl0b3IgIT09IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGxpbmVhckVsZW1lbnRFZGl0b3IpLCB7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRQb2ludHNJbmRpY2VzOiBudWxsXG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBsYXN0UG9pbnRlclVwID0gbnVsbDtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbk1vdmUpO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vblVwKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlEb3duKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULktFWVVQLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5VXApO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm9uUG9pbnRlclVwRW1pdHRlci50cmlnZ2VyKHRoaXMuc3RhdGUuYWN0aXZlVG9vbCwgcG9pbnRlckRvd25TdGF0ZSwgY2hpbGRFdmVudCk7XG5cbiAgICAgIGlmICgoZHJhZ2dpbmdFbGVtZW50ID09PSBudWxsIHx8IGRyYWdnaW5nRWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZHJhZ2dpbmdFbGVtZW50LnR5cGUpID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgcG9pbnRlckNvb3JkcyA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhjaGlsZEV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgbGV0IGR4ID0gcG9pbnRlckNvb3Jkcy54IC0gZHJhZ2dpbmdFbGVtZW50Lng7XG4gICAgICAgIGxldCBkeSA9IHBvaW50ZXJDb29yZHMueSAtIGRyYWdnaW5nRWxlbWVudC55OyAvLyBBbGxvd3MgZG90cyB0byBhdm9pZCBiZWluZyBmbGFnZ2VkIGFzIGluZmluaXRlbHkgc21hbGxcblxuICAgICAgICBpZiAoZHggPT09IHBvaW50c1swXVswXSAmJiBkeSA9PT0gcG9pbnRzWzBdWzFdKSB7XG4gICAgICAgICAgZHkgKz0gMC4wMDAxO1xuICAgICAgICAgIGR4ICs9IDAuMDAwMTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGRyYWdnaW5nRWxlbWVudC5zaW11bGF0ZVByZXNzdXJlID8gW10gOiBbLi4uZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcywgY2hpbGRFdmVudC5wcmVzc3VyZV07XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB7XG4gICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLCBbZHgsIGR5XV0sXG4gICAgICAgICAgcHJlc3N1cmVzLFxuICAgICAgICAgIGxhc3RDb21taXR0ZWRQb2ludDogW2R4LCBkeV1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNJbWFnZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSkge1xuICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSBkcmFnZ2luZ0VsZW1lbnQ7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5maWx0ZXIoZWwgPT4gZWwuaWQgIT09IGltYWdlRWxlbWVudC5pZCkpO1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzTGluZWFyRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpKSB7XG4gICAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQucG9pbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmICghcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkICYmIGRyYWdnaW5nRWxlbWVudCAmJiAhbXVsdGlFbGVtZW50KSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLmRyYWdnaW5nRWxlbWVudC5wb2ludHMsIFtwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueCwgcG9pbnRlckNvb3Jkcy55IC0gZHJhZ2dpbmdFbGVtZW50LnldXVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgbXVsdGlFbGVtZW50OiBkcmFnZ2luZ0VsZW1lbnQsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudDogdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnRcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgIW11bHRpRWxlbWVudCkge1xuICAgICAgICAgIGlmIChpc0JpbmRpbmdFbmFibGVkKHRoaXMuc3RhdGUpICYmIGlzQmluZGluZ0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgICAgICAgIG1heWJlQmluZExpbmVhckVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLCBwb2ludGVyQ29vcmRzKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXSxcbiAgICAgICAgICAgIHN0YXJ0Qm91bmRFbGVtZW50OiBudWxsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBpZiAoIWFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgICAgW2RyYWdnaW5nRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgfSksIHByZXZTdGF0ZSksXG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZHJhZ2dpbmdFbGVtZW50LCB0aGlzLnNjZW5lKVxuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGxcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgZHJhZ2dpbmdFbGVtZW50ICYmIGlzSW52aXNpYmx5U21hbGxFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgLy8gcmVtb3ZlIGludmlzaWJsZSBlbGVtZW50IHdoaWNoIHdhcyBhZGRlZCBpbiBvblBvaW50ZXJEb3duXG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSBkcmFnZ2luZ0VsZW1lbnQuaWQpKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQpIHtcbiAgICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCkge1xuICAgICAgICAgIGNvbnN0IHNjZW5lQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUpOyAvLyB3aGVuIGVkaXRpbmcgdGhlIHBvaW50cyBvZiBhIGxpbmVhciBlbGVtZW50LCB3ZSBjaGVjayBpZiB0aGVcbiAgICAgICAgICAvLyBsaW5lYXIgZWxlbWVudCBzdGlsbCBpcyBpbiB0aGUgZnJhbWUgYWZ0ZXJ3YXJkc1xuICAgICAgICAgIC8vIGlmIG5vdCwgdGhlIGxpbmVhciBlbGVtZW50IHdpbGwgYmUgcmVtb3ZlZCBmcm9tIGl0cyBmcmFtZSAoaWYgYW55KVxuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50ICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgICAgIGNvbnN0IGxpbmVhckVsZW1lbnQgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnQodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuZWxlbWVudElkKTtcblxuICAgICAgICAgICAgaWYgKGxpbmVhckVsZW1lbnQgPT09IG51bGwgfHwgbGluZWFyRWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbGluZWFyRWxlbWVudC5mcmFtZUlkKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGZyYW1lID0gZ2V0Q29udGFpbmluZ0ZyYW1lKGxpbmVhckVsZW1lbnQpO1xuXG4gICAgICAgICAgICAgIGlmIChmcmFtZSAmJiBsaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFlbGVtZW50T3ZlcmxhcHNXaXRoRnJhbWUobGluZWFyRWxlbWVudCwgZnJhbWUpKSB7XG4gICAgICAgICAgICAgICAgICAvLyByZW1vdmUgdGhlIGxpbmVhciBlbGVtZW50IGZyb20gYWxsIGdyb3Vwc1xuICAgICAgICAgICAgICAgICAgLy8gYmVmb3JlIHJlbW92aW5nIGl0IGZyb20gdGhlIGZyYW1lIGFzIHdlbGxcbiAgICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQobGluZWFyRWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgICBncm91cElkczogW11cbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMocmVtb3ZlRWxlbWVudHNGcm9tRnJhbWUodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgW2xpbmVhckVsZW1lbnRdLCB0aGlzLnN0YXRlKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHNlbGVjdGVkIGVsZW1lbnRzIGFuZCBmcmFtZXNcbiAgICAgICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHNjZW5lQ29vcmRzKTtcbiAgICAgICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBsZXQgbmV4dEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcblxuICAgICAgICAgICAgY29uc3QgdXBkYXRlR3JvdXBJZHNBZnRlckVkaXRpbmdHcm91cCA9IGVsZW1lbnRzID0+IHtcbiAgICAgICAgICAgICAgaWYgKGVsZW1lbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZWxlbWVudHMpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gZWxlbWVudC5ncm91cElkcy5pbmRleE9mKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQpO1xuICAgICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICAgIGdyb3VwSWRzOiBlbGVtZW50Lmdyb3VwSWRzLnNsaWNlKDAsIGluZGV4KVxuICAgICAgICAgICAgICAgICAgfSwgZmFsc2UpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG5leHRFbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQuZ3JvdXBJZHMubGVuZ3RoICYmIGdldEVsZW1lbnRzSW5Hcm91cChuZXh0RWxlbWVudHMsIGVsZW1lbnQuZ3JvdXBJZHNbZWxlbWVudC5ncm91cElkcy5sZW5ndGggLSAxXSkubGVuZ3RoIDwgMikge1xuICAgICAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgICBncm91cElkczogW11cbiAgICAgICAgICAgICAgICAgICAgfSwgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKHRvcExheWVyRnJhbWUgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RvcExheWVyRnJhbWUuaWRdKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzVG9BZGQgPSBzZWxlY3RlZEVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQuZnJhbWVJZCAhPT0gdG9wTGF5ZXJGcmFtZS5pZCAmJiBpc0VsZW1lbnRJbkZyYW1lKGVsZW1lbnQsIG5leHRFbGVtZW50cywgdGhpcy5zdGF0ZSkpO1xuXG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkKSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlR3JvdXBJZHNBZnRlckVkaXRpbmdHcm91cChlbGVtZW50c1RvQWRkKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIG5leHRFbGVtZW50cyA9IGFkZEVsZW1lbnRzVG9GcmFtZShuZXh0RWxlbWVudHMsIGVsZW1lbnRzVG9BZGQsIHRvcExheWVyRnJhbWUpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICghdG9wTGF5ZXJGcmFtZSkge1xuICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzVG9SZW1vdmUgPSBzZWxlY3RlZEVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQuZnJhbWVJZCAmJiAhaXNFbGVtZW50SW5GcmFtZShlbGVtZW50LCBuZXh0RWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcbiAgICAgICAgICAgICAgICB1cGRhdGVHcm91cElkc0FmdGVyRWRpdGluZ0dyb3VwKGVsZW1lbnRzVG9SZW1vdmUpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG5leHRFbGVtZW50cyA9IHVwZGF0ZUZyYW1lTWVtYmVyc2hpcE9mU2VsZWN0ZWRFbGVtZW50cyhuZXh0RWxlbWVudHMsIHRoaXMuc3RhdGUsIHRoaXMpO1xuICAgICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dEVsZW1lbnRzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZHJhZ2dpbmdFbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzSW5zaWRlRnJhbWUgPSBnZXRFbGVtZW50c0luTmV3RnJhbWUodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZHJhZ2dpbmdFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhhZGRFbGVtZW50c1RvRnJhbWUodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZWxlbWVudHNJbnNpZGVGcmFtZSwgZHJhZ2dpbmdFbGVtZW50KSk7XG4gICAgICAgIH1cblxuICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZ2V0Tm9ybWFsaXplZERpbWVuc2lvbnMoZHJhZ2dpbmdFbGVtZW50KSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChyZXNpemluZ0VsZW1lbnQpIHtcbiAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgfVxuXG4gICAgICBpZiAocmVzaXppbmdFbGVtZW50ICYmIGlzSW52aXNpYmx5U21hbGxFbGVtZW50KHJlc2l6aW5nRWxlbWVudCkpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5maWx0ZXIoZWwgPT4gZWwuaWQgIT09IHJlc2l6aW5nRWxlbWVudC5pZCkpO1xuICAgICAgfSAvLyBoYW5kbGUgZnJhbWUgbWVtYmVyc2hpcCBmb3IgcmVzaXppbmcgZnJhbWVzIGFuZC9vciBzZWxlY3RlZCBlbGVtZW50c1xuXG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5pc1Jlc2l6aW5nKSB7XG4gICAgICAgIGxldCBuZXh0RWxlbWVudHMgPSB1cGRhdGVGcmFtZU1lbWJlcnNoaXBPZlNlbGVjdGVkRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcy5zdGF0ZSwgdGhpcyk7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRnJhbWVzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpLmZpbHRlcihlbGVtZW50ID0+IGVsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGZyYW1lIG9mIHNlbGVjdGVkRnJhbWVzKSB7XG4gICAgICAgICAgbmV4dEVsZW1lbnRzID0gcmVwbGFjZUFsbEVsZW1lbnRzSW5GcmFtZShuZXh0RWxlbWVudHMsIGdldEVsZW1lbnRzSW5SZXNpemluZ0ZyYW1lKHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIGZyYW1lLCB0aGlzLnN0YXRlKSwgZnJhbWUsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dEVsZW1lbnRzKTtcbiAgICAgIH0gLy8gQ29kZSBiZWxvdyBoYW5kbGVzIHNlbGVjdGlvbiB3aGVuIGVsZW1lbnQocykgd2VyZW4ndFxuICAgICAgLy8gZHJhZyBvciBhZGRlZCB0byBzZWxlY3Rpb24gb24gcG9pbnRlciBkb3duIHBoYXNlLlxuXG5cbiAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuXG4gICAgICBpZiAoKChfZSA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSA9PT0gbnVsbCB8fCBfZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2UuZWxlbWVudElkKSAhPT0gKGhpdEVsZW1lbnQgPT09IG51bGwgfHwgaGl0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogaGl0RWxlbWVudC5pZCkgJiYgaXNMaW5lYXJFbGVtZW50KGhpdEVsZW1lbnQpKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRUxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7IC8vIHNldCBzZWxlY3RlZExpbmVhckVsZW1lbnQgd2hlbiBubyBvdGhlciBlbGVtZW50IHNlbGVjdGVkIGV4Y2VwdFxuICAgICAgICAvLyB0aGUgb25lIHdlJ3ZlIGhpdFxuXG4gICAgICAgIGlmIChzZWxlY3RlZEVMZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihoaXRFbGVtZW50LCB0aGlzLnNjZW5lKVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICBjb25zdCBkcmFnZ2VkRGlzdGFuY2UgPSBkaXN0YW5jZTJkKHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQuY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudC5jbGllbnRZLCB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC5jbGllbnRYLCB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC5jbGllbnRZKTtcblxuICAgICAgICBpZiAoZHJhZ2dlZERpc3RhbmNlID09PSAwKSB7XG4gICAgICAgICAgY29uc3Qgc2NlbmVQb2ludGVyID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgICAgIGNsaWVudFg6IHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LmNsaWVudFgsXG4gICAgICAgICAgICBjbGllbnRZOiB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC5jbGllbnRZXG4gICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgY29uc3QgaGl0RWxlbWVudHMgPSB0aGlzLmdldEVsZW1lbnRzQXRQb3NpdGlvbihzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpO1xuICAgICAgICAgIGhpdEVsZW1lbnRzLmZvckVhY2goaGl0RWxlbWVudCA9PiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2hpdEVsZW1lbnQuaWRdID0ge1xuICAgICAgICAgICAgZXJhc2U6IHRydWUsXG4gICAgICAgICAgICBvcGFjaXR5OiBoaXRFbGVtZW50Lm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZXJhc2VFbGVtZW50cyhwb2ludGVyRG93blN0YXRlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlKS5sZW5ndGgpIHtcbiAgICAgICAgdGhpcy5yZXN0b3JlUmVhZHlUb0VyYXNlRWxlbWVudHMocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChoaXRFbGVtZW50ICYmICFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lndhc0FkZGVkVG9TZWxlY3Rpb24gJiYgKCAvLyBpZiB3ZSdyZSBlZGl0aW5nIGEgbGluZSwgcG9pbnRlcnVwIHNob3VsZG4ndCBzd2l0Y2ggc2VsZWN0aW9uIGlmXG4gICAgICAvLyBib3ggc2VsZWN0ZWRcbiAgICAgICF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8ICFwb2ludGVyRG93blN0YXRlLmJveFNlbGVjdGlvbi5oYXNPY2N1cnJlZCkpIHtcbiAgICAgICAgLy8gd2hlbiBpbnNpZGUgbGluZSBlZGl0b3IsIHNoaWZ0IHNlbGVjdHMgcG9pbnRzIGluc3RlYWRcbiAgICAgICAgaWYgKGNoaWxkRXZlbnQuc2hpZnRLZXkgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF0pIHtcbiAgICAgICAgICAgIGlmIChpc1NlbGVjdGVkVmlhR3JvdXAodGhpcy5zdGF0ZSwgaGl0RWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShfcHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgX3ByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpOyAvLyBXZSB3YW50IHRvIHVuc2VsZWN0IGFsbCBncm91cHMgaGl0RWxlbWVudCBpcyBwYXJ0IG9mXG4gICAgICAgICAgICAgICAgLy8gYXMgd2VsbCBhcyBhbGwgZWxlbWVudHMgdGhhdCBhcmUgcGFydCBvZiB0aGUgZ3JvdXBzXG4gICAgICAgICAgICAgICAgLy8gaGl0RWxlbWVudCBpcyBwYXJ0IG9mXG5cbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGdyb3VwZWRFbGVtZW50IG9mIGhpdEVsZW1lbnQuZ3JvdXBJZHMuZmxhdE1hcChncm91cElkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBncm91cElkKSkpIHtcbiAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2dyb3VwZWRFbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIGhpdEVsZW1lbnQuZ3JvdXBJZHMubWFwKGdJZCA9PiAoe1xuICAgICAgICAgICAgICAgICAgICBbZ0lkXTogZmFsc2VcbiAgICAgICAgICAgICAgICAgIH0pKS5yZWR1Y2UoKHByZXYsIGFjYykgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2KSwgYWNjKSwge30pKSxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMobmV4dFNlbGVjdGVkRWxlbWVudElkcywgX3ByZXZTdGF0ZSlcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICB9KTsgLy8gaWYgbm90IGdyYWdnaW5nIGEgbGluZWFyIGVsZW1lbnQgcG9pbnQgKG91dHNpZGUgZWRpdG9yKVxuICAgICAgICAgICAgfSBlbHNlIGlmICghKChfZiA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuaXNEcmFnZ2luZykpIHtcbiAgICAgICAgICAgICAgLy8gcmVtb3ZlIGVsZW1lbnQgZnJvbSBzZWxlY3Rpb24gd2hpbGVcbiAgICAgICAgICAgICAgLy8ga2VlcGluZyBwcmV2IGVsZW1lbnRzIHNlbGVjdGVkXG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXdTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTtcbiAgICAgICAgICAgICAgICBkZWxldGUgbmV3U2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgIGNvbnN0IG5ld1NlbGVjdGVkRWxlbWVudHMgPSBnZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHtcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV3U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXdTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICAgICAgLy8gc2V0IHNlbGVjdGVkTGluZWFyRWxlbWVudCBvbmx5IGlmIHRoYXRzIHRoZSBvbmx5IGVsZW1lbnQgc2VsZWN0ZWRcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbmV3U2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNMaW5lYXJFbGVtZW50KG5ld1NlbGVjdGVkRWxlbWVudHNbMF0pID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IobmV3U2VsZWN0ZWRFbGVtZW50c1swXSwgdGhpcy5zY2VuZSkgOiBwcmV2U3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSBpZiAoaGl0RWxlbWVudC5mcmFtZUlkICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuZnJhbWVJZF0pIHtcbiAgICAgICAgICAgIC8vIHdoZW4gaGl0RWxlbWVudCBpcyBwYXJ0IG9mIGEgc2VsZWN0ZWQgZnJhbWUsIGRlc2VsZWN0IHRoZSBmcmFtZVxuICAgICAgICAgICAgLy8gdG8gYXZvaWQgZnJhbWUgYW5kIGNvbnRhaW5pbmcgZWxlbWVudHMgc2VsZWN0ZWQgc2ltdWx0YW5lb3VzbHlcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9KTsgLy8gZGVzZWxlY3QgdGhlIGZyYW1lXG5cbiAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5mcmFtZUlkXTsgLy8gZGVzZWxlY3QgZ3JvdXBzIGNvbnRhaW5pbmcgdGhlIGZyYW1lXG5cbiAgICAgICAgICAgICAgKChfYiA9IChfYSA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudChoaXRFbGVtZW50LmZyYW1lSWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZ3JvdXBJZHMpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IFtdKS5mbGF0TWFwKGdpZCA9PiBnZXRFbGVtZW50c0luR3JvdXAodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZ2lkKSkuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBoaXRFbGVtZW50LmxpbmsgfHwgaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSA/IFwiaW5mb1wiIDogZmFsc2VcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gYWRkIGVsZW1lbnQgdG8gc2VsZWN0aW9uIHdoaWxlIGtlZXBpbmcgcHJldiBlbGVtZW50cyBzZWxlY3RlZFxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShfcHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBfcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgICBbaGl0RWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgICAgfSksIF9wcmV2U3RhdGUpXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IGlzTGluZWFyRWxlbWVudChoaXRFbGVtZW50KSAmJiAvLyBEb24ndCBzZXQgYHNlbGVjdGVkTGluZWFyRWxlbWVudGAgaWYgaXRzIHNhbWUgYXMgdGhlIGhpdEVsZW1lbnQsIHRoaXMgaXMgbWFpbmx5IHRvIHByZXZlbnQgcmVzZXR0aW5nIHRoZSBgaG92ZXJQb2ludEluZGV4YCB0byAtMS5cbiAgICAgICAgICAgICAgLy8gRnV0dXJlIHdlIHNob3VsZCB1cGRhdGUgdGhlIEFQSSB0byB0YWtlIGNhcmUgb2Ygc2V0dGluZyB0aGUgY29ycmVjdCBgaG92ZXJQb2ludEluZGV4YCB3aGVuIGluaXRpYWxpemVkXG4gICAgICAgICAgICAgICgoX2EgPSBwcmV2U3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudElkKSAhPT0gaGl0RWxlbWVudC5pZCA/IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKGhpdEVsZW1lbnQsIHRoaXMuc2NlbmUpIDogcHJldlN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgIXRoaXMuc3RhdGUuaXNSZXNpemluZyAmJiAoaGl0RWxlbWVudCAmJiBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQoaGl0RWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkgfHwgIWhpdEVsZW1lbnQgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMpKSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbnVsbFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIERlc2VsZWN0IHNlbGVjdGVkIGVsZW1lbnRzXG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICghYWN0aXZlVG9vbC5sb2NrZWQgJiYgYWN0aXZlVG9vbC50eXBlICE9PSBcImZyZWVkcmF3XCIgJiYgZHJhZ2dpbmdFbGVtZW50ICYmIGRyYWdnaW5nRWxlbWVudC50eXBlICE9PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICBbZHJhZ2dpbmdFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgIH0pLCBwcmV2U3RhdGUpLFxuICAgICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogaXNFbWJlZGRhYmxlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpICYmICFkcmFnZ2luZ0VsZW1lbnQubGluayA/IFwiZWRpdG9yXCIgOiBwcmV2U3RhdGUuc2hvd0h5cGVybGlua1BvcHVwXG4gICAgICAgIH0pKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiB8fCBpc1NvbWVFbGVtZW50U2VsZWN0ZWQodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgfVxuXG4gICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkIHx8IGlzUmVzaXppbmcgfHwgaXNSb3RhdGluZykge1xuICAgICAgICAoaXNCaW5kaW5nRW5hYmxlZCh0aGlzLnN0YXRlKSA/IGJpbmRPclVuYmluZFNlbGVjdGVkRWxlbWVudHMgOiB1bmJpbmRMaW5lYXJFbGVtZW50cykodGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsYXNlclwiKSB7XG4gICAgICAgIHRoaXMubGFzZXJQYXRoTWFuYWdlci5lbmRQYXRoKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKCFhY3RpdmVUb29sLmxvY2tlZCAmJiBhY3RpdmVUb29sLnR5cGUgIT09IFwiZnJlZWRyYXdcIikge1xuICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXSxcbiAgICAgICAgICBhY3RpdmVUb29sOiB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW11cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChoaXRFbGVtZW50ICYmIHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50ICYmIHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQgJiYgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQudGltZVN0YW1wIC0gdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudC50aW1lU3RhbXAgPCAzMDAgJiYgZ2VzdHVyZS5wb2ludGVycy5zaXplIDw9IDEgJiYgaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSAmJiB0aGlzLmlzRW1iZWRkYWJsZUNlbnRlcihoaXRFbGVtZW50LCB0aGlzLmxhc3RQb2ludGVyVXBFdmVudCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVFbWJlZGRhYmxlQ2VudGVyQ2xpY2soaGl0RWxlbWVudCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBtYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpIHtcbiAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiA1MCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHN1Z2dlc3RlZEJpbmRpbmdzID0gZ2V0RWxpZ2libGVFbGVtZW50c0ZvckJpbmRpbmcoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzdWdnZXN0ZWRCaW5kaW5nc1xuICAgIH0pO1xuICB9XG5cbiAgY2xlYXJTZWxlY3Rpb24oaGl0RWxlbWVudCkge1xuICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCBwcmV2U3RhdGUpLFxuICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbCxcbiAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgLy8gQ29udGludWUgZWRpdGluZyB0aGUgc2FtZSBncm91cCBpZiB0aGUgdXNlciBzZWxlY3RlZCBhIGRpZmZlcmVudFxuICAgICAgLy8gZWxlbWVudCBmcm9tIGl0XG4gICAgICBlZGl0aW5nR3JvdXBJZDogcHJldlN0YXRlLmVkaXRpbmdHcm91cElkICYmIGhpdEVsZW1lbnQgIT0gbnVsbCAmJiBpc0VsZW1lbnRJbkdyb3VwKGhpdEVsZW1lbnQsIHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCkgPyBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQgOiBudWxsXG4gICAgfSkpO1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsLFxuICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgfSk7XG4gIH1cblxuICBnZXRUZXh0V3lzaXd5Z1NuYXBwZWRUb0NlbnRlclBvc2l0aW9uKHgsIHksIGFwcFN0YXRlLCBjb250YWluZXIpIHtcbiAgICBpZiAoY29udGFpbmVyKSB7XG4gICAgICBsZXQgZWxlbWVudENlbnRlclggPSBjb250YWluZXIueCArIGNvbnRhaW5lci53aWR0aCAvIDI7XG4gICAgICBsZXQgZWxlbWVudENlbnRlclkgPSBjb250YWluZXIueSArIGNvbnRhaW5lci5oZWlnaHQgLyAyO1xuICAgICAgY29uc3QgZWxlbWVudENlbnRlciA9IGdldENvbnRhaW5lckNlbnRlcihjb250YWluZXIsIGFwcFN0YXRlKTtcblxuICAgICAgaWYgKGVsZW1lbnRDZW50ZXIpIHtcbiAgICAgICAgZWxlbWVudENlbnRlclggPSBlbGVtZW50Q2VudGVyLng7XG4gICAgICAgIGVsZW1lbnRDZW50ZXJZID0gZWxlbWVudENlbnRlci55O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBkaXN0YW5jZVRvQ2VudGVyID0gTWF0aC5oeXBvdCh4IC0gZWxlbWVudENlbnRlclgsIHkgLSBlbGVtZW50Q2VudGVyWSk7XG4gICAgICBjb25zdCBpc1NuYXBwZWRUb0NlbnRlciA9IGRpc3RhbmNlVG9DZW50ZXIgPCBURVhUX1RPX0NFTlRFUl9TTkFQX1RIUkVTSE9MRDtcblxuICAgICAgaWYgKGlzU25hcHBlZFRvQ2VudGVyKSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB2aWV3cG9ydFgsXG4gICAgICAgICAgeTogdmlld3BvcnRZXG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogZWxlbWVudENlbnRlclgsXG4gICAgICAgICAgc2NlbmVZOiBlbGVtZW50Q2VudGVyWVxuICAgICAgICB9LCBhcHBTdGF0ZSk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdmlld3BvcnRYLFxuICAgICAgICAgIHZpZXdwb3J0WSxcbiAgICAgICAgICBlbGVtZW50Q2VudGVyWCxcbiAgICAgICAgICBlbGVtZW50Q2VudGVyWVxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGdldENhbnZhc09mZnNldHMoKSB7XG4gICAgdmFyIF9hO1xuXG4gICAgaWYgKChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmN1cnJlbnQpIHtcbiAgICAgIGNvbnN0IGV4Y2FsaWRyYXdDb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgbGVmdCxcbiAgICAgICAgdG9wXG4gICAgICB9ID0gZXhjYWxpZHJhd0NvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG9mZnNldExlZnQ6IGxlZnQsXG4gICAgICAgIG9mZnNldFRvcDogdG9wXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBvZmZzZXRMZWZ0OiAwLFxuICAgICAgb2Zmc2V0VG9wOiAwXG4gICAgfTtcbiAgfVxuXG4gIHVwZGF0ZUxhbmd1YWdlKCkge1xuICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCBjdXJyZW50TGFuZyA9IGxhbmd1YWdlcy5maW5kKGxhbmcgPT4gbGFuZy5jb2RlID09PSB0aGlzLnByb3BzLmxhbmdDb2RlKSB8fCBkZWZhdWx0TGFuZztcbiAgICAgIHlpZWxkIHNldExhbmd1YWdlKGN1cnJlbnRMYW5nKTtcbiAgICAgIHRoaXMuc2V0QXBwU3RhdGUoe30pO1xuICAgIH0pO1xuICB9XG5cbn1cblxuQXBwLmRlZmF1bHRQcm9wcyA9IHtcbiAgLy8gbmVlZGVkIGZvciB0ZXN0cyB0byBwYXNzIHNpbmNlIHdlIGRpcmVjdGx5IHJlbmRlciBBcHAgaW4gbWFueSB0ZXN0c1xuICBVSU9wdGlvbnM6IERFRkFVTFRfVUlfT1BUSU9OU1xufTtcblxuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBFTlYuVEVTVCB8fCBwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gXCJwcm9kdWN0aW9uXCIpIHtcbiAgd2luZG93LmggPSB3aW5kb3cuaCB8fCB7fTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMod2luZG93LmgsIHtcbiAgICBlbGVtZW50czoge1xuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuXG4gICAgICBnZXQoKSB7XG4gICAgICAgIHZhciBfYTtcblxuICAgICAgICByZXR1cm4gKF9hID0gdGhpcy5hcHApID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcbiAgICAgIH0sXG5cbiAgICAgIHNldChlbGVtZW50cykge1xuICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgcmV0dXJuIChfYSA9IHRoaXMuYXBwKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Euc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGVsZW1lbnRzKTtcbiAgICAgIH1cblxuICAgIH1cbiAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IEFwcDsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../../components/App.tsx\n");
2532
+ 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_71__ = __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 _snapping__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! ../snapping */ \"../../snapping.ts\");\n/* harmony import */ var _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(/*! ../actions/actionBoundText */ \"../../actions/actionBoundText.tsx\");\n/* harmony import */ var _BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(/*! ./BraveMeasureTextError */ \"../../components/BraveMeasureTextError.tsx\");\n/* harmony import */ var _EyeDropper__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(/*! ./EyeDropper */ \"../../components/EyeDropper.tsx\");\n/* harmony import */ var _data_transform__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(/*! ../data/transform */ \"../../data/transform.ts\");\n/* harmony import */ var _Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(/*! ./Sidebar/Sidebar */ \"../../components/Sidebar/Sidebar.tsx\");\n/* harmony import */ var _canvases__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(/*! ./canvases */ \"../../components/canvases/index.tsx\");\n/* harmony import */ var _scene_Renderer__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(/*! ../scene/Renderer */ \"../../scene/Renderer.ts\");\n/* harmony import */ var _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(/*! ../scene/ShapeCache */ \"../../scene/ShapeCache.ts\");\n/* harmony import */ var _MermaidToExcalidraw__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(/*! ./MermaidToExcalidraw */ \"../../components/MermaidToExcalidraw.tsx\");\n/* harmony import */ var _LaserTool_LaserTool__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(/*! ./LaserTool/LaserTool */ \"../../components/LaserTool/LaserTool.tsx\");\n/* harmony import */ var _LaserTool_LaserPathManager__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(/*! ./LaserTool/LaserPathManager */ \"../../components/LaserTool/LaserPathManager.ts\");\n/* harmony import */ var _cursor__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(/*! ../cursor */ \"../../cursor.ts\");\n/* harmony import */ var _emitter__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(/*! ../emitter */ \"../../emitter.ts\");\nvar __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {\n function adopt(value) {\n return value instanceof P ? value : new P(function (resolve) {\n resolve(value);\n });\n }\n\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) {\n try {\n step(generator.next(value));\n } catch (e) {\n reject(e);\n }\n }\n\n function rejected(value) {\n try {\n step(generator[\"throw\"](value));\n } catch (e) {\n reject(e);\n }\n }\n\n function step(result) {\n result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n }\n\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst AppContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst AppPropsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nconst deviceContextInitialValue = {\n viewport: {\n isMobile: false,\n isLandscape: false\n },\n editor: {\n isMobile: false,\n canFitSidebar: false\n },\n isTouchScreen: false\n};\nconst DeviceContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(deviceContextInitialValue);\nDeviceContext.displayName = \"DeviceContext\";\nconst ExcalidrawContainerContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext({\n container: null,\n id: null\n});\nExcalidrawContainerContext.displayName = \"ExcalidrawContainerContext\";\nconst ExcalidrawElementsContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext([]);\nExcalidrawElementsContext.displayName = \"ExcalidrawElementsContext\";\nconst ExcalidrawAppStateContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(Object.assign(Object.assign({}, (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)()), {\n width: 0,\n height: 0,\n offsetLeft: 0,\n offsetTop: 0\n}));\nExcalidrawAppStateContext.displayName = \"ExcalidrawAppStateContext\";\nconst ExcalidrawSetAppStateContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(() => {\n console.warn(\"unitialized ExcalidrawSetAppStateContext context!\");\n});\nExcalidrawSetAppStateContext.displayName = \"ExcalidrawSetAppStateContext\";\nconst ExcalidrawActionManagerContext = react__WEBPACK_IMPORTED_MODULE_1___default().createContext(null);\nExcalidrawActionManagerContext.displayName = \"ExcalidrawActionManagerContext\";\nconst useApp = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(AppContext);\nconst useAppProps = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(AppPropsContext);\nconst useDevice = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(DeviceContext);\nconst useExcalidrawContainer = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawContainerContext);\nconst useExcalidrawElements = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawElementsContext);\nconst useExcalidrawAppState = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawAppStateContext);\nconst useExcalidrawSetAppState = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawSetAppStateContext);\nconst useExcalidrawActionManager = () => (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(ExcalidrawActionManagerContext);\nconst supportsResizeObserver = typeof window !== \"undefined\" && \"ResizeObserver\" in window;\nlet didTapTwice = false;\nlet tappedTwiceTimer = 0;\nlet isHoldingSpace = false;\nlet isPanning = false;\nlet isDraggingScrollBar = false;\nlet currentScrollBars = {\n horizontal: null,\n vertical: null\n};\nlet touchTimeout = 0;\nlet invalidateContextMenu = false;\n/**\n * Map of youtube embed video states\n */\n\nconst YOUTUBE_VIDEO_STATES = new Map();\nlet IS_PLAIN_PASTE = false;\nlet IS_PLAIN_PASTE_TIMER = 0;\nlet PLAIN_PASTE_TOAST_SHOWN = false;\nlet lastPointerUp = null;\nconst gesture = {\n pointers: new Map(),\n lastCenter: null,\n initialDistance: null,\n initialScale: null\n};\n\nclass App extends (react__WEBPACK_IMPORTED_MODULE_1___default().Component) {\n constructor(props) {\n 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.lastPointerDownEvent = null;\n this.lastPointerUpEvent = null;\n this.lastViewportPosition = {\n x: 0,\n y: 0\n };\n this.laserPathManager = new _LaserTool_LaserPathManager__WEBPACK_IMPORTED_MODULE_68__.LaserPathManager(this);\n this.onChangeEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_70__.Emitter();\n this.onPointerDownEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_70__.Emitter();\n this.onPointerUpEmitter = new _emitter__WEBPACK_IMPORTED_MODULE_70__.Emitter();\n\n this.updateEmbeddables = () => {\n const embeddableElements = new Map();\n let updated = false;\n this.scene.getNonDeletedElements().filter(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(element)) {\n embeddableElements.set(element.id, true);\n\n if (element.validated == null) {\n updated = true;\n const validated = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.embeddableURLValidator)(element.link, this.props.validateEmbeddable);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n validated\n }, false);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__.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_60__.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.isMobileBreakpoint = (width, height) => {\n return width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_PORTRAIT || height < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_HEIGHT_LANDSCAPE && width < _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_MAX_WIDTH_LANDSCAPE;\n };\n\n this.refreshViewportBreakpoints = () => {\n const container = this.excalidrawContainerRef.current;\n\n if (!container) {\n return;\n }\n\n const {\n clientWidth: viewportWidth,\n clientHeight: viewportHeight\n } = document.body;\n const prevViewportState = this.device.viewport;\n const nextViewportState = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(prevViewportState, {\n isLandscape: viewportWidth > viewportHeight,\n isMobile: this.isMobileBreakpoint(viewportWidth, viewportHeight)\n });\n\n if (prevViewportState !== nextViewportState) {\n this.device = Object.assign(Object.assign({}, this.device), {\n viewport: nextViewportState\n });\n return true;\n }\n\n return false;\n };\n\n this.refreshEditorBreakpoints = () => {\n const container = this.excalidrawContainerRef.current;\n\n if (!container) {\n return;\n }\n\n const {\n width: editorWidth,\n height: editorHeight\n } = container.getBoundingClientRect();\n const sidebarBreakpoint = this.props.UIOptions.dockedSidebarBreakpoint != null ? this.props.UIOptions.dockedSidebarBreakpoint : _constants__WEBPACK_IMPORTED_MODULE_12__.MQ_RIGHT_SIDEBAR_MIN_WIDTH;\n const prevEditorState = this.device.editor;\n const nextEditorState = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(prevEditorState, {\n isMobile: this.isMobileBreakpoint(editorWidth, editorHeight),\n canFitSidebar: editorWidth > sidebarBreakpoint\n });\n\n if (prevEditorState !== nextEditorState) {\n this.device = Object.assign(Object.assign({}, this.device), {\n editor: nextEditorState\n });\n return true;\n }\n\n return false;\n };\n\n this.onResize = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n this.scene.getElementsIncludingDeleted().forEach(element => _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__.ShapeCache[\"delete\"](element));\n this.refreshViewportBreakpoints();\n this.updateDOMRect();\n\n if (!supportsResizeObserver) {\n this.refreshEditorBreakpoints();\n }\n\n this.setState({});\n });\n\n this.renderInteractiveSceneCallback = ({\n atLeastOneVisibleElement,\n scrollBars,\n elements\n }) => {\n if (scrollBars) {\n currentScrollBars = scrollBars;\n }\n\n const scrolledOutside = // hide when editing text\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? false : !atLeastOneVisibleElement && elements.length > 0;\n\n if (this.state.scrolledOutside !== scrolledOutside) {\n this.setState({\n scrolledOutside\n });\n }\n\n this.scheduleImageRefresh();\n };\n\n this.onScroll = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n const {\n offsetTop,\n offsetLeft\n } = this.getCanvasOffsets();\n this.setState(state => {\n if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {\n return null;\n }\n\n return {\n offsetTop,\n offsetLeft\n };\n });\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.SCROLL_TIMEOUT); // Copy/paste\n\n this.onCut = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, \"keyboard\", event);\n event.preventDefault();\n event.stopPropagation();\n });\n this.onCopy = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n var _a;\n\n const isExcalidrawActive = (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);\n\n if (!isExcalidrawActive || (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n return;\n }\n\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, \"keyboard\", event);\n event.preventDefault();\n event.stopPropagation();\n });\n\n this.onTouchStart = event => {\n // fix for Apple Pencil Scribble\n // On Android, preventing the event would disable contextMenu on tap-hold\n if (!_constants__WEBPACK_IMPORTED_MODULE_12__.isAndroid) {\n event.preventDefault();\n }\n\n if (!didTapTwice) {\n didTapTwice = true;\n clearTimeout(tappedTwiceTimer);\n tappedTwiceTimer = window.setTimeout(App.resetTapTwice, _constants__WEBPACK_IMPORTED_MODULE_12__.TAP_TWICE_TIMEOUT);\n return;\n } // insert text only if we tapped twice with a single finger\n // event.touches.length === 1 will also prevent inserting text when user's zooming\n\n\n if (didTapTwice && event.touches.length === 1) {\n const touch = event.touches[0]; // @ts-ignore\n\n this.handleCanvasDoubleClick({\n clientX: touch.clientX,\n clientY: touch.clientY\n });\n didTapTwice = false;\n clearTimeout(tappedTwiceTimer);\n }\n\n if (_constants__WEBPACK_IMPORTED_MODULE_12__.isAndroid) {\n event.preventDefault();\n }\n\n if (event.touches.length === 2) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n };\n\n this.onTouchEnd = event => {\n this.resetContextMenuTimer();\n\n if (event.touches.length > 0) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n } else {\n gesture.pointers.clear();\n }\n };\n\n this.pasteFromClipboard = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => __awaiter(this, void 0, void 0, function* () {\n var _c, _d, _e;\n\n const isPlainPaste = !!IS_PLAIN_PASTE; // #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 }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state); // must be called in the same frame (thus before any awaits) as the paste\n // event else some browsers (FF...) will clear the clipboardData\n // (something something security)\n\n let file = (_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 && !isPlainPaste) {\n if (data.mixedContent) {\n return this.addElementsFromMixedContentPaste(data.mixedContent, {\n isPlainPaste,\n sceneX,\n sceneY\n });\n } else if (data.text) {\n const string = data.text.trim();\n\n if (string.startsWith(\"<svg\") && string.endsWith(\"</svg>\")) {\n // ignore SVG validation/normalization which will be done during image\n // initialization\n file = (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.SVGStringToFile)(string);\n }\n }\n } // prefer spreadsheet data over image file (MS Office/Libre Office)\n\n\n if ((0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.isSupportedImageFile)(file) && !data.spreadsheet) {\n 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_61__.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.editor.canFitSidebar && _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.get(_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_62__.isSidebarDockedAtom) ? this.state.openSidebar : null\n }), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: null,\n selectedElementIds: nextElementsToSelect.reduce((acc, element) => {\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(element)) {\n acc[element.id] = true;\n }\n\n return acc;\n }, {})\n }, this.scene.getNonDeletedElements(), this.state, this)), () => {\n if (opts.files) {\n this.addNewImagesToImageCache();\n }\n });\n this.setActiveTool({\n type: \"selection\"\n });\n\n if (opts.fitToContent) {\n this.scrollToContent(newElements, {\n fitToContent: true\n });\n }\n };\n\n this.setAppState = (state, callback) => {\n this.setState(state, callback);\n };\n\n this.removePointer = event => {\n if (touchTimeout) {\n this.resetContextMenuTimer();\n }\n\n gesture.pointers.delete(event.pointerId);\n };\n\n this.toggleLock = (source = \"ui\") => {\n if (!this.state.activeTool.locked) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", \"toggleLock\", `${source} (${this.device.editor.isMobile ? \"mobile\" : \"desktop\"})`);\n }\n\n this.setState(prevState => {\n return {\n activeTool: Object.assign(Object.assign(Object.assign({}, prevState.activeTool), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, prevState.activeTool.locked ? {\n type: \"selection\"\n } : prevState.activeTool)), {\n locked: !prevState.activeTool.locked\n })\n };\n });\n };\n\n this.updateFrameRendering = opts => {\n this.setState(prevState => {\n var _a, _b, _c, _d;\n\n const next = typeof opts === \"function\" ? opts(prevState.frameRendering) : opts;\n return {\n frameRendering: {\n enabled: (_a = next === null || next === void 0 ? void 0 : next.enabled) !== null && _a !== void 0 ? _a : prevState.frameRendering.enabled,\n clip: (_b = next === null || next === void 0 ? void 0 : next.clip) !== null && _b !== void 0 ? _b : prevState.frameRendering.clip,\n name: (_c = next === null || next === void 0 ? void 0 : next.name) !== null && _c !== void 0 ? _c : prevState.frameRendering.name,\n outline: (_d = next === null || next === void 0 ? void 0 : next.outline) !== null && _d !== void 0 ? _d : prevState.frameRendering.outline\n }\n };\n });\n };\n\n this.togglePenMode = force => {\n this.setState(prevState => {\n return {\n penMode: force !== null && force !== void 0 ? force : !prevState.penMode,\n penDetected: true\n };\n });\n };\n\n this.onHandToolToggle = () => {\n this.actionManager.executeAction(_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.actionToggleHandTool);\n };\n /**\n * Zooms on canvas viewport center\n */\n\n\n this.zoomCanvas = (\n /** decimal fraction between 0.1 (10% zoom) and 30 (3000% zoom) */\n value) => {\n this.setState(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.state.width / 2 + this.state.offsetLeft,\n viewportY: this.state.height / 2 + this.state.offsetTop,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(value)\n }, this.state)));\n };\n\n this.cancelInProgresAnimation = null;\n\n this.scrollToContent = (target = this.scene.getNonDeletedElements(), opts) => {\n var _a, _b;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this); // convert provided target into ExcalidrawElement[] if necessary\n\n const targetElements = Array.isArray(target) ? target : [target];\n let zoom = this.state.zoom;\n let scrollX = this.state.scrollX;\n let scrollY = this.state.scrollY;\n\n if ((opts === null || opts === void 0 ? void 0 : opts.fitToContent) || (opts === null || opts === void 0 ? void 0 : opts.fitToViewport)) {\n const {\n appState\n } = (0,_actions_actionCanvas__WEBPACK_IMPORTED_MODULE_54__.zoomToFit)({\n targetElements,\n appState: this.state,\n fitToViewport: !!(opts === null || opts === void 0 ? void 0 : opts.fitToViewport),\n viewportZoomFactor: opts === null || opts === void 0 ? void 0 : opts.viewportZoomFactor\n });\n zoom = appState.zoom;\n scrollX = appState.scrollX;\n scrollY = appState.scrollY;\n } else {\n // compute only the viewport location, without any zoom adjustment\n const scroll = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.calculateScrollCenter)(targetElements, this.state);\n scrollX = scroll.scrollX;\n scrollY = scroll.scrollY;\n } // when animating, we use RequestAnimationFrame to prevent the animation\n // from slowing down other processes\n\n\n if (opts === null || opts === void 0 ? void 0 : opts.animate) {\n const origScrollX = this.state.scrollX;\n const origScrollY = this.state.scrollY;\n const origZoom = this.state.zoom.value;\n const cancel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeToValuesRAF)({\n fromValues: {\n scrollX: origScrollX,\n scrollY: origScrollY,\n zoom: origZoom\n },\n toValues: {\n scrollX,\n scrollY,\n zoom: zoom.value\n },\n interpolateValue: (from, to, progress, key) => {\n // for zoom, use different easing\n if (key === \"zoom\") {\n return from * Math.pow(to / from, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.easeOut)(progress));\n } // handle using default\n\n\n return undefined;\n },\n onStep: ({\n scrollX,\n scrollY,\n zoom\n }) => {\n this.setState({\n scrollX,\n scrollY,\n zoom: {\n value: zoom\n }\n });\n },\n onStart: () => {\n this.setState({\n shouldCacheIgnoreZoom: true\n });\n },\n onEnd: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n onCancel: () => {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n },\n duration: (_b = opts === null || opts === void 0 ? void 0 : opts.duration) !== null && _b !== void 0 ? _b : 500\n });\n\n this.cancelInProgresAnimation = () => {\n cancel();\n this.cancelInProgresAnimation = null;\n };\n } else {\n this.setState({\n scrollX,\n scrollY,\n zoom\n });\n }\n };\n /** use when changing scrollX/scrollY/zoom based on user interaction */\n\n\n this.translateCanvas = state => {\n var _a;\n\n (_a = this.cancelInProgresAnimation) === null || _a === void 0 ? void 0 : _a.call(this);\n this.setState(state);\n };\n\n this.setToast = toast => {\n this.setState({\n toast\n });\n };\n\n this.restoreFileFromShare = () => __awaiter(this, void 0, void 0, function* () {\n try {\n const webShareTargetCache = yield caches.open(\"web-share-target\");\n const response = yield webShareTargetCache.match(\"shared-file\");\n\n if (response) {\n const blob = yield response.blob();\n const file = new File([blob], blob.name || \"\", {\n type: blob.type\n });\n this.loadFileToCanvas(file, null);\n yield webShareTargetCache.delete(\"shared-file\");\n window.history.replaceState(null, _constants__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, window.location.pathname);\n }\n } catch (error) {\n this.setState({\n errorMessage: error.message\n });\n }\n });\n /** adds supplied files to existing files in the appState */\n\n\n this.addFiles = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(files => {\n const filesMap = files.reduce((acc, fileData) => {\n acc.set(fileData.id, fileData);\n return acc;\n }, new Map());\n this.files = Object.assign(Object.assign({}, this.files), Object.fromEntries(filesMap));\n this.scene.getNonDeletedElements().forEach(element => {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(element) && filesMap.has(element.fileId)) {\n this.imageCache.delete(element.fileId);\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__.ShapeCache[\"delete\"](element);\n }\n });\n this.scene.informMutation();\n this.addNewImagesToImageCache();\n });\n this.updateScene = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(sceneData => {\n if (sceneData.commitToHistory) {\n this.history.resumeRecording();\n }\n\n if (sceneData.appState) {\n this.setState(sceneData.appState);\n }\n\n if (sceneData.elements) {\n this.scene.replaceAllElements(sceneData.elements);\n }\n\n if (sceneData.collaborators) {\n this.setState({\n collaborators: sceneData.collaborators\n });\n }\n });\n\n this.onSceneUpdated = () => {\n this.setState({});\n };\n /**\n * @returns whether the menu was toggled on or off\n */\n\n\n this.toggleSidebar = ({\n name,\n tab,\n force\n }) => {\n var _a;\n\n let nextName;\n\n if (force === undefined) {\n nextName = ((_a = this.state.openSidebar) === null || _a === void 0 ? void 0 : _a.name) === name ? null : name;\n } else {\n nextName = force ? name : null;\n }\n\n this.setState({\n openSidebar: nextName ? {\n name: nextName,\n tab\n } : null\n });\n return !!nextName;\n };\n\n this.updateCurrentCursorPosition = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n this.lastViewportPosition.x = event.clientX;\n this.lastViewportPosition.y = event.clientY;\n }); // Input handling\n\n this.onKeyDown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // normalize `event.key` when CapsLock is pressed #2372\n if (\"Proxy\" in window && (!event.shiftKey && /^[A-Z]$/.test(event.key) || event.shiftKey && /^[a-z]$/.test(event.key))) {\n event = new Proxy(event, {\n get(ev, prop) {\n const value = ev[prop];\n\n if (typeof value === \"function\") {\n // fix for Proxies hijacking `this`\n return value.bind(ev);\n }\n\n return prop === \"key\" ? // CapsLock inverts capitalization based on ShiftKey, so invert\n // it back\n event.shiftKey ? ev.key.toUpperCase() : ev.key.toLowerCase() : value;\n }\n\n });\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.V) {\n IS_PLAIN_PASTE = event.shiftKey;\n clearTimeout(IS_PLAIN_PASTE_TIMER); // reset (100ms to be safe that we it runs after the ensuing\n // paste event). Though, technically unnecessary to reset since we\n // (re)set the flag before each paste event.\n\n IS_PLAIN_PASTE_TIMER = window.setTimeout(() => {\n IS_PLAIN_PASTE = false;\n }, 100);\n } // prevent browser zoom in input fields\n\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target)) {\n if (event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.MINUS || event.code === _keys__WEBPACK_IMPORTED_MODULE_26__.CODES.EQUAL) {\n event.preventDefault();\n return;\n }\n } // bail if\n\n\n if ( // inside an input\n (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isWritableElement)(event.target) && // unless pressing escape (finalize action)\n event.key !== _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ESCAPE || // or unless using arrows (to move between buttons)\n (0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key) && (0,_utils__WEBPACK_IMPORTED_MODULE_33__.isInputLike)(event.target)) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.QUESTION_MARK) {\n this.setState({\n openDialog: \"help\"\n });\n return;\n } else if (event.key.toLowerCase() === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.E && event.shiftKey && event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n event.preventDefault();\n this.setState({\n openDialog: \"imageExport\"\n });\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_UP || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n let offset = (event.shiftKey ? this.state.width : this.state.height) / this.state.zoom.value;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.PAGE_DOWN) {\n offset = -offset;\n }\n\n if (event.shiftKey) {\n this.translateCanvas(state => ({\n scrollX: state.scrollX + offset\n }));\n } else {\n this.translateCanvas(state => ({\n scrollY: state.scrollY + offset\n }));\n }\n }\n\n if (this.actionManager.handleKeyDown(event)) {\n return;\n }\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {\n this.setState({\n isBindingEnabled: false\n });\n }\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.isArrowKey)(event.key)) {\n const step = this.state.gridSize && (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize) || (event.shiftKey ? _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_SHIFT_TRANSLATE_AMOUNT : _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_TRANSLATE_AMOUNT);\n let offsetX = 0;\n let offsetY = 0;\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_LEFT) {\n offsetX = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_RIGHT) {\n offsetX = step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_UP) {\n offsetY = -step;\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ARROW_DOWN) {\n offsetY = step;\n }\n\n const selectedElements = this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n });\n selectedElements.forEach(element => {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n x: element.x + offsetX,\n y: element.y + offsetY\n });\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element, {\n simultaneouslyUpdated: selectedElements\n });\n });\n this.maybeSuggestBindingForAll(selectedElements);\n event.preventDefault();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ENTER) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n const selectedElement = selectedElements[0];\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElement)) {\n if (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElement, this.scene)\n });\n }\n }\n } else if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isValidTextContainer)(selectedElement)) {\n let container;\n\n if (!(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElement)) {\n container = selectedElement;\n }\n\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(selectedElement, this.state);\n const sceneX = midPoint.x;\n const sceneY = midPoint.y;\n this.startTextEditing({\n sceneX,\n sceneY,\n container\n });\n event.preventDefault();\n return;\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(selectedElement)) {\n this.setState({\n editingFrame: selectedElement.id\n });\n }\n }\n } else if (!event.ctrlKey && !event.altKey && !event.metaKey && this.state.draggingElement === null) {\n const shape = (0,_shapes__WEBPACK_IMPORTED_MODULE_32__.findShapeByKey)(event.key);\n\n if (shape) {\n if (this.state.activeTool.type !== shape) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_9__.trackEvent)(\"toolbar\", shape, `keyboard (${this.device.editor.isMobile ? \"mobile\" : \"desktop\"})`);\n }\n\n this.setActiveTool({\n type: shape\n });\n event.stopPropagation();\n } else if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.Q) {\n this.toggleLock(\"keyboard\");\n event.stopPropagation();\n }\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE && gesture.pointers.size === 0) {\n isHoldingSpace = true;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n event.preventDefault();\n }\n\n if ((event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (this.state.activeTool.type === \"selection\" && !selectedElements.length) {\n return;\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && ((0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(this.state.activeTool.type) || selectedElements.some(element => (0,_scene__WEBPACK_IMPORTED_MODULE_29__.hasBackground)(element.type)))) {\n this.setState({\n openPopup: \"elementBackground\"\n });\n event.stopPropagation();\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S) {\n this.setState({\n openPopup: \"elementStroke\"\n });\n event.stopPropagation();\n }\n }\n\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.K && !event.altKey && !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if (this.state.activeTool.type === \"laser\") {\n this.setActiveTool({\n type: \"selection\"\n });\n } else {\n this.setActiveTool({\n type: \"laser\"\n });\n }\n\n return;\n }\n\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.BACKSPACE || event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.DELETE)) {\n _jotai__WEBPACK_IMPORTED_MODULE_55__.jotaiStore.set(_ActiveConfirmDialog__WEBPACK_IMPORTED_MODULE_56__.activeConfirmDialogAtom, \"clearCanvas\");\n } // eye dropper\n // -----------------------------------------------------------------------\n\n\n const lowerCased = event.key.toLocaleLowerCase();\n const isPickingStroke = lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.S && event.shiftKey;\n const isPickingBackground = event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.I || lowerCased === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.G && event.shiftKey;\n\n if (isPickingStroke || isPickingBackground) {\n this.openEyeDropper({\n type: isPickingStroke ? \"stroke\" : \"background\"\n });\n } // -----------------------------------------------------------------------\n\n });\n this.onWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // prevent browser pinch zoom on DOM elements\n if (!(event.target instanceof HTMLCanvasElement) && event.ctrlKey) {\n event.preventDefault();\n }\n });\n this.onKeyUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.SPACE) {\n if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (this.state.activeTool.type === \"selection\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.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 var _a;\n\n const nextActiveTool = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, tool);\n\n if (nextActiveTool.type === \"hand\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (!isHoldingSpace) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n if ((0,_utils__WEBPACK_IMPORTED_MODULE_33__.isToolIcon)(document.activeElement)) {\n this.focusContainer();\n }\n\n if (!(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElementType)(nextActiveTool.type)) {\n this.setState({\n suggestedBindings: []\n });\n }\n\n if (nextActiveTool.type === \"image\") {\n this.onImageAction({\n insertOnCanvasDirectly: (_a = tool.type === \"image\" && tool.insertOnCanvasDirectly) !== null && _a !== void 0 ? _a : false\n });\n }\n\n this.setState(prevState => {\n const commonResets = {\n snapLines: prevState.snapLines.length ? [] : prevState.snapLines,\n originSnapOffset: null,\n activeEmbeddable: null\n };\n\n if (nextActiveTool.type !== \"selection\") {\n return Object.assign(Object.assign(Object.assign({}, prevState), {\n activeTool: nextActiveTool,\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n selectedGroupIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n editingGroupId: null,\n multiElement: null\n }), commonResets);\n }\n\n return Object.assign(Object.assign(Object.assign({}, prevState), {\n activeTool: nextActiveTool\n }), commonResets);\n });\n };\n\n this.setOpenDialog = dialogType => {\n this.setState({\n openDialog: dialogType\n });\n };\n\n this.setCursor = cursor => {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, cursor);\n };\n\n this.resetCursor = () => {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n };\n /**\n * returns whether user is making a gesture with >= 2 fingers (points)\n * on o touch screen (not on a trackpad). Currently only relates to Darwin\n * (iOS/iPadOS,MacOS), but may work on other devices in the future if\n * GestureEvent is standardized.\n */\n\n\n this.isTouchScreenMultiTouchGesture = () => {\n // we don't want to deselect when using trackpad, and multi-point gestures\n // only work on touch screens, so checking for >= pointers means we're on a\n // touchscreen\n return gesture.pointers.size >= 2;\n }; // fires only on Safari\n\n\n this.onGestureStart = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // we only want to deselect on touch screens because user may have selected\n // elements by mistake while zooming\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null\n });\n }\n\n gesture.initialScale = this.state.zoom.value;\n }); // fires only on Safari\n\n this.onGestureChange = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // onGestureChange only has zoom factor but not the center.\n // If we're on iPad or iPhone, then we recognize multi-touch and will\n // zoom in at the right location in the touchmove handler\n // (handleCanvasPointerMove).\n //\n // On Macbook trackpad, we don't have those events so will zoom in at the\n // current location instead.\n //\n // As such, bail from this handler on touch devices.\n\n if (this.isTouchScreenMultiTouchGesture()) {\n return;\n }\n\n const initialScale = gesture.initialScale;\n\n if (initialScale) {\n this.setState(state => Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * event.scale)\n }, state)));\n }\n }); // fires only on Safari\n\n this.onGestureEnd = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault(); // reselect elements only on touch screens (see onGestureStart)\n\n if (this.isTouchScreenMultiTouchGesture()) {\n this.setState({\n previousSelectedElementIds: {},\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(this.state.previousSelectedElementIds, this.state)\n });\n }\n\n gesture.initialScale = null;\n });\n\n this.startTextEditing = ({\n sceneX,\n sceneY,\n insertAtParentCenter = true,\n container\n }) => {\n var _a, _b;\n\n let shouldBindToContainer = false;\n let parentCenterPosition = insertAtParentCenter && this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n\n if (container && parentCenterPosition) {\n const boundTextElementToContainer = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(container);\n\n if (!boundTextElementToContainer) {\n shouldBindToContainer = true;\n }\n }\n\n let existingTextElement = null;\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1) {\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(selectedElements[0])) {\n existingTextElement = selectedElements[0];\n } else if (container) {\n existingTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(selectedElements[0]);\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n } else {\n existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);\n }\n\n const fontFamily = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.fontFamily) || this.state.currentItemFontFamily;\n const lineHeight = (existingTextElement === null || existingTextElement === void 0 ? void 0 : existingTextElement.lineHeight) || (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(fontFamily);\n const fontSize = this.state.currentItemFontSize;\n\n if (!existingTextElement && shouldBindToContainer && container && !(0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isArrowElement)(container)) {\n const fontString = {\n fontSize,\n fontFamily\n };\n const minWidth = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineWidth)((0,_utils__WEBPACK_IMPORTED_MODULE_33__.getFontString)(fontString), lineHeight);\n const minHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getApproxMinLineHeight)(fontSize, lineHeight);\n const newHeight = Math.max(container.height, minHeight);\n const newWidth = Math.max(container.width, minWidth);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n height: newHeight,\n width: newWidth\n });\n sceneX = container.x + newWidth / 2;\n sceneY = container.y + newHeight / 2;\n\n if (parentCenterPosition) {\n parentCenterPosition = this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);\n }\n }\n\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: sceneX,\n y: sceneY\n });\n const element = existingTextElement ? existingTextElement : (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)({\n x: parentCenterPosition ? parentCenterPosition.elementCenterX : sceneX,\n y: parentCenterPosition ? parentCenterPosition.elementCenterY : sceneY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text: \"\",\n fontSize,\n fontFamily,\n textAlign: parentCenterPosition ? \"center\" : this.state.currentItemTextAlign,\n verticalAlign: parentCenterPosition ? _constants__WEBPACK_IMPORTED_MODULE_12__.VERTICAL_ALIGN.MIDDLE : _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n containerId: shouldBindToContainer ? container === null || container === void 0 ? void 0 : container.id : undefined,\n groupIds: (_a = container === null || container === void 0 ? void 0 : container.groupIds) !== null && _a !== void 0 ? _a : [],\n lineHeight,\n angle: (_b = container === null || container === void 0 ? void 0 : container.angle) !== null && _b !== void 0 ? _b : 0,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n\n if (!existingTextElement && shouldBindToContainer && container) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(container, {\n boundElements: (container.boundElements || []).concat({\n type: \"text\",\n id: element.id\n })\n });\n }\n\n this.setState({\n editingElement: element\n });\n\n if (!existingTextElement) {\n if (container && shouldBindToContainer) {\n const containerIndex = this.scene.getElementIndex(container.id);\n this.scene.insertElementAtIndex(element, containerIndex + 1);\n } else {\n this.scene.addNewElement(element);\n }\n }\n\n this.setState({\n editingElement: element\n });\n this.handleTextWysiwyg(element, {\n isExistingElement: !!existingTextElement\n });\n };\n\n this.handleCanvasDoubleClick = event => {\n // case: double-clicking with arrow/line tool selected would both create\n // text and enter multiElement mode\n if (this.state.multiElement) {\n return;\n } // we should only be able to double click when mode is selection\n\n\n if (this.state.activeTool.type !== \"selection\") {\n return;\n }\n\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(selectedElements[0])) {\n if (event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && (!this.state.editingLinearElement || this.state.editingLinearElement.elementId !== selectedElements[0].id)) {\n this.history.resumeRecording();\n this.setState({\n editingLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(selectedElements[0], this.scene)\n });\n return;\n } else if (this.state.editingLinearElement && this.state.editingLinearElement.elementId === selectedElements[0].id) {\n return;\n }\n }\n\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n let {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedGroupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIds)(this.state);\n\n if (selectedGroupIds.length > 0) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n const selectedGroupId = hitElement && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getSelectedGroupIdForElement)(hitElement, this.state.selectedGroupIds);\n\n if (selectedGroupId) {\n this.setState(prevState => Object.assign(Object.assign({}, prevState), (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: selectedGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)));\n return;\n }\n }\n\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n\n if (!event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] && !this.state.viewModeEnabled) {\n const hitElement = this.getElementAtPosition(sceneX, sceneY);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) {\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"active\"\n }\n });\n return;\n }\n\n const container = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getTextBindableContainerAtPosition)(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY);\n\n if (container) {\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.hasBoundTextElement)(container) || !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTransparent)(container.backgroundColor) || (0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY])) {\n const midPoint = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, this.state);\n sceneX = midPoint.x;\n sceneY = midPoint.y;\n }\n }\n\n this.startTextEditing({\n sceneX,\n sceneY,\n insertAtParentCenter: !event.altKey,\n container\n });\n }\n };\n\n this.getElementLinkAtPosition = (scenePointer, hitElement) => {\n // Reversing so we traverse the elements in decreasing order\n // of z-index\n const elements = this.scene.getNonDeletedElements().slice().reverse();\n let hitElementIndex = Infinity;\n return elements.find((element, index) => {\n if (hitElement && element.id === hitElement.id) {\n hitElementIndex = index;\n }\n\n return element.link && index <= hitElementIndex && (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(element, this.state, [scenePointer.x, scenePointer.y], this.device.editor.isMobile);\n });\n };\n\n this.redirectToLink = (event, isTouchScreen) => {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDownEvent.clientX, this.lastPointerDownEvent.clientY, this.lastPointerUpEvent.clientX, this.lastPointerUpEvent.clientY);\n\n if (!this.hitLinkElement || // For touch screen allow dragging threshold else strict check\n isTouchScreen && draggedDistance > _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD || !isTouchScreen && draggedDistance !== 0) {\n return;\n }\n\n const lastPointerDownCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerDownEvent, this.state);\n const lastPointerDownHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerDownCoords.x, lastPointerDownCoords.y], this.device.editor.isMobile);\n const lastPointerUpCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(this.lastPointerUpEvent, this.state);\n const lastPointerUpHittingLinkIcon = (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLink)(this.hitLinkElement, this.state, [lastPointerUpCoords.x, lastPointerUpCoords.y], this.device.editor.isMobile);\n\n if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {\n let url = this.hitLinkElement.link;\n\n if (url) {\n url = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.normalizeLink)(url);\n let customEvent;\n\n if (this.props.onLinkOpen) {\n customEvent = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.wrapEvent)(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.EXCALIDRAW_LINK, event.nativeEvent);\n this.props.onLinkOpen(Object.assign(Object.assign({}, this.hitLinkElement), {\n link: url\n }), customEvent);\n }\n\n if (!(customEvent === null || customEvent === void 0 ? void 0 : customEvent.defaultPrevented)) {\n const target = (0,_data_url__WEBPACK_IMPORTED_MODULE_46__.isLocalLink)(url) ? \"_self\" : \"_blank\";\n const newWindow = window.open(undefined, target); // https://mathiasbynens.github.io/rel-noopener/\n\n if (newWindow) {\n newWindow.opener = null;\n newWindow.location = url;\n }\n }\n }\n }\n };\n\n this.getTopLayerFrameAtSceneCoords = sceneCoords => {\n const frames = this.scene.getNonDeletedFrames().filter(frame => (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)(sceneCoords, frame));\n return frames.length ? frames[frames.length - 1] : null;\n };\n\n this.handleCanvasPointerMove = event => {\n var _a, _b;\n\n this.savePointer(event.clientX, event.clientY, this.state.cursorButton);\n\n if (gesture.pointers.has(event.pointerId)) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n }\n\n const initialScale = gesture.initialScale;\n\n if (gesture.pointers.size === 2 && gesture.lastCenter && initialScale && gesture.initialDistance) {\n const center = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n const deltaX = center.x - gesture.lastCenter.x;\n const deltaY = center.y - gesture.lastCenter.y;\n gesture.lastCenter = center;\n const distance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n const scaleFactor = this.state.activeTool.type === \"freedraw\" && this.state.penMode ? 1 : distance / gesture.initialDistance;\n const nextZoom = scaleFactor ? (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(initialScale * scaleFactor) : this.state.zoom.value;\n this.setState(state => {\n const zoomState = (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: center.x,\n viewportY: center.y,\n nextZoom\n }, state);\n this.translateCanvas({\n zoom: zoomState.zoom,\n scrollX: zoomState.scrollX + deltaX / nextZoom,\n scrollY: zoomState.scrollY + deltaY / nextZoom,\n shouldCacheIgnoreZoom: true\n });\n });\n this.resetShouldCacheIgnoreZoomDebounced();\n } else {\n gesture.lastCenter = gesture.initialDistance = gesture.initialScale = null;\n }\n\n if (isHoldingSpace || isPanning || isDraggingScrollBar || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state)) {\n return;\n }\n\n const isPointerOverScrollBars = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop);\n const isOverScrollBar = isPointerOverScrollBars.isOverEither;\n\n if (!this.state.draggingElement && !this.state.multiElement) {\n if (isOverScrollBar) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n }\n\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const {\n x: scenePointerX,\n y: scenePointerY\n } = scenePointer;\n\n if (!this.state.draggingElement && (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.isActiveToolNonLinearSnappable)(this.state.activeTool.type)) {\n const {\n originOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.getSnapLinesAtPointer)(this.scene.getNonDeletedElements(), this.state, {\n x: scenePointerX,\n y: scenePointerY\n }, event);\n this.setState({\n snapLines,\n originSnapOffset: originOffset\n });\n } else if (!this.state.draggingElement) {\n this.setState({\n snapLines: []\n });\n }\n\n if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerMove(event, scenePointerX, scenePointerY, this.state);\n\n if (editingLinearElement && editingLinearElement !== this.state.editingLinearElement) {\n // Since we are reading from previous state which is not possible with\n // automatic batching in React 18 hence using flush sync to synchronously\n // update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n this.setState({\n editingLinearElement\n });\n });\n }\n\n if ((editingLinearElement === null || editingLinearElement === void 0 ? void 0 : editingLinearElement.lastUncommittedPoint) != null) {\n this.maybeSuggestBindingAtCursor(scenePointer);\n } else {\n // causes stack overflow if not sync\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n this.setState({\n suggestedBindings: []\n });\n });\n }\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElementType)(this.state.activeTool.type)) {\n // Hovering with a selected tool or creating new linear element via click\n // and point\n const {\n draggingElement\n } = this.state;\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [scenePointer], this.state.startBoundElement);\n } else {\n this.maybeSuggestBindingAtCursor(scenePointer);\n }\n }\n\n if (this.state.multiElement) {\n const {\n multiElement\n } = this.state;\n const {\n x: rx,\n y: ry\n } = multiElement;\n const {\n points,\n lastCommittedPoint\n } = multiElement;\n const lastPoint = points[points.length - 1];\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n\n if (lastPoint === lastCommittedPoint) {\n // if we haven't yet created a temp point and we're beyond commit-zone\n // threshold, add a point\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(scenePointerX - rx, scenePointerY - ry, lastPoint[0], lastPoint[1]) >= _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: [...points, [scenePointerX - rx, scenePointerY - ry]]\n });\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER); // in this branch, we're inside the commit zone, and no uncommitted\n // point exists. Thus do nothing (don't add/remove points).\n }\n } else if (points.length > 2 && lastCommittedPoint && (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(scenePointerX - rx, scenePointerY - ry, lastCommittedPoint[0], lastCommittedPoint[1]) < _constants__WEBPACK_IMPORTED_MODULE_12__.LINE_CONFIRM_THRESHOLD) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: points.slice(0, -1)\n });\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(scenePointerX, scenePointerY, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const [lastCommittedX, lastCommittedY] = (_a = multiElement === null || multiElement === void 0 ? void 0 : multiElement.lastCommittedPoint) !== null && _a !== void 0 ? _a : [0, 0];\n let dxFromLastCommitted = gridX - rx - lastCommittedX;\n let dyFromLastCommitted = gridY - ry - lastCommittedY;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event)) {\n ({\n width: dxFromLastCommitted,\n height: dyFromLastCommitted\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)( // actual coordinate of the last committed point\n lastCommittedX + rx, lastCommittedY + ry, // cursor-grid coordinate\n gridX, gridY));\n }\n\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.isPathALoop)(points, this.state.zoom.value)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } // update last uncommitted point\n\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(multiElement, {\n points: [...points.slice(0, -1), [lastCommittedX + dxFromLastCommitted, lastCommittedY + dyFromLastCommitted]]\n });\n }\n\n return;\n }\n\n const hasDeselectedButton = Boolean(event.buttons);\n\n if (hasDeselectedButton || this.state.activeTool.type !== \"selection\" && this.state.activeTool.type !== \"text\" && this.state.activeTool.type !== \"eraser\") {\n return;\n }\n\n const elements = this.scene.getNonDeletedElements();\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.length === 1 && !isOverScrollBar && !this.state.editingLinearElement) {\n const elementWithTransformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getElementWithTransformHandleType)(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType);\n\n if (elementWithTransformHandleType && elementWithTransformHandleType.transformHandleType) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCursorForResizingElement)(elementWithTransformHandleType));\n return;\n }\n } else if (selectedElements.length > 1 && !isOverScrollBar) {\n const transformHandleType = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getTransformHandleTypeFromCoords)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType);\n\n if (transformHandleType) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCursorForResizingElement)({\n transformHandleType\n }));\n return;\n }\n }\n\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n this.hitLinkElement = this.getElementLinkAtPosition(scenePointer, hitElement);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n return;\n }\n\n if (this.hitLinkElement && !this.state.selectedElementIds[this.hitLinkElement.id]) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.showHyperlinkTooltip)(this.hitLinkElement, this.state);\n } else {\n (0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.hideHyperlinkToolip)();\n\n if (hitElement && (hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement)) && this.state.selectedElementIds[hitElement.id] && !this.state.contextMenu && !this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: \"info\"\n });\n } else if (this.state.activeTool.type === \"text\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(hitElement) ? _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.TEXT : _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.CROSSHAIR);\n } else if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else if (isOverScrollBar) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n } else if (this.state.selectedLinearElement) {\n this.handleHoverSelectedLinearElement(this.state.selectedLinearElement, scenePointerX, scenePointerY);\n } else if ( // if using cmd/ctrl, we're not dragging\n !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) {\n if ((hitElement || this.isHittingCommonBoundingBoxOfSelectedElements(scenePointer, selectedElements)) && !(hitElement === null || hitElement === void 0 ? void 0 : hitElement.locked)) {\n if (hitElement && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, event, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n this.setState({\n activeEmbeddable: {\n element: hitElement,\n state: \"hover\"\n }\n });\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n\n if (((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) === \"hover\") {\n this.setState({\n activeEmbeddable: null\n });\n }\n }\n }\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n };\n\n this.handleEraser = (event, pointerDownState, scenePointer) => {\n const updateElementIds = elements => {\n elements.forEach(element => {\n if (element.locked) {\n return;\n }\n\n idsToUpdate.push(element.id);\n\n if (event.altKey) {\n if (pointerDownState.elementIdsToErase[element.id] && pointerDownState.elementIdsToErase[element.id].erase) {\n pointerDownState.elementIdsToErase[element.id].erase = false;\n }\n } else if (!pointerDownState.elementIdsToErase[element.id]) {\n pointerDownState.elementIdsToErase[element.id] = {\n erase: true,\n opacity: element.opacity\n };\n }\n });\n };\n\n const idsToUpdate = [];\n const distance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y, scenePointer.x, scenePointer.y);\n const threshold = 10 / this.state.zoom.value;\n const point = Object.assign({}, pointerDownState.lastCoords);\n let samplingInterval = 0;\n\n while (samplingInterval <= distance) {\n const hitElements = this.getElementsAtPosition(point.x, point.y);\n updateElementIds(hitElements); // Exit since we reached current point\n\n if (samplingInterval === distance) {\n break;\n } // Calculate next point in the line at a distance of sampling interval\n\n\n samplingInterval = Math.min(samplingInterval + threshold, distance);\n const distanceRatio = samplingInterval / distance;\n const nextX = (1 - distanceRatio) * point.x + distanceRatio * scenePointer.x;\n const nextY = (1 - distanceRatio) * point.y + distanceRatio * scenePointer.y;\n point.x = nextX;\n point.y = nextY;\n }\n\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n const id = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && idsToUpdate.includes(ele.containerId) ? ele.containerId : ele.id;\n\n if (idsToUpdate.includes(id)) {\n if (event.altKey) {\n if (pointerDownState.elementIdsToErase[id] && pointerDownState.elementIdsToErase[id].erase === false) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[id].opacity\n });\n }\n } else {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: _constants__WEBPACK_IMPORTED_MODULE_12__.ELEMENT_READY_TO_ERASE_OPACITY\n });\n }\n }\n\n return ele;\n });\n this.scene.replaceAllElements(elements);\n pointerDownState.lastCoords.x = scenePointer.x;\n pointerDownState.lastCoords.y = scenePointer.y;\n }; // set touch moving for mobile context menu\n\n\n this.handleTouchMove = event => {\n invalidateContextMenu = true;\n };\n\n this.handleCanvasPointerDown = event => {\n var _a, _b; // since contextMenu options are potentially evaluated on each render,\n // and an contextMenu action may depend on selection state, we must\n // close the contextMenu before we update the selection on pointerDown\n // (e.g. resetting selection)\n\n\n if (this.state.contextMenu) {\n this.setState({\n contextMenu: null\n });\n }\n\n if (this.state.snapLines) {\n this.setAppState({\n snapLines: []\n });\n }\n\n this.updateGestureOnPointerDown(event); // if dragging element is freedraw and another pointerdown event occurs\n // a second finger is on the screen\n // discard the freedraw element if it is very short because it is likely\n // just a spike, otherwise finalize the freedraw element when the second\n // finger is lifted\n\n if (event.pointerType === \"touch\" && this.state.draggingElement && this.state.draggingElement.type === \"freedraw\") {\n const element = this.state.draggingElement;\n this.updateScene(Object.assign(Object.assign({}, element.points.length < 10 ? {\n elements: this.scene.getElementsIncludingDeleted().filter(el => el.id !== element.id)\n } : {}), {\n appState: {\n draggingElement: null,\n editingElement: null,\n startBoundElement: null,\n suggestedBindings: [],\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.keys(this.state.selectedElementIds).filter(key => key !== element.id).reduce((obj, key) => {\n obj[key] = this.state.selectedElementIds[key];\n return obj;\n }, {}), this.state)\n }\n }));\n return;\n } // remove any active selection when we start to interact with canvas\n // (mainly, we care about removing selection outside the component which\n // would prevent our copy handling otherwise)\n\n\n const selection = document.getSelection();\n\n if (selection === null || selection === void 0 ? void 0 : selection.anchorNode) {\n selection.removeAllRanges();\n }\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices(event);\n this.maybeCleanupAfterMissingPointerUp(event); //fires only once, if pen is detected, penMode is enabled\n //the user can disable this by toggling the penMode button\n\n if (!this.state.penDetected && event.pointerType === \"pen\") {\n this.setState(prevState => {\n return {\n penMode: true,\n penDetected: true\n };\n });\n }\n\n if (!this.device.isTouchScreen && [\"pen\", \"touch\"].includes(event.pointerType)) {\n this.device = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateObject)(this.device, {\n isTouchScreen: true\n });\n }\n\n if (isPanning) {\n return;\n }\n\n this.lastPointerDownEvent = event; // we must exit before we set `cursorButton` state and `savePointer`\n // else it will send pointer state & laser pointer events in collab when\n // panning\n\n if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) {\n return;\n }\n\n this.setState({\n lastPointerDownWith: event.pointerType,\n cursorButton: \"down\"\n });\n this.savePointer(event.clientX, event.clientY, \"down\"); // only handle left mouse button or touch\n\n if (event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && event.button !== _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.TOUCH) {\n return;\n } // don't select while panning\n\n\n if (gesture.pointers.size > 1) {\n return;\n } // State for the duration of a pointer interaction, which starts with a\n // pointerDown event, ends with a pointerUp event (or another pointerDown)\n\n\n const pointerDownState = this.initialPointerDownState(event);\n this.setState({\n selectedElementsAreBeingDragged: false\n });\n\n if (this.handleDraggingScrollBar(event, pointerDownState)) {\n return;\n }\n\n this.clearSelectionIfNotUsingSelection();\n this.updateBindingEnabledOnPointerMove(event);\n\n if (this.handleSelectionOnPointerDown(event, pointerDownState)) {\n return;\n }\n\n const allowOnPointerDown = !this.state.penMode || event.pointerType !== \"touch\" || this.state.activeTool.type === \"selection\" || this.state.activeTool.type === \"text\" || this.state.activeTool.type === \"image\";\n\n if (!allowOnPointerDown) {\n return;\n }\n\n if (this.state.activeTool.type === \"text\") {\n this.handleTextOnPointerDown(event, pointerDownState);\n return;\n } else if (this.state.activeTool.type === \"arrow\" || this.state.activeTool.type === \"line\") {\n this.handleLinearElementOnPointerDown(event, this.state.activeTool.type, pointerDownState);\n } else if (this.state.activeTool.type === \"image\") {\n // reset image preview on pointerdown\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.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,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n } else if (this.state.activeTool.type === \"frame\") {\n this.createFrameElementOnPointerDown(pointerDownState);\n } else if (this.state.activeTool.type === \"laser\") {\n this.laserPathManager.startPath(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y);\n } else if (this.state.activeTool.type !== \"eraser\" && this.state.activeTool.type !== \"hand\") {\n this.createGenericElementOnPointerDown(this.state.activeTool.type, pointerDownState);\n }\n\n (_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.onPointerDown) === null || _b === void 0 ? void 0 : _b.call(_a, this.state.activeTool, pointerDownState);\n this.onPointerDownEmitter.trigger(this.state.activeTool, pointerDownState, event);\n const onPointerMove = this.onPointerMoveFromPointerDownHandler(pointerDownState);\n const onPointerUp = this.onPointerUpFromPointerDownHandler(pointerDownState);\n const onKeyDown = this.onKeyDownFromPointerDownHandler(pointerDownState);\n const onKeyUp = this.onKeyUpFromPointerDownHandler(pointerDownState);\n lastPointerUp = onPointerUp;\n\n if (!this.state.viewModeEnabled || this.state.activeTool.type === \"laser\") {\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, onKeyDown);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, onKeyUp);\n pointerDownState.eventListeners.onMove = onPointerMove;\n pointerDownState.eventListeners.onUp = onPointerUp;\n pointerDownState.eventListeners.onKeyUp = onKeyUp;\n pointerDownState.eventListeners.onKeyDown = onKeyDown;\n }\n };\n\n this.handleCanvasPointerUp = event => {\n var _a, _b;\n\n this.removePointer(event);\n this.lastPointerUpEvent = event;\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: event.clientX,\n clientY: event.clientY\n }, this.state);\n const clicklength = event.timeStamp - ((_b = (_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a.timeStamp) !== null && _b !== void 0 ? _b : 0);\n\n if (this.device.editor.isMobile && clicklength < 300) {\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, event, scenePointer.x, scenePointer.y)) {\n this.handleEmbeddableCenterClick(hitElement);\n return;\n }\n }\n\n if (this.device.isTouchScreen) {\n const hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);\n this.hitLinkElement = this.getElementLinkAtPosition(scenePointer, hitElement);\n }\n\n if (this.hitLinkElement && !this.state.selectedElementIds[this.hitLinkElement.id]) {\n if (clicklength < 300 && this.hitLinkElement.type === \"embeddable\" && !(0,_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.isPointHittingLinkIcon)(this.hitLinkElement, this.state, [scenePointer.x, scenePointer.y])) {\n this.handleEmbeddableCenterClick(this.hitLinkElement);\n } else {\n this.redirectToLink(event, this.device.isTouchScreen);\n }\n } else if (this.state.viewModeEnabled) {\n this.setState({\n activeEmbeddable: null,\n selectedElementIds: {}\n });\n }\n };\n\n this.maybeOpenContextMenuAfterPointerDownOnTouchDevices = event => {\n // deal with opening context menu on touch devices\n if (event.pointerType === \"touch\") {\n invalidateContextMenu = false;\n\n if (touchTimeout) {\n // If there's already a touchTimeout, this means that there's another\n // touch down and we are doing another touch, so we shouldn't open the\n // context menu.\n invalidateContextMenu = true;\n } else {\n // open the context menu with the first touch's clientX and clientY\n // if the touch is not moving\n touchTimeout = window.setTimeout(() => {\n touchTimeout = 0;\n\n if (!invalidateContextMenu) {\n this.handleCanvasContextMenu(event);\n }\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.TOUCH_CTX_MENU_TIMEOUT);\n }\n }\n };\n\n this.resetContextMenuTimer = () => {\n clearTimeout(touchTimeout);\n touchTimeout = 0;\n invalidateContextMenu = false;\n }; // Returns whether the event is a panning\n\n\n this.handleCanvasPanUsingWheelOrSpaceDrag = event => {\n if (!(gesture.pointers.size <= 1 && (event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.WHEEL || event.button === _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_BUTTON.MAIN && isHoldingSpace || (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isHandToolActive)(this.state) || this.state.viewModeEnabled)) || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement)) {\n return false;\n }\n\n isPanning = true;\n event.preventDefault();\n let nextPastePrevented = false;\n const isLinux = /Linux/.test(window.navigator.platform);\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRABBING);\n let {\n clientX: lastX,\n clientY: lastY\n } = event;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const deltaX = lastX - event.clientX;\n const deltaY = lastY - event.clientY;\n lastX = event.clientX;\n lastY = event.clientY;\n /*\n * Prevent paste event if we move while middle clicking on Linux.\n * See issue #1383.\n */\n\n if (isLinux && !nextPastePrevented && (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1)) {\n nextPastePrevented = true;\n /* Prevent the next paste event */\n\n const preventNextPaste = event => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n event.stopPropagation();\n };\n /*\n * Reenable next paste in case of disabled middle click paste for\n * any reason:\n * - right click paste\n * - empty clipboard\n */\n\n\n const enableNextPaste = () => {\n setTimeout(() => {\n document.body.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }, 100);\n };\n\n document.body.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, preventNextPaste);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, enableNextPaste);\n }\n\n this.translateCanvas({\n scrollX: this.state.scrollX - deltaX / this.state.zoom.value,\n scrollY: this.state.scrollY - deltaY / this.state.zoom.value\n });\n });\n const teardown = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(lastPointerUp = () => {\n lastPointerUp = null;\n isPanning = false;\n\n if (!isHoldingSpace) {\n if (this.state.viewModeEnabled) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.GRAB);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.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,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n\n if (!this.state.activeTool.locked) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n };\n\n this.handleFreeDrawElementOnPointerDown = (event, elementType, pointerDownState) => {\n // Begin a mark capture. This does not have to update state yet.\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, null);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFreeDrawElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: null,\n simulatePressure: event.pressure === 0.5,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n const pressures = element.simulatePressure ? element.pressures : [...element.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [[0, 0]],\n pressures\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }; //create rectangle element with youtube top left on nearest grid point width / hight 640/360\n\n\n this.insertEmbeddableElement = ({\n sceneX,\n sceneY,\n link\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const embedLink = (0,_element_embeddable__WEBPACK_IMPORTED_MODULE_34__.getEmbedLink)(link);\n\n if (!embedLink) {\n return;\n }\n\n if (embedLink.warning) {\n this.setToast({\n message: embedLink.warning,\n closable: true\n });\n }\n\n const element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)({\n type: \"embeddable\",\n x: gridX,\n y: gridY,\n strokeColor: \"transparent\",\n backgroundColor: \"transparent\",\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n roundness: this.getCurrentItemRoundness(\"embeddable\"),\n opacity: this.state.currentItemOpacity,\n locked: false,\n width: embedLink.aspectRatio.w,\n height: embedLink.aspectRatio.h,\n link,\n validated: null\n });\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), element]);\n return element;\n };\n\n this.createImageElement = ({\n sceneX,\n sceneY\n }) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(sceneX, sceneY, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const topLayerFrame = 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,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.\n If so, we want it to be null for start and \"arrow\" for end. If the linear item is not\n an arrow, we want it to be null for both. Otherwise, we want it to use the\n values from appState. */\n\n const {\n currentItemStartArrowhead,\n currentItemEndArrowhead\n } = this.state;\n const [startArrowhead, endArrowhead] = elementType === \"arrow\" ? [currentItemStartArrowhead, currentItemEndArrowhead] : [null, null];\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newLinearElement)({\n type: elementType,\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.state.currentItemRoundness === \"round\" ? {\n type: _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null,\n startArrowhead,\n endArrowhead,\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n });\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete nextSelectedElementIds[element.id];\n return {\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, prevState)\n };\n });\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n points: [...element.points, [0, 0]]\n });\n const boundElement = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getHoveredElementForBinding)(pointerDownState.origin, this.scene);\n this.scene.addNewElement(element);\n this.setState({\n draggingElement: element,\n editingElement: element,\n startBoundElement: boundElement,\n suggestedBindings: []\n });\n }\n };\n\n this.createGenericElementOnPointerDown = (elementType, pointerDownState) => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x: gridX,\n y: gridY\n });\n const baseElementAttributes = {\n x: gridX,\n y: gridY,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n roundness: this.getCurrentItemRoundness(elementType),\n locked: false,\n frameId: topLayerFrame ? topLayerFrame.id : null\n };\n let element;\n\n if (elementType === \"embeddable\") {\n element = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newEmbeddableElement)(Object.assign({\n type: \"embeddable\",\n validated: null\n }, baseElementAttributes));\n } else {\n element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newElement)(Object.assign({\n type: elementType\n }, baseElementAttributes));\n }\n\n if (element.type === \"selection\") {\n this.setState({\n selectionElement: element,\n draggingElement: element\n });\n } else {\n this.scene.addNewElement(element);\n this.setState({\n multiElement: null,\n draggingElement: element,\n editingElement: element\n });\n }\n };\n\n this.createFrameElementOnPointerDown = pointerDownState => {\n var _a;\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerDownState.origin.x, pointerDownState.origin.y, ((_a = this.lastPointerDownEvent) === null || _a === void 0 ? void 0 : _a[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]) ? null : this.state.gridSize);\n const frame = (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.newFrameElement)(Object.assign({\n x: gridX,\n y: gridY,\n opacity: this.state.currentItemOpacity,\n locked: false\n }, _constants__WEBPACK_IMPORTED_MODULE_12__.FRAME_STYLE));\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), frame]);\n this.setState({\n multiElement: null,\n draggingElement: frame,\n editingElement: frame\n });\n };\n\n this.restoreReadyToEraseElements = pointerDownState => {\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n if (pointerDownState.elementIdsToErase[ele.id] && pointerDownState.elementIdsToErase[ele.id].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.id].opacity\n });\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && pointerDownState.elementIdsToErase[ele.containerId] && pointerDownState.elementIdsToErase[ele.containerId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.containerId].opacity\n });\n } else if (ele.frameId && pointerDownState.elementIdsToErase[ele.frameId] && pointerDownState.elementIdsToErase[ele.frameId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n opacity: pointerDownState.elementIdsToErase[ele.frameId].opacity\n });\n }\n\n return ele;\n });\n this.scene.replaceAllElements(elements);\n };\n\n this.eraseElements = pointerDownState => {\n const elements = this.scene.getElementsIncludingDeleted().map(ele => {\n if (pointerDownState.elementIdsToErase[ele.id] && pointerDownState.elementIdsToErase[ele.id].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBoundToContainer)(ele) && pointerDownState.elementIdsToErase[ele.containerId] && pointerDownState.elementIdsToErase[ele.containerId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n } else if (ele.frameId && pointerDownState.elementIdsToErase[ele.frameId] && pointerDownState.elementIdsToErase[ele.frameId].erase) {\n return (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith)(ele, {\n isDeleted: true\n });\n }\n\n return ele;\n });\n this.history.resumeRecording();\n this.scene.replaceAllElements(elements);\n };\n\n this.initializeImage = ({\n imageFile,\n imageElement: _imageElement,\n showCursorImagePreview = false\n }) => __awaiter(this, void 0, void 0, function* () {\n var _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,_cursor__WEBPACK_IMPORTED_MODULE_69__.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,_cursor__WEBPACK_IMPORTED_MODULE_69__.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 return yield this.initializeImage({\n imageFile,\n imageElement,\n showCursorImagePreview\n });\n } catch (error) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(imageElement, {\n isDeleted: true\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n this.setState({\n errorMessage: error.message || (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"errors.imageInsertError\")\n });\n return null;\n }\n });\n\n this.setImagePreviewCursor = imageFile => __awaiter(this, void 0, void 0, function* () {\n // mustn't be larger than 128 px\n // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Basic_User_Interface/Using_URL_values_for_the_cursor_property\n const cursorImageSizePx = 96;\n const imagePreview = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.resizeImageFile)(imageFile, {\n maxWidthOrHeight: cursorImageSizePx\n });\n let previewDataURL = yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.getDataURL)(imagePreview); // SVG cannot be resized via `resizeImageFile` so we resize by rendering to\n // a small canvas\n\n if (imageFile.type === _constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg) {\n const img = yield (0,_element_image__WEBPACK_IMPORTED_MODULE_40__.loadHTMLImageElement)(previewDataURL);\n let height = Math.min(img.height, cursorImageSizePx);\n let width = height * (img.width / img.height);\n\n if (width > cursorImageSizePx) {\n width = cursorImageSizePx;\n height = width * (img.height / img.width);\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.height = height;\n canvas.width = width;\n const context = canvas.getContext(\"2d\");\n context.drawImage(img, 0, 0, width, height);\n previewDataURL = canvas.toDataURL(_constants__WEBPACK_IMPORTED_MODULE_12__.MIME_TYPES.svg);\n }\n\n if (this.state.pendingImageElementId) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, `url(${previewDataURL}) 4 4, auto`);\n }\n });\n\n this.onImageAction = ({\n insertOnCanvasDirectly\n }) => __awaiter(this, void 0, void 0, function* () {\n try {\n const clientX = this.state.width / 2 + this.state.offsetLeft;\n const clientY = this.state.height / 2 + this.state.offsetTop;\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX,\n clientY\n }, this.state);\n const imageFile = yield (0,_data_filesystem__WEBPACK_IMPORTED_MODULE_42__.fileOpen)({\n description: \"Image\",\n extensions: Object.keys(_constants__WEBPACK_IMPORTED_MODULE_12__.IMAGE_MIME_TYPES)\n });\n const imageElement = this.createImageElement({\n sceneX: x,\n sceneY: y\n });\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_65__.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, _b, _c, _d, _e;\n\n const draggingElement = this.state.draggingElement;\n const pointerCoords = pointerDownState.lastCoords;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"selection\" && this.state.activeTool.type !== \"eraser\") {\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.origin.x, pointerDownState.origin.y, pointerCoords.x, pointerCoords.y, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.x, pointerCoords.x), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.origin.y, pointerCoords.y), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event));\n } else {\n let [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const image = (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isInitializedImageElement)(draggingElement) && ((_a = this.imageCache.get(draggingElement.fileId)) === null || _a === void 0 ? void 0 : _a.image);\n const aspectRatio = image && !(image instanceof Promise) ? image.width / image.height : null;\n this.maybeCacheReferenceSnapPoints(event, [draggingElement]);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.snapNewElement)(draggingElement, this.state, event, {\n x: pointerDownState.originInGrid.x + ((_c = (_b = this.state.originSnapOffset) === null || _b === void 0 ? void 0 : _b.x) !== null && _c !== void 0 ? _c : 0),\n y: pointerDownState.originInGrid.y + ((_e = (_d = this.state.originSnapOffset) === null || _d === void 0 ? void 0 : _d.y) !== null && _e !== void 0 ? _e : 0)\n }, {\n x: gridX - pointerDownState.originInGrid.x,\n y: gridY - pointerDownState.originInGrid.y\n });\n gridX += snapOffset.x;\n gridY += snapOffset.y;\n this.setState({\n snapLines\n });\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragNewElement)(draggingElement, this.state.activeTool.type, pointerDownState.originInGrid.x, pointerDownState.originInGrid.y, gridX, gridY, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.x, gridX), (0,_utils__WEBPACK_IMPORTED_MODULE_33__.distance)(pointerDownState.originInGrid.y, gridY), (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), aspectRatio, this.state.originSnapOffset);\n this.maybeSuggestBindingForAll([draggingElement]); // highlight elements that are to be added to frames on frames creation\n\n if (this.state.activeTool.type === \"frame\") {\n this.setState({\n elementsToHighlight: (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getNonDeletedElements(), draggingElement, this.state)\n });\n }\n }\n };\n\n this.maybeHandleResize = (pointerDownState, event) => {\n const selectedElements = this.scene.getSelectedElements(this.state);\n const selectedFrames = selectedElements.filter(element => element.type === \"frame\");\n const transformHandleType = pointerDownState.resize.handleType;\n\n if (selectedFrames.length > 0 && transformHandleType === \"rotation\") {\n return false;\n }\n\n this.setState({\n // TODO: rename this state field to \"isScaling\" to distinguish\n // it from the generic \"isResizing\" which includes scaling and\n // rotating\n isResizing: transformHandleType && transformHandleType !== \"rotation\",\n isRotating: transformHandleType === \"rotation\",\n activeEmbeddable: null\n });\n const pointerCoords = pointerDownState.lastCoords;\n let [resizeX, resizeY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x - pointerDownState.resize.offset.x, pointerCoords.y - pointerDownState.resize.offset.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const frameElementsOffsetsMap = new Map();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getFrameElements)(this.scene.getNonDeletedElements(), frame.id);\n elementsInFrame.forEach(element => {\n frameElementsOffsetsMap.set(frame.id + element.id, {\n x: element.x - frame.x,\n y: element.y - frame.y\n });\n });\n }); // check needed for avoiding flickering when a key gets pressed\n // during dragging\n\n if (!this.state.selectedElementsAreBeingDragged) {\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n const dragOffset = {\n x: gridX - pointerDownState.originInGrid.x,\n y: gridY - pointerDownState.originInGrid.y\n };\n const originalElements = [...pointerDownState.originalElements.values()];\n this.maybeCacheReferenceSnapPoints(event, selectedElements);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.snapResizingElements)(selectedElements, (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(originalElements, this.state), this.state, event, dragOffset, transformHandleType);\n resizeX += snapOffset.x;\n resizeY += snapOffset.y;\n this.setState({\n snapLines\n });\n }\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.transformElements)(pointerDownState, transformHandleType, selectedElements, pointerDownState.resize.arrowDirection, (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event), (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldResizeFromCenter)(event), selectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(selectedElements[0]) ? !(0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event) : (0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldMaintainAspectRatio)(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y, this.state)) {\n this.maybeSuggestBindingForAll(selectedElements);\n const elementsToHighlight = new Set();\n selectedFrames.forEach(frame => {\n const elementsInFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.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__.actionToggleObjectsSnapMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleZenMode, _actions_actionToggleViewMode__WEBPACK_IMPORTED_MODULE_38__.actionToggleViewMode, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleStats];\n } // element contextMenu\n // -------------------------------------------------------------------------\n\n\n options.push(_actions__WEBPACK_IMPORTED_MODULE_5__.copyText);\n\n if (this.state.viewModeEnabled) {\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, ...options];\n }\n\n return [_actions__WEBPACK_IMPORTED_MODULE_5__.actionCut, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopy, _actions_actionClipboard__WEBPACK_IMPORTED_MODULE_52__.actionPaste, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionSelectAllElementsInFrame, _actions_actionFrame__WEBPACK_IMPORTED_MODULE_53__.actionRemoveAllElementsFromFrame, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, ...options, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionCopyStyles, _actions__WEBPACK_IMPORTED_MODULE_5__.actionPasteStyles, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionGroup, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUnbindText, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBindText, _actions_actionBoundText__WEBPACK_IMPORTED_MODULE_58__.actionWrapTextInContainer, _actions__WEBPACK_IMPORTED_MODULE_5__.actionUngroup, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionAddToLibrary, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendBackward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringForward, _actions__WEBPACK_IMPORTED_MODULE_5__.actionSendToBack, _actions__WEBPACK_IMPORTED_MODULE_5__.actionBringToFront, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipHorizontal, _actions__WEBPACK_IMPORTED_MODULE_5__.actionFlipVertical, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleLinearEditor, _actions__WEBPACK_IMPORTED_MODULE_5__.actionLink, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDuplicateSelection, _actions__WEBPACK_IMPORTED_MODULE_5__.actionToggleElementLock, _ContextMenu__WEBPACK_IMPORTED_MODULE_35__.CONTEXT_MENU_SEPARATOR, _actions__WEBPACK_IMPORTED_MODULE_5__.actionDeleteSelected];\n };\n\n this.handleWheel = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n event.preventDefault();\n\n if (isPanning) {\n return;\n }\n\n const {\n deltaX,\n deltaY\n } = event; // note that event.ctrlKey is necessary to handle pinch zooming\n\n if (event.metaKey || event.ctrlKey) {\n const sign = Math.sign(deltaY);\n const MAX_STEP = _constants__WEBPACK_IMPORTED_MODULE_12__.ZOOM_STEP * 100;\n const absDelta = Math.abs(deltaY);\n let delta = deltaY;\n\n if (absDelta > MAX_STEP) {\n delta = MAX_STEP * sign;\n }\n\n let newZoom = this.state.zoom.value - delta / 100; // increase zoom steps the more zoomed-in we are (applies to >100% only)\n\n newZoom += Math.log10(Math.max(1, this.state.zoom.value)) * -sign * // reduced amplification for small deltas (small movements on a trackpad)\n Math.min(1, absDelta / 20);\n this.translateCanvas(state => Object.assign(Object.assign({}, (0,_scene_zoom__WEBPACK_IMPORTED_MODULE_31__.getStateForZoom)({\n viewportX: this.lastViewportPosition.x,\n viewportY: this.lastViewportPosition.y,\n nextZoom: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getNormalizedZoom)(newZoom)\n }, state)), {\n shouldCacheIgnoreZoom: true\n }));\n this.resetShouldCacheIgnoreZoomDebounced();\n return;\n } // scroll horizontally when shift pressed\n\n\n if (event.shiftKey) {\n this.translateCanvas(({\n zoom,\n scrollX\n }) => ({\n // on Mac, shift+wheel tends to result in deltaX\n scrollX: scrollX - (deltaY || deltaX) / zoom.value\n }));\n return;\n }\n\n this.translateCanvas(({\n zoom,\n scrollX,\n scrollY\n }) => ({\n scrollX: scrollX - deltaX / zoom.value,\n scrollY: scrollY - deltaY / zoom.value\n }));\n });\n\n this.savePointer = (x, y, button) => {\n var _a, _b;\n\n if (!x || !y) {\n return;\n }\n\n const {\n x: sceneX,\n y: sceneY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: x,\n clientY: y\n }, this.state);\n\n if (isNaN(sceneX) || isNaN(sceneY)) {// sometimes the pointer goes off screen\n }\n\n const pointer = {\n x: sceneX,\n y: sceneY,\n tool: this.state.activeTool.type === \"laser\" ? \"laser\" : \"pointer\"\n };\n (_b = (_a = this.props).onPointerUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, {\n pointer,\n button,\n pointersMap: gesture.pointers\n });\n };\n\n this.resetShouldCacheIgnoreZoomDebounced = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.debounce)(() => {\n if (!this.unmounted) {\n this.setState({\n shouldCacheIgnoreZoom: false\n });\n }\n }, 300);\n\n this.updateDOMRect = cb => {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n width,\n height,\n left: offsetLeft,\n top: offsetTop\n } = excalidrawContainer.getBoundingClientRect();\n const {\n width: currentWidth,\n height: currentHeight,\n offsetTop: currentOffsetTop,\n offsetLeft: currentOffsetLeft\n } = this.state;\n\n if (width === currentWidth && height === currentHeight && offsetLeft === currentOffsetLeft && offsetTop === currentOffsetTop) {\n if (cb) {\n cb();\n }\n\n return;\n }\n\n this.setState({\n width,\n height,\n offsetLeft,\n offsetTop\n }, () => {\n cb && cb();\n });\n }\n };\n\n this.refresh = () => {\n this.setState(Object.assign({}, this.getCanvasOffsets()));\n };\n\n const defaultAppState = (0,_appState__WEBPACK_IMPORTED_MODULE_10__.getDefaultAppState)();\n const {\n excalidrawRef,\n viewModeEnabled = false,\n zenModeEnabled = false,\n gridModeEnabled = false,\n objectsSnapModeEnabled = false,\n theme = defaultAppState.theme,\n name = defaultAppState.name\n } = props;\n this.state = Object.assign(Object.assign(Object.assign(Object.assign({}, defaultAppState), {\n theme,\n isLoading: true\n }), this.getCanvasOffsets()), {\n viewModeEnabled,\n zenModeEnabled,\n objectsSnapModeEnabled,\n gridSize: gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null,\n name,\n width: window.innerWidth,\n height: window.innerHeight\n });\n this.id = (0,nanoid__WEBPACK_IMPORTED_MODULE_71__.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_64__.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 onChange: cb => this.onChangeEmitter.on(cb),\n onPointerDown: cb => this.onPointerDownEmitter.on(cb),\n onPointerUp: cb => this.onPointerUpEmitter.on(cb)\n };\n\n if (typeof excalidrawRef === \"function\") {\n excalidrawRef(api);\n } else {\n excalidrawRef.current = api;\n }\n\n readyPromise.resolve(api);\n }\n\n this.excalidrawContainerValue = {\n container: this.excalidrawContainerRef.current,\n id: this.id\n };\n this.fonts = new _scene_Fonts__WEBPACK_IMPORTED_MODULE_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.editor.isMobile\n }),\n style: {\n [\"--ui-pointerEvents\"]: this.state.selectionElement || this.state.draggingElement || this.state.resizingElement || this.state.activeTool.type === \"laser\" && // technically we can just test on this once we make it more safe\n this.state.cursorButton === \"down\" || this.state.editingElement && !(0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.disabled : _constants__WEBPACK_IMPORTED_MODULE_12__.POINTER_EVENTS.enabled\n },\n ref: this.excalidrawContainerRef,\n onDrop: this.handleAppOnDrop,\n tabIndex: 0,\n onKeyDown: this.props.handleKeyboardGlobally ? undefined : this.onKeyDown\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AppContext.Provider, Object.assign({\n value: this\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AppPropsContext.Provider, Object.assign({\n value: this.props\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawContainerContext.Provider, Object.assign({\n value: this.excalidrawContainerValue\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(DeviceContext.Provider, Object.assign({\n value: this.device\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawSetAppStateContext.Provider, Object.assign({\n value: this.setAppState\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawAppStateContext.Provider, Object.assign({\n value: this.state\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(ExcalidrawElementsContext.Provider, Object.assign({\n value: this.scene.getNonDeletedElements()\n }, {\n children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(ExcalidrawActionManagerContext.Provider, Object.assign({\n value: this.actionManager\n }, {\n children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_LayerUI__WEBPACK_IMPORTED_MODULE_36__[\"default\"], Object.assign({\n canvas: this.canvas,\n appState: this.state,\n files: this.files,\n setAppState: this.setAppState,\n actionManager: this.actionManager,\n elements: this.scene.getNonDeletedElements(),\n onLockToggle: this.toggleLock,\n onPenModeToggle: this.togglePenMode,\n onHandToolToggle: this.onHandToolToggle,\n langCode: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.getLanguage)().code,\n renderTopRightUI: renderTopRightUI,\n renderCustomStats: renderCustomStats,\n showExitZenModeBtn: typeof ((_a = this.props) === null || _a === void 0 ? void 0 : _a.zenModeEnabled) === \"undefined\" && this.state.zenModeEnabled,\n UIOptions: this.props.UIOptions,\n onExportImage: this.onExportImage,\n renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === \"selection\" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,\n app: this,\n isCollaborating: this.props.isCollaborating\n }, {\n children: [this.props.children, this.state.openDialog === \"mermaid\" && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_MermaidToExcalidraw__WEBPACK_IMPORTED_MODULE_66__[\"default\"], {})]\n })), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-textEditorContainer\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-contextMenuContainer\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(\"div\", {\n className: \"excalidraw-eye-dropper-container\"\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_LaserTool_LaserTool__WEBPACK_IMPORTED_MODULE_67__.LaserToolOverlay, {\n manager: this.laserPathManager\n }), selectedElements.length === 1 && !this.state.contextMenu && this.state.showHyperlinkPopup && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_element_Hyperlink__WEBPACK_IMPORTED_MODULE_45__.Hyperlink, {\n element: selectedElements[0],\n setAppState: this.setAppState,\n onLinkOpen: this.props.onLinkOpen,\n setToast: this.setToast\n }, selectedElements[0].id), this.state.toast !== null && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_Toast__WEBPACK_IMPORTED_MODULE_37__.Toast, {\n message: this.state.toast.message,\n onClose: () => this.setToast(null),\n duration: this.state.toast.duration,\n closable: this.state.toast.closable\n }), this.state.contextMenu && (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_ContextMenu__WEBPACK_IMPORTED_MODULE_35__.ContextMenu, {\n items: this.state.contextMenu.items,\n top: this.state.contextMenu.top,\n left: this.state.contextMenu.left,\n actionManager: this.actionManager,\n onClose: callback => {\n this.setState({\n contextMenu: null\n }, () => {\n this.focusContainer();\n callback === null || callback === void 0 ? void 0 : callback();\n });\n }\n }), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_canvases__WEBPACK_IMPORTED_MODULE_63__.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_63__.InteractiveCanvas, {\n containerRef: this.excalidrawContainerRef,\n canvas: this.interactiveCanvas,\n elements: canvasElements,\n visibleElements: visibleElements,\n selectedElements: selectedElements,\n versionNonce: versionNonce,\n selectionNonce: (_c = this.state.selectionElement) === null || _c === void 0 ? void 0 : _c.versionNonce,\n scale: window.devicePixelRatio,\n appState: this.state,\n renderInteractiveSceneCallback: this.renderInteractiveSceneCallback,\n handleCanvasRef: this.handleInteractiveCanvasRef,\n onContextMenu: this.handleCanvasContextMenu,\n onPointerMove: this.handleCanvasPointerMove,\n onPointerUp: this.handleCanvasPointerUp,\n onPointerCancel: this.removePointer,\n onTouchMove: this.handleTouchMove,\n onPointerDown: this.handleCanvasPointerDown,\n onDoubleClick: this.handleCanvasDoubleClick\n }), this.renderFrameNames()]\n })), this.renderEmbeddables()]\n }))\n }))\n }))\n }))\n }))\n }))\n }))\n }));\n }\n\n componentDidMount() {\n var _a;\n\n return __awaiter(this, void 0, void 0, function* () {\n this.unmounted = false;\n this.excalidrawContainerValue.container = this.excalidrawContainerRef.current;\n\n if (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n const setState = this.setState.bind(this);\n Object.defineProperties(window.h, {\n state: {\n configurable: true,\n get: () => {\n return this.state;\n }\n },\n setState: {\n configurable: true,\n value: (...args) => {\n return this.setState(...args);\n }\n },\n app: {\n configurable: true,\n value: this\n },\n history: {\n configurable: true,\n value: this.history\n }\n });\n }\n\n this.scene.addCallback(this.onSceneUpdated);\n this.addEventListeners();\n\n if (this.props.autoFocus && this.excalidrawContainerRef.current) {\n this.focusContainer();\n }\n\n if ( // bounding rects don't work in tests so updating\n // the state on init would result in making the test enviro run\n // in mobile breakpoint (0 width/height), making everything fail\n !(0,_utils__WEBPACK_IMPORTED_MODULE_33__.isTestEnv)()) {\n this.refreshViewportBreakpoints();\n this.refreshEditorBreakpoints();\n }\n\n if (supportsResizeObserver && this.excalidrawContainerRef.current) {\n this.resizeObserver = new ResizeObserver(() => {\n this.refreshEditorBreakpoints();\n this.updateDOMRect();\n });\n (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(this.excalidrawContainerRef.current);\n }\n\n const searchParams = new URLSearchParams(window.location.search.slice(1));\n\n if (searchParams.has(\"web-share-target\")) {\n // Obtain a file that was shared via the Web Share Target API.\n this.restoreFileFromShare();\n } else {\n this.updateDOMRect(this.initializeScene);\n } // note that this check seems to always pass in localhost\n\n\n if ((0,_constants__WEBPACK_IMPORTED_MODULE_12__.isBrave)() && !(0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.isMeasureTextSupported)()) {\n this.setState({\n errorMessage: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_BraveMeasureTextError__WEBPACK_IMPORTED_MODULE_59__[\"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_64__.Renderer(this.scene);\n this.files = {};\n this.imageCache.clear();\n (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();\n this.unmounted = true;\n this.removeEventListeners();\n this.scene.destroy();\n this.library.destroy();\n this.laserPathManager.destroy();\n this.onChangeEmitter.destroy();\n _scene_ShapeCache__WEBPACK_IMPORTED_MODULE_65__.ShapeCache.destroy();\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.destroy();\n clearTimeout(touchTimeout);\n _scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected.clearCache();\n _groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements.clearCache();\n touchTimeout = 0;\n }\n\n removeEventListeners() {\n var _a, _b, _c, _d;\n\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel);\n (_b = this.nearestScrollableContainer) === null || _b === void 0 ? void 0 : _b.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MESSAGE, this.onWindowMessage, false);\n }\n\n addEventListeners() {\n var _a, _b, _c, _d, _e;\n\n this.removeEventListeners();\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MESSAGE, this.onWindowMessage, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, this.removePointer); // #3553\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.COPY, this.onCopy);\n (_a = this.excalidrawContainerRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.WHEEL, this.onWheel, {\n passive: false\n });\n\n if (this.props.handleKeyboardGlobally) {\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, this.onKeyDown, false);\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, this.onKeyUp, {\n passive: true\n });\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition); // rerender text elements on font load to fix #637 && #1553\n\n (_c = (_b = document.fonts) === null || _b === void 0 ? void 0 : _b.addEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, \"loadingdone\", event => {\n const loadedFontFaces = event.fontfaces;\n this.fonts.onFontsLoaded(loadedFontFaces);\n }); // Safari-only desktop pinch zoom\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_START, this.onGestureStart, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_CHANGE, this.onGestureChange, false);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.GESTURE_END, this.onGestureEnd, false);\n\n if (this.state.viewModeEnabled) {\n return;\n }\n\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.PASTE, this.pasteFromClipboard);\n document.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.CUT, this.onCut);\n\n if (this.props.detectScroll) {\n this.nearestScrollableContainer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getNearestScrollableContainer)(this.excalidrawContainerRef.current);\n this.nearestScrollableContainer.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.SCROLL, this.onScroll);\n }\n\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.RESIZE, this.onResize, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.UNLOAD, this.onUnload, false);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.BLUR, this.onBlur, false);\n (_d = this.excalidrawContainerRef.current) === null || _d === void 0 ? void 0 : _d.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DRAG_OVER, this.disableEvent, false);\n (_e = this.excalidrawContainerRef.current) === null || _e === void 0 ? void 0 : _e.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.DROP, this.disableEvent, false);\n }\n\n componentDidUpdate(prevProps, prevState) {\n var _a, _b, _c, _d, _e, _f;\n\n this.updateEmbeddables();\n\n if (!this.state.showWelcomeScreen && !this.scene.getElementsIncludingDeleted().length) {\n this.setState({\n showWelcomeScreen: true\n });\n }\n\n if (prevProps.UIOptions.dockedSidebarBreakpoint !== this.props.UIOptions.dockedSidebarBreakpoint) {\n this.refreshEditorBreakpoints();\n }\n\n if (prevState.scrollX !== this.state.scrollX || prevState.scrollY !== this.state.scrollY) {\n (_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.onScrollChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.state.scrollX, this.state.scrollY);\n }\n\n if (Object.keys(this.state.selectedElementIds).length && (0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.setState({\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n }\n\n if (this.state.activeTool.type === \"eraser\" && prevState.theme !== this.state.theme) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setEraserCursor)(this.interactiveCanvas, this.state.theme);\n } // Hide hyperlink popup if shown when element type is not selection\n\n\n if (prevState.activeTool.type === \"selection\" && this.state.activeTool.type !== \"selection\" && this.state.showHyperlinkPopup) {\n this.setState({\n showHyperlinkPopup: false\n });\n }\n\n if (prevProps.langCode !== this.props.langCode) {\n this.updateLanguage();\n }\n\n if (prevProps.viewModeEnabled !== this.props.viewModeEnabled) {\n this.setState({\n viewModeEnabled: !!this.props.viewModeEnabled\n });\n }\n\n if (prevState.viewModeEnabled !== this.state.viewModeEnabled) {\n this.addEventListeners();\n this.deselectElements();\n }\n\n if (prevProps.zenModeEnabled !== this.props.zenModeEnabled) {\n this.setState({\n zenModeEnabled: !!this.props.zenModeEnabled\n });\n }\n\n if (prevProps.theme !== this.props.theme && this.props.theme) {\n this.setState({\n theme: this.props.theme\n });\n }\n\n if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {\n this.setState({\n gridSize: this.props.gridModeEnabled ? _constants__WEBPACK_IMPORTED_MODULE_12__.GRID_SIZE : null\n });\n }\n\n if (this.props.name && prevProps.name !== this.props.name) {\n this.setState({\n name: this.props.name\n });\n }\n\n (_c = this.excalidrawContainerRef.current) === null || _c === void 0 ? void 0 : _c.classList.toggle(\"theme--dark\", this.state.theme === \"dark\");\n\n if (this.state.editingLinearElement && !this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {\n // defer so that the commitToHistory flag isn't reset via current update\n setTimeout(() => {\n // execute only if the condition still holds when the deferred callback\n // executes (it can be scheduled multiple times depending on how\n // many times the component renders)\n this.state.editingLinearElement && this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } // failsafe in case the state is being updated in incorrect order resulting\n // in the editingElement being now a deleted element\n\n\n if ((_d = this.state.editingElement) === null || _d === void 0 ? void 0 : _d.isDeleted) {\n this.setState({\n editingElement: null\n });\n }\n\n if (this.state.selectedLinearElement && !this.state.selectedElementIds[this.state.selectedLinearElement.elementId]) {\n // To make sure `selectedLinearElement` is in sync with `selectedElementIds`, however this shouldn't be needed once\n // we have a single API to update `selectedElementIds`\n this.setState({\n selectedLinearElement: null\n });\n }\n\n const {\n multiElement\n } = prevState;\n\n if (prevState.activeTool !== this.state.activeTool && multiElement != null && (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(multiElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(multiElement, this.state, this.scene, (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)(_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1)));\n }\n\n this.history.record(this.state, this.scene.getElementsIncludingDeleted()); // Do not notify consumers if we're still loading the scene. Among other\n // potential issues, this fixes a case where the tab isn't focused during\n // init, which would trigger onChange with empty elements, which would then\n // override whatever is in localStorage currently.\n\n if (!this.state.isLoading) {\n (_f = (_e = this.props).onChange) === null || _f === void 0 ? void 0 : _f.call(_e, this.scene.getElementsIncludingDeleted(), this.state, this.files);\n this.onChangeEmitter.trigger(this.scene.getElementsIncludingDeleted(), this.state, this.files);\n }\n }\n\n static resetTapTwice() {\n didTapTwice = false;\n } // TODO rewrite this to paste both text & images at the same time if\n // pasted data contains both\n\n\n addElementsFromMixedContentPaste(mixedContent, {\n isPlainPaste,\n sceneX,\n sceneY\n }) {\n return __awaiter(this, void 0, void 0, function* () {\n if (!isPlainPaste && mixedContent.some(node => node.type === \"imageUrl\")) {\n const imageURLs = mixedContent.filter(node => node.type === \"imageUrl\").map(node => node.value);\n const responses = yield Promise.all(imageURLs.map(url => __awaiter(this, void 0, void 0, function* () {\n try {\n return {\n file: yield (0,_data_blob__WEBPACK_IMPORTED_MODULE_39__.ImageURLToFile)(url)\n };\n } catch (error) {\n return {\n errorMessage: error.message\n };\n }\n })));\n let y = sceneY;\n let firstImageYOffsetDone = false;\n const nextSelectedIds = {};\n\n for (const response of responses) {\n if (response.file) {\n const imageElement = this.createImageElement({\n sceneX,\n sceneY: y\n });\n const initializedImageElement = yield this.insertImageElement(imageElement, response.file);\n\n if (initializedImageElement) {\n // vertically center first image in the batch\n if (!firstImageYOffsetDone) {\n firstImageYOffsetDone = true;\n y -= initializedImageElement.height / 2;\n } // hack to reset the `y` coord because we vertically center during\n // insertImageElement\n\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(initializedImageElement, {\n y\n }, false);\n y = imageElement.y + imageElement.height + 25;\n nextSelectedIds[imageElement.id] = true;\n }\n }\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedIds, this.state)\n });\n const error = responses.find(response => !!response.errorMessage);\n\n if (error && error.errorMessage) {\n this.setState({\n errorMessage: error.errorMessage\n });\n }\n } else {\n const textNodes = mixedContent.filter(node => node.type === \"text\");\n\n if (textNodes.length) {\n this.addTextFromPaste(textNodes.map(node => node.value).join(\"\\n\\n\"), isPlainPaste);\n }\n }\n });\n }\n\n addTextFromPaste(text, isPlainPaste = false) {\n const {\n x,\n y\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastViewportPosition.x,\n clientY: this.lastViewportPosition.y\n }, this.state);\n const textElementProps = {\n x,\n y,\n strokeColor: this.state.currentItemStrokeColor,\n backgroundColor: this.state.currentItemBackgroundColor,\n fillStyle: this.state.currentItemFillStyle,\n strokeWidth: this.state.currentItemStrokeWidth,\n strokeStyle: this.state.currentItemStrokeStyle,\n roundness: null,\n roughness: this.state.currentItemRoughness,\n opacity: this.state.currentItemOpacity,\n text,\n fontSize: this.state.currentItemFontSize,\n fontFamily: this.state.currentItemFontFamily,\n textAlign: this.state.currentItemTextAlign,\n verticalAlign: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_VERTICAL_ALIGN,\n locked: false\n };\n const LINE_GAP = 10;\n let currentY = y;\n const lines = isPlainPaste ? [text] : text.split(\"\\n\");\n const textElements = lines.reduce((acc, line, idx) => {\n var _a;\n\n const text = line.trim();\n const lineHeight = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getDefaultLineHeight)(textElementProps.fontFamily);\n\n if (text.length) {\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords({\n x,\n y: currentY\n });\n const element = (0,_element__WEBPACK_IMPORTED_MODULE_16__.newTextElement)(Object.assign(Object.assign({}, textElementProps), {\n x,\n y: currentY,\n text,\n lineHeight,\n frameId: topLayerFrame ? topLayerFrame.id : null\n }));\n acc.push(element);\n currentY += element.height + LINE_GAP;\n } else {\n const prevLine = (_a = lines[idx - 1]) === null || _a === void 0 ? void 0 : _a.trim(); // add paragraph only if previous line was not empty, IOW don't add\n // more than one empty line\n\n if (prevLine) {\n currentY += (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getLineHeightInPx)(textElementProps.fontSize, lineHeight) + LINE_GAP;\n }\n }\n\n return acc;\n }, []);\n\n if (textElements.length === 0) {\n return;\n }\n\n const frameId = textElements[0].frameId;\n\n if (frameId) {\n this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));\n } else {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted(), ...textElements]);\n }\n\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.fromEntries(textElements.map(el => [el.id, true])), this.state)\n });\n\n if (!isPlainPaste && textElements.length > 1 && PLAIN_PASTE_TOAST_SHOWN === false && !this.device.editor.isMobile) {\n this.setToast({\n message: (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.t)(\"toast.pasteAsSingleElement\", {\n shortcut: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.getShortcutKey)(\"CtrlOrCmd+Shift+V\")\n }),\n duration: 5000\n });\n PLAIN_PASTE_TOAST_SHOWN = true;\n }\n\n this.history.resumeRecording();\n }\n\n handleTextWysiwyg(element, {\n isExistingElement = false\n }) {\n const updateElement = (text, originalText, isDeleted) => {\n this.scene.replaceAllElements([...this.scene.getElementsIncludingDeleted().map(_element => {\n if (_element.id === element.id && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(_element)) {\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.updateTextElement)(_element, {\n text,\n isDeleted,\n originalText\n });\n }\n\n return _element;\n })]);\n };\n\n (0,_element__WEBPACK_IMPORTED_MODULE_16__.textWysiwyg)({\n id: element.id,\n canvas: this.canvas,\n getViewportCoords: (x, y) => {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: x,\n sceneY: y\n }, this.state);\n return [viewportX - this.state.offsetLeft, viewportY - this.state.offsetTop];\n },\n onChange: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(text => {\n updateElement(text, text, false);\n\n if ((0,_element__WEBPACK_IMPORTED_MODULE_16__.isNonDeletedElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.updateBoundElements)(element);\n }\n }),\n onSubmit: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(({\n text,\n viaKeyboard,\n originalText\n }) => {\n const isDeleted = !text.trim();\n updateElement(text, originalText, isDeleted); // select the created text element only if submitting via keyboard\n // (when submitting via click it should act as signal to deselect)\n\n if (!isDeleted && viaKeyboard) {\n const elementIdToSelect = element.containerId ? element.containerId : element.id;\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [elementIdToSelect]: true\n }), prevState)\n }));\n }\n\n if (isDeleted) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDeletion)(this.scene.getNonDeletedElements(), [element]);\n }\n\n if (!isDeleted || isExistingElement) {\n this.history.resumeRecording();\n }\n\n this.setState({\n draggingElement: null,\n editingElement: null\n });\n\n if (this.state.activeTool.locked) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n }\n\n this.focusContainer();\n }),\n element,\n excalidrawContainer: this.excalidrawContainerRef.current,\n app: this\n }); // deselect all other elements when inserting text\n\n this.deselectElements(); // do an initial update to re-initialize element position since we were\n // modifying element's x/y for sake of editor (case: syncing to remote)\n\n updateElement(element.text, element.originalText, false);\n }\n\n deselectElements() {\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n getTextElementAtPosition(x, y) {\n const element = this.getElementAtPosition(x, y, {\n includeBoundTextElement: true\n });\n\n if (element && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && !element.isDeleted) {\n return element;\n }\n\n return null;\n }\n\n getElementAtPosition(x, y, opts) {\n const allHitElements = this.getElementsAtPosition(x, y, opts === null || opts === void 0 ? void 0 : opts.includeBoundTextElement, opts === null || opts === void 0 ? void 0 : opts.includeLockedElements);\n\n if (allHitElements.length > 1) {\n if (opts === null || opts === void 0 ? void 0 : opts.preferSelected) {\n for (let index = allHitElements.length - 1; index > -1; index--) {\n if (this.state.selectedElementIds[allHitElements[index].id]) {\n return allHitElements[index];\n }\n }\n }\n\n const elementWithHighestZIndex = allHitElements[allHitElements.length - 1]; // If we're hitting element with highest z-index only on its bounding box\n // while also hitting other element figure, the latter should be considered.\n\n return (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(elementWithHighestZIndex, this.state, this.frameNameBoundsCache, x, y) ? allHitElements[allHitElements.length - 2] : elementWithHighestZIndex;\n }\n\n if (allHitElements.length === 1) {\n return allHitElements[0];\n }\n\n return null;\n }\n\n getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {\n const elements = includeBoundTextElement && includeLockedElements ? this.scene.getNonDeletedElements() : this.scene.getNonDeletedElements().filter(element => (includeLockedElements || !element.locked) && (includeBoundTextElement || !((0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(element) && element.containerId)));\n return (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsAtPosition)(elements, element => (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(element, this.state, this.frameNameBoundsCache, x, y)).filter(element => {\n // hitting a frame's element from outside the frame is not considered a hit\n const containingFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(element);\n return containingFrame && this.state.frameRendering.enabled && this.state.frameRendering.clip ? (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isCursorInFrame)({\n x,\n y\n }, containingFrame) : true;\n });\n }\n\n handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {\n const element = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getElement(linearElementEditor.elementId);\n const boundTextElement = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getBoundTextElement)(element);\n\n if (!element) {\n return;\n }\n\n if (this.state.selectedLinearElement) {\n let hoverPointIndex = -1;\n let segmentMidPointHoveredCoords = null;\n\n if ((0,_element_collision__WEBPACK_IMPORTED_MODULE_44__.isHittingElementNotConsideringBoundingBox)(element, this.state, this.frameNameBoundsCache, [scenePointerX, scenePointerY])) {\n hoverPointIndex = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getPointIndexUnderCursor(element, this.state.zoom, scenePointerX, scenePointerY);\n segmentMidPointHoveredCoords = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, {\n x: scenePointerX,\n y: scenePointerY\n }, this.state);\n\n if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.POINTER);\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n } else if ((0,_element_transformHandles__WEBPACK_IMPORTED_MODULE_47__.shouldShowBoundingBox)([element], this.state) && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n } else if (boundTextElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.hitTest)(boundTextElement, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY)) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.MOVE);\n }\n\n if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n hoverPointIndex\n })\n });\n }\n\n if (!_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.arePointsEqual(this.state.selectedLinearElement.segmentMidPointHoveredCoords, segmentMidPointHoveredCoords)) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n segmentMidPointHoveredCoords\n })\n });\n }\n } else {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursor)(this.interactiveCanvas, _constants__WEBPACK_IMPORTED_MODULE_12__.CURSOR_TYPE.AUTO);\n }\n }\n\n maybeCleanupAfterMissingPointerUp(event) {\n if (lastPointerUp !== null) {\n // Unfortunately, sometimes we don't get a pointerup after a pointerdown,\n // this can happen when a contextual menu or alert is triggered. In order to avoid\n // being in a weird state, we clean up on the next pointerdown\n lastPointerUp(event);\n }\n }\n\n updateGestureOnPointerDown(event) {\n gesture.pointers.set(event.pointerId, {\n x: event.clientX,\n y: event.clientY\n });\n\n if (gesture.pointers.size === 2) {\n gesture.lastCenter = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getCenter)(gesture.pointers);\n gesture.initialScale = this.state.zoom.value;\n gesture.initialDistance = (0,_gesture__WEBPACK_IMPORTED_MODULE_22__.getDistance)(Array.from(gesture.pointers.values()));\n }\n }\n\n initialPointerDownState(event) {\n const origin = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n const selectedElements = this.scene.getSelectedElements(this.state);\n const [minX, minY, maxX, maxY] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return {\n origin,\n withCmdOrCtrl: event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD],\n originInGrid: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(origin.x, origin.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize)),\n scrollbars: (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isOverScrollBars)(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop),\n // we need to duplicate because we'll be updating this state\n lastCoords: Object.assign({}, origin),\n originalElements: this.scene.getNonDeletedElements().reduce((acc, element) => {\n acc.set(element.id, (0,_element_newElement__WEBPACK_IMPORTED_MODULE_20__.deepCopyElement)(element));\n return acc;\n }, new Map()),\n resize: {\n handleType: false,\n isResizing: false,\n offset: {\n x: 0,\n y: 0\n },\n arrowDirection: \"origin\",\n center: {\n x: (maxX + minX) / 2,\n y: (maxY + minY) / 2\n }\n },\n hit: {\n element: null,\n allHitElements: [],\n wasAddedToSelection: false,\n hasBeenDuplicated: false,\n hasHitCommonBoundingBoxOfSelectedElements: this.isHittingCommonBoundingBoxOfSelectedElements(origin, selectedElements)\n },\n drag: {\n hasOccurred: false,\n offset: null\n },\n eventListeners: {\n onMove: null,\n onUp: null,\n onKeyUp: null,\n onKeyDown: null\n },\n boxSelection: {\n hasOccurred: false\n },\n elementIdsToErase: {}\n };\n } // Returns whether the event is a dragging a scrollbar\n\n\n handleDraggingScrollBar(event, pointerDownState) {\n if (!(pointerDownState.scrollbars.isOverEither && !this.state.multiElement)) {\n return false;\n }\n\n isDraggingScrollBar = true;\n pointerDownState.lastCoords.x = event.clientX;\n pointerDownState.lastCoords.y = event.clientY;\n const onPointerMove = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n this.handlePointerMoveOverScrollbars(event, pointerDownState);\n });\n const onPointerUp = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(() => {\n isDraggingScrollBar = false;\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.setCursorForShape)(this.interactiveCanvas, this.state);\n lastPointerUp = null;\n this.setState({\n cursorButton: \"up\"\n });\n this.savePointer(event.clientX, event.clientY, \"up\");\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n onPointerMove.flush();\n });\n lastPointerUp = onPointerUp;\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, onPointerMove);\n window.addEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, onPointerUp);\n return true;\n }\n\n isASelectedElement(hitElement) {\n return hitElement != null && this.state.selectedElementIds[hitElement.id];\n }\n\n isHittingCommonBoundingBoxOfSelectedElements(point, selectedElements) {\n if (selectedElements.length < 2) {\n return false;\n } // How many pixels off the shape boundary we still consider a hit\n\n\n const threshold = 10 / this.state.zoom.value;\n const [x1, y1, x2, y2] = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getCommonBounds)(selectedElements);\n return point.x > x1 - threshold && point.x < x2 + threshold && point.y > y1 - threshold && point.y < y2 + threshold;\n }\n\n getCurrentItemRoundness(elementType) {\n return this.state.currentItemRoundness === \"round\" ? {\n type: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isUsingAdaptiveRadius)(elementType) ? _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.ADAPTIVE_RADIUS : _constants__WEBPACK_IMPORTED_MODULE_12__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : null;\n }\n\n maybeCacheReferenceSnapPoints(event, selectedElements, recomputeAnyways = false) {\n if ((0,_snapping__WEBPACK_IMPORTED_MODULE_57__.isSnappingEnabled)({\n event,\n appState: this.state,\n selectedElements\n }) && (recomputeAnyways || !_snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.getReferenceSnapPoints())) {\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.setReferenceSnapPoints((0,_snapping__WEBPACK_IMPORTED_MODULE_57__.getReferenceSnapPoints)(this.scene.getNonDeletedElements(), selectedElements, this.state));\n }\n }\n\n maybeCacheVisibleGaps(event, selectedElements, recomputeAnyways = false) {\n if ((0,_snapping__WEBPACK_IMPORTED_MODULE_57__.isSnappingEnabled)({\n event,\n appState: this.state,\n selectedElements\n }) && (recomputeAnyways || !_snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.getVisibleGaps())) {\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.setVisibleGaps((0,_snapping__WEBPACK_IMPORTED_MODULE_57__.getVisibleGaps)(this.scene.getNonDeletedElements(), selectedElements, this.state));\n }\n }\n\n onKeyDownFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onKeyUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(event => {\n // Prevents focus from escaping excalidraw tab\n event.key === _keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.ALT && event.preventDefault();\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return;\n }\n\n this.maybeDragNewGenericElement(pointerDownState, event);\n });\n }\n\n onPointerMoveFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdatesThrottled)(event => {\n var _a, _b; // We need to initialize dragOffsetXY only after we've updated\n // `state.selectedElementIds` on pointerDown. Doing it here in pointerMove\n // event handler should hopefully ensure we're already working with\n // the updated state.\n\n\n if (pointerDownState.drag.offset === null) {\n pointerDownState.drag.offset = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.tupleToCoors)((0,_element__WEBPACK_IMPORTED_MODULE_16__.getDragOffsetXY)(this.scene.getSelectedElements(this.state), pointerDownState.origin.x, pointerDownState.origin.y));\n }\n\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n if (this.handlePointerMoveOverScrollbars(event, pointerDownState)) {\n return;\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(event, this.state);\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n this.handleEraser(event, pointerDownState, pointerCoords);\n return;\n }\n\n if (this.state.activeTool.type === \"laser\") {\n this.laserPathManager.addPointToPath(pointerCoords.x, pointerCoords.y);\n }\n\n const [gridX, gridY] = (0,_math__WEBPACK_IMPORTED_MODULE_28__.getGridPoint)(pointerCoords.x, pointerCoords.y, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize); // for arrows/lines, don't start dragging until a given threshold\n // to ensure we don't create a 2-point arrow by mistake when\n // user clicks mouse in a way that it moves a tiny bit (thus\n // triggering pointermove)\n\n if (!pointerDownState.drag.hasOccurred && (this.state.activeTool.type === \"arrow\" || this.state.activeTool.type === \"line\")) {\n if ((0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(pointerCoords.x, pointerCoords.y, pointerDownState.origin.x, pointerDownState.origin.y) < _constants__WEBPACK_IMPORTED_MODULE_12__.DRAGGING_THRESHOLD) {\n return;\n }\n }\n\n if (pointerDownState.resize.isResizing) {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n\n if (this.maybeHandleResize(pointerDownState, event)) {\n return true;\n }\n }\n\n if (this.state.selectedLinearElement) {\n const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;\n\n if (_element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.shouldAddMidpoint(this.state.selectedLinearElement, pointerCoords, this.state)) {\n const ret = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.addMidpoint(this.state.selectedLinearElement, pointerCoords, this.state, !event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD]);\n\n if (!ret) {\n return;\n } // Since we are reading from previous state which is not possible with\n // automatic batching in React 18 hence using flush sync to synchronously\n // update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.\n\n\n (0,react_dom__WEBPACK_IMPORTED_MODULE_2__.flushSync)(() => {\n if (this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n pointerDownState: ret.pointerDownState,\n selectedPointsIndices: ret.selectedPointsIndices\n })\n });\n }\n\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: Object.assign(Object.assign({}, this.state.editingLinearElement), {\n pointerDownState: ret.pointerDownState,\n selectedPointsIndices: ret.selectedPointsIndices\n })\n });\n }\n });\n return;\n } else if (linearElementEditor.pointerDownState.segmentMidpoint.value !== null && !linearElementEditor.pointerDownState.segmentMidpoint.added) {\n return;\n }\n\n const didDrag = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointDragging(event, this.state, pointerCoords.x, pointerCoords.y, (element, pointsSceneCoords) => {\n this.maybeSuggestBindingsForLinearElementAtCoords(element, pointsSceneCoords);\n }, linearElementEditor);\n\n if (didDrag) {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n pointerDownState.drag.hasOccurred = true;\n\n if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {\n this.setState({\n editingLinearElement: Object.assign(Object.assign({}, this.state.editingLinearElement), {\n isDragging: true\n })\n });\n }\n\n if (!this.state.selectedLinearElement.isDragging) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, this.state.selectedLinearElement), {\n isDragging: true\n })\n });\n }\n\n return;\n }\n }\n\n const hasHitASelectedElement = pointerDownState.hit.allHitElements.some(element => this.isASelectedElement(element));\n const isSelectingPointsInLineEditor = this.state.editingLinearElement && event.shiftKey && this.state.editingLinearElement.elementId === ((_a = pointerDownState.hit.element) === null || _a === void 0 ? void 0 : _a.id);\n\n if ((hasHitASelectedElement || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) && !isSelectingPointsInLineEditor) {\n const selectedElements = this.scene.getSelectedElements(this.state);\n\n if (selectedElements.every(element => element.locked)) {\n return;\n }\n\n const selectedElementsHasAFrame = selectedElements.find(e => (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isFrameElement)(e));\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(pointerCoords);\n this.setState({\n frameToHighlight: topLayerFrame && !selectedElementsHasAFrame ? topLayerFrame : null\n }); // Marking that click was used for dragging to check\n // if elements should be deselected on pointerup\n\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n }); // prevent dragging even if we're no longer holding cmd/ctrl otherwise\n // it would have weird results (stuff jumping all over the screen)\n // Checking for editingElement to avoid jump while editing on mobile #6503\n\n if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl && !this.state.editingElement && ((_b = this.state.activeEmbeddable) === null || _b === void 0 ? void 0 : _b.state) !== \"active\") {\n const dragOffset = {\n x: pointerCoords.x - pointerDownState.origin.x,\n y: pointerCoords.y - pointerDownState.origin.y\n };\n const originalElements = [...pointerDownState.originalElements.values()]; // We only drag in one direction if shift is pressed\n\n const lockDirection = event.shiftKey;\n\n if (lockDirection) {\n const distanceX = Math.abs(dragOffset.x);\n const distanceY = Math.abs(dragOffset.y);\n const lockX = lockDirection && distanceX < distanceY;\n const lockY = lockDirection && distanceX > distanceY;\n\n if (lockX) {\n dragOffset.x = 0;\n }\n\n if (lockY) {\n dragOffset.y = 0;\n }\n } // Snap cache *must* be synchronously popuplated before initial drag,\n // otherwise the first drag even will not snap, causing a jump before\n // it snaps to its position if previously snapped already.\n\n\n this.maybeCacheVisibleGaps(event, selectedElements);\n this.maybeCacheReferenceSnapPoints(event, selectedElements);\n const {\n snapOffset,\n snapLines\n } = (0,_snapping__WEBPACK_IMPORTED_MODULE_57__.snapDraggedElements)((0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(originalElements, this.state), dragOffset, this.state, event);\n this.setState({\n snapLines\n }); // when we're editing the name of a frame, we want the user to be\n // able to select and interact with the text input\n\n !this.state.editingFrame && (0,_element__WEBPACK_IMPORTED_MODULE_16__.dragSelectedElements)(pointerDownState, selectedElements, dragOffset, this.state, this.scene, snapOffset, event[_keys__WEBPACK_IMPORTED_MODULE_26__.KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);\n this.maybeSuggestBindingForAll(selectedElements); // We duplicate the selected element if alt is pressed on pointer move\n\n if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {\n // Move the currently selected elements to the top of the z index stack, and\n // put the duplicates where the selected elements used to be.\n // (the origin point where the dragging started)\n pointerDownState.hit.hasBeenDuplicated = true;\n const nextElements = [];\n const elementsToAppend = [];\n const groupIdMap = new Map();\n const oldIdToDuplicatedId = new Map();\n const hitElement = pointerDownState.hit.element;\n const selectedElementIds = new Set(this.scene.getSelectedElements({\n selectedElementIds: this.state.selectedElementIds,\n includeBoundTextElement: true,\n includeElementsInFrames: true\n }).map(element => element.id));\n const elements = this.scene.getElementsIncludingDeleted();\n\n for (const element of elements) {\n if (selectedElementIds.has(element.id) || // case: the state.selectedElementIds might not have been\n // updated yet by the time this mousemove event is fired\n element.id === (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && pointerDownState.hit.wasAddedToSelection) {\n const duplicatedElement = (0,_element__WEBPACK_IMPORTED_MODULE_16__.duplicateElement)(this.state.editingGroupId, groupIdMap, element);\n const origElement = pointerDownState.originalElements.get(element.id);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(duplicatedElement, {\n x: origElement.x,\n y: origElement.y\n }); // put duplicated element to pointerDownState.originalElements\n // so that we can snap to the duplicated element without releasing\n\n pointerDownState.originalElements.set(duplicatedElement.id, duplicatedElement);\n nextElements.push(duplicatedElement);\n elementsToAppend.push(element);\n oldIdToDuplicatedId.set(element.id, duplicatedElement.id);\n } else {\n nextElements.push(element);\n }\n }\n\n const nextSceneElements = [...nextElements, ...elementsToAppend];\n (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.bindTextToShapeAfterDuplication)(nextElements, elementsToAppend, oldIdToDuplicatedId);\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.fixBindingsAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, \"duplicatesServeAsOld\");\n (0,_frame__WEBPACK_IMPORTED_MODULE_50__.bindElementsToFramesAfterDuplication)(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);\n this.scene.replaceAllElements(nextSceneElements);\n this.maybeCacheVisibleGaps(event, selectedElements, true);\n this.maybeCacheReferenceSnapPoints(event, selectedElements, true);\n }\n\n return;\n }\n } // It is very important to read this.state within each move event,\n // otherwise we would read a stale one!\n\n\n const draggingElement = this.state.draggingElement;\n\n if (!draggingElement) {\n return;\n }\n\n if (draggingElement.type === \"freedraw\") {\n const points = draggingElement.points;\n const dx = pointerCoords.x - draggingElement.x;\n const dy = pointerCoords.y - draggingElement.y;\n const lastPoint = points.length > 0 && points[points.length - 1];\n const discardPoint = lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;\n\n if (!discardPoint) {\n const pressures = draggingElement.simulatePressure ? draggingElement.pressures : [...draggingElement.pressures, event.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures\n });\n }\n } else if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n pointerDownState.drag.hasOccurred = true;\n this.setState({\n selectedElementsAreBeingDragged: true\n });\n const points = draggingElement.points;\n let dx = gridX - draggingElement.x;\n let dy = gridY - draggingElement.y;\n\n if ((0,_keys__WEBPACK_IMPORTED_MODULE_26__.shouldRotateWithDiscreteAngle)(event) && points.length === 2) {\n ({\n width: dx,\n height: dy\n } = (0,_element__WEBPACK_IMPORTED_MODULE_16__.getLockedLinearCursorAlignSize)(draggingElement.x, draggingElement.y, pointerCoords.x, pointerCoords.y));\n }\n\n if (points.length === 1) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]]\n });\n } else if (points.length === 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points.slice(0, -1), [dx, dy]]\n });\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n // When creating a linear element by dragging\n this.maybeSuggestBindingsForLinearElementAtCoords(draggingElement, [pointerCoords], this.state.startBoundElement);\n }\n } else {\n pointerDownState.lastCoords.x = pointerCoords.x;\n pointerDownState.lastCoords.y = pointerCoords.y;\n this.maybeDragNewGenericElement(pointerDownState, event);\n }\n\n if (this.state.activeTool.type === \"selection\") {\n pointerDownState.boxSelection.hasOccurred = true;\n const elements = this.scene.getNonDeletedElements(); // box-select line editor points\n\n if (this.state.editingLinearElement) {\n _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handleBoxSelection(event, this.state, this.setState.bind(this)); // regular box-select\n } else {\n let shouldReuseSelection = true;\n\n if (!event.shiftKey && (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(elements, this.state)) {\n if (pointerDownState.withCmdOrCtrl && pointerDownState.hit.element) {\n this.setState(prevState => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)(Object.assign(Object.assign({}, prevState), {\n selectedElementIds: {\n [pointerDownState.hit.element.id]: true\n }\n }), this.scene.getNonDeletedElements(), prevState, this));\n } else {\n shouldReuseSelection = false;\n }\n }\n\n const elementsWithinSelection = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getElementsWithinSelection)(elements, draggingElement);\n this.setState(prevState => {\n const nextSelectedElementIds = Object.assign(Object.assign({}, shouldReuseSelection && prevState.selectedElementIds), elementsWithinSelection.reduce((acc, element) => {\n acc[element.id] = true;\n return acc;\n }, {}));\n\n if (pointerDownState.hit.element) {\n // if using ctrl/cmd, select the hitElement only if we\n // haven't box-selected anything else\n if (!elementsWithinSelection.length) {\n nextSelectedElementIds[pointerDownState.hit.element.id] = true;\n } else {\n delete nextSelectedElementIds[pointerDownState.hit.element.id];\n }\n }\n\n prevState = !shouldReuseSelection ? Object.assign(Object.assign({}, prevState), {\n selectedGroupIds: {},\n editingGroupId: null\n }) : prevState;\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // select linear element only when we haven't box-selected anything else\n selectedLinearElement: elementsWithinSelection.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(elementsWithinSelection[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(elementsWithinSelection[0], this.scene) : null,\n showHyperlinkPopup: elementsWithinSelection.length === 1 && (elementsWithinSelection[0].link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(elementsWithinSelection[0])) ? \"info\" : false\n });\n });\n }\n }\n });\n } // Returns whether the pointer move happened over either scrollbar\n\n\n handlePointerMoveOverScrollbars(event, pointerDownState) {\n if (pointerDownState.scrollbars.isOverHorizontal) {\n const x = event.clientX;\n const dx = x - pointerDownState.lastCoords.x;\n this.translateCanvas({\n scrollX: this.state.scrollX - dx / this.state.zoom.value\n });\n pointerDownState.lastCoords.x = x;\n return true;\n }\n\n if (pointerDownState.scrollbars.isOverVertical) {\n const y = event.clientY;\n const dy = y - pointerDownState.lastCoords.y;\n this.translateCanvas({\n scrollY: this.state.scrollY - dy / this.state.zoom.value\n });\n pointerDownState.lastCoords.y = y;\n return true;\n }\n\n return false;\n }\n\n onPointerUpFromPointerDownHandler(pointerDownState) {\n return (0,_utils__WEBPACK_IMPORTED_MODULE_33__.withBatchedUpdates)(childEvent => {\n var _a, _b, _c, _d, _e, _f;\n\n if (pointerDownState.eventListeners.onMove) {\n pointerDownState.eventListeners.onMove.flush();\n }\n\n const {\n draggingElement,\n resizingElement,\n multiElement,\n activeTool,\n isResizing,\n isRotating\n } = this.state;\n this.setState({\n isResizing: false,\n isRotating: false,\n resizingElement: null,\n selectionElement: null,\n frameToHighlight: null,\n elementsToHighlight: null,\n cursorButton: \"up\",\n // text elements are reset on finalize, and resetting on pointerup\n // may cause issues with double taps\n editingElement: multiElement || (0,_element__WEBPACK_IMPORTED_MODULE_16__.isTextElement)(this.state.editingElement) ? this.state.editingElement : null,\n snapLines: [],\n originSnapOffset: null\n });\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.setReferenceSnapPoints(null);\n _snapping__WEBPACK_IMPORTED_MODULE_57__.SnapCache.setVisibleGaps(null);\n this.savePointer(childEvent.clientX, childEvent.clientY, \"up\");\n this.setState({\n selectedElementsAreBeingDragged: false\n }); // Handle end of dragging a point of a linear element, might close a loop\n // and sets binding element\n\n if (this.state.editingLinearElement) {\n if (!pointerDownState.boxSelection.hasOccurred && ((_b = (_a = pointerDownState.hit) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.id) !== this.state.editingLinearElement.elementId) {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n } else {\n const editingLinearElement = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state);\n\n if (editingLinearElement !== this.state.editingLinearElement) {\n this.setState({\n editingLinearElement,\n suggestedBindings: []\n });\n }\n }\n } else if (this.state.selectedLinearElement) {\n if (((_d = (_c = pointerDownState.hit) === null || _c === void 0 ? void 0 : _c.element) === null || _d === void 0 ? void 0 : _d.id) !== this.state.selectedLinearElement.elementId) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement to null if there is more than one element selected since we don't want to show linear element handles\n\n if (selectedELements.length > 1) {\n this.setState({\n selectedLinearElement: null\n });\n }\n } else {\n const linearElementEditor = _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state);\n const {\n startBindingElement,\n endBindingElement\n } = linearElementEditor;\n const element = this.scene.getElement(linearElementEditor.elementId);\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(element)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindLinearElement)(element, startBindingElement, endBindingElement);\n }\n\n if (linearElementEditor !== this.state.selectedLinearElement) {\n this.setState({\n selectedLinearElement: Object.assign(Object.assign({}, linearElementEditor), {\n selectedPointsIndices: null\n }),\n suggestedBindings: []\n });\n }\n }\n }\n\n lastPointerUp = null;\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_MOVE, pointerDownState.eventListeners.onMove);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.POINTER_UP, pointerDownState.eventListeners.onUp);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYDOWN, pointerDownState.eventListeners.onKeyDown);\n window.removeEventListener(_constants__WEBPACK_IMPORTED_MODULE_12__.EVENT.KEYUP, pointerDownState.eventListeners.onKeyUp);\n\n if (this.state.pendingImageElementId) {\n this.setState({\n pendingImageElementId: null\n });\n }\n\n this.onPointerUpEmitter.trigger(this.state.activeTool, pointerDownState, childEvent);\n\n if ((draggingElement === null || draggingElement === void 0 ? void 0 : draggingElement.type) === \"freedraw\") {\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n const points = draggingElement.points;\n let dx = pointerCoords.x - draggingElement.x;\n let dy = pointerCoords.y - draggingElement.y; // Allows dots to avoid being flagged as infinitely small\n\n if (dx === points[0][0] && dy === points[0][1]) {\n dy += 0.0001;\n dx += 0.0001;\n }\n\n const pressures = draggingElement.simulatePressure ? [] : [...draggingElement.pressures, childEvent.pressure];\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...points, [dx, dy]],\n pressures,\n lastCommittedPoint: [dx, dy]\n });\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isImageElement)(draggingElement)) {\n const imageElement = draggingElement;\n\n try {\n this.initializeImageDimensions(imageElement);\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({\n [imageElement.id]: true\n }, this.state)\n }, () => {\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n });\n } catch (error) {\n console.error(error);\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== imageElement.id));\n this.actionManager.executeAction(_actions__WEBPACK_IMPORTED_MODULE_5__.actionFinalize);\n }\n\n return;\n }\n\n if ((0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(draggingElement)) {\n if (draggingElement.points.length > 1) {\n this.history.resumeRecording();\n }\n\n const pointerCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state);\n\n if (!pointerDownState.drag.hasOccurred && draggingElement && !multiElement) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, {\n points: [...draggingElement.points, [pointerCoords.x - draggingElement.x, pointerCoords.y - draggingElement.y]]\n });\n this.setState({\n multiElement: draggingElement,\n editingElement: this.state.draggingElement\n });\n } else if (pointerDownState.drag.hasOccurred && !multiElement) {\n if ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isBindingElement)(draggingElement, false)) {\n (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.maybeBindLinearElement)(draggingElement, this.state, this.scene, pointerCoords);\n }\n\n this.setState({\n suggestedBindings: [],\n startBoundElement: null\n });\n\n if (!activeTool.locked) {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n this.setState(prevState => ({\n draggingElement: null,\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n }),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(draggingElement, this.scene)\n }));\n } else {\n this.setState(prevState => ({\n draggingElement: null\n }));\n }\n }\n\n return;\n }\n\n if (activeTool.type !== \"selection\" && draggingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(draggingElement)) {\n // remove invisible element which was added in onPointerDown\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== draggingElement.id));\n this.setState({\n draggingElement: null\n });\n return;\n }\n\n if (draggingElement) {\n if (pointerDownState.drag.hasOccurred) {\n const sceneCoords = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)(childEvent, this.state); // when editing the points of a linear element, we check if the\n // linear element still is in the frame afterwards\n // if not, the linear element will be removed from its frame (if any)\n\n if (this.state.selectedLinearElement && this.state.selectedLinearElement.isDragging) {\n const linearElement = this.scene.getElement(this.state.selectedLinearElement.elementId);\n\n if (linearElement === null || linearElement === void 0 ? void 0 : linearElement.frameId) {\n const frame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getContainingFrame)(linearElement);\n\n if (frame && linearElement) {\n if (!(0,_frame__WEBPACK_IMPORTED_MODULE_50__.elementOverlapsWithFrame)(linearElement, frame)) {\n // remove the linear element from all groups\n // before removing it from the frame as well\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(linearElement, {\n groupIds: []\n });\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.removeElementsFromFrame)(this.scene.getElementsIncludingDeleted(), [linearElement], this.state));\n }\n }\n }\n } else {\n // update the relationships between selected elements and frames\n const topLayerFrame = this.getTopLayerFrameAtSceneCoords(sceneCoords);\n const selectedElements = this.scene.getSelectedElements(this.state);\n let nextElements = this.scene.getElementsIncludingDeleted();\n\n const updateGroupIdsAfterEditingGroup = elements => {\n if (elements.length > 0) {\n for (const element of elements) {\n const index = element.groupIds.indexOf(this.state.editingGroupId);\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: element.groupIds.slice(0, index)\n }, false);\n }\n\n nextElements.forEach(element => {\n if (element.groupIds.length && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(nextElements, element.groupIds[element.groupIds.length - 1]).length < 2) {\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(element, {\n groupIds: []\n }, false);\n }\n });\n this.setState({\n editingGroupId: null\n });\n }\n };\n\n if (topLayerFrame && !this.state.selectedElementIds[topLayerFrame.id]) {\n const elementsToAdd = selectedElements.filter(element => element.frameId !== topLayerFrame.id && (0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n\n if (this.state.editingGroupId) {\n updateGroupIdsAfterEditingGroup(elementsToAdd);\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(nextElements, elementsToAdd, topLayerFrame);\n } else if (!topLayerFrame) {\n if (this.state.editingGroupId) {\n const elementsToRemove = selectedElements.filter(element => element.frameId && !(0,_frame__WEBPACK_IMPORTED_MODULE_50__.isElementInFrame)(element, nextElements, this.state));\n updateGroupIdsAfterEditingGroup(elementsToRemove);\n }\n }\n\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(nextElements, this.state, this);\n this.scene.replaceAllElements(nextElements);\n }\n }\n\n if (draggingElement.type === \"frame\") {\n const elementsInsideFrame = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInNewFrame)(this.scene.getElementsIncludingDeleted(), draggingElement);\n this.scene.replaceAllElements((0,_frame__WEBPACK_IMPORTED_MODULE_50__.addElementsToFrame)(this.scene.getElementsIncludingDeleted(), elementsInsideFrame, draggingElement));\n }\n\n (0,_element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement)(draggingElement, (0,_element__WEBPACK_IMPORTED_MODULE_16__.getNormalizedDimensions)(draggingElement));\n }\n\n if (resizingElement) {\n this.history.resumeRecording();\n }\n\n if (resizingElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isInvisiblySmallElement)(resizingElement)) {\n this.scene.replaceAllElements(this.scene.getElementsIncludingDeleted().filter(el => el.id !== resizingElement.id));\n } // handle frame membership for resizing frames and/or selected elements\n\n\n if (pointerDownState.resize.isResizing) {\n let nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.updateFrameMembershipOfSelectedElements)(this.scene.getElementsIncludingDeleted(), this.state, this);\n const selectedFrames = this.scene.getSelectedElements(this.state).filter(element => element.type === \"frame\");\n\n for (const frame of selectedFrames) {\n nextElements = (0,_frame__WEBPACK_IMPORTED_MODULE_50__.replaceAllElementsInFrame)(nextElements, (0,_frame__WEBPACK_IMPORTED_MODULE_50__.getElementsInResizingFrame)(this.scene.getElementsIncludingDeleted(), frame, this.state), frame, this.state);\n }\n\n this.scene.replaceAllElements(nextElements);\n } // Code below handles selection when element(s) weren't\n // drag or added to selection on pointer down phase.\n\n\n const hitElement = pointerDownState.hit.element;\n\n if (((_e = this.state.selectedLinearElement) === null || _e === void 0 ? void 0 : _e.elementId) !== (hitElement === null || hitElement === void 0 ? void 0 : hitElement.id) && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement)) {\n const selectedELements = this.scene.getSelectedElements(this.state); // set selectedLinearElement when no other element selected except\n // the one we've hit\n\n if (selectedELements.length === 1) {\n this.setState({\n selectedLinearElement: new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene)\n });\n }\n }\n\n if ((0,_appState__WEBPACK_IMPORTED_MODULE_10__.isEraserActive)(this.state)) {\n const draggedDistance = (0,_math__WEBPACK_IMPORTED_MODULE_28__.distance2d)(this.lastPointerDownEvent.clientX, this.lastPointerDownEvent.clientY, this.lastPointerUpEvent.clientX, this.lastPointerUpEvent.clientY);\n\n if (draggedDistance === 0) {\n const scenePointer = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.viewportCoordsToSceneCoords)({\n clientX: this.lastPointerUpEvent.clientX,\n clientY: this.lastPointerUpEvent.clientY\n }, this.state);\n const hitElements = this.getElementsAtPosition(scenePointer.x, scenePointer.y);\n hitElements.forEach(hitElement => pointerDownState.elementIdsToErase[hitElement.id] = {\n erase: true,\n opacity: hitElement.opacity\n });\n }\n\n this.eraseElements(pointerDownState);\n return;\n } else if (Object.keys(pointerDownState.elementIdsToErase).length) {\n this.restoreReadyToEraseElements(pointerDownState);\n }\n\n if (hitElement && !pointerDownState.drag.hasOccurred && !pointerDownState.hit.wasAddedToSelection && ( // if we're editing a line, pointerup shouldn't switch selection if\n // box selected\n !this.state.editingLinearElement || !pointerDownState.boxSelection.hasOccurred)) {\n // when inside line editor, shift selects points instead\n if (childEvent.shiftKey && !this.state.editingLinearElement) {\n if (this.state.selectedElementIds[hitElement.id]) {\n if ((0,_groups__WEBPACK_IMPORTED_MODULE_23__.isSelectedViaGroup)(this.state, hitElement)) {\n this.setState(_prevState => {\n const nextSelectedElementIds = Object.assign({}, _prevState.selectedElementIds); // We want to unselect all groups hitElement is part of\n // as well as all elements that are part of the groups\n // hitElement is part of\n\n for (const groupedElement of hitElement.groupIds.flatMap(groupId => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), groupId))) {\n delete nextSelectedElementIds[groupedElement.id];\n }\n\n return {\n selectedGroupIds: Object.assign(Object.assign({}, _prevState.selectedElementIds), hitElement.groupIds.map(gId => ({\n [gId]: false\n })).reduce((prev, acc) => Object.assign(Object.assign({}, prev), acc), {})),\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(nextSelectedElementIds, _prevState)\n };\n }); // if not gragging a linear element point (outside editor)\n } else if (!((_f = this.state.selectedLinearElement) === null || _f === void 0 ? void 0 : _f.isDragging)) {\n // remove element from selection while\n // keeping prev elements selected\n this.setState(prevState => {\n const newSelectedElementIds = Object.assign({}, prevState.selectedElementIds);\n delete newSelectedElementIds[hitElement.id];\n const newSelectedElements = (0,_scene__WEBPACK_IMPORTED_MODULE_29__.getSelectedElements)(this.scene.getNonDeletedElements(), {\n selectedElementIds: newSelectedElementIds\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: newSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n // set selectedLinearElement only if thats the only element selected\n selectedLinearElement: newSelectedElements.length === 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(newSelectedElements[0]) ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(newSelectedElements[0], this.scene) : prevState.selectedLinearElement\n });\n });\n }\n } else if (hitElement.frameId && this.state.selectedElementIds[hitElement.frameId]) {\n // when hitElement is part of a selected frame, deselect the frame\n // to avoid frame and containing elements selected simultaneously\n this.setState(prevState => {\n var _a, _b;\n\n const nextSelectedElementIds = Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [hitElement.id]: true\n }); // deselect the frame\n\n delete nextSelectedElementIds[hitElement.frameId]; // deselect groups containing the frame\n\n ((_b = (_a = this.scene.getElement(hitElement.frameId)) === null || _a === void 0 ? void 0 : _a.groupIds) !== null && _b !== void 0 ? _b : []).flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_23__.getElementsInGroup)(this.scene.getNonDeletedElements(), gid)).forEach(element => {\n delete nextSelectedElementIds[element.id];\n });\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: nextSelectedElementIds\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n showHyperlinkPopup: hitElement.link || (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) ? \"info\" : false\n });\n });\n } else {\n // add element to selection while keeping prev elements selected\n this.setState(_prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, _prevState.selectedElementIds), {\n [hitElement.id]: true\n }), _prevState)\n }));\n }\n } else {\n this.setState(prevState => {\n var _a;\n\n return Object.assign(Object.assign({}, (0,_groups__WEBPACK_IMPORTED_MODULE_23__.selectGroupsForSelectedElements)({\n editingGroupId: prevState.editingGroupId,\n selectedElementIds: {\n [hitElement.id]: true\n }\n }, this.scene.getNonDeletedElements(), prevState, this)), {\n selectedLinearElement: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isLinearElement)(hitElement) && // Don't set `selectedLinearElement` if its same as the hitElement, this is mainly to prevent resetting the `hoverPointIndex` to -1.\n // Future we should update the API to take care of setting the correct `hoverPointIndex` when initialized\n ((_a = prevState.selectedLinearElement) === null || _a === void 0 ? void 0 : _a.elementId) !== hitElement.id ? new _element_linearElementEditor__WEBPACK_IMPORTED_MODULE_18__.LinearElementEditor(hitElement, this.scene) : prevState.selectedLinearElement\n });\n });\n }\n }\n\n if (!pointerDownState.drag.hasOccurred && !this.state.isResizing && (hitElement && (0,_element__WEBPACK_IMPORTED_MODULE_16__.isHittingElementBoundingBoxWithoutHittingElement)(hitElement, this.state, this.frameNameBoundsCache, pointerDownState.origin.x, pointerDownState.origin.y) || !hitElement && pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements)) {\n if (this.state.editingLinearElement) {\n this.setState({\n editingLinearElement: null\n });\n } else {\n // Deselect selected elements\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n selectedGroupIds: {},\n editingGroupId: null,\n activeEmbeddable: null\n });\n }\n\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\" && draggingElement && draggingElement.type !== \"selection\") {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)(Object.assign(Object.assign({}, prevState.selectedElementIds), {\n [draggingElement.id]: true\n }), prevState),\n showHyperlinkPopup: (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(draggingElement) && !draggingElement.link ? \"editor\" : prevState.showHyperlinkPopup\n }));\n }\n\n if (activeTool.type !== \"selection\" || (0,_scene__WEBPACK_IMPORTED_MODULE_29__.isSomeElementSelected)(this.scene.getNonDeletedElements(), this.state)) {\n this.history.resumeRecording();\n }\n\n if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {\n ((0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.isBindingEnabled)(this.state) ? _element_binding__WEBPACK_IMPORTED_MODULE_17__.bindOrUnbindSelectedElements : _element_binding__WEBPACK_IMPORTED_MODULE_17__.unbindLinearElements)(this.scene.getSelectedElements(this.state));\n }\n\n if (activeTool.type === \"laser\") {\n this.laserPathManager.endPath();\n return;\n }\n\n if (!activeTool.locked && activeTool.type !== \"freedraw\") {\n (0,_cursor__WEBPACK_IMPORTED_MODULE_69__.resetCursor)(this.interactiveCanvas);\n this.setState({\n draggingElement: null,\n suggestedBindings: [],\n activeTool: (0,_utils__WEBPACK_IMPORTED_MODULE_33__.updateActiveTool)(this.state, {\n type: \"selection\"\n })\n });\n } else {\n this.setState({\n draggingElement: null,\n suggestedBindings: []\n });\n }\n\n if (hitElement && this.lastPointerUpEvent && this.lastPointerDownEvent && this.lastPointerUpEvent.timeStamp - this.lastPointerDownEvent.timeStamp < 300 && gesture.pointers.size <= 1 && (0,_element_typeChecks__WEBPACK_IMPORTED_MODULE_21__.isEmbeddableElement)(hitElement) && this.isEmbeddableCenter(hitElement, this.lastPointerUpEvent, pointerDownState.origin.x, pointerDownState.origin.y)) {\n this.handleEmbeddableCenterClick(hitElement);\n }\n });\n }\n\n maybeSuggestBindingForAll(selectedElements) {\n if (selectedElements.length > 50) {\n return;\n }\n\n const suggestedBindings = (0,_element_binding__WEBPACK_IMPORTED_MODULE_17__.getEligibleElementsForBinding)(selectedElements);\n this.setState({\n suggestedBindings\n });\n }\n\n clearSelection(hitElement) {\n this.setState(prevState => ({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, prevState),\n activeEmbeddable: null,\n selectedGroupIds: {},\n // Continue editing the same group if the user selected a different\n // element from it\n editingGroupId: prevState.editingGroupId && hitElement != null && (0,_groups__WEBPACK_IMPORTED_MODULE_23__.isElementInGroup)(hitElement, prevState.editingGroupId) ? prevState.editingGroupId : null\n }));\n this.setState({\n selectedElementIds: (0,_scene_selection__WEBPACK_IMPORTED_MODULE_51__.makeNextSelectedElementIds)({}, this.state),\n activeEmbeddable: null,\n previousSelectedElementIds: this.state.selectedElementIds\n });\n }\n\n getTextWysiwygSnappedToCenterPosition(x, y, appState, container) {\n if (container) {\n let elementCenterX = container.x + container.width / 2;\n let elementCenterY = container.y + container.height / 2;\n const elementCenter = (0,_element_textElement__WEBPACK_IMPORTED_MODULE_43__.getContainerCenter)(container, appState);\n\n if (elementCenter) {\n elementCenterX = elementCenter.x;\n elementCenterY = elementCenter.y;\n }\n\n const distanceToCenter = Math.hypot(x - elementCenterX, y - elementCenterY);\n const isSnappedToCenter = distanceToCenter < _constants__WEBPACK_IMPORTED_MODULE_12__.TEXT_TO_CENTER_SNAP_THRESHOLD;\n\n if (isSnappedToCenter) {\n const {\n x: viewportX,\n y: viewportY\n } = (0,_utils__WEBPACK_IMPORTED_MODULE_33__.sceneCoordsToViewportCoords)({\n sceneX: elementCenterX,\n sceneY: elementCenterY\n }, appState);\n return {\n viewportX,\n viewportY,\n elementCenterX,\n elementCenterY\n };\n }\n }\n }\n\n getCanvasOffsets() {\n var _a;\n\n if ((_a = this.excalidrawContainerRef) === null || _a === void 0 ? void 0 : _a.current) {\n const excalidrawContainer = this.excalidrawContainerRef.current;\n const {\n left,\n top\n } = excalidrawContainer.getBoundingClientRect();\n return {\n offsetLeft: left,\n offsetTop: top\n };\n }\n\n return {\n offsetLeft: 0,\n offsetTop: 0\n };\n }\n\n updateLanguage() {\n return __awaiter(this, void 0, void 0, function* () {\n const currentLang = _i18n__WEBPACK_IMPORTED_MODULE_25__.languages.find(lang => lang.code === this.props.langCode) || _i18n__WEBPACK_IMPORTED_MODULE_25__.defaultLang;\n yield (0,_i18n__WEBPACK_IMPORTED_MODULE_25__.setLanguage)(currentLang);\n this.setAppState({});\n });\n }\n\n}\n\nApp.defaultProps = {\n // needed for tests to pass since we directly render App in many tests\n UIOptions: _constants__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_UI_OPTIONS\n};\n\nif (\"development\" === _constants__WEBPACK_IMPORTED_MODULE_12__.ENV.TEST || \"development\" !== \"production\") {\n window.h = window.h || {};\n Object.defineProperties(window.h, {\n elements: {\n configurable: true,\n\n get() {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.getElementsIncludingDeleted();\n },\n\n set(elements) {\n var _a;\n\n return (_a = this.app) === null || _a === void 0 ? void 0 : _a.scene.replaceAllElements(elements);\n }\n\n }\n });\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNBOztBQUVBLDhCQUE4QixnRkFBNkI7QUFDM0Q7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0EsMEJBQTBCLDZFQUEwQixHQUFHO0FBQ3ZEO0FBQ0EsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQSx3RUFBd0UsMERBQWdCO0FBQ3hGLEtBQUs7QUFDTDtBQUNBLDBCQUEwQiw2RUFBMEIsR0FBRztBQUN2RDtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLHlFQUFrQjs7QUFFOUM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxtREFBbUQsc0VBQTZCOztBQUVoRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsRUFBRSxvRUFBMkI7QUFDdkM7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsMEJBQTBCLGtEQUFjLCtDQUErQywrQ0FBVztBQUNsRyxZQUFZLG1EQUFXO0FBQ3ZCLHlCQUF5QjtBQUN6QixLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGFBQWEsMkRBQWtCO0FBQy9COztBQUVBLElBQUksYUFBb0IsS0FBSyxpREFBUSxJQUFJLGFBQW9CO0FBQzdEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDs7QUFFQSxpRUFBZSxHQUFHIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4uLy4uL2NvbXBvbmVudHMvQXBwLnRzeD82N2FlIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX2F3YWl0ZXIgPSB0aGlzICYmIHRoaXMuX19hd2FpdGVyIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcbiAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkge1xuICAgICAgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7XG4gICAgfVxuXG4gICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xuICB9KTtcbn07XG5cbmltcG9ydCB7IGpzeCBhcyBfanN4LCBqc3hzIGFzIF9qc3hzLCBGcmFnbWVudCBhcyBfRnJhZ21lbnQgfSBmcm9tIFwicmVhY3QvanN4LXJ1bnRpbWVcIjtcbmltcG9ydCBSZWFjdCwgeyB1c2VDb250ZXh0IH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBmbHVzaFN5bmMgfSBmcm9tIFwicmVhY3QtZG9tXCI7XG5pbXBvcnQgcm91Z2ggZnJvbSBcInJvdWdoanMvYmluL3JvdWdoXCI7XG5pbXBvcnQgY2xzeCBmcm9tIFwiY2xzeFwiO1xuaW1wb3J0IHsgbmFub2lkIH0gZnJvbSBcIm5hbm9pZFwiO1xuaW1wb3J0IHsgYWN0aW9uQWRkVG9MaWJyYXJ5LCBhY3Rpb25CcmluZ0ZvcndhcmQsIGFjdGlvbkJyaW5nVG9Gcm9udCwgYWN0aW9uQ29weSwgYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcsIGNvcHlUZXh0LCBhY3Rpb25Db3B5U3R5bGVzLCBhY3Rpb25DdXQsIGFjdGlvbkRlbGV0ZVNlbGVjdGVkLCBhY3Rpb25EdXBsaWNhdGVTZWxlY3Rpb24sIGFjdGlvbkZpbmFsaXplLCBhY3Rpb25GbGlwSG9yaXpvbnRhbCwgYWN0aW9uRmxpcFZlcnRpY2FsLCBhY3Rpb25Hcm91cCwgYWN0aW9uUGFzdGVTdHlsZXMsIGFjdGlvblNlbGVjdEFsbCwgYWN0aW9uU2VuZEJhY2t3YXJkLCBhY3Rpb25TZW5kVG9CYWNrLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlU3RhdHMsIGFjdGlvblRvZ2dsZVplbk1vZGUsIGFjdGlvblVuYmluZFRleHQsIGFjdGlvbkJpbmRUZXh0LCBhY3Rpb25Vbmdyb3VwLCBhY3Rpb25MaW5rLCBhY3Rpb25Ub2dnbGVFbGVtZW50TG9jaywgYWN0aW9uVG9nZ2xlTGluZWFyRWRpdG9yLCBhY3Rpb25Ub2dnbGVPYmplY3RzU25hcE1vZGUgfSBmcm9tIFwiLi4vYWN0aW9uc1wiO1xuaW1wb3J0IHsgY3JlYXRlUmVkb0FjdGlvbiwgY3JlYXRlVW5kb0FjdGlvbiB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkhpc3RvcnlcIjtcbmltcG9ydCB7IEFjdGlvbk1hbmFnZXIgfSBmcm9tIFwiLi4vYWN0aW9ucy9tYW5hZ2VyXCI7XG5pbXBvcnQgeyBhY3Rpb25zIH0gZnJvbSBcIi4uL2FjdGlvbnMvcmVnaXN0ZXJcIjtcbmltcG9ydCB7IHRyYWNrRXZlbnQgfSBmcm9tIFwiLi4vYW5hbHl0aWNzXCI7XG5pbXBvcnQgeyBnZXREZWZhdWx0QXBwU3RhdGUsIGlzRXJhc2VyQWN0aXZlLCBpc0hhbmRUb29sQWN0aXZlIH0gZnJvbSBcIi4uL2FwcFN0YXRlXCI7XG5pbXBvcnQgeyBwYXJzZUNsaXBib2FyZCB9IGZyb20gXCIuLi9jbGlwYm9hcmRcIjtcbmltcG9ydCB7IEFQUF9OQU1FLCBDVVJTT1JfVFlQRSwgREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hULCBERUZBVUxUX1VJX09QVElPTlMsIERFRkFVTFRfVkVSVElDQUxfQUxJR04sIERSQUdHSU5HX1RIUkVTSE9MRCwgRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZLCBFTEVNRU5UX1NISUZUX1RSQU5TTEFURV9BTU9VTlQsIEVMRU1FTlRfVFJBTlNMQVRFX0FNT1VOVCwgRU5WLCBFVkVOVCwgRlJBTUVfU1RZTEUsIEdSSURfU0laRSwgSU1BR0VfTUlNRV9UWVBFUywgSU1BR0VfUkVOREVSX1RJTUVPVVQsIGlzQW5kcm9pZCwgaXNCcmF2ZSwgTElORV9DT05GSVJNX1RIUkVTSE9MRCwgTUFYX0FMTE9XRURfRklMRV9CWVRFUywgTUlNRV9UWVBFUywgTVFfTUFYX0hFSUdIVF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9MQU5EU0NBUEUsIE1RX01BWF9XSURUSF9QT1JUUkFJVCwgTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEgsIFBPSU5URVJfQlVUVE9OLCBST1VORE5FU1MsIFNDUk9MTF9USU1FT1VULCBUQVBfVFdJQ0VfVElNRU9VVCwgVEVYVF9UT19DRU5URVJfU05BUF9USFJFU0hPTEQsIFRIRU1FLCBUSEVNRV9GSUxURVIsIFRPVUNIX0NUWF9NRU5VX1RJTUVPVVQsIFZFUlRJQ0FMX0FMSUdOLCBZT1VUVUJFX1NUQVRFUywgWk9PTV9TVEVQLCBQT0lOVEVSX0VWRU5UUyB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGV4cG9ydENhbnZhcywgbG9hZEZyb21CbG9iIH0gZnJvbSBcIi4uL2RhdGFcIjtcbmltcG9ydCBMaWJyYXJ5LCB7IGRpc3RyaWJ1dGVMaWJyYXJ5SXRlbXNPblNxdWFyZUdyaWQgfSBmcm9tIFwiLi4vZGF0YS9saWJyYXJ5XCI7XG5pbXBvcnQgeyByZXN0b3JlLCByZXN0b3JlRWxlbWVudHMgfSBmcm9tIFwiLi4vZGF0YS9yZXN0b3JlXCI7XG5pbXBvcnQgeyBkcmFnTmV3RWxlbWVudCwgZHJhZ1NlbGVjdGVkRWxlbWVudHMsIGR1cGxpY2F0ZUVsZW1lbnQsIGdldENvbW1vbkJvdW5kcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50LCBnZXREcmFnT2Zmc2V0WFksIGdldEVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSwgZ2V0Tm9ybWFsaXplZERpbWVuc2lvbnMsIGdldFJlc2l6ZUFycm93RGlyZWN0aW9uLCBnZXRSZXNpemVPZmZzZXRYWSwgZ2V0TG9ja2VkTGluZWFyQ3Vyc29yQWxpZ25TaXplLCBnZXRUcmFuc2Zvcm1IYW5kbGVUeXBlRnJvbUNvb3JkcywgaGl0VGVzdCwgaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50LCBpc0ludmlzaWJseVNtYWxsRWxlbWVudCwgaXNOb25EZWxldGVkRWxlbWVudCwgaXNUZXh0RWxlbWVudCwgbmV3RWxlbWVudCwgbmV3TGluZWFyRWxlbWVudCwgbmV3VGV4dEVsZW1lbnQsIG5ld0ltYWdlRWxlbWVudCwgdGV4dFd5c2l3eWcsIHRyYW5zZm9ybUVsZW1lbnRzLCB1cGRhdGVUZXh0RWxlbWVudCwgcmVkcmF3VGV4dEJvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnRcIjtcbmltcG9ydCB7IGJpbmRPclVuYmluZExpbmVhckVsZW1lbnQsIGJpbmRPclVuYmluZFNlbGVjdGVkRWxlbWVudHMsIGZpeEJpbmRpbmdzQWZ0ZXJEZWxldGlvbiwgZml4QmluZGluZ3NBZnRlckR1cGxpY2F0aW9uLCBnZXRFbGlnaWJsZUVsZW1lbnRzRm9yQmluZGluZywgZ2V0SG92ZXJlZEVsZW1lbnRGb3JCaW5kaW5nLCBpc0JpbmRpbmdFbmFibGVkLCBpc0xpbmVhckVsZW1lbnRTaW1wbGVBbmRBbHJlYWR5Qm91bmQsIG1heWJlQmluZExpbmVhckVsZW1lbnQsIHNob3VsZEVuYWJsZUJpbmRpbmdGb3JQb2ludGVyRXZlbnQsIHVuYmluZExpbmVhckVsZW1lbnRzLCB1cGRhdGVCb3VuZEVsZW1lbnRzIH0gZnJvbSBcIi4uL2VsZW1lbnQvYmluZGluZ1wiO1xuaW1wb3J0IHsgTGluZWFyRWxlbWVudEVkaXRvciB9IGZyb20gXCIuLi9lbGVtZW50L2xpbmVhckVsZW1lbnRFZGl0b3JcIjtcbmltcG9ydCB7IG11dGF0ZUVsZW1lbnQsIG5ld0VsZW1lbnRXaXRoIH0gZnJvbSBcIi4uL2VsZW1lbnQvbXV0YXRlRWxlbWVudFwiO1xuaW1wb3J0IHsgZGVlcENvcHlFbGVtZW50LCBkdXBsaWNhdGVFbGVtZW50cywgbmV3RnJhbWVFbGVtZW50LCBuZXdGcmVlRHJhd0VsZW1lbnQsIG5ld0VtYmVkZGFibGVFbGVtZW50IH0gZnJvbSBcIi4uL2VsZW1lbnQvbmV3RWxlbWVudFwiO1xuaW1wb3J0IHsgaGFzQm91bmRUZXh0RWxlbWVudCwgaXNBcnJvd0VsZW1lbnQsIGlzQmluZGluZ0VsZW1lbnQsIGlzQmluZGluZ0VsZW1lbnRUeXBlLCBpc0JvdW5kVG9Db250YWluZXIsIGlzRnJhbWVFbGVtZW50LCBpc0ltYWdlRWxlbWVudCwgaXNFbWJlZGRhYmxlRWxlbWVudCwgaXNJbml0aWFsaXplZEltYWdlRWxlbWVudCwgaXNMaW5lYXJFbGVtZW50LCBpc0xpbmVhckVsZW1lbnRUeXBlLCBpc1VzaW5nQWRhcHRpdmVSYWRpdXMgfSBmcm9tIFwiLi4vZWxlbWVudC90eXBlQ2hlY2tzXCI7XG5pbXBvcnQgeyBnZXRDZW50ZXIsIGdldERpc3RhbmNlIH0gZnJvbSBcIi4uL2dlc3R1cmVcIjtcbmltcG9ydCB7IGVkaXRHcm91cEZvclNlbGVjdGVkRWxlbWVudCwgZ2V0RWxlbWVudHNJbkdyb3VwLCBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50LCBnZXRTZWxlY3RlZEdyb3VwSWRzLCBpc0VsZW1lbnRJbkdyb3VwLCBpc1NlbGVjdGVkVmlhR3JvdXAsIHNlbGVjdEdyb3Vwc0ZvclNlbGVjdGVkRWxlbWVudHMgfSBmcm9tIFwiLi4vZ3JvdXBzXCI7XG5pbXBvcnQgSGlzdG9yeSBmcm9tIFwiLi4vaGlzdG9yeVwiO1xuaW1wb3J0IHsgZGVmYXVsdExhbmcsIGdldExhbmd1YWdlLCBsYW5ndWFnZXMsIHNldExhbmd1YWdlLCB0IH0gZnJvbSBcIi4uL2kxOG5cIjtcbmltcG9ydCB7IENPREVTLCBzaG91bGRSZXNpemVGcm9tQ2VudGVyLCBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvLCBzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZSwgaXNBcnJvd0tleSwgS0VZUyB9IGZyb20gXCIuLi9rZXlzXCI7XG5pbXBvcnQgeyBpc0VsZW1lbnRJblZpZXdwb3J0IH0gZnJvbSBcIi4uL2VsZW1lbnQvc2l6ZUhlbHBlcnNcIjtcbmltcG9ydCB7IGRpc3RhbmNlMmQsIGdldENvcm5lclJhZGl1cywgZ2V0R3JpZFBvaW50LCBpc1BhdGhBTG9vcCB9IGZyb20gXCIuLi9tYXRoXCI7XG5pbXBvcnQgeyBjYWxjdWxhdGVTY3JvbGxDZW50ZXIsIGdldEVsZW1lbnRzQXRQb3NpdGlvbiwgZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24sIGdldE5vcm1hbGl6ZWRab29tLCBnZXRTZWxlY3RlZEVsZW1lbnRzLCBoYXNCYWNrZ3JvdW5kLCBpc092ZXJTY3JvbGxCYXJzLCBpc1NvbWVFbGVtZW50U2VsZWN0ZWQgfSBmcm9tIFwiLi4vc2NlbmVcIjtcbmltcG9ydCBTY2VuZSBmcm9tIFwiLi4vc2NlbmUvU2NlbmVcIjtcbmltcG9ydCB7IGdldFN0YXRlRm9yWm9vbSB9IGZyb20gXCIuLi9zY2VuZS96b29tXCI7XG5pbXBvcnQgeyBmaW5kU2hhcGVCeUtleSB9IGZyb20gXCIuLi9zaGFwZXNcIjtcbmltcG9ydCB7IGRlYm91bmNlLCBkaXN0YW5jZSwgZ2V0Rm9udFN0cmluZywgZ2V0TmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIsIGlzSW5wdXRMaWtlLCBpc1Rvb2xJY29uLCBpc1dyaXRhYmxlRWxlbWVudCwgcmVzb2x2YWJsZVByb21pc2UsIHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3JkcywgdHVwbGVUb0Nvb3JzLCB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMsIHdpdGhCYXRjaGVkVXBkYXRlcywgd3JhcEV2ZW50LCB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQsIHVwZGF0ZU9iamVjdCwgdXBkYXRlQWN0aXZlVG9vbCwgZ2V0U2hvcnRjdXRLZXksIGlzVHJhbnNwYXJlbnQsIGVhc2VUb1ZhbHVlc1JBRiwgbXV0ZUZTQWJvcnRFcnJvciwgaXNUZXN0RW52LCBlYXNlT3V0IH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgeyBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yLCBleHRyYWN0U3JjLCBnZXRFbWJlZExpbmsgfSBmcm9tIFwiLi4vZWxlbWVudC9lbWJlZGRhYmxlXCI7XG5pbXBvcnQgeyBDb250ZXh0TWVudSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiB9IGZyb20gXCIuL0NvbnRleHRNZW51XCI7XG5pbXBvcnQgTGF5ZXJVSSBmcm9tIFwiLi9MYXllclVJXCI7XG5pbXBvcnQgeyBUb2FzdCB9IGZyb20gXCIuL1RvYXN0XCI7XG5pbXBvcnQgeyBhY3Rpb25Ub2dnbGVWaWV3TW9kZSB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvblRvZ2dsZVZpZXdNb2RlXCI7XG5pbXBvcnQgeyBkYXRhVVJMVG9GaWxlLCBnZW5lcmF0ZUlkRnJvbUZpbGUsIGdldERhdGFVUkwsIGdldEZpbGVGcm9tRXZlbnQsIEltYWdlVVJMVG9GaWxlLCBpc0ltYWdlRmlsZUhhbmRsZSwgaXNTdXBwb3J0ZWRJbWFnZUZpbGUsIGxvYWRTY2VuZU9yTGlicmFyeUZyb21CbG9iLCBub3JtYWxpemVGaWxlLCBwYXJzZUxpYnJhcnlKU09OLCByZXNpemVJbWFnZUZpbGUsIFNWR1N0cmluZ1RvRmlsZSB9IGZyb20gXCIuLi9kYXRhL2Jsb2JcIjtcbmltcG9ydCB7IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cywgbG9hZEhUTUxJbWFnZUVsZW1lbnQsIG5vcm1hbGl6ZVNWRywgdXBkYXRlSW1hZ2VDYWNoZSBhcyBfdXBkYXRlSW1hZ2VDYWNoZSB9IGZyb20gXCIuLi9lbGVtZW50L2ltYWdlXCI7XG5pbXBvcnQgdGhyb3R0bGUgZnJvbSBcImxvZGFzaC50aHJvdHRsZVwiO1xuaW1wb3J0IHsgZmlsZU9wZW4gfSBmcm9tIFwiLi4vZGF0YS9maWxlc3lzdGVtXCI7XG5pbXBvcnQgeyBiaW5kVGV4dFRvU2hhcGVBZnRlckR1cGxpY2F0aW9uLCBnZXRBcHByb3hNaW5MaW5lSGVpZ2h0LCBnZXRBcHByb3hNaW5MaW5lV2lkdGgsIGdldEJvdW5kVGV4dEVsZW1lbnQsIGdldENvbnRhaW5lckNlbnRlciwgZ2V0Q29udGFpbmVyRWxlbWVudCwgZ2V0RGVmYXVsdExpbmVIZWlnaHQsIGdldExpbmVIZWlnaHRJblB4LCBnZXRUZXh0QmluZGFibGVDb250YWluZXJBdFBvc2l0aW9uLCBpc01lYXN1cmVUZXh0U3VwcG9ydGVkLCBpc1ZhbGlkVGV4dENvbnRhaW5lciB9IGZyb20gXCIuLi9lbGVtZW50L3RleHRFbGVtZW50XCI7XG5pbXBvcnQgeyBpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveCB9IGZyb20gXCIuLi9lbGVtZW50L2NvbGxpc2lvblwiO1xuaW1wb3J0IHsgc2hvd0h5cGVybGlua1Rvb2x0aXAsIGhpZGVIeXBlcmxpbmtUb29saXAsIEh5cGVybGluaywgaXNQb2ludEhpdHRpbmdMaW5rLCBpc1BvaW50SGl0dGluZ0xpbmtJY29uIH0gZnJvbSBcIi4uL2VsZW1lbnQvSHlwZXJsaW5rXCI7XG5pbXBvcnQgeyBpc0xvY2FsTGluaywgbm9ybWFsaXplTGluaywgdG9WYWxpZFVSTCB9IGZyb20gXCIuLi9kYXRhL3VybFwiO1xuaW1wb3J0IHsgc2hvdWxkU2hvd0JvdW5kaW5nQm94IH0gZnJvbSBcIi4uL2VsZW1lbnQvdHJhbnNmb3JtSGFuZGxlc1wiO1xuaW1wb3J0IHsgYWN0aW9uVW5sb2NrQWxsRWxlbWVudHMgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25FbGVtZW50TG9ja1wiO1xuaW1wb3J0IHsgRm9udHMgfSBmcm9tIFwiLi4vc2NlbmUvRm9udHNcIjtcbmltcG9ydCB7IGdldEZyYW1lRWxlbWVudHMsIGlzQ3Vyc29ySW5GcmFtZSwgYmluZEVsZW1lbnRzVG9GcmFtZXNBZnRlckR1cGxpY2F0aW9uLCBhZGRFbGVtZW50c1RvRnJhbWUsIHJlcGxhY2VBbGxFbGVtZW50c0luRnJhbWUsIHJlbW92ZUVsZW1lbnRzRnJvbUZyYW1lLCBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSwgZ2V0RWxlbWVudHNJbk5ld0ZyYW1lLCBnZXRDb250YWluaW5nRnJhbWUsIGVsZW1lbnRPdmVybGFwc1dpdGhGcmFtZSwgdXBkYXRlRnJhbWVNZW1iZXJzaGlwT2ZTZWxlY3RlZEVsZW1lbnRzLCBpc0VsZW1lbnRJbkZyYW1lIH0gZnJvbSBcIi4uL2ZyYW1lXCI7XG5pbXBvcnQgeyBleGNsdWRlRWxlbWVudHNJbkZyYW1lc0Zyb21TZWxlY3Rpb24sIG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzIH0gZnJvbSBcIi4uL3NjZW5lL3NlbGVjdGlvblwiO1xuaW1wb3J0IHsgYWN0aW9uUGFzdGUgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25DbGlwYm9hcmRcIjtcbmltcG9ydCB7IGFjdGlvblJlbW92ZUFsbEVsZW1lbnRzRnJvbUZyYW1lLCBhY3Rpb25TZWxlY3RBbGxFbGVtZW50c0luRnJhbWUgfSBmcm9tIFwiLi4vYWN0aW9ucy9hY3Rpb25GcmFtZVwiO1xuaW1wb3J0IHsgYWN0aW9uVG9nZ2xlSGFuZFRvb2wsIHpvb21Ub0ZpdCB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkNhbnZhc1wiO1xuaW1wb3J0IHsgam90YWlTdG9yZSB9IGZyb20gXCIuLi9qb3RhaVwiO1xuaW1wb3J0IHsgYWN0aXZlQ29uZmlybURpYWxvZ0F0b20gfSBmcm9tIFwiLi9BY3RpdmVDb25maXJtRGlhbG9nXCI7XG5pbXBvcnQgeyBnZXRTbmFwTGluZXNBdFBvaW50ZXIsIHNuYXBEcmFnZ2VkRWxlbWVudHMsIGlzQWN0aXZlVG9vbE5vbkxpbmVhclNuYXBwYWJsZSwgc25hcE5ld0VsZW1lbnQsIHNuYXBSZXNpemluZ0VsZW1lbnRzLCBpc1NuYXBwaW5nRW5hYmxlZCwgZ2V0VmlzaWJsZUdhcHMsIGdldFJlZmVyZW5jZVNuYXBQb2ludHMsIFNuYXBDYWNoZSB9IGZyb20gXCIuLi9zbmFwcGluZ1wiO1xuaW1wb3J0IHsgYWN0aW9uV3JhcFRleHRJbkNvbnRhaW5lciB9IGZyb20gXCIuLi9hY3Rpb25zL2FjdGlvbkJvdW5kVGV4dFwiO1xuaW1wb3J0IEJyYXZlTWVhc3VyZVRleHRFcnJvciBmcm9tIFwiLi9CcmF2ZU1lYXN1cmVUZXh0RXJyb3JcIjtcbmltcG9ydCB7IGFjdGl2ZUV5ZURyb3BwZXJBdG9tIH0gZnJvbSBcIi4vRXllRHJvcHBlclwiO1xuaW1wb3J0IHsgY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzIH0gZnJvbSBcIi4uL2RhdGEvdHJhbnNmb3JtXCI7XG5pbXBvcnQgeyBpc1NpZGViYXJEb2NrZWRBdG9tIH0gZnJvbSBcIi4vU2lkZWJhci9TaWRlYmFyXCI7XG5pbXBvcnQgeyBTdGF0aWNDYW52YXMsIEludGVyYWN0aXZlQ2FudmFzIH0gZnJvbSBcIi4vY2FudmFzZXNcIjtcbmltcG9ydCB7IFJlbmRlcmVyIH0gZnJvbSBcIi4uL3NjZW5lL1JlbmRlcmVyXCI7XG5pbXBvcnQgeyBTaGFwZUNhY2hlIH0gZnJvbSBcIi4uL3NjZW5lL1NoYXBlQ2FjaGVcIjtcbmltcG9ydCBNZXJtYWlkVG9FeGNhbGlkcmF3IGZyb20gXCIuL01lcm1haWRUb0V4Y2FsaWRyYXdcIjtcbmltcG9ydCB7IExhc2VyVG9vbE92ZXJsYXkgfSBmcm9tIFwiLi9MYXNlclRvb2wvTGFzZXJUb29sXCI7XG5pbXBvcnQgeyBMYXNlclBhdGhNYW5hZ2VyIH0gZnJvbSBcIi4vTGFzZXJUb29sL0xhc2VyUGF0aE1hbmFnZXJcIjtcbmltcG9ydCB7IHNldEVyYXNlckN1cnNvciwgc2V0Q3Vyc29yLCByZXNldEN1cnNvciwgc2V0Q3Vyc29yRm9yU2hhcGUgfSBmcm9tIFwiLi4vY3Vyc29yXCI7XG5pbXBvcnQgeyBFbWl0dGVyIH0gZnJvbSBcIi4uL2VtaXR0ZXJcIjtcbmNvbnN0IEFwcENvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0KG51bGwpO1xuY29uc3QgQXBwUHJvcHNDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChudWxsKTtcbmNvbnN0IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWUgPSB7XG4gIHZpZXdwb3J0OiB7XG4gICAgaXNNb2JpbGU6IGZhbHNlLFxuICAgIGlzTGFuZHNjYXBlOiBmYWxzZVxuICB9LFxuICBlZGl0b3I6IHtcbiAgICBpc01vYmlsZTogZmFsc2UsXG4gICAgY2FuRml0U2lkZWJhcjogZmFsc2VcbiAgfSxcbiAgaXNUb3VjaFNjcmVlbjogZmFsc2Vcbn07XG5jb25zdCBEZXZpY2VDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChkZXZpY2VDb250ZXh0SW5pdGlhbFZhbHVlKTtcbkRldmljZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkRldmljZUNvbnRleHRcIjtcbmV4cG9ydCBjb25zdCBFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoe1xuICBjb250YWluZXI6IG51bGwsXG4gIGlkOiBudWxsXG59KTtcbkV4Y2FsaWRyYXdDb250YWluZXJDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoW10pO1xuRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dC5kaXNwbGF5TmFtZSA9IFwiRXhjYWxpZHJhd0VsZW1lbnRzQ29udGV4dFwiO1xuY29uc3QgRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXREZWZhdWx0QXBwU3RhdGUoKSksIHtcbiAgd2lkdGg6IDAsXG4gIGhlaWdodDogMCxcbiAgb2Zmc2V0TGVmdDogMCxcbiAgb2Zmc2V0VG9wOiAwXG59KSk7XG5FeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3QXBwU3RhdGVDb250ZXh0XCI7XG5jb25zdCBFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dCgoKSA9PiB7XG4gIGNvbnNvbGUud2FybihcInVuaXRpYWxpemVkIEV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQgY29udGV4dCFcIik7XG59KTtcbkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdTZXRBcHBTdGF0ZUNvbnRleHRcIjtcbmNvbnN0IEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQobnVsbCk7XG5FeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dFwiO1xuZXhwb3J0IGNvbnN0IHVzZUFwcCA9ICgpID0+IHVzZUNvbnRleHQoQXBwQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlQXBwUHJvcHMgPSAoKSA9PiB1c2VDb250ZXh0KEFwcFByb3BzQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRGV2aWNlID0gKCkgPT4gdXNlQ29udGV4dChEZXZpY2VDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3Q29udGFpbmVyID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3Q29udGFpbmVyQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0VsZW1lbnRzID0gKCkgPT4gdXNlQ29udGV4dChFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0KTtcbmV4cG9ydCBjb25zdCB1c2VFeGNhbGlkcmF3QXBwU3RhdGUgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBcHBTdGF0ZUNvbnRleHQpO1xuZXhwb3J0IGNvbnN0IHVzZUV4Y2FsaWRyYXdTZXRBcHBTdGF0ZSA9ICgpID0+IHVzZUNvbnRleHQoRXhjYWxpZHJhd1NldEFwcFN0YXRlQ29udGV4dCk7XG5leHBvcnQgY29uc3QgdXNlRXhjYWxpZHJhd0FjdGlvbk1hbmFnZXIgPSAoKSA9PiB1c2VDb250ZXh0KEV4Y2FsaWRyYXdBY3Rpb25NYW5hZ2VyQ29udGV4dCk7XG5jb25zdCBzdXBwb3J0c1Jlc2l6ZU9ic2VydmVyID0gdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiAmJiBcIlJlc2l6ZU9ic2VydmVyXCIgaW4gd2luZG93O1xubGV0IGRpZFRhcFR3aWNlID0gZmFsc2U7XG5sZXQgdGFwcGVkVHdpY2VUaW1lciA9IDA7XG5sZXQgaXNIb2xkaW5nU3BhY2UgPSBmYWxzZTtcbmxldCBpc1Bhbm5pbmcgPSBmYWxzZTtcbmxldCBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gZmFsc2U7XG5sZXQgY3VycmVudFNjcm9sbEJhcnMgPSB7XG4gIGhvcml6b250YWw6IG51bGwsXG4gIHZlcnRpY2FsOiBudWxsXG59O1xubGV0IHRvdWNoVGltZW91dCA9IDA7XG5sZXQgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG4vKipcbiAqIE1hcCBvZiB5b3V0dWJlIGVtYmVkIHZpZGVvIHN0YXRlc1xuICovXG5cbmNvbnN0IFlPVVRVQkVfVklERU9fU1RBVEVTID0gbmV3IE1hcCgpO1xubGV0IElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG5sZXQgSVNfUExBSU5fUEFTVEVfVElNRVIgPSAwO1xubGV0IFBMQUlOX1BBU1RFX1RPQVNUX1NIT1dOID0gZmFsc2U7XG5sZXQgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG5jb25zdCBnZXN0dXJlID0ge1xuICBwb2ludGVyczogbmV3IE1hcCgpLFxuICBsYXN0Q2VudGVyOiBudWxsLFxuICBpbml0aWFsRGlzdGFuY2U6IG51bGwsXG4gIGluaXRpYWxTY2FsZTogbnVsbFxufTtcblxuY2xhc3MgQXBwIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICB2YXIgX2E7XG5cbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyA9IG51bGw7XG4gICAgdGhpcy51bm1vdW50ZWQgPSBmYWxzZTtcbiAgICB0aGlzLmRldmljZSA9IGRldmljZUNvbnRleHRJbml0aWFsVmFsdWU7XG4gICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmID0gUmVhY3QuY3JlYXRlUmVmKCk7XG4gICAgdGhpcy5maWxlcyA9IHt9O1xuICAgIHRoaXMuaW1hZ2VDYWNoZSA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmlGcmFtZVJlZnMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCA9IG51bGw7XG4gICAgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQgPSBudWxsO1xuICAgIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24gPSB7XG4gICAgICB4OiAwLFxuICAgICAgeTogMFxuICAgIH07XG4gICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyID0gbmV3IExhc2VyUGF0aE1hbmFnZXIodGhpcyk7XG4gICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyRG93bkVtaXR0ZXIgPSBuZXcgRW1pdHRlcigpO1xuICAgIHRoaXMub25Qb2ludGVyVXBFbWl0dGVyID0gbmV3IEVtaXR0ZXIoKTtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBlbWJlZGRhYmxlRWxlbWVudHMgPSBuZXcgTWFwKCk7XG4gICAgICBsZXQgdXBkYXRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgZW1iZWRkYWJsZUVsZW1lbnRzLnNldChlbGVtZW50LmlkLCB0cnVlKTtcblxuICAgICAgICAgIGlmIChlbGVtZW50LnZhbGlkYXRlZCA9PSBudWxsKSB7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlZCA9IGVtYmVkZGFibGVVUkxWYWxpZGF0b3IoZWxlbWVudC5saW5rLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSk7XG4gICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgdmFsaWRhdGVkXG4gICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICBTaGFwZUNhY2hlLmRlbGV0ZShlbGVtZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWQpIHtcbiAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgfSAvLyBHQ1xuXG5cbiAgICAgIHRoaXMuaUZyYW1lUmVmcy5mb3JFYWNoKChyZWYsIGlkKSA9PiB7XG4gICAgICAgIGlmICghZW1iZWRkYWJsZUVsZW1lbnRzLmhhcyhpZCkpIHtcbiAgICAgICAgICB0aGlzLmlGcmFtZVJlZnMuZGVsZXRlKGlkKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQgPSBmcmFtZUVsZW1lbnQgPT4ge1xuICAgICAgcmV0dXJuIGAke3RoaXMuaWR9LWZyYW1lLW5hbWUtJHtmcmFtZUVsZW1lbnQuaWR9YDtcbiAgICB9O1xuXG4gICAgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSA9IHtcbiAgICAgIGdldDogZnJhbWVFbGVtZW50ID0+IHtcbiAgICAgICAgbGV0IGJvdW5kcyA9IHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLmdldChmcmFtZUVsZW1lbnQuaWQpO1xuXG4gICAgICAgIGlmICghYm91bmRzIHx8IGJvdW5kcy56b29tICE9PSB0aGlzLnN0YXRlLnpvb20udmFsdWUgfHwgYm91bmRzLnZlcnNpb25Ob25jZSAhPT0gZnJhbWVFbGVtZW50LnZlcnNpb25Ob25jZSkge1xuICAgICAgICAgIGNvbnN0IGZyYW1lTmFtZURpdiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMuZ2V0RnJhbWVOYW1lRE9NSWQoZnJhbWVFbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoZnJhbWVOYW1lRGl2KSB7XG4gICAgICAgICAgICBjb25zdCBib3ggPSBmcmFtZU5hbWVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBjb25zdCBib3hTY2VuZVRvcExlZnQgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgICBjbGllbnRYOiBib3gueCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LnlcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICAgICAgY29uc3QgYm94U2NlbmVCb3R0b21SaWdodCA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgICAgICAgIGNsaWVudFg6IGJveC5yaWdodCxcbiAgICAgICAgICAgICAgY2xpZW50WTogYm94LmJvdHRvbVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBib3VuZHMgPSB7XG4gICAgICAgICAgICAgIHg6IGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICB5OiBib3hTY2VuZVRvcExlZnQueSxcbiAgICAgICAgICAgICAgd2lkdGg6IGJveFNjZW5lQm90dG9tUmlnaHQueCAtIGJveFNjZW5lVG9wTGVmdC54LFxuICAgICAgICAgICAgICBoZWlnaHQ6IGJveFNjZW5lQm90dG9tUmlnaHQueSAtIGJveFNjZW5lVG9wTGVmdC55LFxuICAgICAgICAgICAgICBhbmdsZTogMCxcbiAgICAgICAgICAgICAgem9vbTogdGhpcy5zdGF0ZS56b29tLnZhbHVlLFxuICAgICAgICAgICAgICB2ZXJzaW9uTm9uY2U6IGZyYW1lRWxlbWVudC52ZXJzaW9uTm9uY2VcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUuX2NhY2hlLnNldChmcmFtZUVsZW1lbnQuaWQsIGJvdW5kcyk7XG5cbiAgICAgICAgICAgIHJldHVybiBib3VuZHM7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYm91bmRzO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBAcHJpdmF0ZVxuICAgICAgICovXG4gICAgICBfY2FjaGU6IG5ldyBNYXAoKVxuICAgIH07XG5cbiAgICB0aGlzLnJlbmRlckZyYW1lTmFtZXMgPSAoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCB8fCAhdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5uYW1lKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc0RhcmtUaGVtZSA9IHRoaXMuc3RhdGUudGhlbWUgPT09IFwiZGFya1wiO1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEZyYW1lcygpLm1hcCgoZiwgaW5kZXgpID0+IHtcbiAgICAgICAgaWYgKCFpc0VsZW1lbnRJblZpZXdwb3J0KGYsIHRoaXMuY2FudmFzLndpZHRoIC8gd2luZG93LmRldmljZVBpeGVsUmF0aW8sIHRoaXMuY2FudmFzLmhlaWdodCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLCB7XG4gICAgICAgICAgb2Zmc2V0TGVmdDogdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LFxuICAgICAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFk6IHRoaXMuc3RhdGUuc2Nyb2xsWSxcbiAgICAgICAgICB6b29tOiB0aGlzLnN0YXRlLnpvb21cbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAvLyBpZiBmcmFtZSBub3QgdmlzaWJsZSwgZG9uJ3QgcmVuZGVyIGl0cyBuYW1lXG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogeDEsXG4gICAgICAgICAgeTogeTFcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBmLngsXG4gICAgICAgICAgc2NlbmVZOiBmLnlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB4MlxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IGYueCArIGYud2lkdGgsXG4gICAgICAgICAgc2NlbmVZOiBmLnkgKyBmLmhlaWdodFxuICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9HQVAgPSAyMDtcbiAgICAgICAgY29uc3QgRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgPSA2O1xuXG4gICAgICAgIGNvbnN0IHJlc2V0ID0gKCkgPT4ge1xuICAgICAgICAgIHZhciBfYTtcblxuICAgICAgICAgIGlmICgoKF9hID0gZi5uYW1lKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudHJpbSgpKSA9PT0gXCJcIikge1xuICAgICAgICAgICAgbXV0YXRlRWxlbWVudChmLCB7XG4gICAgICAgICAgICAgIG5hbWU6IG51bGxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZWRpdGluZ0ZyYW1lOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbGV0IGZyYW1lTmFtZUpTWDtcblxuICAgICAgICBpZiAoZi5pZCA9PT0gdGhpcy5zdGF0ZS5lZGl0aW5nRnJhbWUpIHtcbiAgICAgICAgICBjb25zdCBmcmFtZU5hbWVJbkVkaXQgPSBmLm5hbWUgPT0gbnVsbCA/IGBGcmFtZSAke2luZGV4ICsgMX1gIDogZi5uYW1lO1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IF9qc3goXCJpbnB1dFwiLCB7XG4gICAgICAgICAgICBhdXRvRm9jdXM6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogZnJhbWVOYW1lSW5FZGl0LFxuICAgICAgICAgICAgb25DaGFuZ2U6IGUgPT4ge1xuICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGYsIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBlLnRhcmdldC52YWx1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkJsdXI6ICgpID0+IHJlc2V0KCksXG4gICAgICAgICAgICBvbktleURvd246IGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgLy8gZm9yIHNvbWUgaW5leHBsaWNhYmxlIHJlYXNvbiwgYG9uQmx1cmAgdHJpZ2dlcmVkIG9uIEVTQ1xuICAgICAgICAgICAgICAvLyBkb2VzIG5vdCByZXNldCBgc3RhdGUuZWRpdGluZ0ZyYW1lYCBkZXNwaXRlIGJlaW5nIGNhbGxlZCxcbiAgICAgICAgICAgICAgLy8gYW5kIHdlIG5lZWQgdG8gcmVzZXQgaXQgaGVyZSBhcyB3ZWxsXG4gICAgICAgICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuRVNDQVBFIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5FTlRFUikge1xuICAgICAgICAgICAgICAgIHJlc2V0KCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLnZpZXdCYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgICAgIGZpbHRlcjogaXNEYXJrVGhlbWUgPyBUSEVNRV9GSUxURVIgOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgekluZGV4OiAyLFxuICAgICAgICAgICAgICBib3JkZXI6IFwibm9uZVwiLFxuICAgICAgICAgICAgICBkaXNwbGF5OiBcImJsb2NrXCIsXG4gICAgICAgICAgICAgIHBhZGRpbmc6IGAke0ZSQU1FX05BTUVfRURJVF9QQURESU5HfXB4YCxcbiAgICAgICAgICAgICAgYm9yZGVyUmFkaXVzOiA0LFxuICAgICAgICAgICAgICBib3hTaGFkb3c6IFwiaW5zZXQgMCAwIDAgMXB4IHZhcigtLWNvbG9yLXByaW1hcnkpXCIsXG4gICAgICAgICAgICAgIGZvbnRGYW1pbHk6IFwiQXNzaXN0YW50XCIsXG4gICAgICAgICAgICAgIGZvbnRTaXplOiBcIjE0cHhcIixcbiAgICAgICAgICAgICAgdHJhbnNmb3JtOiBgdHJhbnNsYXRlWSgtJHtGUkFNRV9OQU1FX0VESVRfUEFERElOR31weClgLFxuICAgICAgICAgICAgICBjb2xvcjogXCJ2YXIoLS1jb2xvci1ncmF5LTgwKVwiLFxuICAgICAgICAgICAgICBvdmVyZmxvdzogXCJoaWRkZW5cIixcbiAgICAgICAgICAgICAgbWF4V2lkdGg6IGAke01hdGgubWluKHgyIC0geDEgLSBGUkFNRV9OQU1FX0VESVRfUEFERElORywgZG9jdW1lbnQuYm9keS5jbGllbnRXaWR0aCAtIHgxIC0gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcpfXB4YFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNpemU6IGZyYW1lTmFtZUluRWRpdC5sZW5ndGggKyAxIHx8IDEsXG4gICAgICAgICAgICBkaXI6IFwiYXV0b1wiLFxuICAgICAgICAgICAgYXV0b0NvbXBsZXRlOiBcIm9mZlwiLFxuICAgICAgICAgICAgYXV0b0NhcGl0YWxpemU6IFwib2ZmXCIsXG4gICAgICAgICAgICBhdXRvQ29ycmVjdDogXCJvZmZcIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZyYW1lTmFtZUpTWCA9IGYubmFtZSA9PSBudWxsIHx8IGYubmFtZS50cmltKCkgPT09IFwiXCIgPyBgRnJhbWUgJHtpbmRleCArIDF9YCA6IGYubmFtZS50cmltKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBpZDogdGhpcy5nZXRGcmFtZU5hbWVET01JZChmKSxcbiAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgcG9zaXRpb246IFwiYWJzb2x1dGVcIixcbiAgICAgICAgICAgIHRvcDogYCR7eTEgLSBGUkFNRV9OQU1FX0dBUCAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wfXB4YCxcbiAgICAgICAgICAgIGxlZnQ6IGAke3gxIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0IC0gKHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID09PSBmLmlkID8gRlJBTUVfTkFNRV9FRElUX1BBRERJTkcgOiAwKX1weGAsXG4gICAgICAgICAgICB6SW5kZXg6IDIsXG4gICAgICAgICAgICBmb250U2l6ZTogXCIxNHB4XCIsXG4gICAgICAgICAgICBjb2xvcjogaXNEYXJrVGhlbWUgPyBcInZhcigtLWNvbG9yLWdyYXktNjApXCIgOiBcInZhcigtLWNvbG9yLWdyYXktNTApXCIsXG4gICAgICAgICAgICB3aWR0aDogXCJtYXgtY29udGVudFwiLFxuICAgICAgICAgICAgbWF4V2lkdGg6IGAke3gyIC0geDEgKyBGUkFNRV9OQU1FX0VESVRfUEFERElORyAqIDJ9cHhgLFxuICAgICAgICAgICAgb3ZlcmZsb3c6IGYuaWQgPT09IHRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lID8gXCJ2aXNpYmxlXCIgOiBcImhpZGRlblwiLFxuICAgICAgICAgICAgd2hpdGVTcGFjZTogXCJub3dyYXBcIixcbiAgICAgICAgICAgIHRleHRPdmVyZmxvdzogXCJlbGxpcHNpc1wiLFxuICAgICAgICAgICAgY3Vyc29yOiBDVVJTT1JfVFlQRS5NT1ZFLFxuICAgICAgICAgICAgcG9pbnRlckV2ZW50czogdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQgPyBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZCA6IFBPSU5URVJfRVZFTlRTLmVuYWJsZWRcbiAgICAgICAgICB9LFxuICAgICAgICAgIG9uUG9pbnRlckRvd246IGV2ZW50ID0+IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24oZXZlbnQpLFxuICAgICAgICAgIG9uV2hlZWw6IGV2ZW50ID0+IHRoaXMuaGFuZGxlV2hlZWwoZXZlbnQpLFxuICAgICAgICAgIG9uQ29udGV4dE1lbnU6IHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUsXG4gICAgICAgICAgb25Eb3VibGVDbGljazogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogZi5pZFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IGZyYW1lTmFtZUpTWFxuICAgICAgICB9KSwgZi5pZCk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5mb2N1c0NvbnRhaW5lciA9ICgpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5mb2N1cygpO1xuICAgIH07XG5cbiAgICB0aGlzLmdldFNjZW5lRWxlbWVudHNJbmNsdWRpbmdEZWxldGVkID0gKCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZ2V0U2NlbmVFbGVtZW50cyA9ICgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgIH07XG5cbiAgICB0aGlzLm9uSW5zZXJ0RWxlbWVudHMgPSBlbGVtZW50cyA9PiB7XG4gICAgICB0aGlzLmFkZEVsZW1lbnRzRnJvbVBhc3RlT3JMaWJyYXJ5KHtcbiAgICAgICAgZWxlbWVudHMsXG4gICAgICAgIHBvc2l0aW9uOiBcImNlbnRlclwiLFxuICAgICAgICBmaWxlczogbnVsbFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMub25FeHBvcnRJbWFnZSA9ICh0eXBlLCBlbGVtZW50cykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgdHJhY2tFdmVudChcImV4cG9ydFwiLCB0eXBlLCBcInVpXCIpO1xuICAgICAgY29uc3QgZmlsZUhhbmRsZSA9IHlpZWxkIGV4cG9ydENhbnZhcyh0eXBlLCBlbGVtZW50cywgdGhpcy5zdGF0ZSwgdGhpcy5maWxlcywge1xuICAgICAgICBleHBvcnRCYWNrZ3JvdW5kOiB0aGlzLnN0YXRlLmV4cG9ydEJhY2tncm91bmQsXG4gICAgICAgIG5hbWU6IHRoaXMuc3RhdGUubmFtZSxcbiAgICAgICAgdmlld0JhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS52aWV3QmFja2dyb3VuZENvbG9yXG4gICAgICB9KS5jYXRjaChtdXRlRlNBYm9ydEVycm9yKS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZXhwb3J0RW1iZWRTY2VuZSAmJiBmaWxlSGFuZGxlICYmIGlzSW1hZ2VGaWxlSGFuZGxlKGZpbGVIYW5kbGUpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGZpbGVIYW5kbGVcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLm9wZW5FeWVEcm9wcGVyID0gKHtcbiAgICAgIHR5cGVcbiAgICB9KSA9PiB7XG4gICAgICBqb3RhaVN0b3JlLnNldChhY3RpdmVFeWVEcm9wcGVyQXRvbSwge1xuICAgICAgICBzd2FwUHJldmlld09uQWx0OiB0cnVlLFxuICAgICAgICBjb2xvclBpY2tlclR5cGU6IHR5cGUgPT09IFwic3Ryb2tlXCIgPyBcImVsZW1lbnRTdHJva2VcIiA6IFwiZWxlbWVudEJhY2tncm91bmRcIixcbiAgICAgICAgb25TZWxlY3Q6IChjb2xvciwgZXZlbnQpID0+IHtcbiAgICAgICAgICBjb25zdCBzaG91bGRVcGRhdGVTdHJva2VDb2xvciA9IHR5cGUgPT09IFwiYmFja2dyb3VuZFwiICYmIGV2ZW50LmFsdEtleSB8fCB0eXBlID09PSBcInN0cm9rZVwiICYmICFldmVudC5hbHRLZXk7XG4gICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICAgIGlmICghc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICAgIGlmIChzaG91bGRVcGRhdGVTdHJva2VDb2xvcikge1xuICAgICAgICAgICAgICB0aGlzLnN5bmNBY3Rpb25SZXN1bHQoe1xuICAgICAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgICBjdXJyZW50SXRlbVN0cm9rZUNvbG9yOiBjb2xvclxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCh7XG4gICAgICAgICAgICAgICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZSksIHtcbiAgICAgICAgICAgICAgICAgIGN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yOiBjb2xvclxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVTY2VuZSh7XG4gICAgICAgICAgICAgIGVsZW1lbnRzOiB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbCA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2VsLmlkXSkge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsLCB7XG4gICAgICAgICAgICAgICAgICAgIFtzaG91bGRVcGRhdGVTdHJva2VDb2xvciA/IFwic3Ryb2tlQ29sb3JcIiA6IFwiYmFja2dyb3VuZENvbG9yXCJdOiBjb2xvclxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGVsO1xuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBrZWVwT3Blbk9uQWx0OiBmYWxzZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhhY3Rpb25SZXN1bHQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2YsIF9nLCBfaCwgX2o7XG5cbiAgICAgIGlmICh0aGlzLnVubW91bnRlZCB8fCBhY3Rpb25SZXN1bHQgPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgbGV0IGVkaXRpbmdFbGVtZW50ID0gbnVsbDtcblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5lbGVtZW50cykge1xuICAgICAgICBhY3Rpb25SZXN1bHQuZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICB2YXIgX2E7XG5cbiAgICAgICAgICBpZiAoKChfYSA9IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pZCkgPT09IGVsZW1lbnQuaWQgJiYgdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCAhPT0gZWxlbWVudCAmJiBpc05vbkRlbGV0ZWRFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoYWN0aW9uUmVzdWx0LmVsZW1lbnRzKTtcblxuICAgICAgICBpZiAoYWN0aW9uUmVzdWx0LmNvbW1pdFRvSGlzdG9yeSkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aW9uUmVzdWx0LmZpbGVzKSB7XG4gICAgICAgIHRoaXMuZmlsZXMgPSBhY3Rpb25SZXN1bHQucmVwbGFjZUZpbGVzID8gYWN0aW9uUmVzdWx0LmZpbGVzIDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgYWN0aW9uUmVzdWx0LmZpbGVzKTtcbiAgICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGlvblJlc3VsdC5hcHBTdGF0ZSB8fCBlZGl0aW5nRWxlbWVudCB8fCB0aGlzLnN0YXRlLmNvbnRleHRNZW51KSB7XG4gICAgICAgIGlmIChhY3Rpb25SZXN1bHQuY29tbWl0VG9IaXN0b3J5KSB7XG4gICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHZpZXdNb2RlRW5hYmxlZCA9ICgoX2EgPSBhY3Rpb25SZXN1bHQgPT09IG51bGwgfHwgYWN0aW9uUmVzdWx0ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS52aWV3TW9kZUVuYWJsZWQpIHx8IGZhbHNlO1xuICAgICAgICBsZXQgemVuTW9kZUVuYWJsZWQgPSAoKF9iID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuemVuTW9kZUVuYWJsZWQpIHx8IGZhbHNlO1xuICAgICAgICBsZXQgZ3JpZFNpemUgPSAoKF9jID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MuZ3JpZFNpemUpIHx8IG51bGw7XG4gICAgICAgIGNvbnN0IHRoZW1lID0gKChfZCA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnRoZW1lKSB8fCB0aGlzLnByb3BzLnRoZW1lIHx8IFRIRU1FLkxJR0hUO1xuICAgICAgICBsZXQgbmFtZSA9IChfZiA9IChfZSA9IGFjdGlvblJlc3VsdCA9PT0gbnVsbCB8fCBhY3Rpb25SZXN1bHQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFjdGlvblJlc3VsdC5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLm5hbWUpICE9PSBudWxsICYmIF9mICE9PSB2b2lkIDAgPyBfZiA6IHRoaXMuc3RhdGUubmFtZTtcbiAgICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gKF9oID0gKF9nID0gYWN0aW9uUmVzdWx0ID09PSBudWxsIHx8IGFjdGlvblJlc3VsdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogYWN0aW9uUmVzdWx0LmFwcFN0YXRlKSA9PT0gbnVsbCB8fCBfZyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2cuZXJyb3JNZXNzYWdlKSAhPT0gbnVsbCAmJiBfaCAhPT0gdm9pZCAwID8gX2ggOiB0aGlzLnN0YXRlLmVycm9yTWVzc2FnZTtcblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMudmlld01vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgdmlld01vZGVFbmFibGVkID0gdGhpcy5wcm9wcy52aWV3TW9kZUVuYWJsZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICB6ZW5Nb2RlRW5hYmxlZCA9IHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgZ3JpZFNpemUgPSB0aGlzLnByb3BzLmdyaWRNb2RlRW5hYmxlZCA/IEdSSURfU0laRSA6IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMubmFtZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIG5hbWUgPSB0aGlzLnByb3BzLm5hbWU7XG4gICAgICAgIH1cblxuICAgICAgICBlZGl0aW5nRWxlbWVudCA9IGVkaXRpbmdFbGVtZW50IHx8ICgoX2ogPSBhY3Rpb25SZXN1bHQuYXBwU3RhdGUpID09PSBudWxsIHx8IF9qID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfai5lZGl0aW5nRWxlbWVudCkgfHwgbnVsbDtcblxuICAgICAgICBpZiAoZWRpdGluZ0VsZW1lbnQgPT09IG51bGwgfHwgZWRpdGluZ0VsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVkaXRpbmdFbGVtZW50LmlzRGVsZXRlZCkge1xuICAgICAgICAgIGVkaXRpbmdFbGVtZW50ID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIC8vIHVzaW5nIE9iamVjdC5hc3NpZ24gaW5zdGVhZCBvZiBzcHJlYWQgdG8gZm9vbCBUUyA0LjIuMisgaW50b1xuICAgICAgICAgIC8vIHJlZ2FyZGluZyB0aGUgcmVzdWx0aW5nIHR5cGUgYXMgbm90IGNvbnRhaW5pbmcgdW5kZWZpbmVkXG4gICAgICAgICAgLy8gKHdoaWNoIHRoZSBmb2xsb3dpbmcgZXhwcmVzc2lvbiB3aWxsIG5ldmVyIGNvbnRhaW4pXG4gICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oYWN0aW9uUmVzdWx0LmFwcFN0YXRlIHx8IHt9LCB7XG4gICAgICAgICAgICAvLyBOT1RFIHRoaXMgd2lsbCBwcmV2ZW50IG9wZW5pbmcgY29udGV4dCBtZW51IHVzaW5nIGFuIGFjdGlvblxuICAgICAgICAgICAgLy8gb3IgcHJvZ3JhbW1hdGljYWxseSBmcm9tIHRoZSBob3N0LCBzbyBpdCB3aWxsIG5lZWQgdG8gYmVcbiAgICAgICAgICAgIC8vIHJld3JpdHRlbiBsYXRlclxuICAgICAgICAgICAgY29udGV4dE1lbnU6IG51bGwsXG4gICAgICAgICAgICBlZGl0aW5nRWxlbWVudCxcbiAgICAgICAgICAgIHZpZXdNb2RlRW5hYmxlZCxcbiAgICAgICAgICAgIHplbk1vZGVFbmFibGVkLFxuICAgICAgICAgICAgZ3JpZFNpemUsXG4gICAgICAgICAgICB0aGVtZSxcbiAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2VcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIGlmIChhY3Rpb25SZXN1bHQuc3luY0hpc3RvcnkpIHtcbiAgICAgICAgICAgIHRoaXMuaGlzdG9yeS5zZXRDdXJyZW50U3RhdGUodGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTsgLy8gTGlmZWN5Y2xlXG5cbiAgICB0aGlzLm9uQmx1ciA9IHdpdGhCYXRjaGVkVXBkYXRlcygoKSA9PiB7XG4gICAgICBpc0hvbGRpbmdTcGFjZSA9IGZhbHNlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQ6IHRydWVcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGhpcy5vblVubG9hZCA9ICgpID0+IHtcbiAgICAgIHRoaXMub25CbHVyKCk7XG4gICAgfTtcblxuICAgIHRoaXMuZGlzYWJsZUV2ZW50ID0gZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZXNldEhpc3RvcnkgPSAoKSA9PiB7XG4gICAgICB0aGlzLmhpc3RvcnkuY2xlYXIoKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJlc2V0cyBzY2VuZSAmIGhpc3RvcnkuXG4gICAgICogISBEbyBub3QgdXNlIHRvIGNsZWFyIHNjZW5lIHVzZXIgYWN0aW9uICFcbiAgICAgKi9cblxuXG4gICAgdGhpcy5yZXNldFNjZW5lID0gd2l0aEJhdGNoZWRVcGRhdGVzKG9wdHMgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIGdldERlZmF1bHRBcHBTdGF0ZSgpKSwge1xuICAgICAgICBpc0xvYWRpbmc6IChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucmVzZXRMb2FkaW5nU3RhdGUpID8gZmFsc2UgOiBzdGF0ZS5pc0xvYWRpbmcsXG4gICAgICAgIHRoZW1lOiB0aGlzLnN0YXRlLnRoZW1lXG4gICAgICB9KSk7XG4gICAgICB0aGlzLnJlc2V0SGlzdG9yeSgpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5pbml0aWFsaXplU2NlbmUgPSAoKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB2YXIgX2I7XG5cbiAgICAgIGlmIChcImxhdW5jaFF1ZXVlXCIgaW4gd2luZG93ICYmIFwiTGF1bmNoUGFyYW1zXCIgaW4gd2luZG93KSB7XG4gICAgICAgIHdpbmRvdy5sYXVuY2hRdWV1ZS5zZXRDb25zdW1lcihsYXVuY2hQYXJhbXMgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgICAgIGlmICghbGF1bmNoUGFyYW1zLmZpbGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGZpbGVIYW5kbGUgPSBsYXVuY2hQYXJhbXMuZmlsZXNbMF07XG4gICAgICAgICAgY29uc3QgYmxvYiA9IHlpZWxkIGZpbGVIYW5kbGUuZ2V0RmlsZSgpO1xuICAgICAgICAgIHRoaXMubG9hZEZpbGVUb0NhbnZhcyhuZXcgRmlsZShbYmxvYl0sIGJsb2IubmFtZSB8fCBcIlwiLCB7XG4gICAgICAgICAgICB0eXBlOiBibG9iLnR5cGVcbiAgICAgICAgICB9KSwgZmlsZUhhbmRsZSk7XG4gICAgICAgIH0pKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMucHJvcHMudGhlbWUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5pc0xvYWRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBsZXQgaW5pdGlhbERhdGEgPSBudWxsO1xuXG4gICAgICB0cnkge1xuICAgICAgICBpbml0aWFsRGF0YSA9ICh5aWVsZCB0aGlzLnByb3BzLmluaXRpYWxEYXRhKSB8fCBudWxsO1xuXG4gICAgICAgIGlmIChpbml0aWFsRGF0YSA9PT0gbnVsbCB8fCBpbml0aWFsRGF0YSA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbERhdGEubGlicmFyeUl0ZW1zKSB7XG4gICAgICAgICAgdGhpcy5saWJyYXJ5LnVwZGF0ZUxpYnJhcnkoe1xuICAgICAgICAgICAgbGlicmFyeUl0ZW1zOiBpbml0aWFsRGF0YS5saWJyYXJ5SXRlbXMsXG4gICAgICAgICAgICBtZXJnZTogdHJ1ZVxuICAgICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgaW5pdGlhbERhdGEgPSB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZSB8fCBcIkVuY291bnRlcmVkIGFuIGVycm9yIGR1cmluZyBpbXBvcnRpbmcgb3IgcmVzdG9yaW5nIHNjZW5lIGRhdGFcIlxuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2NlbmUgPSByZXN0b3JlKGluaXRpYWxEYXRhLCBudWxsLCBudWxsLCB7XG4gICAgICAgIHJlcGFpckJpbmRpbmdzOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIHNjZW5lLmFwcFN0YXRlID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzY2VuZS5hcHBTdGF0ZSksIHtcbiAgICAgICAgdGhlbWU6IHRoaXMucHJvcHMudGhlbWUgfHwgc2NlbmUuYXBwU3RhdGUudGhlbWUsXG4gICAgICAgIC8vIHdlJ3JlIGZhbGxpbmcgYmFjayB0byBjdXJyZW50IChwcmUtaW5pdCkgc3RhdGUgd2hlbiBkZWNpZGluZ1xuICAgICAgICAvLyB3aGV0aGVyIHRvIG9wZW4gdGhlIGxpYnJhcnksIHRvIGhhbmRsZSBhIGNhc2Ugd2hlcmUgd2VcbiAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZSBvdXRzaWRlIG9mIGluaXRpYWxEYXRhIChlLmcuIHdoZW4gbG9hZGluZyB0aGUgYXBwXG4gICAgICAgIC8vIHdpdGggYSBsaWJyYXJ5IGluc3RhbGwgbGluaywgd2hpY2ggc2hvdWxkIGF1dG8tb3BlbiB0aGUgbGlicmFyeSlcbiAgICAgICAgb3BlblNpZGViYXI6ICgoX2IgPSBzY2VuZS5hcHBTdGF0ZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLm9wZW5TaWRlYmFyKSB8fCB0aGlzLnN0YXRlLm9wZW5TaWRlYmFyLFxuICAgICAgICBhY3RpdmVUb29sOiBzY2VuZS5hcHBTdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiaW1hZ2VcIiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbCksIHtcbiAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgIH0pIDogc2NlbmUuYXBwU3RhdGUuYWN0aXZlVG9vbCxcbiAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgdG9hc3Q6IHRoaXMuc3RhdGUudG9hc3RcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaW5pdGlhbERhdGEgPT09IG51bGwgfHwgaW5pdGlhbERhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGluaXRpYWxEYXRhLnNjcm9sbFRvQ29udGVudCkge1xuICAgICAgICBzY2VuZS5hcHBTdGF0ZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCBjYWxjdWxhdGVTY3JvbGxDZW50ZXIoc2NlbmUuZWxlbWVudHMsIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2NlbmUuYXBwU3RhdGUpLCB7XG4gICAgICAgICAgd2lkdGg6IHRoaXMuc3RhdGUud2lkdGgsXG4gICAgICAgICAgaGVpZ2h0OiB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgICAgICBvZmZzZXRUb3A6IHRoaXMuc3RhdGUub2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnQ6IHRoaXMuc3RhdGUub2Zmc2V0TGVmdFxuICAgICAgICB9KSkpO1xuICAgICAgfSAvLyBGb250RmFjZVNldCBsb2FkaW5nZG9uZSBldmVudCB3ZSBsaXN0ZW4gb24gbWF5IG5vdCBhbHdheXMgZmlyZVxuICAgICAgLy8gKGxvb2tpbmcgYXQgeW91IFNhZmFyaSksIHNvIG9uIGluaXQgd2UgbWFudWFsbHkgbG9hZCBmb250cyBmb3IgY3VycmVudFxuICAgICAgLy8gdGV4dCBlbGVtZW50cyBvbiBjYW52YXMsIGFuZCByZXJlbmRlciB0aGVtIG9uY2UgZG9uZS4gVGhpcyBhbHNvXG4gICAgICAvLyBzZWVtcyBmYXN0ZXIgZXZlbiBpbiBicm93c2VycyB0aGF0IGRvIGZpcmUgdGhlIGxvYWRpbmdkb25lIGV2ZW50LlxuXG5cbiAgICAgIHRoaXMuZm9udHMubG9hZEZvbnRzRm9yRWxlbWVudHMoc2NlbmUuZWxlbWVudHMpO1xuICAgICAgdGhpcy5yZXNldEhpc3RvcnkoKTtcbiAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lKSwge1xuICAgICAgICBjb21taXRUb0hpc3Rvcnk6IHRydWVcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRoaXMuaXNNb2JpbGVCcmVha3BvaW50ID0gKHdpZHRoLCBoZWlnaHQpID0+IHtcbiAgICAgIHJldHVybiB3aWR0aCA8IE1RX01BWF9XSURUSF9QT1JUUkFJVCB8fCBoZWlnaHQgPCBNUV9NQVhfSEVJR0hUX0xBTkRTQ0FQRSAmJiB3aWR0aCA8IE1RX01BWF9XSURUSF9MQU5EU0NBUEU7XG4gICAgfTtcblxuICAgIHRoaXMucmVmcmVzaFZpZXdwb3J0QnJlYWtwb2ludHMgPSAoKSA9PiB7XG4gICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudDtcblxuICAgICAgaWYgKCFjb250YWluZXIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIGNsaWVudFdpZHRoOiB2aWV3cG9ydFdpZHRoLFxuICAgICAgICBjbGllbnRIZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0XG4gICAgICB9ID0gZG9jdW1lbnQuYm9keTtcbiAgICAgIGNvbnN0IHByZXZWaWV3cG9ydFN0YXRlID0gdGhpcy5kZXZpY2Uudmlld3BvcnQ7XG4gICAgICBjb25zdCBuZXh0Vmlld3BvcnRTdGF0ZSA9IHVwZGF0ZU9iamVjdChwcmV2Vmlld3BvcnRTdGF0ZSwge1xuICAgICAgICBpc0xhbmRzY2FwZTogdmlld3BvcnRXaWR0aCA+IHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgICBpc01vYmlsZTogdGhpcy5pc01vYmlsZUJyZWFrcG9pbnQodmlld3BvcnRXaWR0aCwgdmlld3BvcnRIZWlnaHQpXG4gICAgICB9KTtcblxuICAgICAgaWYgKHByZXZWaWV3cG9ydFN0YXRlICE9PSBuZXh0Vmlld3BvcnRTdGF0ZSkge1xuICAgICAgICB0aGlzLmRldmljZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5kZXZpY2UpLCB7XG4gICAgICAgICAgdmlld3BvcnQ6IG5leHRWaWV3cG9ydFN0YXRlXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cyA9ICgpID0+IHtcbiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAoIWNvbnRhaW5lcikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgd2lkdGg6IGVkaXRvcldpZHRoLFxuICAgICAgICBoZWlnaHQ6IGVkaXRvckhlaWdodFxuICAgICAgfSA9IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGNvbnN0IHNpZGViYXJCcmVha3BvaW50ID0gdGhpcy5wcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT0gbnVsbCA/IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50IDogTVFfUklHSFRfU0lERUJBUl9NSU5fV0lEVEg7XG4gICAgICBjb25zdCBwcmV2RWRpdG9yU3RhdGUgPSB0aGlzLmRldmljZS5lZGl0b3I7XG4gICAgICBjb25zdCBuZXh0RWRpdG9yU3RhdGUgPSB1cGRhdGVPYmplY3QocHJldkVkaXRvclN0YXRlLCB7XG4gICAgICAgIGlzTW9iaWxlOiB0aGlzLmlzTW9iaWxlQnJlYWtwb2ludChlZGl0b3JXaWR0aCwgZWRpdG9ySGVpZ2h0KSxcbiAgICAgICAgY2FuRml0U2lkZWJhcjogZWRpdG9yV2lkdGggPiBzaWRlYmFyQnJlYWtwb2ludFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChwcmV2RWRpdG9yU3RhdGUgIT09IG5leHRFZGl0b3JTdGF0ZSkge1xuICAgICAgICB0aGlzLmRldmljZSA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5kZXZpY2UpLCB7XG4gICAgICAgICAgZWRpdG9yOiBuZXh0RWRpdG9yU3RhdGVcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMub25SZXNpemUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoKCkgPT4ge1xuICAgICAgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5mb3JFYWNoKGVsZW1lbnQgPT4gU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCkpO1xuICAgICAgdGhpcy5yZWZyZXNoVmlld3BvcnRCcmVha3BvaW50cygpO1xuICAgICAgdGhpcy51cGRhdGVET01SZWN0KCk7XG5cbiAgICAgIGlmICghc3VwcG9ydHNSZXNpemVPYnNlcnZlcikge1xuICAgICAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cygpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHt9KTtcbiAgICB9KTtcblxuICAgIHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrID0gKHtcbiAgICAgIGF0TGVhc3RPbmVWaXNpYmxlRWxlbWVudCxcbiAgICAgIHNjcm9sbEJhcnMsXG4gICAgICBlbGVtZW50c1xuICAgIH0pID0+IHtcbiAgICAgIGlmIChzY3JvbGxCYXJzKSB7XG4gICAgICAgIGN1cnJlbnRTY3JvbGxCYXJzID0gc2Nyb2xsQmFycztcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2Nyb2xsZWRPdXRzaWRlID0gLy8gaGlkZSB3aGVuIGVkaXRpbmcgdGV4dFxuICAgICAgaXNUZXh0RWxlbWVudCh0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50KSA/IGZhbHNlIDogIWF0TGVhc3RPbmVWaXNpYmxlRWxlbWVudCAmJiBlbGVtZW50cy5sZW5ndGggPiAwO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zY3JvbGxlZE91dHNpZGUgIT09IHNjcm9sbGVkT3V0c2lkZSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzY3JvbGxlZE91dHNpZGVcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2NoZWR1bGVJbWFnZVJlZnJlc2goKTtcbiAgICB9O1xuXG4gICAgdGhpcy5vblNjcm9sbCA9IGRlYm91bmNlKCgpID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgb2Zmc2V0VG9wLFxuICAgICAgICBvZmZzZXRMZWZ0XG4gICAgICB9ID0gdGhpcy5nZXRDYW52YXNPZmZzZXRzKCk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlID0+IHtcbiAgICAgICAgaWYgKHN0YXRlLm9mZnNldExlZnQgPT09IG9mZnNldExlZnQgJiYgc3RhdGUub2Zmc2V0VG9wID09PSBvZmZzZXRUb3ApIHtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgb2Zmc2V0VG9wLFxuICAgICAgICAgIG9mZnNldExlZnRcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH0sIFNDUk9MTF9USU1FT1VUKTsgLy8gQ29weS9wYXN0ZVxuXG4gICAgdGhpcy5vbkN1dCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IGlzRXhjYWxpZHJhd0FjdGl2ZSA9IChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY29udGFpbnMoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCk7XG5cbiAgICAgIGlmICghaXNFeGNhbGlkcmF3QWN0aXZlIHx8IGlzV3JpdGFibGVFbGVtZW50KGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25DdXQsIFwia2V5Ym9hcmRcIiwgZXZlbnQpO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH0pO1xuICAgIHRoaXMub25Db3B5ID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaXNFeGNhbGlkcmF3QWN0aXZlID0gKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jb250YWlucyhkb2N1bWVudC5hY3RpdmVFbGVtZW50KTtcblxuICAgICAgaWYgKCFpc0V4Y2FsaWRyYXdBY3RpdmUgfHwgaXNXcml0YWJsZUVsZW1lbnQoZXZlbnQudGFyZ2V0KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkNvcHksIFwia2V5Ym9hcmRcIiwgZXZlbnQpO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5vblRvdWNoU3RhcnQgPSBldmVudCA9PiB7XG4gICAgICAvLyBmaXggZm9yIEFwcGxlIFBlbmNpbCBTY3JpYmJsZVxuICAgICAgLy8gT24gQW5kcm9pZCwgcHJldmVudGluZyB0aGUgZXZlbnQgd291bGQgZGlzYWJsZSBjb250ZXh0TWVudSBvbiB0YXAtaG9sZFxuICAgICAgaWYgKCFpc0FuZHJvaWQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFkaWRUYXBUd2ljZSkge1xuICAgICAgICBkaWRUYXBUd2ljZSA9IHRydWU7XG4gICAgICAgIGNsZWFyVGltZW91dCh0YXBwZWRUd2ljZVRpbWVyKTtcbiAgICAgICAgdGFwcGVkVHdpY2VUaW1lciA9IHdpbmRvdy5zZXRUaW1lb3V0KEFwcC5yZXNldFRhcFR3aWNlLCBUQVBfVFdJQ0VfVElNRU9VVCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gaW5zZXJ0IHRleHQgb25seSBpZiB3ZSB0YXBwZWQgdHdpY2Ugd2l0aCBhIHNpbmdsZSBmaW5nZXJcbiAgICAgIC8vIGV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSAxIHdpbGwgYWxzbyBwcmV2ZW50IGluc2VydGluZyB0ZXh0IHdoZW4gdXNlcidzIHpvb21pbmdcblxuXG4gICAgICBpZiAoZGlkVGFwVHdpY2UgJiYgZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgY29uc3QgdG91Y2ggPSBldmVudC50b3VjaGVzWzBdOyAvLyBAdHMtaWdub3JlXG5cbiAgICAgICAgdGhpcy5oYW5kbGVDYW52YXNEb3VibGVDbGljayh7XG4gICAgICAgICAgY2xpZW50WDogdG91Y2guY2xpZW50WCxcbiAgICAgICAgICBjbGllbnRZOiB0b3VjaC5jbGllbnRZXG4gICAgICAgIH0pO1xuICAgICAgICBkaWRUYXBUd2ljZSA9IGZhbHNlO1xuICAgICAgICBjbGVhclRpbWVvdXQodGFwcGVkVHdpY2VUaW1lcik7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0FuZHJvaWQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMub25Ub3VjaEVuZCA9IGV2ZW50ID0+IHtcbiAgICAgIHRoaXMucmVzZXRDb250ZXh0TWVudVRpbWVyKCk7XG5cbiAgICAgIGlmIChldmVudC50b3VjaGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHt9LFxuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHModGhpcy5zdGF0ZS5wcmV2aW91c1NlbGVjdGVkRWxlbWVudElkcywgdGhpcy5zdGF0ZSlcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBnZXN0dXJlLnBvaW50ZXJzLmNsZWFyKCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMucGFzdGVGcm9tQ2xpcGJvYXJkID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfYywgX2QsIF9lO1xuXG4gICAgICBjb25zdCBpc1BsYWluUGFzdGUgPSAhIUlTX1BMQUlOX1BBU1RFOyAvLyAjNjg2XG5cbiAgICAgIGNvbnN0IHRhcmdldCA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG4gICAgICBjb25zdCBpc0V4Y2FsaWRyYXdBY3RpdmUgPSAoX2MgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmNvbnRhaW5zKHRhcmdldCk7XG5cbiAgICAgIGlmIChldmVudCAmJiAhaXNFeGNhbGlkcmF3QWN0aXZlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudFVuZGVyQ3Vyc29yID0gZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludCh0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLngsIHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSk7XG5cbiAgICAgIGlmIChldmVudCAmJiAoIShlbGVtZW50VW5kZXJDdXJzb3IgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCkgfHwgaXNXcml0YWJsZUVsZW1lbnQodGFyZ2V0KSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgY2xpZW50WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgICBjbGllbnRZOiB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnlcbiAgICAgIH0sIHRoaXMuc3RhdGUpOyAvLyBtdXN0IGJlIGNhbGxlZCBpbiB0aGUgc2FtZSBmcmFtZSAodGh1cyBiZWZvcmUgYW55IGF3YWl0cykgYXMgdGhlIHBhc3RlXG4gICAgICAvLyBldmVudCBlbHNlIHNvbWUgYnJvd3NlcnMgKEZGLi4uKSB3aWxsIGNsZWFyIHRoZSBjbGlwYm9hcmREYXRhXG4gICAgICAvLyAoc29tZXRoaW5nIHNvbWV0aGluZyBzZWN1cml0eSlcblxuICAgICAgbGV0IGZpbGUgPSAoX2QgPSBldmVudCA9PT0gbnVsbCB8fCBldmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXZlbnQuY2xpcGJvYXJkRGF0YSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmZpbGVzWzBdO1xuICAgICAgY29uc3QgZGF0YSA9IHlpZWxkIHBhcnNlQ2xpcGJvYXJkKGV2ZW50LCBpc1BsYWluUGFzdGUpO1xuXG4gICAgICBpZiAoIWZpbGUgJiYgIWlzUGxhaW5QYXN0ZSkge1xuICAgICAgICBpZiAoZGF0YS5taXhlZENvbnRlbnQpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5hZGRFbGVtZW50c0Zyb21NaXhlZENvbnRlbnRQYXN0ZShkYXRhLm1peGVkQ29udGVudCwge1xuICAgICAgICAgICAgaXNQbGFpblBhc3RlLFxuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS50ZXh0KSB7XG4gICAgICAgICAgY29uc3Qgc3RyaW5nID0gZGF0YS50ZXh0LnRyaW0oKTtcblxuICAgICAgICAgIGlmIChzdHJpbmcuc3RhcnRzV2l0aChcIjxzdmdcIikgJiYgc3RyaW5nLmVuZHNXaXRoKFwiPC9zdmc+XCIpKSB7XG4gICAgICAgICAgICAvLyBpZ25vcmUgU1ZHIHZhbGlkYXRpb24vbm9ybWFsaXphdGlvbiB3aGljaCB3aWxsIGJlIGRvbmUgZHVyaW5nIGltYWdlXG4gICAgICAgICAgICAvLyBpbml0aWFsaXphdGlvblxuICAgICAgICAgICAgZmlsZSA9IFNWR1N0cmluZ1RvRmlsZShzdHJpbmcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSAvLyBwcmVmZXIgc3ByZWFkc2hlZXQgZGF0YSBvdmVyIGltYWdlIGZpbGUgKE1TIE9mZmljZS9MaWJyZSBPZmZpY2UpXG5cblxuICAgICAgaWYgKGlzU3VwcG9ydGVkSW1hZ2VGaWxlKGZpbGUpICYmICFkYXRhLnNwcmVhZHNoZWV0KSB7XG4gICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50KHtcbiAgICAgICAgICBzY2VuZVgsXG4gICAgICAgICAgc2NlbmVZXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmluc2VydEltYWdlRWxlbWVudChpbWFnZUVsZW1lbnQsIGZpbGUpO1xuICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnByb3BzLm9uUGFzdGUpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAoKHlpZWxkIHRoaXMucHJvcHMub25QYXN0ZShkYXRhLCBldmVudCkpID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZGF0YS5lcnJvck1lc3NhZ2UpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBkYXRhLmVycm9yTWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5zcHJlYWRzaGVldCAmJiAhaXNQbGFpblBhc3RlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHBhc3RlRGlhbG9nOiB7XG4gICAgICAgICAgICBkYXRhOiBkYXRhLnNwcmVhZHNoZWV0LFxuICAgICAgICAgICAgc2hvd246IHRydWVcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmVsZW1lbnRzKSB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzID0gZGF0YS5wcm9ncmFtbWF0aWNBUEkgPyBjb252ZXJ0VG9FeGNhbGlkcmF3RWxlbWVudHMoZGF0YS5lbGVtZW50cykgOiBkYXRhLmVsZW1lbnRzOyAvLyBUT0RPIHJlbW92ZSBmb3JtYXR0aW5nIGZyb20gZWxlbWVudHMgaWYgaXNQbGFpblBhc3RlXG5cbiAgICAgICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSh7XG4gICAgICAgICAgZWxlbWVudHMsXG4gICAgICAgICAgZmlsZXM6IGRhdGEuZmlsZXMgfHwgbnVsbCxcbiAgICAgICAgICBwb3NpdGlvbjogXCJjdXJzb3JcIixcbiAgICAgICAgICByZXRhaW5TZWVkOiBpc1BsYWluUGFzdGVcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEudGV4dCkge1xuICAgICAgICBjb25zdCBtYXliZVVybCA9IGV4dHJhY3RTcmMoZGF0YS50ZXh0KTtcblxuICAgICAgICBpZiAoIWlzUGxhaW5QYXN0ZSAmJiBlbWJlZGRhYmxlVVJMVmFsaWRhdG9yKG1heWJlVXJsLCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSkgJiYgKC9eKGh0dHB8aHR0cHMpOlxcL1xcL1teXFxzLyQuPyNdLlteXFxzXSokLy50ZXN0KG1heWJlVXJsKSB8fCAoKF9lID0gZ2V0RW1iZWRMaW5rKG1heWJlVXJsKSkgPT09IG51bGwgfHwgX2UgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9lLnR5cGUpID09PSBcInZpZGVvXCIpKSB7XG4gICAgICAgICAgY29uc3QgZW1iZWRkYWJsZSA9IHRoaXMuaW5zZXJ0RW1iZWRkYWJsZUVsZW1lbnQoe1xuICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgc2NlbmVZLFxuICAgICAgICAgICAgbGluazogbm9ybWFsaXplTGluayhtYXliZVVybClcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmIChlbWJlZGRhYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgW2VtYmVkZGFibGUuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuYWRkVGV4dEZyb21QYXN0ZShkYXRhLnRleHQsIGlzUGxhaW5QYXN0ZSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgIH0pO1xuICAgICAgZXZlbnQgPT09IG51bGwgfHwgZXZlbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSkpO1xuXG4gICAgdGhpcy5hZGRFbGVtZW50c0Zyb21QYXN0ZU9yTGlicmFyeSA9IG9wdHMgPT4ge1xuICAgICAgY29uc3QgZWxlbWVudHMgPSByZXN0b3JlRWxlbWVudHMob3B0cy5lbGVtZW50cywgbnVsbCwgdW5kZWZpbmVkKTtcbiAgICAgIGNvbnN0IFttaW5YLCBtaW5ZLCBtYXhYLCBtYXhZXSA9IGdldENvbW1vbkJvdW5kcyhlbGVtZW50cyk7XG4gICAgICBjb25zdCBlbGVtZW50c0NlbnRlclggPSBkaXN0YW5jZShtaW5YLCBtYXhYKSAvIDI7XG4gICAgICBjb25zdCBlbGVtZW50c0NlbnRlclkgPSBkaXN0YW5jZShtaW5ZLCBtYXhZKSAvIDI7XG4gICAgICBjb25zdCBjbGllbnRYID0gdHlwZW9mIG9wdHMucG9zaXRpb24gPT09IFwib2JqZWN0XCIgPyBvcHRzLnBvc2l0aW9uLmNsaWVudFggOiBvcHRzLnBvc2l0aW9uID09PSBcImN1cnNvclwiID8gdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54IDogdGhpcy5zdGF0ZS53aWR0aCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldExlZnQ7XG4gICAgICBjb25zdCBjbGllbnRZID0gdHlwZW9mIG9wdHMucG9zaXRpb24gPT09IFwib2JqZWN0XCIgPyBvcHRzLnBvc2l0aW9uLmNsaWVudFkgOiBvcHRzLnBvc2l0aW9uID09PSBcImN1cnNvclwiID8gdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55IDogdGhpcy5zdGF0ZS5oZWlnaHQgLyAyICsgdGhpcy5zdGF0ZS5vZmZzZXRUb3A7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYLFxuICAgICAgICBjbGllbnRZXG4gICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGR4ID0geCAtIGVsZW1lbnRzQ2VudGVyWDtcbiAgICAgIGNvbnN0IGR5ID0geSAtIGVsZW1lbnRzQ2VudGVyWTtcbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KGR4LCBkeSwgdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBuZXdFbGVtZW50cyA9IGR1cGxpY2F0ZUVsZW1lbnRzKGVsZW1lbnRzLm1hcChlbGVtZW50ID0+IHtcbiAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZW1lbnQsIHtcbiAgICAgICAgICB4OiBlbGVtZW50LnggKyBncmlkWCAtIG1pblgsXG4gICAgICAgICAgeTogZWxlbWVudC55ICsgZ3JpZFkgLSBtaW5ZXG4gICAgICAgIH0pO1xuICAgICAgfSksIHtcbiAgICAgICAgcmFuZG9taXplU2VlZDogIW9wdHMucmV0YWluU2VlZFxuICAgICAgfSk7XG4gICAgICBjb25zdCBuZXh0RWxlbWVudHMgPSBbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgLi4ubmV3RWxlbWVudHNdO1xuICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dEVsZW1lbnRzKTtcbiAgICAgIG5ld0VsZW1lbnRzLmZvckVhY2gobmV3RWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChpc1RleHRFbGVtZW50KG5ld0VsZW1lbnQpICYmIGlzQm91bmRUb0NvbnRhaW5lcihuZXdFbGVtZW50KSkge1xuICAgICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IGdldENvbnRhaW5lckVsZW1lbnQobmV3RWxlbWVudCk7XG4gICAgICAgICAgcmVkcmF3VGV4dEJvdW5kaW5nQm94KG5ld0VsZW1lbnQsIGNvbnRhaW5lcik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpZiAob3B0cy5maWxlcykge1xuICAgICAgICB0aGlzLmZpbGVzID0gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLmZpbGVzKSwgb3B0cy5maWxlcyk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgIGNvbnN0IG5leHRFbGVtZW50c1RvU2VsZWN0ID0gZXhjbHVkZUVsZW1lbnRzSW5GcmFtZXNGcm9tU2VsZWN0aW9uKG5ld0VsZW1lbnRzKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUpLCB7XG4gICAgICAgIC8vIGtlZXAgc2lkZWJhciAocHJlc3VtYWJseSB0aGUgbGlicmFyeSkgb3BlbiBpZiBpdCdzIGRvY2tlZCBhbmRcbiAgICAgICAgLy8gY2FuIGZpdC5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gTm90ZSwgd2Ugc2hvdWxkIGNsb3NlIHRoZSBzaWRlYmFyIG9ubHkgaWYgd2UncmUgZHJvcHBpbmcgaXRlbXNcbiAgICAgICAgLy8gZnJvbSBsaWJyYXJ5LCBub3Qgd2hlbiBwYXN0aW5nIGZyb20gY2xpcGJvYXJkLiBBbGFzLlxuICAgICAgICBvcGVuU2lkZWJhcjogdGhpcy5zdGF0ZS5vcGVuU2lkZWJhciAmJiB0aGlzLmRldmljZS5lZGl0b3IuY2FuRml0U2lkZWJhciAmJiBqb3RhaVN0b3JlLmdldChpc1NpZGViYXJEb2NrZWRBdG9tKSA/IHRoaXMuc3RhdGUub3BlblNpZGViYXIgOiBudWxsXG4gICAgICB9KSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRFbGVtZW50c1RvU2VsZWN0LnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgaWYgKCFpc0JvdW5kVG9Db250YWluZXIoZWxlbWVudCkpIHtcbiAgICAgICAgICAgIGFjY1tlbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgfSwge30pXG4gICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlLCB0aGlzKSksICgpID0+IHtcbiAgICAgICAgaWYgKG9wdHMuZmlsZXMpIHtcbiAgICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgIH0pO1xuXG4gICAgICBpZiAob3B0cy5maXRUb0NvbnRlbnQpIHtcbiAgICAgICAgdGhpcy5zY3JvbGxUb0NvbnRlbnQobmV3RWxlbWVudHMsIHtcbiAgICAgICAgICBmaXRUb0NvbnRlbnQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuc2V0QXBwU3RhdGUgPSAoc3RhdGUsIGNhbGxiYWNrKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlLCBjYWxsYmFjayk7XG4gICAgfTtcblxuICAgIHRoaXMucmVtb3ZlUG9pbnRlciA9IGV2ZW50ID0+IHtcbiAgICAgIGlmICh0b3VjaFRpbWVvdXQpIHtcbiAgICAgICAgdGhpcy5yZXNldENvbnRleHRNZW51VGltZXIoKTtcbiAgICAgIH1cblxuICAgICAgZ2VzdHVyZS5wb2ludGVycy5kZWxldGUoZXZlbnQucG9pbnRlcklkKTtcbiAgICB9O1xuXG4gICAgdGhpcy50b2dnbGVMb2NrID0gKHNvdXJjZSA9IFwidWlcIikgPT4ge1xuICAgICAgaWYgKCF0aGlzLnN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgIHRyYWNrRXZlbnQoXCJ0b29sYmFyXCIsIFwidG9nZ2xlTG9ja1wiLCBgJHtzb3VyY2V9ICgke3RoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSA/IFwibW9iaWxlXCIgOiBcImRlc2t0b3BcIn0pYCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhY3RpdmVUb29sOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLmFjdGl2ZVRvb2wpLCB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHByZXZTdGF0ZS5hY3RpdmVUb29sLmxvY2tlZCA/IHtcbiAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgICB9IDogcHJldlN0YXRlLmFjdGl2ZVRvb2wpKSwge1xuICAgICAgICAgICAgbG9ja2VkOiAhcHJldlN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkXG4gICAgICAgICAgfSlcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnVwZGF0ZUZyYW1lUmVuZGVyaW5nID0gb3B0cyA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIHZhciBfYSwgX2IsIF9jLCBfZDtcblxuICAgICAgICBjb25zdCBuZXh0ID0gdHlwZW9mIG9wdHMgPT09IFwiZnVuY3Rpb25cIiA/IG9wdHMocHJldlN0YXRlLmZyYW1lUmVuZGVyaW5nKSA6IG9wdHM7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZnJhbWVSZW5kZXJpbmc6IHtcbiAgICAgICAgICAgIGVuYWJsZWQ6IChfYSA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5lbmFibGVkKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcuZW5hYmxlZCxcbiAgICAgICAgICAgIGNsaXA6IChfYiA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5jbGlwKSAhPT0gbnVsbCAmJiBfYiAhPT0gdm9pZCAwID8gX2IgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcuY2xpcCxcbiAgICAgICAgICAgIG5hbWU6IChfYyA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5uYW1lKSAhPT0gbnVsbCAmJiBfYyAhPT0gdm9pZCAwID8gX2MgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcubmFtZSxcbiAgICAgICAgICAgIG91dGxpbmU6IChfZCA9IG5leHQgPT09IG51bGwgfHwgbmV4dCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dC5vdXRsaW5lKSAhPT0gbnVsbCAmJiBfZCAhPT0gdm9pZCAwID8gX2QgOiBwcmV2U3RhdGUuZnJhbWVSZW5kZXJpbmcub3V0bGluZVxuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnRvZ2dsZVBlbk1vZGUgPSBmb3JjZSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgcGVuTW9kZTogZm9yY2UgIT09IG51bGwgJiYgZm9yY2UgIT09IHZvaWQgMCA/IGZvcmNlIDogIXByZXZTdGF0ZS5wZW5Nb2RlLFxuICAgICAgICAgIHBlbkRldGVjdGVkOiB0cnVlXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5vbkhhbmRUb29sVG9nZ2xlID0gKCkgPT4ge1xuICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uVG9nZ2xlSGFuZFRvb2wpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogWm9vbXMgb24gY2FudmFzIHZpZXdwb3J0IGNlbnRlclxuICAgICAqL1xuXG5cbiAgICB0aGlzLnpvb21DYW52YXMgPSAoXG4gICAgLyoqIGRlY2ltYWwgZnJhY3Rpb24gYmV0d2VlbiAwLjEgKDEwJSB6b29tKSBhbmQgMzAgKDMwMDAlIHpvb20pICovXG4gICAgdmFsdWUpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgdmlld3BvcnRYOiB0aGlzLnN0YXRlLndpZHRoIC8gMiArIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCxcbiAgICAgICAgdmlld3BvcnRZOiB0aGlzLnN0YXRlLmhlaWdodCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldFRvcCxcbiAgICAgICAgbmV4dFpvb206IGdldE5vcm1hbGl6ZWRab29tKHZhbHVlKVxuICAgICAgfSwgdGhpcy5zdGF0ZSkpKTtcbiAgICB9O1xuXG4gICAgdGhpcy5jYW5jZWxJblByb2dyZXNBbmltYXRpb24gPSBudWxsO1xuXG4gICAgdGhpcy5zY3JvbGxUb0NvbnRlbnQgPSAodGFyZ2V0ID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgb3B0cykgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgKF9hID0gdGhpcy5jYW5jZWxJblByb2dyZXNBbmltYXRpb24pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jYWxsKHRoaXMpOyAvLyBjb252ZXJ0IHByb3ZpZGVkIHRhcmdldCBpbnRvIEV4Y2FsaWRyYXdFbGVtZW50W10gaWYgbmVjZXNzYXJ5XG5cbiAgICAgIGNvbnN0IHRhcmdldEVsZW1lbnRzID0gQXJyYXkuaXNBcnJheSh0YXJnZXQpID8gdGFyZ2V0IDogW3RhcmdldF07XG4gICAgICBsZXQgem9vbSA9IHRoaXMuc3RhdGUuem9vbTtcbiAgICAgIGxldCBzY3JvbGxYID0gdGhpcy5zdGF0ZS5zY3JvbGxYO1xuICAgICAgbGV0IHNjcm9sbFkgPSB0aGlzLnN0YXRlLnNjcm9sbFk7XG5cbiAgICAgIGlmICgob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvQ29udGVudCkgfHwgKG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5maXRUb1ZpZXdwb3J0KSkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgYXBwU3RhdGVcbiAgICAgICAgfSA9IHpvb21Ub0ZpdCh7XG4gICAgICAgICAgdGFyZ2V0RWxlbWVudHMsXG4gICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgZml0VG9WaWV3cG9ydDogISEob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmZpdFRvVmlld3BvcnQpLFxuICAgICAgICAgIHZpZXdwb3J0Wm9vbUZhY3Rvcjogb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnZpZXdwb3J0Wm9vbUZhY3RvclxuICAgICAgICB9KTtcbiAgICAgICAgem9vbSA9IGFwcFN0YXRlLnpvb207XG4gICAgICAgIHNjcm9sbFggPSBhcHBTdGF0ZS5zY3JvbGxYO1xuICAgICAgICBzY3JvbGxZID0gYXBwU3RhdGUuc2Nyb2xsWTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGNvbXB1dGUgb25seSB0aGUgdmlld3BvcnQgbG9jYXRpb24sIHdpdGhvdXQgYW55IHpvb20gYWRqdXN0bWVudFxuICAgICAgICBjb25zdCBzY3JvbGwgPSBjYWxjdWxhdGVTY3JvbGxDZW50ZXIodGFyZ2V0RWxlbWVudHMsIHRoaXMuc3RhdGUpO1xuICAgICAgICBzY3JvbGxYID0gc2Nyb2xsLnNjcm9sbFg7XG4gICAgICAgIHNjcm9sbFkgPSBzY3JvbGwuc2Nyb2xsWTtcbiAgICAgIH0gLy8gd2hlbiBhbmltYXRpbmcsIHdlIHVzZSBSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgdG8gcHJldmVudCB0aGUgYW5pbWF0aW9uXG4gICAgICAvLyBmcm9tIHNsb3dpbmcgZG93biBvdGhlciBwcm9jZXNzZXNcblxuXG4gICAgICBpZiAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmFuaW1hdGUpIHtcbiAgICAgICAgY29uc3Qgb3JpZ1Njcm9sbFggPSB0aGlzLnN0YXRlLnNjcm9sbFg7XG4gICAgICAgIGNvbnN0IG9yaWdTY3JvbGxZID0gdGhpcy5zdGF0ZS5zY3JvbGxZO1xuICAgICAgICBjb25zdCBvcmlnWm9vbSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgICAgY29uc3QgY2FuY2VsID0gZWFzZVRvVmFsdWVzUkFGKHtcbiAgICAgICAgICBmcm9tVmFsdWVzOiB7XG4gICAgICAgICAgICBzY3JvbGxYOiBvcmlnU2Nyb2xsWCxcbiAgICAgICAgICAgIHNjcm9sbFk6IG9yaWdTY3JvbGxZLFxuICAgICAgICAgICAgem9vbTogb3JpZ1pvb21cbiAgICAgICAgICB9LFxuICAgICAgICAgIHRvVmFsdWVzOiB7XG4gICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgIHpvb206IHpvb20udmFsdWVcbiAgICAgICAgICB9LFxuICAgICAgICAgIGludGVycG9sYXRlVmFsdWU6IChmcm9tLCB0bywgcHJvZ3Jlc3MsIGtleSkgPT4ge1xuICAgICAgICAgICAgLy8gZm9yIHpvb20sIHVzZSBkaWZmZXJlbnQgZWFzaW5nXG4gICAgICAgICAgICBpZiAoa2V5ID09PSBcInpvb21cIikge1xuICAgICAgICAgICAgICByZXR1cm4gZnJvbSAqIE1hdGgucG93KHRvIC8gZnJvbSwgZWFzZU91dChwcm9ncmVzcykpO1xuICAgICAgICAgICAgfSAvLyBoYW5kbGUgdXNpbmcgZGVmYXVsdFxuXG5cbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvblN0ZXA6ICh7XG4gICAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgIHpvb21cbiAgICAgICAgICB9KSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2Nyb2xsWCxcbiAgICAgICAgICAgICAgc2Nyb2xsWSxcbiAgICAgICAgICAgICAgem9vbToge1xuICAgICAgICAgICAgICAgIHZhbHVlOiB6b29tXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgb25TdGFydDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogdHJ1ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvbkVuZDogKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgb25DYW5jZWw6ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIGR1cmF0aW9uOiAoX2IgPSBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuZHVyYXRpb24pICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDUwMFxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9ICgpID0+IHtcbiAgICAgICAgICBjYW5jZWwoKTtcbiAgICAgICAgICB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbiA9IG51bGw7XG4gICAgICAgIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzY3JvbGxYLFxuICAgICAgICAgIHNjcm9sbFksXG4gICAgICAgICAgem9vbVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICAgIC8qKiB1c2Ugd2hlbiBjaGFuZ2luZyBzY3JvbGxYL3Njcm9sbFkvem9vbSBiYXNlZCBvbiB1c2VyIGludGVyYWN0aW9uICovXG5cblxuICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzID0gc3RhdGUgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICAoX2EgPSB0aGlzLmNhbmNlbEluUHJvZ3Jlc0FuaW1hdGlvbikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbGwodGhpcyk7XG4gICAgICB0aGlzLnNldFN0YXRlKHN0YXRlKTtcbiAgICB9O1xuXG4gICAgdGhpcy5zZXRUb2FzdCA9IHRvYXN0ID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB0b2FzdFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzdG9yZUZpbGVGcm9tU2hhcmUgPSAoKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB3ZWJTaGFyZVRhcmdldENhY2hlID0geWllbGQgY2FjaGVzLm9wZW4oXCJ3ZWItc2hhcmUtdGFyZ2V0XCIpO1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IHlpZWxkIHdlYlNoYXJlVGFyZ2V0Q2FjaGUubWF0Y2goXCJzaGFyZWQtZmlsZVwiKTtcblxuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICBjb25zdCBibG9iID0geWllbGQgcmVzcG9uc2UuYmxvYigpO1xuICAgICAgICAgIGNvbnN0IGZpbGUgPSBuZXcgRmlsZShbYmxvYl0sIGJsb2IubmFtZSB8fCBcIlwiLCB7XG4gICAgICAgICAgICB0eXBlOiBibG9iLnR5cGVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLmxvYWRGaWxlVG9DYW52YXMoZmlsZSwgbnVsbCk7XG4gICAgICAgICAgeWllbGQgd2ViU2hhcmVUYXJnZXRDYWNoZS5kZWxldGUoXCJzaGFyZWQtZmlsZVwiKTtcbiAgICAgICAgICB3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUobnVsbCwgQVBQX05BTUUsIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICAvKiogYWRkcyBzdXBwbGllZCBmaWxlcyB0byBleGlzdGluZyBmaWxlcyBpbiB0aGUgYXBwU3RhdGUgKi9cblxuXG4gICAgdGhpcy5hZGRGaWxlcyA9IHdpdGhCYXRjaGVkVXBkYXRlcyhmaWxlcyA9PiB7XG4gICAgICBjb25zdCBmaWxlc01hcCA9IGZpbGVzLnJlZHVjZSgoYWNjLCBmaWxlRGF0YSkgPT4ge1xuICAgICAgICBhY2Muc2V0KGZpbGVEYXRhLmlkLCBmaWxlRGF0YSk7XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCBuZXcgTWFwKCkpO1xuICAgICAgdGhpcy5maWxlcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5maWxlcyksIE9iamVjdC5mcm9tRW50cmllcyhmaWxlc01hcCkpO1xuICAgICAgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICBpZiAoaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChlbGVtZW50KSAmJiBmaWxlc01hcC5oYXMoZWxlbWVudC5maWxlSWQpKSB7XG4gICAgICAgICAgdGhpcy5pbWFnZUNhY2hlLmRlbGV0ZShlbGVtZW50LmZpbGVJZCk7XG4gICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUoKTtcbiAgICB9KTtcbiAgICB0aGlzLnVwZGF0ZVNjZW5lID0gd2l0aEJhdGNoZWRVcGRhdGVzKHNjZW5lRGF0YSA9PiB7XG4gICAgICBpZiAoc2NlbmVEYXRhLmNvbW1pdFRvSGlzdG9yeSkge1xuICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuYXBwU3RhdGUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShzY2VuZURhdGEuYXBwU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc2NlbmVEYXRhLmVsZW1lbnRzKSB7XG4gICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKHNjZW5lRGF0YS5lbGVtZW50cyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY2VuZURhdGEuY29sbGFib3JhdG9ycykge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBjb2xsYWJvcmF0b3JzOiBzY2VuZURhdGEuY29sbGFib3JhdG9yc1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub25TY2VuZVVwZGF0ZWQgPSAoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHt9KTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHdoZXRoZXIgdGhlIG1lbnUgd2FzIHRvZ2dsZWQgb24gb3Igb2ZmXG4gICAgICovXG5cblxuICAgIHRoaXMudG9nZ2xlU2lkZWJhciA9ICh7XG4gICAgICBuYW1lLFxuICAgICAgdGFiLFxuICAgICAgZm9yY2VcbiAgICB9KSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGxldCBuZXh0TmFtZTtcblxuICAgICAgaWYgKGZvcmNlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbmV4dE5hbWUgPSAoKF9hID0gdGhpcy5zdGF0ZS5vcGVuU2lkZWJhcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm5hbWUpID09PSBuYW1lID8gbnVsbCA6IG5hbWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuZXh0TmFtZSA9IGZvcmNlID8gbmFtZSA6IG51bGw7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBvcGVuU2lkZWJhcjogbmV4dE5hbWUgPyB7XG4gICAgICAgICAgbmFtZTogbmV4dE5hbWUsXG4gICAgICAgICAgdGFiXG4gICAgICAgIH0gOiBudWxsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiAhIW5leHROYW1lO1xuICAgIH07XG5cbiAgICB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbiA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICB0aGlzLmxhc3RWaWV3cG9ydFBvc2l0aW9uLnggPSBldmVudC5jbGllbnRYO1xuICAgICAgdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55ID0gZXZlbnQuY2xpZW50WTtcbiAgICB9KTsgLy8gSW5wdXQgaGFuZGxpbmdcblxuICAgIHRoaXMub25LZXlEb3duID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIG5vcm1hbGl6ZSBgZXZlbnQua2V5YCB3aGVuIENhcHNMb2NrIGlzIHByZXNzZWQgIzIzNzJcbiAgICAgIGlmIChcIlByb3h5XCIgaW4gd2luZG93ICYmICghZXZlbnQuc2hpZnRLZXkgJiYgL15bQS1aXSQvLnRlc3QoZXZlbnQua2V5KSB8fCBldmVudC5zaGlmdEtleSAmJiAvXlthLXpdJC8udGVzdChldmVudC5rZXkpKSkge1xuICAgICAgICBldmVudCA9IG5ldyBQcm94eShldmVudCwge1xuICAgICAgICAgIGdldChldiwgcHJvcCkge1xuICAgICAgICAgICAgY29uc3QgdmFsdWUgPSBldltwcm9wXTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgIC8vIGZpeCBmb3IgUHJveGllcyBoaWphY2tpbmcgYHRoaXNgXG4gICAgICAgICAgICAgIHJldHVybiB2YWx1ZS5iaW5kKGV2KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHByb3AgPT09IFwia2V5XCIgPyAvLyBDYXBzTG9jayBpbnZlcnRzIGNhcGl0YWxpemF0aW9uIGJhc2VkIG9uIFNoaWZ0S2V5LCBzbyBpbnZlcnRcbiAgICAgICAgICAgIC8vIGl0IGJhY2tcbiAgICAgICAgICAgIGV2ZW50LnNoaWZ0S2V5ID8gZXYua2V5LnRvVXBwZXJDYXNlKCkgOiBldi5rZXkudG9Mb3dlckNhc2UoKSA6IHZhbHVlO1xuICAgICAgICAgIH1cblxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIGV2ZW50LmtleS50b0xvd2VyQ2FzZSgpID09PSBLRVlTLlYpIHtcbiAgICAgICAgSVNfUExBSU5fUEFTVEUgPSBldmVudC5zaGlmdEtleTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KElTX1BMQUlOX1BBU1RFX1RJTUVSKTsgLy8gcmVzZXQgKDEwMG1zIHRvIGJlIHNhZmUgdGhhdCB3ZSBpdCBydW5zIGFmdGVyIHRoZSBlbnN1aW5nXG4gICAgICAgIC8vIHBhc3RlIGV2ZW50KS4gVGhvdWdoLCB0ZWNobmljYWxseSB1bm5lY2Vzc2FyeSB0byByZXNldCBzaW5jZSB3ZVxuICAgICAgICAvLyAocmUpc2V0IHRoZSBmbGFnIGJlZm9yZSBlYWNoIHBhc3RlIGV2ZW50LlxuXG4gICAgICAgIElTX1BMQUlOX1BBU1RFX1RJTUVSID0gd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIElTX1BMQUlOX1BBU1RFID0gZmFsc2U7XG4gICAgICAgIH0sIDEwMCk7XG4gICAgICB9IC8vIHByZXZlbnQgYnJvd3NlciB6b29tIGluIGlucHV0IGZpZWxkc1xuXG5cbiAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiBpc1dyaXRhYmxlRWxlbWVudChldmVudC50YXJnZXQpKSB7XG4gICAgICAgIGlmIChldmVudC5jb2RlID09PSBDT0RFUy5NSU5VUyB8fCBldmVudC5jb2RlID09PSBDT0RFUy5FUVVBTCkge1xuICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IC8vIGJhaWwgaWZcblxuXG4gICAgICBpZiAoIC8vIGluc2lkZSBhbiBpbnB1dFxuICAgICAgaXNXcml0YWJsZUVsZW1lbnQoZXZlbnQudGFyZ2V0KSAmJiAvLyB1bmxlc3MgcHJlc3NpbmcgZXNjYXBlIChmaW5hbGl6ZSBhY3Rpb24pXG4gICAgICBldmVudC5rZXkgIT09IEtFWVMuRVNDQVBFIHx8IC8vIG9yIHVubGVzcyB1c2luZyBhcnJvd3MgKHRvIG1vdmUgYmV0d2VlbiBidXR0b25zKVxuICAgICAgaXNBcnJvd0tleShldmVudC5rZXkpICYmIGlzSW5wdXRMaWtlKGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlFVRVNUSU9OX01BUkspIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgb3BlbkRpYWxvZzogXCJoZWxwXCJcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5LnRvTG93ZXJDYXNlKCkgPT09IEtFWVMuRSAmJiBldmVudC5zaGlmdEtleSAmJiBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBvcGVuRGlhbG9nOiBcImltYWdlRXhwb3J0XCJcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX1VQIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX0RPV04pIHtcbiAgICAgICAgbGV0IG9mZnNldCA9IChldmVudC5zaGlmdEtleSA/IHRoaXMuc3RhdGUud2lkdGggOiB0aGlzLnN0YXRlLmhlaWdodCkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5QQUdFX0RPV04pIHtcbiAgICAgICAgICBvZmZzZXQgPSAtb2Zmc2V0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LnNoaWZ0S2V5KSB7XG4gICAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gKHtcbiAgICAgICAgICAgIHNjcm9sbFg6IHN0YXRlLnNjcm9sbFggKyBvZmZzZXRcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gKHtcbiAgICAgICAgICAgIHNjcm9sbFk6IHN0YXRlLnNjcm9sbFkgKyBvZmZzZXRcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuYWN0aW9uTWFuYWdlci5oYW5kbGVLZXlEb3duKGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudFtLRVlTLkNUUkxfT1JfQ01EXSAmJiB0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0Fycm93S2V5KGV2ZW50LmtleSkpIHtcbiAgICAgICAgY29uc3Qgc3RlcCA9IHRoaXMuc3RhdGUuZ3JpZFNpemUgJiYgKGV2ZW50LnNoaWZ0S2V5ID8gRUxFTUVOVF9UUkFOU0xBVEVfQU1PVU5UIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSkgfHwgKGV2ZW50LnNoaWZ0S2V5ID8gRUxFTUVOVF9TSElGVF9UUkFOU0xBVEVfQU1PVU5UIDogRUxFTUVOVF9UUkFOU0xBVEVfQU1PVU5UKTtcbiAgICAgICAgbGV0IG9mZnNldFggPSAwO1xuICAgICAgICBsZXQgb2Zmc2V0WSA9IDA7XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19MRUZUKSB7XG4gICAgICAgICAgb2Zmc2V0WCA9IC1zdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19SSUdIVCkge1xuICAgICAgICAgIG9mZnNldFggPSBzdGVwO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5BUlJPV19VUCkge1xuICAgICAgICAgIG9mZnNldFkgPSAtc3RlcDtcbiAgICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkgPT09IEtFWVMuQVJST1dfRE9XTikge1xuICAgICAgICAgIG9mZnNldFkgPSBzdGVwO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyxcbiAgICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZSxcbiAgICAgICAgICBpbmNsdWRlRWxlbWVudHNJbkZyYW1lczogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgeDogZWxlbWVudC54ICsgb2Zmc2V0WCxcbiAgICAgICAgICAgIHk6IGVsZW1lbnQueSArIG9mZnNldFlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB1cGRhdGVCb3VuZEVsZW1lbnRzKGVsZW1lbnQsIHtcbiAgICAgICAgICAgIHNpbXVsdGFuZW91c2x5VXBkYXRlZDogc2VsZWN0ZWRFbGVtZW50c1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkgPT09IEtFWVMuRU5URVIpIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnQgPSBzZWxlY3RlZEVsZW1lbnRzWzBdO1xuXG4gICAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgICAgICBpZiAoaXNMaW5lYXJFbGVtZW50KHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50IHx8IHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuZWxlbWVudElkICE9PSBzZWxlY3RlZEVsZW1lbnRzWzBdLmlkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKHNlbGVjdGVkRWxlbWVudCwgdGhpcy5zY2VuZSlcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSBpZiAoaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnQpIHx8IGlzVmFsaWRUZXh0Q29udGFpbmVyKHNlbGVjdGVkRWxlbWVudCkpIHtcbiAgICAgICAgICAgIGxldCBjb250YWluZXI7XG5cbiAgICAgICAgICAgIGlmICghaXNUZXh0RWxlbWVudChzZWxlY3RlZEVsZW1lbnQpKSB7XG4gICAgICAgICAgICAgIGNvbnRhaW5lciA9IHNlbGVjdGVkRWxlbWVudDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbWlkUG9pbnQgPSBnZXRDb250YWluZXJDZW50ZXIoc2VsZWN0ZWRFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICAgIGNvbnN0IHNjZW5lWCA9IG1pZFBvaW50Lng7XG4gICAgICAgICAgICBjb25zdCBzY2VuZVkgPSBtaWRQb2ludC55O1xuICAgICAgICAgICAgdGhpcy5zdGFydFRleHRFZGl0aW5nKHtcbiAgICAgICAgICAgICAgc2NlbmVYLFxuICAgICAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgICAgIGNvbnRhaW5lclxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaXNGcmFtZUVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50KSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdGcmFtZTogc2VsZWN0ZWRFbGVtZW50LmlkXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoIWV2ZW50LmN0cmxLZXkgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQubWV0YUtleSAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCA9PT0gbnVsbCkge1xuICAgICAgICBjb25zdCBzaGFwZSA9IGZpbmRTaGFwZUJ5S2V5KGV2ZW50LmtleSk7XG5cbiAgICAgICAgaWYgKHNoYXBlKSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlICE9PSBzaGFwZSkge1xuICAgICAgICAgICAgdHJhY2tFdmVudChcInRvb2xiYXJcIiwgc2hhcGUsIGBrZXlib2FyZCAoJHt0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGUgPyBcIm1vYmlsZVwiIDogXCJkZXNrdG9wXCJ9KWApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgICAgICB0eXBlOiBzaGFwZVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5RKSB7XG4gICAgICAgICAgdGhpcy50b2dnbGVMb2NrKFwia2V5Ym9hcmRcIik7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5TUEFDRSAmJiBnZXN0dXJlLnBvaW50ZXJzLnNpemUgPT09IDApIHtcbiAgICAgICAgaXNIb2xkaW5nU3BhY2UgPSB0cnVlO1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9XG5cbiAgICAgIGlmICgoZXZlbnQua2V5ID09PSBLRVlTLkcgfHwgZXZlbnQua2V5ID09PSBLRVlTLlMpICYmICFldmVudC5hbHRLZXkgJiYgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiICYmICFzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5rZXkgPT09IEtFWVMuRyAmJiAoaGFzQmFja2dyb3VuZCh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSkgfHwgc2VsZWN0ZWRFbGVtZW50cy5zb21lKGVsZW1lbnQgPT4gaGFzQmFja2dyb3VuZChlbGVtZW50LnR5cGUpKSkpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIG9wZW5Qb3B1cDogXCJlbGVtZW50QmFja2dyb3VuZFwiXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLlMpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIG9wZW5Qb3B1cDogXCJlbGVtZW50U3Ryb2tlXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQua2V5ID09PSBLRVlTLksgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgICB0aGlzLnNldEFjdGl2ZVRvb2woe1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2V0QWN0aXZlVG9vbCh7XG4gICAgICAgICAgICB0eXBlOiBcImxhc2VyXCJcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmIChldmVudC5rZXkgPT09IEtFWVMuQkFDS1NQQUNFIHx8IGV2ZW50LmtleSA9PT0gS0VZUy5ERUxFVEUpKSB7XG4gICAgICAgIGpvdGFpU3RvcmUuc2V0KGFjdGl2ZUNvbmZpcm1EaWFsb2dBdG9tLCBcImNsZWFyQ2FudmFzXCIpO1xuICAgICAgfSAvLyBleWUgZHJvcHBlclxuICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gICAgICBjb25zdCBsb3dlckNhc2VkID0gZXZlbnQua2V5LnRvTG9jYWxlTG93ZXJDYXNlKCk7XG4gICAgICBjb25zdCBpc1BpY2tpbmdTdHJva2UgPSBsb3dlckNhc2VkID09PSBLRVlTLlMgJiYgZXZlbnQuc2hpZnRLZXk7XG4gICAgICBjb25zdCBpc1BpY2tpbmdCYWNrZ3JvdW5kID0gZXZlbnQua2V5ID09PSBLRVlTLkkgfHwgbG93ZXJDYXNlZCA9PT0gS0VZUy5HICYmIGV2ZW50LnNoaWZ0S2V5O1xuXG4gICAgICBpZiAoaXNQaWNraW5nU3Ryb2tlIHx8IGlzUGlja2luZ0JhY2tncm91bmQpIHtcbiAgICAgICAgdGhpcy5vcGVuRXllRHJvcHBlcih7XG4gICAgICAgICAgdHlwZTogaXNQaWNraW5nU3Ryb2tlID8gXCJzdHJva2VcIiA6IFwiYmFja2dyb3VuZFwiXG4gICAgICAgIH0pO1xuICAgICAgfSAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgfSk7XG4gICAgdGhpcy5vbldoZWVsID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIC8vIHByZXZlbnQgYnJvd3NlciBwaW5jaCB6b29tIG9uIERPTSBlbGVtZW50c1xuICAgICAgaWYgKCEoZXZlbnQudGFyZ2V0IGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQpICYmIGV2ZW50LmN0cmxLZXkpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLm9uS2V5VXAgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gS0VZUy5TUEFDRSkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlzSG9sZGluZ1NwYWNlID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUuaXNCaW5kaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBpc0JpbmRpbmdFbmFibGVkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNBcnJvd0tleShldmVudC5rZXkpKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICAgIGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgPyBiaW5kT3JVbmJpbmRTZWxlY3RlZEVsZW1lbnRzKHNlbGVjdGVkRWxlbWVudHMpIDogdW5iaW5kTGluZWFyRWxlbWVudHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuc2V0QWN0aXZlVG9vbCA9IHRvb2wgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBuZXh0QWN0aXZlVG9vbCA9IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwgdG9vbCk7XG5cbiAgICAgIGlmIChuZXh0QWN0aXZlVG9vbC50eXBlID09PSBcImhhbmRcIikge1xuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICB9IGVsc2UgaWYgKCFpc0hvbGRpbmdTcGFjZSkge1xuICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzVG9vbEljb24oZG9jdW1lbnQuYWN0aXZlRWxlbWVudCkpIHtcbiAgICAgICAgdGhpcy5mb2N1c0NvbnRhaW5lcigpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzTGluZWFyRWxlbWVudFR5cGUobmV4dEFjdGl2ZVRvb2wudHlwZSkpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSA9PT0gXCJpbWFnZVwiKSB7XG4gICAgICAgIHRoaXMub25JbWFnZUFjdGlvbih7XG4gICAgICAgICAgaW5zZXJ0T25DYW52YXNEaXJlY3RseTogKF9hID0gdG9vbC50eXBlID09PSBcImltYWdlXCIgJiYgdG9vbC5pbnNlcnRPbkNhbnZhc0RpcmVjdGx5KSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICBjb25zdCBjb21tb25SZXNldHMgPSB7XG4gICAgICAgICAgc25hcExpbmVzOiBwcmV2U3RhdGUuc25hcExpbmVzLmxlbmd0aCA/IFtdIDogcHJldlN0YXRlLnNuYXBMaW5lcyxcbiAgICAgICAgICBvcmlnaW5TbmFwT2Zmc2V0OiBudWxsLFxuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAobmV4dEFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2wsXG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCBwcmV2U3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHByZXZTdGF0ZSksXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIG11bHRpRWxlbWVudDogbnVsbFxuICAgICAgICAgIH0pLCBjb21tb25SZXNldHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUpLCB7XG4gICAgICAgICAgYWN0aXZlVG9vbDogbmV4dEFjdGl2ZVRvb2xcbiAgICAgICAgfSksIGNvbW1vblJlc2V0cyk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5zZXRPcGVuRGlhbG9nID0gZGlhbG9nVHlwZSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgb3BlbkRpYWxvZzogZGlhbG9nVHlwZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMuc2V0Q3Vyc29yID0gY3Vyc29yID0+IHtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBjdXJzb3IpO1xuICAgIH07XG5cbiAgICB0aGlzLnJlc2V0Q3Vyc29yID0gKCkgPT4ge1xuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiByZXR1cm5zIHdoZXRoZXIgdXNlciBpcyBtYWtpbmcgYSBnZXN0dXJlIHdpdGggPj0gMiBmaW5nZXJzIChwb2ludHMpXG4gICAgICogb24gbyB0b3VjaCBzY3JlZW4gKG5vdCBvbiBhIHRyYWNrcGFkKS4gQ3VycmVudGx5IG9ubHkgcmVsYXRlcyB0byBEYXJ3aW5cbiAgICAgKiAoaU9TL2lQYWRPUyxNYWNPUyksIGJ1dCBtYXkgd29yayBvbiBvdGhlciBkZXZpY2VzIGluIHRoZSBmdXR1cmUgaWZcbiAgICAgKiBHZXN0dXJlRXZlbnQgaXMgc3RhbmRhcmRpemVkLlxuICAgICAqL1xuXG5cbiAgICB0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSA9ICgpID0+IHtcbiAgICAgIC8vIHdlIGRvbid0IHdhbnQgdG8gZGVzZWxlY3Qgd2hlbiB1c2luZyB0cmFja3BhZCwgYW5kIG11bHRpLXBvaW50IGdlc3R1cmVzXG4gICAgICAvLyBvbmx5IHdvcmsgb24gdG91Y2ggc2NyZWVucywgc28gY2hlY2tpbmcgZm9yID49IHBvaW50ZXJzIG1lYW5zIHdlJ3JlIG9uIGFcbiAgICAgIC8vIHRvdWNoc2NyZWVuXG4gICAgICByZXR1cm4gZ2VzdHVyZS5wb2ludGVycy5zaXplID49IDI7XG4gICAgfTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuXG4gICAgdGhpcy5vbkdlc3R1cmVTdGFydCA9IHdpdGhCYXRjaGVkVXBkYXRlcyhldmVudCA9PiB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyB3ZSBvbmx5IHdhbnQgdG8gZGVzZWxlY3Qgb24gdG91Y2ggc2NyZWVucyBiZWNhdXNlIHVzZXIgbWF5IGhhdmUgc2VsZWN0ZWRcbiAgICAgIC8vIGVsZW1lbnRzIGJ5IG1pc3Rha2Ugd2hpbGUgem9vbWluZ1xuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICB9KTsgLy8gZmlyZXMgb25seSBvbiBTYWZhcmlcblxuICAgIHRoaXMub25HZXN0dXJlQ2hhbmdlID0gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIG9uR2VzdHVyZUNoYW5nZSBvbmx5IGhhcyB6b29tIGZhY3RvciBidXQgbm90IHRoZSBjZW50ZXIuXG4gICAgICAvLyBJZiB3ZSdyZSBvbiBpUGFkIG9yIGlQaG9uZSwgdGhlbiB3ZSByZWNvZ25pemUgbXVsdGktdG91Y2ggYW5kIHdpbGxcbiAgICAgIC8vIHpvb20gaW4gYXQgdGhlIHJpZ2h0IGxvY2F0aW9uIGluIHRoZSB0b3VjaG1vdmUgaGFuZGxlclxuICAgICAgLy8gKGhhbmRsZUNhbnZhc1BvaW50ZXJNb3ZlKS5cbiAgICAgIC8vXG4gICAgICAvLyBPbiBNYWNib29rIHRyYWNrcGFkLCB3ZSBkb24ndCBoYXZlIHRob3NlIGV2ZW50cyBzbyB3aWxsIHpvb20gaW4gYXQgdGhlXG4gICAgICAvLyBjdXJyZW50IGxvY2F0aW9uIGluc3RlYWQuXG4gICAgICAvL1xuICAgICAgLy8gQXMgc3VjaCwgYmFpbCBmcm9tIHRoaXMgaGFuZGxlciBvbiB0b3VjaCBkZXZpY2VzLlxuXG4gICAgICBpZiAodGhpcy5pc1RvdWNoU2NyZWVuTXVsdGlUb3VjaEdlc3R1cmUoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGluaXRpYWxTY2FsZSA9IGdlc3R1cmUuaW5pdGlhbFNjYWxlO1xuXG4gICAgICBpZiAoaW5pdGlhbFNjYWxlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbih7fSwgZ2V0U3RhdGVGb3Jab29tKHtcbiAgICAgICAgICB2aWV3cG9ydFg6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueCxcbiAgICAgICAgICB2aWV3cG9ydFk6IHRoaXMubGFzdFZpZXdwb3J0UG9zaXRpb24ueSxcbiAgICAgICAgICBuZXh0Wm9vbTogZ2V0Tm9ybWFsaXplZFpvb20oaW5pdGlhbFNjYWxlICogZXZlbnQuc2NhbGUpXG4gICAgICAgIH0sIHN0YXRlKSkpO1xuICAgICAgfVxuICAgIH0pOyAvLyBmaXJlcyBvbmx5IG9uIFNhZmFyaVxuXG4gICAgdGhpcy5vbkdlc3R1cmVFbmQgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gcmVzZWxlY3QgZWxlbWVudHMgb25seSBvbiB0b3VjaCBzY3JlZW5zIChzZWUgb25HZXN0dXJlU3RhcnQpXG5cbiAgICAgIGlmICh0aGlzLmlzVG91Y2hTY3JlZW5NdWx0aVRvdWNoR2VzdHVyZSgpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB7fSxcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHRoaXMuc3RhdGUucHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHMsIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLmluaXRpYWxTY2FsZSA9IG51bGw7XG4gICAgfSk7XG5cbiAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcgPSAoe1xuICAgICAgc2NlbmVYLFxuICAgICAgc2NlbmVZLFxuICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXIgPSB0cnVlLFxuICAgICAgY29udGFpbmVyXG4gICAgfSkgPT4ge1xuICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgbGV0IHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IGZhbHNlO1xuICAgICAgbGV0IHBhcmVudENlbnRlclBvc2l0aW9uID0gaW5zZXJ0QXRQYXJlbnRDZW50ZXIgJiYgdGhpcy5nZXRUZXh0V3lzaXd5Z1NuYXBwZWRUb0NlbnRlclBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZLCB0aGlzLnN0YXRlLCBjb250YWluZXIpO1xuXG4gICAgICBpZiAoY29udGFpbmVyICYmIHBhcmVudENlbnRlclBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lciA9IGdldEJvdW5kVGV4dEVsZW1lbnQoY29udGFpbmVyKTtcblxuICAgICAgICBpZiAoIWJvdW5kVGV4dEVsZW1lbnRUb0NvbnRhaW5lcikge1xuICAgICAgICAgIHNob3VsZEJpbmRUb0NvbnRhaW5lciA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgbGV0IGV4aXN0aW5nVGV4dEVsZW1lbnQgPSBudWxsO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIGlmIChpc1RleHRFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHNlbGVjdGVkRWxlbWVudHNbMF07XG4gICAgICAgIH0gZWxzZSBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IGdldEJvdW5kVGV4dEVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZXhpc3RpbmdUZXh0RWxlbWVudCA9IHRoaXMuZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZm9udEZhbWlseSA9IChleGlzdGluZ1RleHRFbGVtZW50ID09PSBudWxsIHx8IGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4aXN0aW5nVGV4dEVsZW1lbnQuZm9udEZhbWlseSkgfHwgdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRGYW1pbHk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gKGV4aXN0aW5nVGV4dEVsZW1lbnQgPT09IG51bGwgfHwgZXhpc3RpbmdUZXh0RWxlbWVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogZXhpc3RpbmdUZXh0RWxlbWVudC5saW5lSGVpZ2h0KSB8fCBnZXREZWZhdWx0TGluZUhlaWdodChmb250RmFtaWx5KTtcbiAgICAgIGNvbnN0IGZvbnRTaXplID0gdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZvbnRTaXplO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQgJiYgc2hvdWxkQmluZFRvQ29udGFpbmVyICYmIGNvbnRhaW5lciAmJiAhaXNBcnJvd0VsZW1lbnQoY29udGFpbmVyKSkge1xuICAgICAgICBjb25zdCBmb250U3RyaW5nID0ge1xuICAgICAgICAgIGZvbnRTaXplLFxuICAgICAgICAgIGZvbnRGYW1pbHlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgbWluV2lkdGggPSBnZXRBcHByb3hNaW5MaW5lV2lkdGgoZ2V0Rm9udFN0cmluZyhmb250U3RyaW5nKSwgbGluZUhlaWdodCk7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IGdldEFwcHJveE1pbkxpbmVIZWlnaHQoZm9udFNpemUsIGxpbmVIZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdIZWlnaHQgPSBNYXRoLm1heChjb250YWluZXIuaGVpZ2h0LCBtaW5IZWlnaHQpO1xuICAgICAgICBjb25zdCBuZXdXaWR0aCA9IE1hdGgubWF4KGNvbnRhaW5lci53aWR0aCwgbWluV2lkdGgpO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGNvbnRhaW5lciwge1xuICAgICAgICAgIGhlaWdodDogbmV3SGVpZ2h0LFxuICAgICAgICAgIHdpZHRoOiBuZXdXaWR0aFxuICAgICAgICB9KTtcbiAgICAgICAgc2NlbmVYID0gY29udGFpbmVyLnggKyBuZXdXaWR0aCAvIDI7XG4gICAgICAgIHNjZW5lWSA9IGNvbnRhaW5lci55ICsgbmV3SGVpZ2h0IC8gMjtcblxuICAgICAgICBpZiAocGFyZW50Q2VudGVyUG9zaXRpb24pIHtcbiAgICAgICAgICBwYXJlbnRDZW50ZXJQb3NpdGlvbiA9IHRoaXMuZ2V0VGV4dFd5c2l3eWdTbmFwcGVkVG9DZW50ZXJQb3NpdGlvbihzY2VuZVgsIHNjZW5lWSwgdGhpcy5zdGF0ZSwgY29udGFpbmVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBleGlzdGluZ1RleHRFbGVtZW50ID8gZXhpc3RpbmdUZXh0RWxlbWVudCA6IG5ld1RleHRFbGVtZW50KHtcbiAgICAgICAgeDogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWCA6IHNjZW5lWCxcbiAgICAgICAgeTogcGFyZW50Q2VudGVyUG9zaXRpb24gPyBwYXJlbnRDZW50ZXJQb3NpdGlvbi5lbGVtZW50Q2VudGVyWSA6IHNjZW5lWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIHRleHQ6IFwiXCIsXG4gICAgICAgIGZvbnRTaXplLFxuICAgICAgICBmb250RmFtaWx5LFxuICAgICAgICB0ZXh0QWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gXCJjZW50ZXJcIiA6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1UZXh0QWxpZ24sXG4gICAgICAgIHZlcnRpY2FsQWxpZ246IHBhcmVudENlbnRlclBvc2l0aW9uID8gVkVSVElDQUxfQUxJR04uTUlERExFIDogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgICAgY29udGFpbmVySWQ6IHNob3VsZEJpbmRUb0NvbnRhaW5lciA/IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5pZCA6IHVuZGVmaW5lZCxcbiAgICAgICAgZ3JvdXBJZHM6IChfYSA9IGNvbnRhaW5lciA9PT0gbnVsbCB8fCBjb250YWluZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNvbnRhaW5lci5ncm91cElkcykgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogW10sXG4gICAgICAgIGxpbmVIZWlnaHQsXG4gICAgICAgIGFuZ2xlOiAoX2IgPSBjb250YWluZXIgPT09IG51bGwgfHwgY29udGFpbmVyID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjb250YWluZXIuYW5nbGUpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDAsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfSk7XG5cbiAgICAgIGlmICghZXhpc3RpbmdUZXh0RWxlbWVudCAmJiBzaG91bGRCaW5kVG9Db250YWluZXIgJiYgY29udGFpbmVyKSB7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoY29udGFpbmVyLCB7XG4gICAgICAgICAgYm91bmRFbGVtZW50czogKGNvbnRhaW5lci5ib3VuZEVsZW1lbnRzIHx8IFtdKS5jb25jYXQoe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICBpZDogZWxlbWVudC5pZFxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nVGV4dEVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGNvbnRhaW5lciAmJiBzaG91bGRCaW5kVG9Db250YWluZXIpIHtcbiAgICAgICAgICBjb25zdCBjb250YWluZXJJbmRleCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudEluZGV4KGNvbnRhaW5lci5pZCk7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50QXRJbmRleChlbGVtZW50LCBjb250YWluZXJJbmRleCArIDEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChlbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnRcbiAgICAgIH0pO1xuICAgICAgdGhpcy5oYW5kbGVUZXh0V3lzaXd5ZyhlbGVtZW50LCB7XG4gICAgICAgIGlzRXhpc3RpbmdFbGVtZW50OiAhIWV4aXN0aW5nVGV4dEVsZW1lbnRcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrID0gZXZlbnQgPT4ge1xuICAgICAgLy8gY2FzZTogZG91YmxlLWNsaWNraW5nIHdpdGggYXJyb3cvbGluZSB0b29sIHNlbGVjdGVkIHdvdWxkIGJvdGggY3JlYXRlXG4gICAgICAvLyB0ZXh0IGFuZCBlbnRlciBtdWx0aUVsZW1lbnQgbW9kZVxuICAgICAgaWYgKHRoaXMuc3RhdGUubXVsdGlFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gd2Ugc2hvdWxkIG9ubHkgYmUgYWJsZSB0byBkb3VibGUgY2xpY2sgd2hlbiBtb2RlIGlzIHNlbGVjdGlvblxuXG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQoc2VsZWN0ZWRFbGVtZW50c1swXSkpIHtcbiAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdICYmICghdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCAhPT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogbmV3IExpbmVhckVsZW1lbnRFZGl0b3Ioc2VsZWN0ZWRFbGVtZW50c1swXSwgdGhpcy5zY2VuZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCA9PT0gc2VsZWN0ZWRFbGVtZW50c1swXS5pZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcbiAgICAgIGxldCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkR3JvdXBJZHMgPSBnZXRTZWxlY3RlZEdyb3VwSWRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRHcm91cElkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRHcm91cElkID0gaGl0RWxlbWVudCAmJiBnZXRTZWxlY3RlZEdyb3VwSWRGb3JFbGVtZW50KGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUuc2VsZWN0ZWRHcm91cElkcyk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkR3JvdXBJZCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogc2VsZWN0ZWRHcm91cElkLFxuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG5cbiAgICAgIGlmICghZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gJiYgIXRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZKTtcblxuICAgICAgICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZToge1xuICAgICAgICAgICAgICBlbGVtZW50OiBoaXRFbGVtZW50LFxuICAgICAgICAgICAgICBzdGF0ZTogXCJhY3RpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgc2NlbmVYLCBzY2VuZVkpO1xuXG4gICAgICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgICAgICBpZiAoaGFzQm91bmRUZXh0RWxlbWVudChjb250YWluZXIpIHx8ICFpc1RyYW5zcGFyZW50KGNvbnRhaW5lci5iYWNrZ3JvdW5kQ29sb3IpIHx8IGlzSGl0dGluZ0VsZW1lbnROb3RDb25zaWRlcmluZ0JvdW5kaW5nQm94KGNvbnRhaW5lciwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgW3NjZW5lWCwgc2NlbmVZXSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG1pZFBvaW50ID0gZ2V0Q29udGFpbmVyQ2VudGVyKGNvbnRhaW5lciwgdGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICBzY2VuZVggPSBtaWRQb2ludC54O1xuICAgICAgICAgICAgc2NlbmVZID0gbWlkUG9pbnQueTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICBzY2VuZVksXG4gICAgICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXI6ICFldmVudC5hbHRLZXksXG4gICAgICAgICAgY29udGFpbmVyXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbiA9IChzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpID0+IHtcbiAgICAgIC8vIFJldmVyc2luZyBzbyB3ZSB0cmF2ZXJzZSB0aGUgZWxlbWVudHMgaW4gZGVjcmVhc2luZyBvcmRlclxuICAgICAgLy8gb2Ygei1pbmRleFxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLnNsaWNlKCkucmV2ZXJzZSgpO1xuICAgICAgbGV0IGhpdEVsZW1lbnRJbmRleCA9IEluZmluaXR5O1xuICAgICAgcmV0dXJuIGVsZW1lbnRzLmZpbmQoKGVsZW1lbnQsIGluZGV4KSA9PiB7XG4gICAgICAgIGlmIChoaXRFbGVtZW50ICYmIGVsZW1lbnQuaWQgPT09IGhpdEVsZW1lbnQuaWQpIHtcbiAgICAgICAgICBoaXRFbGVtZW50SW5kZXggPSBpbmRleDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGVtZW50LmxpbmsgJiYgaW5kZXggPD0gaGl0RWxlbWVudEluZGV4ICYmIGlzUG9pbnRIaXR0aW5nTGluayhlbGVtZW50LCB0aGlzLnN0YXRlLCBbc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55XSwgdGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlKTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICB0aGlzLnJlZGlyZWN0VG9MaW5rID0gKGV2ZW50LCBpc1RvdWNoU2NyZWVuKSA9PiB7XG4gICAgICBjb25zdCBkcmFnZ2VkRGlzdGFuY2UgPSBkaXN0YW5jZTJkKHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQuY2xpZW50WCwgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudC5jbGllbnRZLCB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC5jbGllbnRYLCB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC5jbGllbnRZKTtcblxuICAgICAgaWYgKCF0aGlzLmhpdExpbmtFbGVtZW50IHx8IC8vIEZvciB0b3VjaCBzY3JlZW4gYWxsb3cgZHJhZ2dpbmcgdGhyZXNob2xkIGVsc2Ugc3RyaWN0IGNoZWNrXG4gICAgICBpc1RvdWNoU2NyZWVuICYmIGRyYWdnZWREaXN0YW5jZSA+IERSQUdHSU5HX1RIUkVTSE9MRCB8fCAhaXNUb3VjaFNjcmVlbiAmJiBkcmFnZ2VkRGlzdGFuY2UgIT09IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBsYXN0UG9pbnRlckRvd25Db29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHModGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlckRvd25IaXR0aW5nTGlua0ljb24gPSBpc1BvaW50SGl0dGluZ0xpbmsodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSwgW2xhc3RQb2ludGVyRG93bkNvb3Jkcy54LCBsYXN0UG9pbnRlckRvd25Db29yZHMueV0sIHRoaXMuZGV2aWNlLmVkaXRvci5pc01vYmlsZSk7XG4gICAgICBjb25zdCBsYXN0UG9pbnRlclVwQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IGxhc3RQb2ludGVyVXBIaXR0aW5nTGlua0ljb24gPSBpc1BvaW50SGl0dGluZ0xpbmsodGhpcy5oaXRMaW5rRWxlbWVudCwgdGhpcy5zdGF0ZSwgW2xhc3RQb2ludGVyVXBDb29yZHMueCwgbGFzdFBvaW50ZXJVcENvb3Jkcy55XSwgdGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlKTtcblxuICAgICAgaWYgKGxhc3RQb2ludGVyRG93bkhpdHRpbmdMaW5rSWNvbiAmJiBsYXN0UG9pbnRlclVwSGl0dGluZ0xpbmtJY29uKSB7XG4gICAgICAgIGxldCB1cmwgPSB0aGlzLmhpdExpbmtFbGVtZW50Lmxpbms7XG5cbiAgICAgICAgaWYgKHVybCkge1xuICAgICAgICAgIHVybCA9IG5vcm1hbGl6ZUxpbmsodXJsKTtcbiAgICAgICAgICBsZXQgY3VzdG9tRXZlbnQ7XG5cbiAgICAgICAgICBpZiAodGhpcy5wcm9wcy5vbkxpbmtPcGVuKSB7XG4gICAgICAgICAgICBjdXN0b21FdmVudCA9IHdyYXBFdmVudChFVkVOVC5FWENBTElEUkFXX0xJTkssIGV2ZW50Lm5hdGl2ZUV2ZW50KTtcbiAgICAgICAgICAgIHRoaXMucHJvcHMub25MaW5rT3BlbihPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuaGl0TGlua0VsZW1lbnQpLCB7XG4gICAgICAgICAgICAgIGxpbms6IHVybFxuICAgICAgICAgICAgfSksIGN1c3RvbUV2ZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIShjdXN0b21FdmVudCA9PT0gbnVsbCB8fCBjdXN0b21FdmVudCA9PT0gdm9pZCAwID8gdm9pZCAwIDogY3VzdG9tRXZlbnQuZGVmYXVsdFByZXZlbnRlZCkpIHtcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldCA9IGlzTG9jYWxMaW5rKHVybCkgPyBcIl9zZWxmXCIgOiBcIl9ibGFua1wiO1xuICAgICAgICAgICAgY29uc3QgbmV3V2luZG93ID0gd2luZG93Lm9wZW4odW5kZWZpbmVkLCB0YXJnZXQpOyAvLyBodHRwczovL21hdGhpYXNieW5lbnMuZ2l0aHViLmlvL3JlbC1ub29wZW5lci9cblxuICAgICAgICAgICAgaWYgKG5ld1dpbmRvdykge1xuICAgICAgICAgICAgICBuZXdXaW5kb3cub3BlbmVyID0gbnVsbDtcbiAgICAgICAgICAgICAgbmV3V2luZG93LmxvY2F0aW9uID0gdXJsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzID0gc2NlbmVDb29yZHMgPT4ge1xuICAgICAgY29uc3QgZnJhbWVzID0gdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRnJhbWVzKCkuZmlsdGVyKGZyYW1lID0+IGlzQ3Vyc29ySW5GcmFtZShzY2VuZUNvb3JkcywgZnJhbWUpKTtcbiAgICAgIHJldHVybiBmcmFtZXMubGVuZ3RoID8gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXSA6IG51bGw7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnNhdmVQb2ludGVyKGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFksIHRoaXMuc3RhdGUuY3Vyc29yQnV0dG9uKTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuaGFzKGV2ZW50LnBvaW50ZXJJZCkpIHtcbiAgICAgICAgZ2VzdHVyZS5wb2ludGVycy5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICAgICAgeDogZXZlbnQuY2xpZW50WCxcbiAgICAgICAgICB5OiBldmVudC5jbGllbnRZXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbml0aWFsU2NhbGUgPSBnZXN0dXJlLmluaXRpYWxTY2FsZTtcblxuICAgICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMiAmJiBnZXN0dXJlLmxhc3RDZW50ZXIgJiYgaW5pdGlhbFNjYWxlICYmIGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlKSB7XG4gICAgICAgIGNvbnN0IGNlbnRlciA9IGdldENlbnRlcihnZXN0dXJlLnBvaW50ZXJzKTtcbiAgICAgICAgY29uc3QgZGVsdGFYID0gY2VudGVyLnggLSBnZXN0dXJlLmxhc3RDZW50ZXIueDtcbiAgICAgICAgY29uc3QgZGVsdGFZID0gY2VudGVyLnkgLSBnZXN0dXJlLmxhc3RDZW50ZXIueTtcbiAgICAgICAgZ2VzdHVyZS5sYXN0Q2VudGVyID0gY2VudGVyO1xuICAgICAgICBjb25zdCBkaXN0YW5jZSA9IGdldERpc3RhbmNlKEFycmF5LmZyb20oZ2VzdHVyZS5wb2ludGVycy52YWx1ZXMoKSkpO1xuICAgICAgICBjb25zdCBzY2FsZUZhY3RvciA9IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImZyZWVkcmF3XCIgJiYgdGhpcy5zdGF0ZS5wZW5Nb2RlID8gMSA6IGRpc3RhbmNlIC8gZ2VzdHVyZS5pbml0aWFsRGlzdGFuY2U7XG4gICAgICAgIGNvbnN0IG5leHRab29tID0gc2NhbGVGYWN0b3IgPyBnZXROb3JtYWxpemVkWm9vbShpbml0aWFsU2NhbGUgKiBzY2FsZUZhY3RvcikgOiB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoc3RhdGUgPT4ge1xuICAgICAgICAgIGNvbnN0IHpvb21TdGF0ZSA9IGdldFN0YXRlRm9yWm9vbSh7XG4gICAgICAgICAgICB2aWV3cG9ydFg6IGNlbnRlci54LFxuICAgICAgICAgICAgdmlld3BvcnRZOiBjZW50ZXIueSxcbiAgICAgICAgICAgIG5leHRab29tXG4gICAgICAgICAgfSwgc3RhdGUpO1xuICAgICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgICAgIHpvb206IHpvb21TdGF0ZS56b29tLFxuICAgICAgICAgICAgc2Nyb2xsWDogem9vbVN0YXRlLnNjcm9sbFggKyBkZWx0YVggLyBuZXh0Wm9vbSxcbiAgICAgICAgICAgIHNjcm9sbFk6IHpvb21TdGF0ZS5zY3JvbGxZICsgZGVsdGFZIC8gbmV4dFpvb20sXG4gICAgICAgICAgICBzaG91bGRDYWNoZUlnbm9yZVpvb206IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUubGFzdENlbnRlciA9IGdlc3R1cmUuaW5pdGlhbERpc3RhbmNlID0gZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNIb2xkaW5nU3BhY2UgfHwgaXNQYW5uaW5nIHx8IGlzRHJhZ2dpbmdTY3JvbGxCYXIgfHwgaXNIYW5kVG9vbEFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzID0gaXNPdmVyU2Nyb2xsQmFycyhjdXJyZW50U2Nyb2xsQmFycywgZXZlbnQuY2xpZW50WCAtIHRoaXMuc3RhdGUub2Zmc2V0TGVmdCwgZXZlbnQuY2xpZW50WSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wKTtcbiAgICAgIGNvbnN0IGlzT3ZlclNjcm9sbEJhciA9IGlzUG9pbnRlck92ZXJTY3JvbGxCYXJzLmlzT3ZlckVpdGhlcjtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgaWYgKGlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyhldmVudCwgdGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lUG9pbnRlclgsXG4gICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgIH0gPSBzY2VuZVBvaW50ZXI7XG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQgJiYgaXNBY3RpdmVUb29sTm9uTGluZWFyU25hcHBhYmxlKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgb3JpZ2luT2Zmc2V0LFxuICAgICAgICAgIHNuYXBMaW5lc1xuICAgICAgICB9ID0gZ2V0U25hcExpbmVzQXRQb2ludGVyKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICB4OiBzY2VuZVBvaW50ZXJYLFxuICAgICAgICAgIHk6IHNjZW5lUG9pbnRlcllcbiAgICAgICAgfSwgZXZlbnQpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXMsXG4gICAgICAgICAgb3JpZ2luU25hcE9mZnNldDogb3JpZ2luT2Zmc2V0XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmICghdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICBjb25zdCBlZGl0aW5nTGluZWFyRWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlck1vdmUoZXZlbnQsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclksIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChlZGl0aW5nTGluZWFyRWxlbWVudCAmJiBlZGl0aW5nTGluZWFyRWxlbWVudCAhPT0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIC8vIFNpbmNlIHdlIGFyZSByZWFkaW5nIGZyb20gcHJldmlvdXMgc3RhdGUgd2hpY2ggaXMgbm90IHBvc3NpYmxlIHdpdGhcbiAgICAgICAgICAvLyBhdXRvbWF0aWMgYmF0Y2hpbmcgaW4gUmVhY3QgMTggaGVuY2UgdXNpbmcgZmx1c2ggc3luYyB0byBzeW5jaHJvbm91c2x5XG4gICAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZS4gQ2hlY2sgaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzU1MDggZm9yIG1vcmUgZGV0YWlscy5cbiAgICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgoZWRpdGluZ0xpbmVhckVsZW1lbnQgPT09IG51bGwgfHwgZWRpdGluZ0xpbmVhckVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGVkaXRpbmdMaW5lYXJFbGVtZW50Lmxhc3RVbmNvbW1pdHRlZFBvaW50KSAhPSBudWxsKSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3Ioc2NlbmVQb2ludGVyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBjYXVzZXMgc3RhY2sgb3ZlcmZsb3cgaWYgbm90IHN5bmNcbiAgICAgICAgICBmbHVzaFN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnRUeXBlKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlKSkge1xuICAgICAgICAvLyBIb3ZlcmluZyB3aXRoIGEgc2VsZWN0ZWQgdG9vbCBvciBjcmVhdGluZyBuZXcgbGluZWFyIGVsZW1lbnQgdmlhIGNsaWNrXG4gICAgICAgIC8vIGFuZCBwb2ludFxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50XG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuXG4gICAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgZmFsc2UpKSB7XG4gICAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyhkcmFnZ2luZ0VsZW1lbnQsIFtzY2VuZVBvaW50ZXJdLCB0aGlzLnN0YXRlLnN0YXJ0Qm91bmRFbGVtZW50KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdBdEN1cnNvcihzY2VuZVBvaW50ZXIpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgbXVsdGlFbGVtZW50XG4gICAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgeDogcngsXG4gICAgICAgICAgeTogcnlcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHBvaW50cyxcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnRcbiAgICAgICAgfSA9IG11bHRpRWxlbWVudDtcbiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXTtcbiAgICAgICAgc2V0Q3Vyc29yRm9yU2hhcGUodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKGxhc3RQb2ludCA9PT0gbGFzdENvbW1pdHRlZFBvaW50KSB7XG4gICAgICAgICAgLy8gaWYgd2UgaGF2ZW4ndCB5ZXQgY3JlYXRlZCBhIHRlbXAgcG9pbnQgYW5kIHdlJ3JlIGJleW9uZCBjb21taXQtem9uZVxuICAgICAgICAgIC8vIHRocmVzaG9sZCwgYWRkIGEgcG9pbnRcbiAgICAgICAgICBpZiAoZGlzdGFuY2UyZChzY2VuZVBvaW50ZXJYIC0gcngsIHNjZW5lUG9pbnRlclkgLSByeSwgbGFzdFBvaW50WzBdLCBsYXN0UG9pbnRbMV0pID49IExJTkVfQ09ORklSTV9USFJFU0hPTEQpIHtcbiAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW3NjZW5lUG9pbnRlclggLSByeCwgc2NlbmVQb2ludGVyWSAtIHJ5XV1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuUE9JTlRFUik7IC8vIGluIHRoaXMgYnJhbmNoLCB3ZSdyZSBpbnNpZGUgdGhlIGNvbW1pdCB6b25lLCBhbmQgbm8gdW5jb21taXR0ZWRcbiAgICAgICAgICAgIC8vIHBvaW50IGV4aXN0cy4gVGh1cyBkbyBub3RoaW5nIChkb24ndCBhZGQvcmVtb3ZlIHBvaW50cykuXG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHBvaW50cy5sZW5ndGggPiAyICYmIGxhc3RDb21taXR0ZWRQb2ludCAmJiBkaXN0YW5jZTJkKHNjZW5lUG9pbnRlclggLSByeCwgc2NlbmVQb2ludGVyWSAtIHJ5LCBsYXN0Q29tbWl0dGVkUG9pbnRbMF0sIGxhc3RDb21taXR0ZWRQb2ludFsxXSkgPCBMSU5FX0NPTkZJUk1fVEhSRVNIT0xEKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgIG11dGF0ZUVsZW1lbnQobXVsdGlFbGVtZW50LCB7XG4gICAgICAgICAgICBwb2ludHM6IHBvaW50cy5zbGljZSgwLCAtMSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKTtcbiAgICAgICAgICBjb25zdCBbbGFzdENvbW1pdHRlZFgsIGxhc3RDb21taXR0ZWRZXSA9IChfYSA9IG11bHRpRWxlbWVudCA9PT0gbnVsbCB8fCBtdWx0aUVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG11bHRpRWxlbWVudC5sYXN0Q29tbWl0dGVkUG9pbnQpICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IFswLCAwXTtcbiAgICAgICAgICBsZXQgZHhGcm9tTGFzdENvbW1pdHRlZCA9IGdyaWRYIC0gcnggLSBsYXN0Q29tbWl0dGVkWDtcbiAgICAgICAgICBsZXQgZHlGcm9tTGFzdENvbW1pdHRlZCA9IGdyaWRZIC0gcnkgLSBsYXN0Q29tbWl0dGVkWTtcblxuICAgICAgICAgIGlmIChzaG91bGRSb3RhdGVXaXRoRGlzY3JldGVBbmdsZShldmVudCkpIHtcbiAgICAgICAgICAgICh7XG4gICAgICAgICAgICAgIHdpZHRoOiBkeEZyb21MYXN0Q29tbWl0dGVkLFxuICAgICAgICAgICAgICBoZWlnaHQ6IGR5RnJvbUxhc3RDb21taXR0ZWRcbiAgICAgICAgICAgIH0gPSBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUoIC8vIGFjdHVhbCBjb29yZGluYXRlIG9mIHRoZSBsYXN0IGNvbW1pdHRlZCBwb2ludFxuICAgICAgICAgICAgbGFzdENvbW1pdHRlZFggKyByeCwgbGFzdENvbW1pdHRlZFkgKyByeSwgLy8gY3Vyc29yLWdyaWQgY29vcmRpbmF0ZVxuICAgICAgICAgICAgZ3JpZFgsIGdyaWRZKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGlzUGF0aEFMb29wKHBvaW50cywgdGhpcy5zdGF0ZS56b29tLnZhbHVlKSkge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgIH0gLy8gdXBkYXRlIGxhc3QgdW5jb21taXR0ZWQgcG9pbnRcblxuXG4gICAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cy5zbGljZSgwLCAtMSksIFtsYXN0Q29tbWl0dGVkWCArIGR4RnJvbUxhc3RDb21taXR0ZWQsIGxhc3RDb21taXR0ZWRZICsgZHlGcm9tTGFzdENvbW1pdHRlZF1dXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhhc0Rlc2VsZWN0ZWRCdXR0b24gPSBCb29sZWFuKGV2ZW50LmJ1dHRvbnMpO1xuXG4gICAgICBpZiAoaGFzRGVzZWxlY3RlZEJ1dHRvbiB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJ0ZXh0XCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwiZXJhc2VyXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCk7XG4gICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgIWlzT3ZlclNjcm9sbEJhciAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICBjb25zdCBlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgPSBnZXRFbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUoZWxlbWVudHMsIHRoaXMuc3RhdGUsIHNjZW5lUG9pbnRlclgsIHNjZW5lUG9pbnRlclksIHRoaXMuc3RhdGUuem9vbSwgZXZlbnQucG9pbnRlclR5cGUpO1xuXG4gICAgICAgIGlmIChlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUgJiYgZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlLnRyYW5zZm9ybUhhbmRsZVR5cGUpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgZ2V0Q3Vyc29yRm9yUmVzaXppbmdFbGVtZW50KGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSkpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDEgJiYgIWlzT3ZlclNjcm9sbEJhcikge1xuICAgICAgICBjb25zdCB0cmFuc2Zvcm1IYW5kbGVUeXBlID0gZ2V0VHJhbnNmb3JtSGFuZGxlVHlwZUZyb21Db29yZHMoZ2V0Q29tbW9uQm91bmRzKHNlbGVjdGVkRWxlbWVudHMpLCBzY2VuZVBvaW50ZXJYLCBzY2VuZVBvaW50ZXJZLCB0aGlzLnN0YXRlLnpvb20sIGV2ZW50LnBvaW50ZXJUeXBlKTtcblxuICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZSkge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBnZXRDdXJzb3JGb3JSZXNpemluZ0VsZW1lbnQoe1xuICAgICAgICAgICAgdHJhbnNmb3JtSGFuZGxlVHlwZVxuICAgICAgICAgIH0pKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgIHRoaXMuaGl0TGlua0VsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbihzY2VuZVBvaW50ZXIsIGhpdEVsZW1lbnQpO1xuXG4gICAgICBpZiAoaXNFcmFzZXJBY3RpdmUodGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5oaXRMaW5rRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5oaXRMaW5rRWxlbWVudC5pZF0pIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICBzaG93SHlwZXJsaW5rVG9vbHRpcCh0aGlzLmhpdExpbmtFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGhpZGVIeXBlcmxpbmtUb29saXAoKTtcblxuICAgICAgICBpZiAoaGl0RWxlbWVudCAmJiAoaGl0RWxlbWVudC5saW5rIHx8IGlzRW1iZWRkYWJsZUVsZW1lbnQoaGl0RWxlbWVudCkpICYmIHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2hpdEVsZW1lbnQuaWRdICYmICF0aGlzLnN0YXRlLmNvbnRleHRNZW51ICYmICF0aGlzLnN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBcImluZm9cIlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInRleHRcIikge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBpc1RleHRFbGVtZW50KGhpdEVsZW1lbnQpID8gQ1VSU09SX1RZUEUuVEVYVCA6IENVUlNPUl9UWVBFLkNST1NTSEFJUik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQik7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNPdmVyU2Nyb2xsQmFyKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkFVVE8pO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVIb3ZlclNlbGVjdGVkTGluZWFyRWxlbWVudCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSk7XG4gICAgICAgIH0gZWxzZSBpZiAoIC8vIGlmIHVzaW5nIGNtZC9jdHJsLCB3ZSdyZSBub3QgZHJhZ2dpbmdcbiAgICAgICAgIWV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgICAgaWYgKChoaXRFbGVtZW50IHx8IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMoc2NlbmVQb2ludGVyLCBzZWxlY3RlZEVsZW1lbnRzKSkgJiYgIShoaXRFbGVtZW50ID09PSBudWxsIHx8IGhpdEVsZW1lbnQgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGhpdEVsZW1lbnQubG9ja2VkKSkge1xuICAgICAgICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSAmJiB0aGlzLmlzRW1iZWRkYWJsZUNlbnRlcihoaXRFbGVtZW50LCBldmVudCwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiB7XG4gICAgICAgICAgICAgICAgICBlbGVtZW50OiBoaXRFbGVtZW50LFxuICAgICAgICAgICAgICAgICAgc3RhdGU6IFwiaG92ZXJcIlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuTU9WRSk7XG5cbiAgICAgICAgICAgICAgaWYgKCgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiaG92ZXJcIikge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUVyYXNlciA9IChldmVudCwgcG9pbnRlckRvd25TdGF0ZSwgc2NlbmVQb2ludGVyKSA9PiB7XG4gICAgICBjb25zdCB1cGRhdGVFbGVtZW50SWRzID0gZWxlbWVudHMgPT4ge1xuICAgICAgICBlbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIGlmIChlbGVtZW50LmxvY2tlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlkc1RvVXBkYXRlLnB1c2goZWxlbWVudC5pZCk7XG5cbiAgICAgICAgICBpZiAoZXZlbnQuYWx0S2V5KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGVtZW50LmlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlbWVudC5pZF0uZXJhc2UgPSBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKCFwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdKSB7XG4gICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZW1lbnQuaWRdID0ge1xuICAgICAgICAgICAgICBlcmFzZTogdHJ1ZSxcbiAgICAgICAgICAgICAgb3BhY2l0eTogZWxlbWVudC5vcGFjaXR5XG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9O1xuXG4gICAgICBjb25zdCBpZHNUb1VwZGF0ZSA9IFtdO1xuICAgICAgY29uc3QgZGlzdGFuY2UgPSBkaXN0YW5jZTJkKHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy54LCBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSwgc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcbiAgICAgIGNvbnN0IHRocmVzaG9sZCA9IDEwIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgICAgY29uc3QgcG9pbnQgPSBPYmplY3QuYXNzaWduKHt9LCBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMpO1xuICAgICAgbGV0IHNhbXBsaW5nSW50ZXJ2YWwgPSAwO1xuXG4gICAgICB3aGlsZSAoc2FtcGxpbmdJbnRlcnZhbCA8PSBkaXN0YW5jZSkge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHBvaW50LngsIHBvaW50LnkpO1xuICAgICAgICB1cGRhdGVFbGVtZW50SWRzKGhpdEVsZW1lbnRzKTsgLy8gRXhpdCBzaW5jZSB3ZSByZWFjaGVkIGN1cnJlbnQgcG9pbnRcblxuICAgICAgICBpZiAoc2FtcGxpbmdJbnRlcnZhbCA9PT0gZGlzdGFuY2UpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfSAvLyBDYWxjdWxhdGUgbmV4dCBwb2ludCBpbiB0aGUgbGluZSBhdCBhIGRpc3RhbmNlIG9mIHNhbXBsaW5nIGludGVydmFsXG5cblxuICAgICAgICBzYW1wbGluZ0ludGVydmFsID0gTWF0aC5taW4oc2FtcGxpbmdJbnRlcnZhbCArIHRocmVzaG9sZCwgZGlzdGFuY2UpO1xuICAgICAgICBjb25zdCBkaXN0YW5jZVJhdGlvID0gc2FtcGxpbmdJbnRlcnZhbCAvIGRpc3RhbmNlO1xuICAgICAgICBjb25zdCBuZXh0WCA9ICgxIC0gZGlzdGFuY2VSYXRpbykgKiBwb2ludC54ICsgZGlzdGFuY2VSYXRpbyAqIHNjZW5lUG9pbnRlci54O1xuICAgICAgICBjb25zdCBuZXh0WSA9ICgxIC0gZGlzdGFuY2VSYXRpbykgKiBwb2ludC55ICsgZGlzdGFuY2VSYXRpbyAqIHNjZW5lUG9pbnRlci55O1xuICAgICAgICBwb2ludC54ID0gbmV4dFg7XG4gICAgICAgIHBvaW50LnkgPSBuZXh0WTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGUgPT4ge1xuICAgICAgICBjb25zdCBpZCA9IGlzQm91bmRUb0NvbnRhaW5lcihlbGUpICYmIGlkc1RvVXBkYXRlLmluY2x1ZGVzKGVsZS5jb250YWluZXJJZCkgPyBlbGUuY29udGFpbmVySWQgOiBlbGUuaWQ7XG5cbiAgICAgICAgaWYgKGlkc1RvVXBkYXRlLmluY2x1ZGVzKGlkKSkge1xuICAgICAgICAgIGlmIChldmVudC5hbHRLZXkpIHtcbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2lkXS5lcmFzZSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbaWRdLm9wYWNpdHlcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgICAgb3BhY2l0eTogRUxFTUVOVF9SRUFEWV9UT19FUkFTRV9PUEFDSVRZXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHNjZW5lUG9pbnRlci54O1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBzY2VuZVBvaW50ZXIueTtcbiAgICB9OyAvLyBzZXQgdG91Y2ggbW92aW5nIGZvciBtb2JpbGUgY29udGV4dCBtZW51XG5cblxuICAgIHRoaXMuaGFuZGxlVG91Y2hNb3ZlID0gZXZlbnQgPT4ge1xuICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gdHJ1ZTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyRG93biA9IGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2I7IC8vIHNpbmNlIGNvbnRleHRNZW51IG9wdGlvbnMgYXJlIHBvdGVudGlhbGx5IGV2YWx1YXRlZCBvbiBlYWNoIHJlbmRlcixcbiAgICAgIC8vIGFuZCBhbiBjb250ZXh0TWVudSBhY3Rpb24gbWF5IGRlcGVuZCBvbiBzZWxlY3Rpb24gc3RhdGUsIHdlIG11c3RcbiAgICAgIC8vIGNsb3NlIHRoZSBjb250ZXh0TWVudSBiZWZvcmUgd2UgdXBkYXRlIHRoZSBzZWxlY3Rpb24gb24gcG9pbnRlckRvd25cbiAgICAgIC8vIChlLmcuIHJlc2V0dGluZyBzZWxlY3Rpb24pXG5cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuY29udGV4dE1lbnUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgY29udGV4dE1lbnU6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNuYXBMaW5lcykge1xuICAgICAgICB0aGlzLnNldEFwcFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXM6IFtdXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnVwZGF0ZUdlc3R1cmVPblBvaW50ZXJEb3duKGV2ZW50KTsgLy8gaWYgZHJhZ2dpbmcgZWxlbWVudCBpcyBmcmVlZHJhdyBhbmQgYW5vdGhlciBwb2ludGVyZG93biBldmVudCBvY2N1cnNcbiAgICAgIC8vIGEgc2Vjb25kIGZpbmdlciBpcyBvbiB0aGUgc2NyZWVuXG4gICAgICAvLyBkaXNjYXJkIHRoZSBmcmVlZHJhdyBlbGVtZW50IGlmIGl0IGlzIHZlcnkgc2hvcnQgYmVjYXVzZSBpdCBpcyBsaWtlbHlcbiAgICAgIC8vIGp1c3QgYSBzcGlrZSwgb3RoZXJ3aXNlIGZpbmFsaXplIHRoZSBmcmVlZHJhdyBlbGVtZW50IHdoZW4gdGhlIHNlY29uZFxuICAgICAgLy8gZmluZ2VyIGlzIGxpZnRlZFxuXG4gICAgICBpZiAoZXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIiAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudCAmJiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50O1xuICAgICAgICB0aGlzLnVwZGF0ZVNjZW5lKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZWxlbWVudC5wb2ludHMubGVuZ3RoIDwgMTAgPyB7XG4gICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkuZmlsdGVyKGVsID0+IGVsLmlkICE9PSBlbGVtZW50LmlkKVxuICAgICAgICB9IDoge30pLCB7XG4gICAgICAgICAgYXBwU3RhdGU6IHtcbiAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgICBzdWdnZXN0ZWRCaW5kaW5nczogW10sXG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5rZXlzKHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5maWx0ZXIoa2V5ID0+IGtleSAhPT0gZWxlbWVudC5pZCkucmVkdWNlKChvYmosIGtleSkgPT4ge1xuICAgICAgICAgICAgICBvYmpba2V5XSA9IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW2tleV07XG4gICAgICAgICAgICAgIHJldHVybiBvYmo7XG4gICAgICAgICAgICB9LCB7fSksIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gcmVtb3ZlIGFueSBhY3RpdmUgc2VsZWN0aW9uIHdoZW4gd2Ugc3RhcnQgdG8gaW50ZXJhY3Qgd2l0aCBjYW52YXNcbiAgICAgIC8vIChtYWlubHksIHdlIGNhcmUgYWJvdXQgcmVtb3Zpbmcgc2VsZWN0aW9uIG91dHNpZGUgdGhlIGNvbXBvbmVudCB3aGljaFxuICAgICAgLy8gIHdvdWxkIHByZXZlbnQgb3VyIGNvcHkgaGFuZGxpbmcgb3RoZXJ3aXNlKVxuXG5cbiAgICAgIGNvbnN0IHNlbGVjdGlvbiA9IGRvY3VtZW50LmdldFNlbGVjdGlvbigpO1xuXG4gICAgICBpZiAoc2VsZWN0aW9uID09PSBudWxsIHx8IHNlbGVjdGlvbiA9PT0gdm9pZCAwID8gdm9pZCAwIDogc2VsZWN0aW9uLmFuY2hvck5vZGUpIHtcbiAgICAgICAgc2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlT3BlbkNvbnRleHRNZW51QWZ0ZXJQb2ludGVyRG93bk9uVG91Y2hEZXZpY2VzKGV2ZW50KTtcbiAgICAgIHRoaXMubWF5YmVDbGVhbnVwQWZ0ZXJNaXNzaW5nUG9pbnRlclVwKGV2ZW50KTsgLy9maXJlcyBvbmx5IG9uY2UsIGlmIHBlbiBpcyBkZXRlY3RlZCwgcGVuTW9kZSBpcyBlbmFibGVkXG4gICAgICAvL3RoZSB1c2VyIGNhbiBkaXNhYmxlIHRoaXMgYnkgdG9nZ2xpbmcgdGhlIHBlbk1vZGUgYnV0dG9uXG5cbiAgICAgIGlmICghdGhpcy5zdGF0ZS5wZW5EZXRlY3RlZCAmJiBldmVudC5wb2ludGVyVHlwZSA9PT0gXCJwZW5cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHBlbk1vZGU6IHRydWUsXG4gICAgICAgICAgICBwZW5EZXRlY3RlZDogdHJ1ZVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4gJiYgW1wicGVuXCIsIFwidG91Y2hcIl0uaW5jbHVkZXMoZXZlbnQucG9pbnRlclR5cGUpKSB7XG4gICAgICAgIHRoaXMuZGV2aWNlID0gdXBkYXRlT2JqZWN0KHRoaXMuZGV2aWNlLCB7XG4gICAgICAgICAgaXNUb3VjaFNjcmVlbjogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUGFubmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQgPSBldmVudDsgLy8gd2UgbXVzdCBleGl0IGJlZm9yZSB3ZSBzZXQgYGN1cnNvckJ1dHRvbmAgc3RhdGUgYW5kIGBzYXZlUG9pbnRlcmBcbiAgICAgIC8vIGVsc2UgaXQgd2lsbCBzZW5kIHBvaW50ZXIgc3RhdGUgJiBsYXNlciBwb2ludGVyIGV2ZW50cyBpbiBjb2xsYWIgd2hlblxuICAgICAgLy8gcGFubmluZ1xuXG4gICAgICBpZiAodGhpcy5oYW5kbGVDYW52YXNQYW5Vc2luZ1doZWVsT3JTcGFjZURyYWcoZXZlbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGxhc3RQb2ludGVyRG93bldpdGg6IGV2ZW50LnBvaW50ZXJUeXBlLFxuICAgICAgICBjdXJzb3JCdXR0b246IFwiZG93blwiXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSwgXCJkb3duXCIpOyAvLyBvbmx5IGhhbmRsZSBsZWZ0IG1vdXNlIGJ1dHRvbiBvciB0b3VjaFxuXG4gICAgICBpZiAoZXZlbnQuYnV0dG9uICE9PSBQT0lOVEVSX0JVVFRPTi5NQUlOICYmIGV2ZW50LmJ1dHRvbiAhPT0gUE9JTlRFUl9CVVRUT04uVE9VQ0gpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSAvLyBkb24ndCBzZWxlY3Qgd2hpbGUgcGFubmluZ1xuXG5cbiAgICAgIGlmIChnZXN0dXJlLnBvaW50ZXJzLnNpemUgPiAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gLy8gU3RhdGUgZm9yIHRoZSBkdXJhdGlvbiBvZiBhIHBvaW50ZXIgaW50ZXJhY3Rpb24sIHdoaWNoIHN0YXJ0cyB3aXRoIGFcbiAgICAgIC8vIHBvaW50ZXJEb3duIGV2ZW50LCBlbmRzIHdpdGggYSBwb2ludGVyVXAgZXZlbnQgKG9yIGFub3RoZXIgcG9pbnRlckRvd24pXG5cblxuICAgICAgY29uc3QgcG9pbnRlckRvd25TdGF0ZSA9IHRoaXMuaW5pdGlhbFBvaW50ZXJEb3duU3RhdGUoZXZlbnQpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IGZhbHNlXG4gICAgICB9KTtcblxuICAgICAgaWYgKHRoaXMuaGFuZGxlRHJhZ2dpbmdTY3JvbGxCYXIoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5jbGVhclNlbGVjdGlvbklmTm90VXNpbmdTZWxlY3Rpb24oKTtcbiAgICAgIHRoaXMudXBkYXRlQmluZGluZ0VuYWJsZWRPblBvaW50ZXJNb3ZlKGV2ZW50KTtcblxuICAgICAgaWYgKHRoaXMuaGFuZGxlU2VsZWN0aW9uT25Qb2ludGVyRG93bihldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBhbGxvd09uUG9pbnRlckRvd24gPSAhdGhpcy5zdGF0ZS5wZW5Nb2RlIHx8IGV2ZW50LnBvaW50ZXJUeXBlICE9PSBcInRvdWNoXCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwidGV4dFwiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImltYWdlXCI7XG5cbiAgICAgIGlmICghYWxsb3dPblBvaW50ZXJEb3duKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInRleHRcIikge1xuICAgICAgICB0aGlzLmhhbmRsZVRleHRPblBvaW50ZXJEb3duKGV2ZW50LCBwb2ludGVyRG93blN0YXRlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJhcnJvd1wiIHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxpbmVcIikge1xuICAgICAgICB0aGlzLmhhbmRsZUxpbmVhckVsZW1lbnRPblBvaW50ZXJEb3duKGV2ZW50LCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImltYWdlXCIpIHtcbiAgICAgICAgLy8gcmVzZXQgaW1hZ2UgcHJldmlldyBvbiBwb2ludGVyZG93blxuICAgICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuQ1JPU1NIQUlSKTsgLy8gcmV0cmlldmUgdGhlIGxhdGVzdCBlbGVtZW50IGFzIHRoZSBzdGF0ZSBtYXkgYmUgc3RhbGVcblxuICAgICAgICBjb25zdCBwZW5kaW5nSW1hZ2VFbGVtZW50ID0gdGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQgJiYgdGhpcy5zY2VuZS5nZXRFbGVtZW50KHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkKTtcblxuICAgICAgICBpZiAoIXBlbmRpbmdJbWFnZUVsZW1lbnQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IHBlbmRpbmdJbWFnZUVsZW1lbnQsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IHBlbmRpbmdJbWFnZUVsZW1lbnQsXG4gICAgICAgICAgcGVuZGluZ0ltYWdlRWxlbWVudElkOiBudWxsLFxuICAgICAgICAgIG11bHRpRWxlbWVudDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgbXV0YXRlRWxlbWVudChwZW5kaW5nSW1hZ2VFbGVtZW50LCB7XG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlRnJlZURyYXdFbGVtZW50T25Qb2ludGVyRG93bihldmVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJjdXN0b21cIikge1xuICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICB0aGlzLmNyZWF0ZUZyYW1lRWxlbWVudE9uUG9pbnRlckRvd24ocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyLnN0YXJ0UGF0aChwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCwgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJlcmFzZXJcIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJoYW5kXCIpIHtcbiAgICAgICAgdGhpcy5jcmVhdGVHZW5lcmljRWxlbWVudE9uUG9pbnRlckRvd24odGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICAoX2IgPSAoX2EgPSB0aGlzLnByb3BzKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eub25Qb2ludGVyRG93bikgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbCwgcG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICB0aGlzLm9uUG9pbnRlckRvd25FbWl0dGVyLnRyaWdnZXIodGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlLCBldmVudCk7XG4gICAgICBjb25zdCBvblBvaW50ZXJNb3ZlID0gdGhpcy5vblBvaW50ZXJNb3ZlRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGNvbnN0IG9uUG9pbnRlclVwID0gdGhpcy5vblBvaW50ZXJVcEZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICBjb25zdCBvbktleURvd24gPSB0aGlzLm9uS2V5RG93bkZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSk7XG4gICAgICBjb25zdCBvbktleVVwID0gdGhpcy5vbktleVVwRnJvbVBvaW50ZXJEb3duSGFuZGxlcihwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIGxhc3RQb2ludGVyVXAgPSBvblBvaW50ZXJVcDtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCB8fCB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJsYXNlclwiKSB7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfTU9WRSwgb25Qb2ludGVyTW92ZSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgb25LZXlEb3duKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIG9uS2V5VXApO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSA9IG9uUG9pbnRlck1vdmU7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25VcCA9IG9uUG9pbnRlclVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5VXAgPSBvbktleVVwO1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uS2V5RG93biA9IG9uS2V5RG93bjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAgPSBldmVudCA9PiB7XG4gICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICB0aGlzLnJlbW92ZVBvaW50ZXIoZXZlbnQpO1xuICAgICAgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQgPSBldmVudDtcbiAgICAgIGNvbnN0IHNjZW5lUG9pbnRlciA9IHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3Jkcyh7XG4gICAgICAgIGNsaWVudFg6IGV2ZW50LmNsaWVudFgsXG4gICAgICAgIGNsaWVudFk6IGV2ZW50LmNsaWVudFlcbiAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgY2xpY2tsZW5ndGggPSBldmVudC50aW1lU3RhbXAgLSAoKF9iID0gKF9hID0gdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRpbWVTdGFtcCkgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogMCk7XG5cbiAgICAgIGlmICh0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGUgJiYgY2xpY2tsZW5ndGggPCAzMDApIHtcbiAgICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KTtcblxuICAgICAgICBpZiAoaXNFbWJlZGRhYmxlRWxlbWVudChoaXRFbGVtZW50KSAmJiB0aGlzLmlzRW1iZWRkYWJsZUNlbnRlcihoaXRFbGVtZW50LCBldmVudCwgc2NlbmVQb2ludGVyLngsIHNjZW5lUG9pbnRlci55KSkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKGhpdEVsZW1lbnQpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5kZXZpY2UuaXNUb3VjaFNjcmVlbikge1xuICAgICAgICBjb25zdCBoaXRFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnkpO1xuICAgICAgICB0aGlzLmhpdExpbmtFbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50TGlua0F0UG9zaXRpb24oc2NlbmVQb2ludGVyLCBoaXRFbGVtZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGl0TGlua0VsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuaGl0TGlua0VsZW1lbnQuaWRdKSB7XG4gICAgICAgIGlmIChjbGlja2xlbmd0aCA8IDMwMCAmJiB0aGlzLmhpdExpbmtFbGVtZW50LnR5cGUgPT09IFwiZW1iZWRkYWJsZVwiICYmICFpc1BvaW50SGl0dGluZ0xpbmtJY29uKHRoaXMuaGl0TGlua0VsZW1lbnQsIHRoaXMuc3RhdGUsIFtzY2VuZVBvaW50ZXIueCwgc2NlbmVQb2ludGVyLnldKSkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlRW1iZWRkYWJsZUNlbnRlckNsaWNrKHRoaXMuaGl0TGlua0VsZW1lbnQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMucmVkaXJlY3RUb0xpbmsoZXZlbnQsIHRoaXMuZGV2aWNlLmlzVG91Y2hTY3JlZW4pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGwsXG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7fVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZU9wZW5Db250ZXh0TWVudUFmdGVyUG9pbnRlckRvd25PblRvdWNoRGV2aWNlcyA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIGRlYWwgd2l0aCBvcGVuaW5nIGNvbnRleHQgbWVudSBvbiB0b3VjaCBkZXZpY2VzXG4gICAgICBpZiAoZXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIikge1xuICAgICAgICBpbnZhbGlkYXRlQ29udGV4dE1lbnUgPSBmYWxzZTtcblxuICAgICAgICBpZiAodG91Y2hUaW1lb3V0KSB7XG4gICAgICAgICAgLy8gSWYgdGhlcmUncyBhbHJlYWR5IGEgdG91Y2hUaW1lb3V0LCB0aGlzIG1lYW5zIHRoYXQgdGhlcmUncyBhbm90aGVyXG4gICAgICAgICAgLy8gdG91Y2ggZG93biBhbmQgd2UgYXJlIGRvaW5nIGFub3RoZXIgdG91Y2gsIHNvIHdlIHNob3VsZG4ndCBvcGVuIHRoZVxuICAgICAgICAgIC8vIGNvbnRleHQgbWVudS5cbiAgICAgICAgICBpbnZhbGlkYXRlQ29udGV4dE1lbnUgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIG9wZW4gdGhlIGNvbnRleHQgbWVudSB3aXRoIHRoZSBmaXJzdCB0b3VjaCdzIGNsaWVudFggYW5kIGNsaWVudFlcbiAgICAgICAgICAvLyBpZiB0aGUgdG91Y2ggaXMgbm90IG1vdmluZ1xuICAgICAgICAgIHRvdWNoVGltZW91dCA9IHdpbmRvdy5zZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHRvdWNoVGltZW91dCA9IDA7XG5cbiAgICAgICAgICAgIGlmICghaW52YWxpZGF0ZUNvbnRleHRNZW51KSB7XG4gICAgICAgICAgICAgIHRoaXMuaGFuZGxlQ2FudmFzQ29udGV4dE1lbnUoZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIFRPVUNIX0NUWF9NRU5VX1RJTUVPVVQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMucmVzZXRDb250ZXh0TWVudVRpbWVyID0gKCkgPT4ge1xuICAgICAgY2xlYXJUaW1lb3V0KHRvdWNoVGltZW91dCk7XG4gICAgICB0b3VjaFRpbWVvdXQgPSAwO1xuICAgICAgaW52YWxpZGF0ZUNvbnRleHRNZW51ID0gZmFsc2U7XG4gICAgfTsgLy8gUmV0dXJucyB3aGV0aGVyIHRoZSBldmVudCBpcyBhIHBhbm5pbmdcblxuXG4gICAgdGhpcy5oYW5kbGVDYW52YXNQYW5Vc2luZ1doZWVsT3JTcGFjZURyYWcgPSBldmVudCA9PiB7XG4gICAgICBpZiAoIShnZXN0dXJlLnBvaW50ZXJzLnNpemUgPD0gMSAmJiAoZXZlbnQuYnV0dG9uID09PSBQT0lOVEVSX0JVVFRPTi5XSEVFTCB8fCBldmVudC5idXR0b24gPT09IFBPSU5URVJfQlVUVE9OLk1BSU4gJiYgaXNIb2xkaW5nU3BhY2UgfHwgaXNIYW5kVG9vbEFjdGl2ZSh0aGlzLnN0YXRlKSB8fCB0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkpIHx8IGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpc1Bhbm5pbmcgPSB0cnVlO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGxldCBuZXh0UGFzdGVQcmV2ZW50ZWQgPSBmYWxzZTtcbiAgICAgIGNvbnN0IGlzTGludXggPSAvTGludXgvLnRlc3Qod2luZG93Lm5hdmlnYXRvci5wbGF0Zm9ybSk7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgQ1VSU09SX1RZUEUuR1JBQkJJTkcpO1xuICAgICAgbGV0IHtcbiAgICAgICAgY2xpZW50WDogbGFzdFgsXG4gICAgICAgIGNsaWVudFk6IGxhc3RZXG4gICAgICB9ID0gZXZlbnQ7XG4gICAgICBjb25zdCBvblBvaW50ZXJNb3ZlID0gd2l0aEJhdGNoZWRVcGRhdGVzVGhyb3R0bGVkKGV2ZW50ID0+IHtcbiAgICAgICAgY29uc3QgZGVsdGFYID0gbGFzdFggLSBldmVudC5jbGllbnRYO1xuICAgICAgICBjb25zdCBkZWx0YVkgPSBsYXN0WSAtIGV2ZW50LmNsaWVudFk7XG4gICAgICAgIGxhc3RYID0gZXZlbnQuY2xpZW50WDtcbiAgICAgICAgbGFzdFkgPSBldmVudC5jbGllbnRZO1xuICAgICAgICAvKlxuICAgICAgICAgKiBQcmV2ZW50IHBhc3RlIGV2ZW50IGlmIHdlIG1vdmUgd2hpbGUgbWlkZGxlIGNsaWNraW5nIG9uIExpbnV4LlxuICAgICAgICAgKiBTZWUgaXNzdWUgIzEzODMuXG4gICAgICAgICAqL1xuXG4gICAgICAgIGlmIChpc0xpbnV4ICYmICFuZXh0UGFzdGVQcmV2ZW50ZWQgJiYgKE1hdGguYWJzKGRlbHRhWCkgPiAxIHx8IE1hdGguYWJzKGRlbHRhWSkgPiAxKSkge1xuICAgICAgICAgIG5leHRQYXN0ZVByZXZlbnRlZCA9IHRydWU7XG4gICAgICAgICAgLyogUHJldmVudCB0aGUgbmV4dCBwYXN0ZSBldmVudCAqL1xuXG4gICAgICAgICAgY29uc3QgcHJldmVudE5leHRQYXN0ZSA9IGV2ZW50ID0+IHtcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QQVNURSwgcHJldmVudE5leHRQYXN0ZSk7XG4gICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICB9O1xuICAgICAgICAgIC8qXG4gICAgICAgICAgICogUmVlbmFibGUgbmV4dCBwYXN0ZSBpbiBjYXNlIG9mIGRpc2FibGVkIG1pZGRsZSBjbGljayBwYXN0ZSBmb3JcbiAgICAgICAgICAgKiBhbnkgcmVhc29uOlxuICAgICAgICAgICAqIC0gcmlnaHQgY2xpY2sgcGFzdGVcbiAgICAgICAgICAgKiAtIGVtcHR5IGNsaXBib2FyZFxuICAgICAgICAgICAqL1xuXG5cbiAgICAgICAgICBjb25zdCBlbmFibGVOZXh0UGFzdGUgPSAoKSA9PiB7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCBwcmV2ZW50TmV4dFBhc3RlKTtcbiAgICAgICAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgZW5hYmxlTmV4dFBhc3RlKTtcbiAgICAgICAgICAgIH0sIDEwMCk7XG4gICAgICAgICAgfTtcblxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QQVNURSwgcHJldmVudE5leHRQYXN0ZSk7XG4gICAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgZW5hYmxlTmV4dFBhc3RlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgICBzY3JvbGxYOiB0aGlzLnN0YXRlLnNjcm9sbFggLSBkZWx0YVggLyB0aGlzLnN0YXRlLnpvb20udmFsdWUsXG4gICAgICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZIC0gZGVsdGFZIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgICBjb25zdCB0ZWFyZG93biA9IHdpdGhCYXRjaGVkVXBkYXRlcyhsYXN0UG9pbnRlclVwID0gKCkgPT4ge1xuICAgICAgICBsYXN0UG9pbnRlclVwID0gbnVsbDtcbiAgICAgICAgaXNQYW5uaW5nID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKCFpc0hvbGRpbmdTcGFjZSkge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLkdSQUIpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIlxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUpO1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0ZWFyZG93bik7XG4gICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkJMVVIsIHRlYXJkb3duKTtcbiAgICAgICAgb25Qb2ludGVyTW92ZS5mbHVzaCgpO1xuICAgICAgfSk7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0ZWFyZG93bik7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX01PVkUsIG9uUG9pbnRlck1vdmUsIHtcbiAgICAgICAgcGFzc2l2ZTogdHJ1ZVxuICAgICAgfSk7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0ZWFyZG93bik7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9O1xuXG4gICAgdGhpcy5jbGVhclNlbGVjdGlvbklmTm90VXNpbmdTZWxlY3Rpb24gPSAoKSA9PiB7XG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHdoZXRoZXIgdGhlIHBvaW50ZXIgZXZlbnQgaGFzIGJlZW4gY29tcGxldGVseSBoYW5kbGVkXG4gICAgICovXG5cblxuICAgIHRoaXMuaGFuZGxlU2VsZWN0aW9uT25Qb2ludGVyRG93biA9IChldmVudCwgcG9pbnRlckRvd25TdGF0ZSkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpO1xuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIGNvbnN0IGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZSA9IGdldEVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZShlbGVtZW50cywgdGhpcy5zdGF0ZSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG5cbiAgICAgICAgICBpZiAoZWxlbWVudFdpdGhUcmFuc2Zvcm1IYW5kbGVUeXBlICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICByZXNpemluZ0VsZW1lbnQ6IGVsZW1lbnRXaXRoVHJhbnNmb3JtSGFuZGxlVHlwZS5lbGVtZW50XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmhhbmRsZVR5cGUgPSBlbGVtZW50V2l0aFRyYW5zZm9ybUhhbmRsZVR5cGUudHJhbnNmb3JtSGFuZGxlVHlwZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSA9IGdldFRyYW5zZm9ybUhhbmRsZVR5cGVGcm9tQ29vcmRzKGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgdGhpcy5zdGF0ZS56b29tLCBldmVudC5wb2ludGVyVHlwZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZSkge1xuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmlzUmVzaXppbmcgPSB0cnVlO1xuICAgICAgICAgIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldCA9IHR1cGxlVG9Db29ycyhnZXRSZXNpemVPZmZzZXRYWShwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlLCBzZWxlY3RlZEVsZW1lbnRzLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSk7XG5cbiAgICAgICAgICBpZiAoc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGggPT09IDEgJiYgaXNMaW5lYXJFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pICYmIHNlbGVjdGVkRWxlbWVudHNbMF0ucG9pbnRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuYXJyb3dEaXJlY3Rpb24gPSBnZXRSZXNpemVBcnJvd0RpcmVjdGlvbihwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5oYW5kbGVUeXBlLCBzZWxlY3RlZEVsZW1lbnRzWzBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICBjb25zdCBsaW5lYXJFbGVtZW50RWRpdG9yID0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudDtcbiAgICAgICAgICAgIGNvbnN0IHJldCA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlckRvd24oZXZlbnQsIHRoaXMuc3RhdGUsIHRoaXMuaGlzdG9yeSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4sIGxpbmVhckVsZW1lbnRFZGl0b3IpO1xuXG4gICAgICAgICAgICBpZiAocmV0LmhpdEVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCA9IHJldC5oaXRFbGVtZW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAocmV0LmxpbmVhckVsZW1lbnRFZGl0b3IpIHtcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiByZXQubGluZWFyRWxlbWVudEVkaXRvclxuICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQ6IHJldC5saW5lYXJFbGVtZW50RWRpdG9yXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHJldC5kaWRBZGRQb2ludCkge1xuICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIGhpdEVsZW1lbnQgbWF5IGFscmVhZHkgYmUgc2V0IGFib3ZlLCBzbyBjaGVjayBmaXJzdFxuXG5cbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50ID0gKF9hID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbihwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KTtcblxuICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50KSB7XG4gICAgICAgICAgICAvLyBFYXJseSByZXR1cm4gaWYgcG9pbnRlciBpcyBoaXR0aW5nIGxpbmsgaWNvblxuICAgICAgICAgICAgY29uc3QgaGl0TGlua0VsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRMaW5rQXRQb3NpdGlvbih7XG4gICAgICAgICAgICAgIHg6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsXG4gICAgICAgICAgICAgIHk6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnlcbiAgICAgICAgICAgIH0sIHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpO1xuXG4gICAgICAgICAgICBpZiAoaGl0TGlua0VsZW1lbnQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gLy8gRm9yIG92ZXJsYXBwZWQgZWxlbWVudHMgb25lIHBvc2l0aW9uIG1heSBoaXRcbiAgICAgICAgICAvLyBtdWx0aXBsZSBlbGVtZW50c1xuXG5cbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC5hbGxIaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkpO1xuICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuICAgICAgICAgIGNvbnN0IHNvbWVIaXRFbGVtZW50SXNTZWxlY3RlZCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmFsbEhpdEVsZW1lbnRzLnNvbWUoZWxlbWVudCA9PiB0aGlzLmlzQVNlbGVjdGVkRWxlbWVudChlbGVtZW50KSk7XG5cbiAgICAgICAgICBpZiAoKGhpdEVsZW1lbnQgPT09IG51bGwgfHwgIXNvbWVIaXRFbGVtZW50SXNTZWxlY3RlZCkgJiYgIWV2ZW50LnNoaWZ0S2V5ICYmICFwb2ludGVyRG93blN0YXRlLmhpdC5oYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cykge1xuICAgICAgICAgICAgdGhpcy5jbGVhclNlbGVjdGlvbihoaXRFbGVtZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICAgIFt0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZF06IHRydWVcbiAgICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICAgIH0pOyAvLyBJZiB3ZSBjbGljayBvbiBzb21ldGhpbmdcbiAgICAgICAgICB9IGVsc2UgaWYgKGhpdEVsZW1lbnQgIT0gbnVsbCkge1xuICAgICAgICAgICAgLy8gb24gQ01EL0NUUkwsIGRyaWxsIGRvd24gdG8gaGl0IGVsZW1lbnQgcmVnYXJkbGVzcyBvZiBncm91cHMgZXRjLlxuICAgICAgICAgICAgaWYgKGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdKSB7XG4gICAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF0pIHtcbiAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgZWRpdEdyb3VwRm9yU2VsZWN0ZWRFbGVtZW50KHByZXZTdGF0ZSwgaGl0RWxlbWVudCkpLCB7XG4gICAgICAgICAgICAgICAgcHJldmlvdXNTZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgIH0pKTsgLy8gbWFyayBhcyBub3QgY29tcGxldGVseSBoYW5kbGVkIHNvIGFzIHRvIGFsbG93IGRyYWdnaW5nIGV0Yy5cblxuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9IC8vIGRlc2VsZWN0IGlmIGl0ZW0gaXMgc2VsZWN0ZWRcbiAgICAgICAgICAgIC8vIGlmIHNoaWZ0IGlzIG5vdCBjbGlja2VkLCB0aGlzIHdpbGwgYWx3YXlzIHJldHVybiB0cnVlXG4gICAgICAgICAgICAvLyBvdGhlcndpc2UsIGl0IHdpbGwgdHJpZ2dlciBzZWxlY3Rpb24gYmFzZWQgb24gY3VycmVudFxuICAgICAgICAgICAgLy8gc3RhdGUgb2YgdGhlIGJveFxuXG5cbiAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF0pIHtcbiAgICAgICAgICAgICAgLy8gaWYgd2UgYXJlIGN1cnJlbnRseSBlZGl0aW5nIGEgZ3JvdXAsIGV4aXRpbmcgZWRpdGluZyBtb2RlIGFuZCBkZXNlbGVjdCB0aGUgZ3JvdXAuXG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkICYmICFpc0VsZW1lbnRJbkdyb3VwKGhpdEVsZW1lbnQsIHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkR3JvdXBJZHM6IHt9LFxuICAgICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGwsXG4gICAgICAgICAgICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0gLy8gQWRkIGhpdCBlbGVtZW50IHRvIHNlbGVjdGlvbi4gQXQgdGhpcyBwb2ludCBpZiB3ZSdyZSBub3QgaG9sZGluZ1xuICAgICAgICAgICAgICAvLyBTSElGVCB0aGUgcHJldmlvdXNseSBzZWxlY3RlZCBlbGVtZW50KHMpIHdlcmUgZGVzZWxlY3RlZCBhYm92ZVxuICAgICAgICAgICAgICAvLyAobWFrZSBzdXJlIHlvdSB1c2Ugc2V0U3RhdGUgdXBkYXRlciB0byB1c2UgbGF0ZXN0IHN0YXRlKVxuICAgICAgICAgICAgICAvLyBXaXRoIHNoaWZ0LXNlbGVjdGlvbiwgd2Ugd2FudCB0byBtYWtlIHN1cmUgdGhhdCBmcmFtZXMgYW5kIHRoZWlyIGNvbnRhaW5pbmdcbiAgICAgICAgICAgICAgLy8gZWxlbWVudHMgYXJlIG5vdCBzZWxlY3RlZCBhdCB0aGUgc2FtZSB0aW1lLlxuXG5cbiAgICAgICAgICAgICAgaWYgKCFzb21lSGl0RWxlbWVudElzU2VsZWN0ZWQgJiYgIXBvaW50ZXJEb3duU3RhdGUuaGl0Lmhhc0hpdENvbW1vbkJvdW5kaW5nQm94T2ZTZWxlY3RlZEVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgICAgICAgW2hpdEVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzbHlTZWxlY3RlZEVsZW1lbnRzID0gW107XG4gICAgICAgICAgICAgICAgICBPYmplY3Qua2V5cyhwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKS5mb3JFYWNoKGlkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudChpZCk7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgJiYgcHJldmlvdXNseVNlbGVjdGVkRWxlbWVudHMucHVzaChlbGVtZW50KTtcbiAgICAgICAgICAgICAgICAgIH0pOyAvLyBpZiBoaXRFbGVtZW50IGlzIGZyYW1lLCBkZXNlbGVjdCBhbGwgb2YgaXRzIGVsZW1lbnRzIGlmIHRoZXkgYXJlIHNlbGVjdGVkXG5cbiAgICAgICAgICAgICAgICAgIGlmIChoaXRFbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIikge1xuICAgICAgICAgICAgICAgICAgICBnZXRGcmFtZUVsZW1lbnRzKHByZXZpb3VzbHlTZWxlY3RlZEVsZW1lbnRzLCBoaXRFbGVtZW50LmlkKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaGl0RWxlbWVudC5mcmFtZUlkKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGlmIGhpdEVsZW1lbnQgaXMgaW4gYSBmcmFtZSBhbmQgaXRzIGZyYW1lIGhhcyBiZWVuIHNlbGVjdGVkXG4gICAgICAgICAgICAgICAgICAgIC8vIGRpc2FibGUgc2VsZWN0aW9uIGZvciB0aGUgZ2l2ZW4gZWxlbWVudFxuICAgICAgICAgICAgICAgICAgICBpZiAobmV4dFNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmZyYW1lSWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGhpdEVsZW1lbnQgaXMgbmVpdGhlciBhIGZyYW1lIG5vciBhbiBlbGVtZW50IGluIGEgZnJhbWVcbiAgICAgICAgICAgICAgICAgICAgLy8gYnV0IHNpbmNlIGhpdEVsZW1lbnQgY291bGQgYmUgaW4gYSBncm91cCB3aXRoIHNvbWUgZnJhbWVzXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgbWVhbnMgc2VsZWN0aW5nIGhpdEVsZW1lbnQgd2lsbCBoYXZlIHRoZSBmcmFtZXMgc2VsZWN0ZWQgYXMgd2VsbFxuICAgICAgICAgICAgICAgICAgICAvLyBiZWNhdXNlIHdlIHdhbnQgdG8ga2VlcCB0aGUgaW52YXJpYW50OlxuICAgICAgICAgICAgICAgICAgICAvLyAtIGZyYW1lcyBhbmQgdGhlaXIgZWxlbWVudHMgYXJlIG5vdCBzZWxlY3RlZCBhdCB0aGUgc2FtZSB0aW1lXG4gICAgICAgICAgICAgICAgICAgIC8vIHdlIGRlc2VsZWN0IGVsZW1lbnRzIGluIHRob3NlIGZyYW1lcyB0aGF0IHdlcmUgcHJldmlvdXNseSBzZWxlY3RlZFxuICAgICAgICAgICAgICAgICAgICBjb25zdCBncm91cElkcyA9IGhpdEVsZW1lbnQuZ3JvdXBJZHM7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZyYW1lc0luR3JvdXBzID0gbmV3IFNldChncm91cElkcy5mbGF0TWFwKGdpZCA9PiBnZXRFbGVtZW50c0luR3JvdXAodGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgZ2lkKSkuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpLm1hcChmcmFtZSA9PiBmcmFtZS5pZCkpO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChmcmFtZXNJbkdyb3Vwcy5zaXplID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgIHByZXZpb3VzbHlTZWxlY3RlZEVsZW1lbnRzLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC5mcmFtZUlkICYmIGZyYW1lc0luR3JvdXBzLmhhcyhlbGVtZW50LmZyYW1lSWQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlc2VsZWN0IGVsZW1lbnQgYW5kIGdyb3VwcyBjb250YWluaW5nIHRoZSBlbGVtZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50Lmdyb3VwSWRzLmZsYXRNYXAoZ2lkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBnaWQpKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzXG4gICAgICAgICAgICAgICAgICB9LCB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBwcmV2U3RhdGUsIHRoaXMpKSwge1xuICAgICAgICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpID8gXCJpbmZvXCIgOiBmYWxzZVxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQud2FzQWRkZWRUb1NlbGVjdGlvbiA9IHRydWU7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWRFbGVtZW50SWRzOiB0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVUZXh0T25Qb2ludGVyRG93biA9IChldmVudCwgcG9pbnRlckRvd25TdGF0ZSkgPT4ge1xuICAgICAgLy8gaWYgd2UncmUgY3VycmVudGx5IHN0aWxsIGVkaXRpbmcgdGV4dCwgY2xpY2tpbmcgb3V0c2lkZVxuICAgICAgLy8gc2hvdWxkIG9ubHkgZmluYWxpemUgaXQsIG5vdCBjcmVhdGUgYW5vdGhlciAoaXJyZXNwZWN0aXZlXG4gICAgICAvLyBvZiBzdGF0ZS5hY3RpdmVUb29sLmxvY2tlZClcbiAgICAgIGlmIChpc1RleHRFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgbGV0IHNjZW5lWCA9IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLng7XG4gICAgICBsZXQgc2NlbmVZID0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLmdldEVsZW1lbnRBdFBvc2l0aW9uKHNjZW5lWCwgc2NlbmVZLCB7XG4gICAgICAgIGluY2x1ZGVCb3VuZFRleHRFbGVtZW50OiB0cnVlXG4gICAgICB9KTsgLy8gRklYTUVcblxuICAgICAgbGV0IGNvbnRhaW5lciA9IGdldFRleHRCaW5kYWJsZUNvbnRhaW5lckF0UG9zaXRpb24odGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgc2NlbmVYLCBzY2VuZVkpO1xuXG4gICAgICBpZiAoaGFzQm91bmRUZXh0RWxlbWVudChlbGVtZW50KSkge1xuICAgICAgICBjb250YWluZXIgPSBlbGVtZW50O1xuICAgICAgICBzY2VuZVggPSBlbGVtZW50LnggKyBlbGVtZW50LndpZHRoIC8gMjtcbiAgICAgICAgc2NlbmVZID0gZWxlbWVudC55ICsgZWxlbWVudC5oZWlnaHQgLyAyO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnN0YXJ0VGV4dEVkaXRpbmcoe1xuICAgICAgICBzY2VuZVgsXG4gICAgICAgIHNjZW5lWSxcbiAgICAgICAgaW5zZXJ0QXRQYXJlbnRDZW50ZXI6ICFldmVudC5hbHRLZXksXG4gICAgICAgIGNvbnRhaW5lclxuICAgICAgfSk7XG4gICAgICByZXNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzKTtcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLmFjdGl2ZVRvb2wubG9ja2VkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUZyZWVEcmF3RWxlbWVudE9uUG9pbnRlckRvd24gPSAoZXZlbnQsIGVsZW1lbnRUeXBlLCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICAvLyBCZWdpbiBhIG1hcmsgY2FwdHVyZS4gVGhpcyBkb2VzIG5vdCBoYXZlIHRvIHVwZGF0ZSBzdGF0ZSB5ZXQuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBudWxsKTtcbiAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBuZXdGcmVlRHJhd0VsZW1lbnQoe1xuICAgICAgICB0eXBlOiBlbGVtZW50VHlwZSxcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZUNvbG9yLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgc3Ryb2tlV2lkdGg6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VXaWR0aCxcbiAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICBvcGFjaXR5OiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtT3BhY2l0eSxcbiAgICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgICBzaW11bGF0ZVByZXNzdXJlOiBldmVudC5wcmVzc3VyZSA9PT0gMC41LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzID0gT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7XG4gICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMobmV4dFNlbGVjdGVkRWxlbWVudElkcywgcHJldlN0YXRlKVxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgICBjb25zdCBwcmVzc3VyZXMgPSBlbGVtZW50LnNpbXVsYXRlUHJlc3N1cmUgPyBlbGVtZW50LnByZXNzdXJlcyA6IFsuLi5lbGVtZW50LnByZXNzdXJlcywgZXZlbnQucHJlc3N1cmVdO1xuICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgIHBvaW50czogW1swLCAwXV0sXG4gICAgICAgIHByZXNzdXJlc1xuICAgICAgfSk7XG4gICAgICBjb25zdCBib3VuZEVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4sIHRoaXMuc2NlbmUpO1xuICAgICAgdGhpcy5zY2VuZS5hZGROZXdFbGVtZW50KGVsZW1lbnQpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IGVsZW1lbnQsXG4gICAgICAgIHN0YXJ0Qm91bmRFbGVtZW50OiBib3VuZEVsZW1lbnQsXG4gICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgfSk7XG4gICAgfTsgLy9jcmVhdGUgcmVjdGFuZ2xlIGVsZW1lbnQgd2l0aCB5b3V0dWJlIHRvcCBsZWZ0IG9uIG5lYXJlc3QgZ3JpZCBwb2ludCB3aWR0aCAvIGhpZ2h0IDY0MC8zNjBcblxuXG4gICAgdGhpcy5pbnNlcnRFbWJlZGRhYmxlRWxlbWVudCA9ICh7XG4gICAgICBzY2VuZVgsXG4gICAgICBzY2VuZVksXG4gICAgICBsaW5rXG4gICAgfSkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChzY2VuZVgsIHNjZW5lWSwgKChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVtLRVlTLkNUUkxfT1JfQ01EXSkgPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBlbWJlZExpbmsgPSBnZXRFbWJlZExpbmsobGluayk7XG5cbiAgICAgIGlmICghZW1iZWRMaW5rKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGVtYmVkTGluay53YXJuaW5nKSB7XG4gICAgICAgIHRoaXMuc2V0VG9hc3Qoe1xuICAgICAgICAgIG1lc3NhZ2U6IGVtYmVkTGluay53YXJuaW5nLFxuICAgICAgICAgIGNsb3NhYmxlOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50ID0gbmV3RW1iZWRkYWJsZUVsZW1lbnQoe1xuICAgICAgICB0eXBlOiBcImVtYmVkZGFibGVcIixcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogXCJ0cmFuc3BhcmVudFwiLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IFwidHJhbnNwYXJlbnRcIixcbiAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICBzdHJva2VXaWR0aDogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVdpZHRoLFxuICAgICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgIHJvdW5kbmVzczogdGhpcy5nZXRDdXJyZW50SXRlbVJvdW5kbmVzcyhcImVtYmVkZGFibGVcIiksXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICB3aWR0aDogZW1iZWRMaW5rLmFzcGVjdFJhdGlvLncsXG4gICAgICAgIGhlaWdodDogZW1iZWRMaW5rLmFzcGVjdFJhdGlvLmgsXG4gICAgICAgIGxpbmssXG4gICAgICAgIHZhbGlkYXRlZDogbnVsbFxuICAgICAgfSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZWxlbWVudF0pO1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfTtcblxuICAgIHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50ID0gKHtcbiAgICAgIHNjZW5lWCxcbiAgICAgIHNjZW5lWVxuICAgIH0pID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQoc2NlbmVYLCBzY2VuZVksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoe1xuICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgeTogZ3JpZFlcbiAgICAgIH0pO1xuICAgICAgY29uc3QgZWxlbWVudCA9IG5ld0ltYWdlRWxlbWVudCh7XG4gICAgICAgIHR5cGU6IFwiaW1hZ2VcIixcbiAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgIHk6IGdyaWRZLFxuICAgICAgICBzdHJva2VDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZUNvbG9yLFxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgICAgc3Ryb2tlV2lkdGg6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VXaWR0aCxcbiAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgICByb3VuZG5lc3M6IG51bGwsXG4gICAgICAgIG9wYWNpdHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1PcGFjaXR5LFxuICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICBmcmFtZUlkOiB0b3BMYXllckZyYW1lID8gdG9wTGF5ZXJGcmFtZS5pZCA6IG51bGxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlTGluZWFyRWxlbWVudE9uUG9pbnRlckRvd24gPSAoZXZlbnQsIGVsZW1lbnRUeXBlLCBwb2ludGVyRG93blN0YXRlKSA9PiB7XG4gICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG11bHRpRWxlbWVudFxuICAgICAgICB9ID0gdGhpcy5zdGF0ZTsgLy8gZmluYWxpemUgaWYgY29tcGxldGluZyBhIGxvb3BcblxuICAgICAgICBpZiAobXVsdGlFbGVtZW50LnR5cGUgPT09IFwibGluZVwiICYmIGlzUGF0aEFMb29wKG11bHRpRWxlbWVudC5wb2ludHMsIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KG11bHRpRWxlbWVudCwge1xuICAgICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50OiBtdWx0aUVsZW1lbnQucG9pbnRzW211bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoIC0gMV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHJ4LFxuICAgICAgICAgIHk6IHJ5LFxuICAgICAgICAgIGxhc3RDb21taXR0ZWRQb2ludFxuICAgICAgICB9ID0gbXVsdGlFbGVtZW50OyAvLyBjbGlja2luZyBpbnNpZGUgY29tbWl0IHpvbmUg4oaSIGZpbmFsaXplIGFycm93XG5cbiAgICAgICAgaWYgKG11bHRpRWxlbWVudC5wb2ludHMubGVuZ3RoID4gMSAmJiBsYXN0Q29tbWl0dGVkUG9pbnQgJiYgZGlzdGFuY2UyZChwb2ludGVyRG93blN0YXRlLm9yaWdpbi54IC0gcngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnkgLSByeSwgbGFzdENvbW1pdHRlZFBvaW50WzBdLCBsYXN0Q29tbWl0dGVkUG9pbnRbMV0pIDwgTElORV9DT05GSVJNX1RIUkVTSE9MRCkge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgW211bHRpRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICB9KSwgcHJldlN0YXRlKVxuICAgICAgICB9KSk7IC8vIGNsaWNraW5nIG91dHNpZGUgY29tbWl0IHpvbmUg4oaSIHVwZGF0ZSByZWZlcmVuY2UgZm9yIGxhc3QgY29tbWl0dGVkXG4gICAgICAgIC8vIHBvaW50XG5cbiAgICAgICAgbXV0YXRlRWxlbWVudChtdWx0aUVsZW1lbnQsIHtcbiAgICAgICAgICBsYXN0Q29tbWl0dGVkUG9pbnQ6IG11bHRpRWxlbWVudC5wb2ludHNbbXVsdGlFbGVtZW50LnBvaW50cy5sZW5ndGggLSAxXVxuICAgICAgICB9KTtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgICB4OiBncmlkWCxcbiAgICAgICAgICB5OiBncmlkWVxuICAgICAgICB9KTtcbiAgICAgICAgLyogSWYgYXJyb3cgaXMgcHJlLWFycm93aGVhZHMsIGl0IHdpbGwgaGF2ZSB1bmRlZmluZWQgZm9yIGJvdGggc3RhcnQgYW5kIGVuZCBhcnJvd2hlYWRzLlxuICAgICAgICBJZiBzbywgd2Ugd2FudCBpdCB0byBiZSBudWxsIGZvciBzdGFydCBhbmQgXCJhcnJvd1wiIGZvciBlbmQuIElmIHRoZSBsaW5lYXIgaXRlbSBpcyBub3RcbiAgICAgICAgYW4gYXJyb3csIHdlIHdhbnQgaXQgdG8gYmUgbnVsbCBmb3IgYm90aC4gT3RoZXJ3aXNlLCB3ZSB3YW50IGl0IHRvIHVzZSB0aGVcbiAgICAgICAgdmFsdWVzIGZyb20gYXBwU3RhdGUuICovXG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGN1cnJlbnRJdGVtU3RhcnRBcnJvd2hlYWQsXG4gICAgICAgICAgY3VycmVudEl0ZW1FbmRBcnJvd2hlYWRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGNvbnN0IFtzdGFydEFycm93aGVhZCwgZW5kQXJyb3doZWFkXSA9IGVsZW1lbnRUeXBlID09PSBcImFycm93XCIgPyBbY3VycmVudEl0ZW1TdGFydEFycm93aGVhZCwgY3VycmVudEl0ZW1FbmRBcnJvd2hlYWRdIDogW251bGwsIG51bGxdO1xuICAgICAgICBjb25zdCBlbGVtZW50ID0gbmV3TGluZWFyRWxlbWVudCh7XG4gICAgICAgICAgdHlwZTogZWxlbWVudFR5cGUsXG4gICAgICAgICAgeDogZ3JpZFgsXG4gICAgICAgICAgeTogZ3JpZFksXG4gICAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1CYWNrZ3JvdW5kQ29sb3IsXG4gICAgICAgICAgZmlsbFN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtRmlsbFN0eWxlLFxuICAgICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgICAgc3Ryb2tlU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VTdHlsZSxcbiAgICAgICAgICByb3VnaG5lc3M6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VnaG5lc3MsXG4gICAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgICAgcm91bmRuZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91bmRuZXNzID09PSBcInJvdW5kXCIgPyB7XG4gICAgICAgICAgICB0eXBlOiBST1VORE5FU1MuUFJPUE9SVElPTkFMX1JBRElVU1xuICAgICAgICAgIH0gOiBudWxsLFxuICAgICAgICAgIHN0YXJ0QXJyb3doZWFkLFxuICAgICAgICAgIGVuZEFycm93aGVhZCxcbiAgICAgICAgICBsb2NrZWQ6IGZhbHNlLFxuICAgICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBwcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKTtcbiAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRFbGVtZW50SWRzLCBwcmV2U3RhdGUpXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgIHBvaW50czogWy4uLmVsZW1lbnQucG9pbnRzLCBbMCwgMF1dXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBib3VuZEVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4sIHRoaXMuc2NlbmUpO1xuICAgICAgICB0aGlzLnNjZW5lLmFkZE5ld0VsZW1lbnQoZWxlbWVudCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBzdGFydEJvdW5kRWxlbWVudDogYm91bmRFbGVtZW50LFxuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5jcmVhdGVHZW5lcmljRWxlbWVudE9uUG9pbnRlckRvd24gPSAoZWxlbWVudFR5cGUsIHBvaW50ZXJEb3duU3RhdGUpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgKChfYSA9IHRoaXMubGFzdFBvaW50ZXJEb3duRXZlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVtLRVlTLkNUUkxfT1JfQ01EXSkgPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyh7XG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWVxuICAgICAgfSk7XG4gICAgICBjb25zdCBiYXNlRWxlbWVudEF0dHJpYnV0ZXMgPSB7XG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtQmFja2dyb3VuZENvbG9yLFxuICAgICAgICBmaWxsU3R5bGU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1GaWxsU3R5bGUsXG4gICAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICAgIHN0cm9rZVN0eWxlOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlU3R5bGUsXG4gICAgICAgIHJvdWdobmVzczogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVJvdWdobmVzcyxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIHJvdW5kbmVzczogdGhpcy5nZXRDdXJyZW50SXRlbVJvdW5kbmVzcyhlbGVtZW50VHlwZSksXG4gICAgICAgIGxvY2tlZDogZmFsc2UsXG4gICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgfTtcbiAgICAgIGxldCBlbGVtZW50O1xuXG4gICAgICBpZiAoZWxlbWVudFR5cGUgPT09IFwiZW1iZWRkYWJsZVwiKSB7XG4gICAgICAgIGVsZW1lbnQgPSBuZXdFbWJlZGRhYmxlRWxlbWVudChPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICB0eXBlOiBcImVtYmVkZGFibGVcIixcbiAgICAgICAgICB2YWxpZGF0ZWQ6IG51bGxcbiAgICAgICAgfSwgYmFzZUVsZW1lbnRBdHRyaWJ1dGVzKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbGVtZW50ID0gbmV3RWxlbWVudChPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICB0eXBlOiBlbGVtZW50VHlwZVxuICAgICAgICB9LCBiYXNlRWxlbWVudEF0dHJpYnV0ZXMpKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGVsZW1lbnQudHlwZSA9PT0gXCJzZWxlY3Rpb25cIikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3Rpb25FbGVtZW50OiBlbGVtZW50LFxuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChlbGVtZW50KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgbXVsdGlFbGVtZW50OiBudWxsLFxuICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogZWxlbWVudCxcbiAgICAgICAgICBlZGl0aW5nRWxlbWVudDogZWxlbWVudFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5jcmVhdGVGcmFtZUVsZW1lbnRPblBvaW50ZXJEb3duID0gcG9pbnRlckRvd25TdGF0ZSA9PiB7XG4gICAgICB2YXIgX2E7XG5cbiAgICAgIGNvbnN0IFtncmlkWCwgZ3JpZFldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnksICgoX2EgPSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2FbS0VZUy5DVFJMX09SX0NNRF0pID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgY29uc3QgZnJhbWUgPSBuZXdGcmFtZUVsZW1lbnQoT2JqZWN0LmFzc2lnbih7XG4gICAgICAgIHg6IGdyaWRYLFxuICAgICAgICB5OiBncmlkWSxcbiAgICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICAgIGxvY2tlZDogZmFsc2VcbiAgICAgIH0sIEZSQU1FX1NUWUxFKSk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhbLi4udGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZnJhbWVdKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBtdWx0aUVsZW1lbnQ6IG51bGwsXG4gICAgICAgIGRyYWdnaW5nRWxlbWVudDogZnJhbWUsXG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBmcmFtZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzdG9yZVJlYWR5VG9FcmFzZUVsZW1lbnRzID0gcG9pbnRlckRvd25TdGF0ZSA9PiB7XG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsZSA9PiB7XG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgb3BhY2l0eTogcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChpc0JvdW5kVG9Db250YWluZXIoZWxlKSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5jb250YWluZXJJZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgb3BhY2l0eTogcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChlbGUuZnJhbWVJZCAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXSAmJiBwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5mcmFtZUlkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdLm9wYWNpdHlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlbGU7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGVsZW1lbnRzKTtcbiAgICB9O1xuXG4gICAgdGhpcy5lcmFzZUVsZW1lbnRzID0gcG9pbnRlckRvd25TdGF0ZSA9PiB7XG4gICAgICBjb25zdCBlbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCkubWFwKGVsZSA9PiB7XG4gICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmVsZW1lbnRJZHNUb0VyYXNlW2VsZS5pZF0gJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuaWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNCb3VuZFRvQ29udGFpbmVyKGVsZSkgJiYgcG9pbnRlckRvd25TdGF0ZS5lbGVtZW50SWRzVG9FcmFzZVtlbGUuY29udGFpbmVySWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmNvbnRhaW5lcklkXS5lcmFzZSkge1xuICAgICAgICAgIHJldHVybiBuZXdFbGVtZW50V2l0aChlbGUsIHtcbiAgICAgICAgICAgIGlzRGVsZXRlZDogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGVsZS5mcmFtZUlkICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdICYmIHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbZWxlLmZyYW1lSWRdLmVyYXNlKSB7XG4gICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZSwge1xuICAgICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZWxlO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhlbGVtZW50cyk7XG4gICAgfTtcblxuICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlID0gKHtcbiAgICAgIGltYWdlRmlsZSxcbiAgICAgIGltYWdlRWxlbWVudDogX2ltYWdlRWxlbWVudCxcbiAgICAgIHNob3dDdXJzb3JJbWFnZVByZXZpZXcgPSBmYWxzZVxuICAgIH0pID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfZiwgX2csIF9oLCBfajsgLy8gYXQgdGhpcyBwb2ludCB0aGlzIHNob3VsZCBiZSBndWFyYW50ZWVkIGltYWdlIGZpbGUsIGJ1dCB3ZSBkbyB0aGlzIGNoZWNrXG4gICAgICAvLyB0byBzYXRpc2Z5IFRTIGRvd24gdGhlIGxpbmVcblxuXG4gICAgICBpZiAoIWlzU3VwcG9ydGVkSW1hZ2VGaWxlKGltYWdlRmlsZSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMudW5zdXBwb3J0ZWRGaWxlVHlwZVwiKSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1pbWVUeXBlID0gaW1hZ2VGaWxlLnR5cGU7XG4gICAgICBzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcywgXCJ3YWl0XCIpO1xuXG4gICAgICBpZiAobWltZVR5cGUgPT09IE1JTUVfVFlQRVMuc3ZnKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaW1hZ2VGaWxlID0gU1ZHU3RyaW5nVG9GaWxlKHlpZWxkIG5vcm1hbGl6ZVNWRyh5aWVsZCBpbWFnZUZpbGUudGV4dCgpKSwgaW1hZ2VGaWxlLm5hbWUpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHQoXCJlcnJvcnMuc3ZnSW1hZ2VJbnNlcnRFcnJvclwiKSk7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gZ2VuZXJhdGUgaW1hZ2UgaWQgKGJ5IGRlZmF1bHQgdGhlIGZpbGUgZGlnZXN0KSBiZWZvcmUgYW55XG4gICAgICAvLyByZXNpemluZy9jb21wcmVzc2lvbiB0YWtlcyBwbGFjZSB0byBrZWVwIGl0IG1vcmUgcG9ydGFibGVcblxuXG4gICAgICBjb25zdCBmaWxlSWQgPSB5aWVsZCAoKF9nID0gKF9mID0gdGhpcy5wcm9wcykuZ2VuZXJhdGVJZEZvckZpbGUpID09PSBudWxsIHx8IF9nID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZy5jYWxsKF9mLCBpbWFnZUZpbGUpKSB8fCBnZW5lcmF0ZUlkRnJvbUZpbGUoaW1hZ2VGaWxlKTtcblxuICAgICAgaWYgKCFmaWxlSWQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFwiQ291bGRuJ3QgZ2VuZXJhdGUgZmlsZSBpZCBvciB0aGUgc3VwcGxpZWQgYGdlbmVyYXRlSWRGb3JGaWxlYCBkaWRuJ3QgcmVzb2x2ZSB0byBvbmUuXCIpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IodChcImVycm9ycy5pbWFnZUluc2VydEVycm9yXCIpKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXhpc3RpbmdGaWxlRGF0YSA9IHRoaXMuZmlsZXNbZmlsZUlkXTtcblxuICAgICAgaWYgKCEoZXhpc3RpbmdGaWxlRGF0YSA9PT0gbnVsbCB8fCBleGlzdGluZ0ZpbGVEYXRhID09PSB2b2lkIDAgPyB2b2lkIDAgOiBleGlzdGluZ0ZpbGVEYXRhLmRhdGFVUkwpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaW1hZ2VGaWxlID0geWllbGQgcmVzaXplSW1hZ2VGaWxlKGltYWdlRmlsZSwge1xuICAgICAgICAgICAgbWF4V2lkdGhPckhlaWdodDogREVGQVVMVF9NQVhfSU1BR0VfV0lEVEhfT1JfSEVJR0hUXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcImVycm9yIHRyeWluZyB0byByZXNpbmcgaW1hZ2UgZmlsZSBvbiBpbnNlcnRpb25cIiwgZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGltYWdlRmlsZS5zaXplID4gTUFYX0FMTE9XRURfRklMRV9CWVRFUykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0KFwiZXJyb3JzLmZpbGVUb29CaWdcIiwge1xuICAgICAgICAgICAgbWF4U2l6ZTogYCR7TWF0aC50cnVuYyhNQVhfQUxMT1dFRF9GSUxFX0JZVEVTIC8gMTAyNCAvIDEwMjQpfU1CYFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoc2hvd0N1cnNvckltYWdlUHJldmlldykge1xuICAgICAgICBjb25zdCBkYXRhVVJMID0gKF9oID0gdGhpcy5maWxlc1tmaWxlSWRdKSA9PT0gbnVsbCB8fCBfaCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2guZGF0YVVSTDsgLy8gb3B0aW1pemF0aW9uIHNvIHRoYXQgd2UgZG9uJ3QgdW5uZWNlc3NhcmlseSByZXNpemUgdGhlIG9yaWdpbmFsXG4gICAgICAgIC8vIGZ1bGwtc2l6ZSBmaWxlIGZvciBjdXJzb3IgcHJldmlld1xuICAgICAgICAvLyAoaXQncyBtdWNoIGZhc3RlciB0byBjb252ZXJ0IHRoZSByZXNpemVkIGRhdGFVUkwgdG8gRmlsZSlcblxuICAgICAgICBjb25zdCByZXNpemVkRmlsZSA9IGRhdGFVUkwgJiYgZGF0YVVSTFRvRmlsZShkYXRhVVJMKTtcbiAgICAgICAgdGhpcy5zZXRJbWFnZVByZXZpZXdDdXJzb3IocmVzaXplZEZpbGUgfHwgaW1hZ2VGaWxlKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YVVSTCA9ICgoX2ogPSB0aGlzLmZpbGVzW2ZpbGVJZF0pID09PSBudWxsIHx8IF9qID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfai5kYXRhVVJMKSB8fCAoeWllbGQgZ2V0RGF0YVVSTChpbWFnZUZpbGUpKTtcbiAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IG11dGF0ZUVsZW1lbnQoX2ltYWdlRWxlbWVudCwge1xuICAgICAgICBmaWxlSWRcbiAgICAgIH0sIGZhbHNlKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgIHZhciBfaztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIHRoaXMuZmlsZXMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZmlsZXMpLCB7XG4gICAgICAgICAgICBbZmlsZUlkXToge1xuICAgICAgICAgICAgICBtaW1lVHlwZSxcbiAgICAgICAgICAgICAgaWQ6IGZpbGVJZCxcbiAgICAgICAgICAgICAgZGF0YVVSTCxcbiAgICAgICAgICAgICAgY3JlYXRlZDogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgbGFzdFJldHJpZXZlZDogRGF0ZS5ub3coKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGNvbnN0IGNhY2hlZEltYWdlRGF0YSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoZmlsZUlkKTtcblxuICAgICAgICAgIGlmICghY2FjaGVkSW1hZ2VEYXRhKSB7XG4gICAgICAgICAgICB0aGlzLmFkZE5ld0ltYWdlc1RvSW1hZ2VDYWNoZSgpO1xuICAgICAgICAgICAgeWllbGQgdGhpcy51cGRhdGVJbWFnZUNhY2hlKFtpbWFnZUVsZW1lbnRdKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoKGNhY2hlZEltYWdlRGF0YSA9PT0gbnVsbCB8fCBjYWNoZWRJbWFnZURhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGNhY2hlZEltYWdlRGF0YS5pbWFnZSkgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgICAgICB5aWVsZCBjYWNoZWRJbWFnZURhdGEuaW1hZ2U7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUucGVuZGluZ0ltYWdlRWxlbWVudElkICE9PSBpbWFnZUVsZW1lbnQuaWQgJiYgKChfayA9IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50KSA9PT0gbnVsbCB8fCBfayA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2suaWQpICE9PSBpbWFnZUVsZW1lbnQuaWQpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlRGltZW5zaW9ucyhpbWFnZUVsZW1lbnQsIHRydWUpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlc29sdmUoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKHQoXCJlcnJvcnMuaW1hZ2VJbnNlcnRFcnJvclwiKSkpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIGlmICghc2hvd0N1cnNvckltYWdlUHJldmlldykge1xuICAgICAgICAgICAgcmVzZXRDdXJzb3IodGhpcy5pbnRlcmFjdGl2ZUNhbnZhcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KSk7XG4gICAgfSk7XG4gICAgLyoqXG4gICAgICogaW5zZXJ0cyBpbWFnZSBpbnRvIGVsZW1lbnRzIGFycmF5IGFuZCByZXJlbmRlcnNcbiAgICAgKi9cblxuXG4gICAgdGhpcy5pbnNlcnRJbWFnZUVsZW1lbnQgPSAoaW1hZ2VFbGVtZW50LCBpbWFnZUZpbGUsIHNob3dDdXJzb3JJbWFnZVByZXZpZXcpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHRoaXMuc2NlbmUuYWRkTmV3RWxlbWVudChpbWFnZUVsZW1lbnQpO1xuXG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4geWllbGQgdGhpcy5pbml0aWFsaXplSW1hZ2Uoe1xuICAgICAgICAgIGltYWdlRmlsZSxcbiAgICAgICAgICBpbWFnZUVsZW1lbnQsXG4gICAgICAgICAgc2hvd0N1cnNvckltYWdlUHJldmlld1xuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIG11dGF0ZUVsZW1lbnQoaW1hZ2VFbGVtZW50LCB7XG4gICAgICAgICAgaXNEZWxldGVkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IubWVzc2FnZSB8fCB0KFwiZXJyb3JzLmltYWdlSW5zZXJ0RXJyb3JcIilcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5zZXRJbWFnZVByZXZpZXdDdXJzb3IgPSBpbWFnZUZpbGUgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgLy8gbXVzdG4ndCBiZSBsYXJnZXIgdGhhbiAxMjggcHhcbiAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0NTUy9DU1NfQmFzaWNfVXNlcl9JbnRlcmZhY2UvVXNpbmdfVVJMX3ZhbHVlc19mb3JfdGhlX2N1cnNvcl9wcm9wZXJ0eVxuICAgICAgY29uc3QgY3Vyc29ySW1hZ2VTaXplUHggPSA5NjtcbiAgICAgIGNvbnN0IGltYWdlUHJldmlldyA9IHlpZWxkIHJlc2l6ZUltYWdlRmlsZShpbWFnZUZpbGUsIHtcbiAgICAgICAgbWF4V2lkdGhPckhlaWdodDogY3Vyc29ySW1hZ2VTaXplUHhcbiAgICAgIH0pO1xuICAgICAgbGV0IHByZXZpZXdEYXRhVVJMID0geWllbGQgZ2V0RGF0YVVSTChpbWFnZVByZXZpZXcpOyAvLyBTVkcgY2Fubm90IGJlIHJlc2l6ZWQgdmlhIGByZXNpemVJbWFnZUZpbGVgIHNvIHdlIHJlc2l6ZSBieSByZW5kZXJpbmcgdG9cbiAgICAgIC8vIGEgc21hbGwgY2FudmFzXG5cbiAgICAgIGlmIChpbWFnZUZpbGUudHlwZSA9PT0gTUlNRV9UWVBFUy5zdmcpIHtcbiAgICAgICAgY29uc3QgaW1nID0geWllbGQgbG9hZEhUTUxJbWFnZUVsZW1lbnQocHJldmlld0RhdGFVUkwpO1xuICAgICAgICBsZXQgaGVpZ2h0ID0gTWF0aC5taW4oaW1nLmhlaWdodCwgY3Vyc29ySW1hZ2VTaXplUHgpO1xuICAgICAgICBsZXQgd2lkdGggPSBoZWlnaHQgKiAoaW1nLndpZHRoIC8gaW1nLmhlaWdodCk7XG5cbiAgICAgICAgaWYgKHdpZHRoID4gY3Vyc29ySW1hZ2VTaXplUHgpIHtcbiAgICAgICAgICB3aWR0aCA9IGN1cnNvckltYWdlU2l6ZVB4O1xuICAgICAgICAgIGhlaWdodCA9IHdpZHRoICogKGltZy5oZWlnaHQgLyBpbWcud2lkdGgpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodDtcbiAgICAgICAgY2FudmFzLndpZHRoID0gd2lkdGg7XG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xuICAgICAgICBjb250ZXh0LmRyYXdJbWFnZShpbWcsIDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xuICAgICAgICBwcmV2aWV3RGF0YVVSTCA9IGNhbnZhcy50b0RhdGFVUkwoTUlNRV9UWVBFUy5zdmcpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWQpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIGB1cmwoJHtwcmV2aWV3RGF0YVVSTH0pIDQgNCwgYXV0b2ApO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5vbkltYWdlQWN0aW9uID0gKHtcbiAgICAgIGluc2VydE9uQ2FudmFzRGlyZWN0bHlcbiAgICB9KSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjbGllbnRYID0gdGhpcy5zdGF0ZS53aWR0aCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldExlZnQ7XG4gICAgICAgIGNvbnN0IGNsaWVudFkgPSB0aGlzLnN0YXRlLmhlaWdodCAvIDIgKyB0aGlzLnN0YXRlLm9mZnNldFRvcDtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKHtcbiAgICAgICAgICBjbGllbnRYLFxuICAgICAgICAgIGNsaWVudFlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIGNvbnN0IGltYWdlRmlsZSA9IHlpZWxkIGZpbGVPcGVuKHtcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJJbWFnZVwiLFxuICAgICAgICAgIGV4dGVuc2lvbnM6IE9iamVjdC5rZXlzKElNQUdFX01JTUVfVFlQRVMpXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSB0aGlzLmNyZWF0ZUltYWdlRWxlbWVudCh7XG4gICAgICAgICAgc2NlbmVYOiB4LFxuICAgICAgICAgIHNjZW5lWTogeVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoaW5zZXJ0T25DYW52YXNEaXJlY3RseSkge1xuICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlKTtcbiAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMoaW1hZ2VFbGVtZW50KTtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe1xuICAgICAgICAgICAgICBbaW1hZ2VFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgfSwgdGhpcy5zdGF0ZSlcbiAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFjdGlvbk1hbmFnZXIuZXhlY3V0ZUFjdGlvbihhY3Rpb25GaW5hbGl6ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IGltYWdlRWxlbWVudC5pZFxuICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgaW1hZ2VGaWxlLFxuICAgICAgICAgICAgLyogc2hvd0N1cnNvckltYWdlUHJldmlldyAqL1xuICAgICAgICAgICAgdHJ1ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmIChlcnJvci5uYW1lICE9PSBcIkFib3J0RXJyb3JcIikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGwsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgYWN0aXZlVG9vbDogdXBkYXRlQWN0aXZlVG9vbCh0aGlzLnN0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgfSlcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmluaXRpYWxpemVJbWFnZURpbWVuc2lvbnMgPSAoaW1hZ2VFbGVtZW50LCBmb3JjZU5hdHVyYWxTaXplID0gZmFsc2UpID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgY29uc3QgaW1hZ2UgPSBpc0luaXRpYWxpemVkSW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCkgJiYgKChfYSA9IHRoaXMuaW1hZ2VDYWNoZS5nZXQoaW1hZ2VFbGVtZW50LmZpbGVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pbWFnZSk7XG5cbiAgICAgIGlmICghaW1hZ2UgfHwgaW1hZ2UgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgIGlmIChpbWFnZUVsZW1lbnQud2lkdGggPCBEUkFHR0lOR19USFJFU0hPTEQgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUgJiYgaW1hZ2VFbGVtZW50LmhlaWdodCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSkge1xuICAgICAgICAgIGNvbnN0IHBsYWNlaG9sZGVyU2l6ZSA9IDEwMCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgICAgeDogaW1hZ2VFbGVtZW50LnggLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgeTogaW1hZ2VFbGVtZW50LnkgLSBwbGFjZWhvbGRlclNpemUgLyAyLFxuICAgICAgICAgICAgd2lkdGg6IHBsYWNlaG9sZGVyU2l6ZSxcbiAgICAgICAgICAgIGhlaWdodDogcGxhY2Vob2xkZXJTaXplXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChmb3JjZU5hdHVyYWxTaXplIHx8IC8vIGlmIHVzZXItY3JlYXRlZCBib3VuZGluZyBib3ggaXMgYmVsb3cgdGhyZXNob2xkLCBhc3N1bWUgdGhlXG4gICAgICAvLyBpbnRlbnRpb24gd2FzIHRvIGNsaWNrIGluc3RlYWQgb2YgZHJhZywgYW5kIHVzZSB0aGUgaW1hZ2Unc1xuICAgICAgLy8gaW50cmluc2ljIHNpemVcbiAgICAgIGltYWdlRWxlbWVudC53aWR0aCA8IERSQUdHSU5HX1RIUkVTSE9MRCAvIHRoaXMuc3RhdGUuem9vbS52YWx1ZSAmJiBpbWFnZUVsZW1lbnQuaGVpZ2h0IDwgRFJBR0dJTkdfVEhSRVNIT0xEIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlKSB7XG4gICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IE1hdGgubWF4KHRoaXMuc3RhdGUuaGVpZ2h0IC0gMTIwLCAxNjApOyAvLyBtYXggNjUlIG9mIGNhbnZhcyBoZWlnaHQsIGNsYW1wZWQgdG8gPDMwMHB4LCB2aCAtIDEyMHB4PlxuXG4gICAgICAgIGNvbnN0IG1heEhlaWdodCA9IE1hdGgubWluKG1pbkhlaWdodCwgTWF0aC5mbG9vcih0aGlzLnN0YXRlLmhlaWdodCAqIDAuNSkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWUpO1xuICAgICAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1pbihpbWFnZS5uYXR1cmFsSGVpZ2h0LCBtYXhIZWlnaHQpO1xuICAgICAgICBjb25zdCB3aWR0aCA9IGhlaWdodCAqIChpbWFnZS5uYXR1cmFsV2lkdGggLyBpbWFnZS5uYXR1cmFsSGVpZ2h0KTsgLy8gYWRkIGN1cnJlbnQgaW1hZ2VFbGVtZW50IHdpZHRoL2hlaWdodCB0byBhY2NvdW50IGZvciBwcmV2aW91cyBjZW50ZXJpbmdcbiAgICAgICAgLy8gb2YgdGhlIHBsYWNlaG9sZGVyIGltYWdlXG5cbiAgICAgICAgY29uc3QgeCA9IGltYWdlRWxlbWVudC54ICsgaW1hZ2VFbGVtZW50LndpZHRoIC8gMiAtIHdpZHRoIC8gMjtcbiAgICAgICAgY29uc3QgeSA9IGltYWdlRWxlbWVudC55ICsgaW1hZ2VFbGVtZW50LmhlaWdodCAvIDIgLSBoZWlnaHQgLyAyO1xuICAgICAgICBtdXRhdGVFbGVtZW50KGltYWdlRWxlbWVudCwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeSxcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHRcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcbiAgICAvKiogdXBkYXRlcyBpbWFnZSBjYWNoZSwgcmVmcmVzaGluZyB1cGRhdGVkIGVsZW1lbnRzIGFuZC9vciBzZXR0aW5nIHN0YXR1c1xuICAgICAgICB0byBlcnJvciBmb3IgaW1hZ2VzIHRoYXQgZmFpbCBkdXJpbmcgPGltZz4gZWxlbWVudCBjcmVhdGlvbiAqL1xuXG5cbiAgICB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUgPSAoZWxlbWVudHMsIGZpbGVzID0gdGhpcy5maWxlcykgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgY29uc3Qge1xuICAgICAgICB1cGRhdGVkRmlsZXMsXG4gICAgICAgIGVycm9yZWRGaWxlc1xuICAgICAgfSA9IHlpZWxkIF91cGRhdGVJbWFnZUNhY2hlKHtcbiAgICAgICAgaW1hZ2VDYWNoZTogdGhpcy5pbWFnZUNhY2hlLFxuICAgICAgICBmaWxlSWRzOiBlbGVtZW50cy5tYXAoZWxlbWVudCA9PiBlbGVtZW50LmZpbGVJZCksXG4gICAgICAgIGZpbGVzXG4gICAgICB9KTtcblxuICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplIHx8IGVycm9yZWRGaWxlcy5zaXplKSB7XG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgIGlmICh1cGRhdGVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgU2hhcGVDYWNoZS5kZWxldGUoZWxlbWVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChlcnJvcmVkRmlsZXMuc2l6ZSkge1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChlbGVtZW50ID0+IHtcbiAgICAgICAgICBpZiAoaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChlbGVtZW50KSAmJiBlcnJvcmVkRmlsZXMuaGFzKGVsZW1lbnQuZmlsZUlkKSkge1xuICAgICAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRXaXRoKGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgc3RhdHVzOiBcImVycm9yXCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBlbGVtZW50O1xuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHVwZGF0ZWRGaWxlcyxcbiAgICAgICAgZXJyb3JlZEZpbGVzXG4gICAgICB9O1xuICAgIH0pO1xuICAgIC8qKiBhZGRzIG5ldyBpbWFnZXMgdG8gaW1hZ2VDYWNoZSBhbmQgcmUtcmVuZGVycyBpZiBuZWVkZWQgKi9cblxuXG4gICAgdGhpcy5hZGROZXdJbWFnZXNUb0ltYWdlQ2FjaGUgPSAoaW1hZ2VFbGVtZW50cyA9IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cyh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpKSwgZmlsZXMgPSB0aGlzLmZpbGVzKSA9PiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCB1bmNhY2hlZEltYWdlRWxlbWVudHMgPSBpbWFnZUVsZW1lbnRzLmZpbHRlcihlbGVtZW50ID0+ICFlbGVtZW50LmlzRGVsZXRlZCAmJiAhdGhpcy5pbWFnZUNhY2hlLmhhcyhlbGVtZW50LmZpbGVJZCkpO1xuXG4gICAgICBpZiAodW5jYWNoZWRJbWFnZUVsZW1lbnRzLmxlbmd0aCkge1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgdXBkYXRlZEZpbGVzXG4gICAgICAgIH0gPSB5aWVsZCB0aGlzLnVwZGF0ZUltYWdlQ2FjaGUodW5jYWNoZWRJbWFnZUVsZW1lbnRzLCBmaWxlcyk7XG5cbiAgICAgICAgaWYgKHVwZGF0ZWRGaWxlcy5zaXplKSB7XG4gICAgICAgICAgdGhpcy5zY2VuZS5pbmZvcm1NdXRhdGlvbigpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgLyoqIGdlbmVyYWxseSB5b3Ugc2hvdWxkIHVzZSBgYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKClgIGRpcmVjdGx5IGlmIHlvdSBuZWVkXG4gICAgICogIHRvIHJlbmRlciBuZXcgaW1hZ2VzLiBUaGlzIGlzIGp1c3QgYSBmYWlsc2FmZSAgKi9cblxuXG4gICAgdGhpcy5zY2hlZHVsZUltYWdlUmVmcmVzaCA9IHRocm90dGxlKCgpID0+IHtcbiAgICAgIHRoaXMuYWRkTmV3SW1hZ2VzVG9JbWFnZUNhY2hlKCk7XG4gICAgfSwgSU1BR0VfUkVOREVSX1RJTUVPVVQpO1xuXG4gICAgdGhpcy51cGRhdGVCaW5kaW5nRW5hYmxlZE9uUG9pbnRlck1vdmUgPSBldmVudCA9PiB7XG4gICAgICBjb25zdCBzaG91bGRFbmFibGVCaW5kaW5nID0gc2hvdWxkRW5hYmxlQmluZGluZ0ZvclBvaW50ZXJFdmVudChldmVudCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmlzQmluZGluZ0VuYWJsZWQgIT09IHNob3VsZEVuYWJsZUJpbmRpbmcpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNCaW5kaW5nRW5hYmxlZDogc2hvdWxkRW5hYmxlQmluZGluZ1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nQXRDdXJzb3IgPSBwb2ludGVyQ29vcmRzID0+IHtcbiAgICAgIGNvbnN0IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgPSBnZXRIb3ZlcmVkRWxlbWVudEZvckJpbmRpbmcocG9pbnRlckNvb3JkcywgdGhpcy5zY2VuZSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQgIT0gbnVsbCA/IFtob3ZlcmVkQmluZGFibGVFbGVtZW50XSA6IFtdXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nc0ZvckxpbmVhckVsZW1lbnRBdENvb3JkcyA9IChsaW5lYXJFbGVtZW50LFxuICAgIC8qKiBzY2VuZSBjb29yZHMgKi9cbiAgICBwb2ludGVyQ29vcmRzLCAvLyBEdXJpbmcgbGluZSBjcmVhdGlvbiB0aGUgc3RhcnQgYmluZGluZyBoYXNuJ3QgYmVlbiB3cml0dGVuIHlldFxuICAgIC8vIGludG8gYGxpbmVhckVsZW1lbnRgXG4gICAgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50KSA9PiB7XG4gICAgICBpZiAoIXBvaW50ZXJDb29yZHMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3VnZ2VzdGVkQmluZGluZ3MgPSBwb2ludGVyQ29vcmRzLnJlZHVjZSgoYWNjLCBjb29yZHMpID0+IHtcbiAgICAgICAgY29uc3QgaG92ZXJlZEJpbmRhYmxlRWxlbWVudCA9IGdldEhvdmVyZWRFbGVtZW50Rm9yQmluZGluZyhjb29yZHMsIHRoaXMuc2NlbmUpO1xuXG4gICAgICAgIGlmIChob3ZlcmVkQmluZGFibGVFbGVtZW50ICE9IG51bGwgJiYgIWlzTGluZWFyRWxlbWVudFNpbXBsZUFuZEFscmVhZHlCb3VuZChsaW5lYXJFbGVtZW50LCBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQgPT09IG51bGwgfHwgb3Bwb3NpdGVCaW5kaW5nQm91bmRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHBvc2l0ZUJpbmRpbmdCb3VuZEVsZW1lbnQuaWQsIGhvdmVyZWRCaW5kYWJsZUVsZW1lbnQpKSB7XG4gICAgICAgICAgYWNjLnB1c2goaG92ZXJlZEJpbmRhYmxlRWxlbWVudCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwgW10pO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5oYW5kbGVJbnRlcmFjdGl2ZUNhbnZhc1JlZiA9IGNhbnZhcyA9PiB7XG4gICAgICB2YXIgX2EsIF9iLCBfYzsgLy8gY2FudmFzIGlzIG51bGwgd2hlbiB1bm1vdW50aW5nXG5cblxuICAgICAgaWYgKGNhbnZhcyAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzID0gY2FudmFzOyAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAvLyBOT1RFIHdoZWVsLCB0b3VjaHN0YXJ0LCB0b3VjaGVuZCBldmVudHMgbXVzdCBiZSByZWdpc3RlcmVkIG91dHNpZGVcbiAgICAgICAgLy8gb2YgcmVhY3QgYmVjYXVzZSByZWFjdCBiaW5kcyB0aGVtIHRoZW0gcGFzc2l2ZWx5IChzbyB3ZSBjYW4ndCBwcmV2ZW50XG4gICAgICAgIC8vIGRlZmF1bHQgb24gdGhlbSlcblxuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuV0hFRUwsIHRoaXMuaGFuZGxlV2hlZWwpO1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlQ2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULlRPVUNIX0VORCwgdGhpcy5vblRvdWNoRW5kKTsgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIChfYSA9IHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLmhhbmRsZVdoZWVsKTtcbiAgICAgICAgKF9iID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfU1RBUlQsIHRoaXMub25Ub3VjaFN0YXJ0KTtcbiAgICAgICAgKF9jID0gdGhpcy5pbnRlcmFjdGl2ZUNhbnZhcykgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuVE9VQ0hfRU5ELCB0aGlzLm9uVG91Y2hFbmQpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmhhbmRsZUFwcE9uRHJvcCA9IGV2ZW50ID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIHZhciBfbCwgX20sIF9vLCBfcDsgLy8gbXVzdCBiZSByZXRyaWV2ZWQgZmlyc3QsIGluIHRoZSBzYW1lIGZyYW1lXG5cblxuICAgICAgY29uc3Qge1xuICAgICAgICBmaWxlLFxuICAgICAgICBmaWxlSGFuZGxlXG4gICAgICB9ID0geWllbGQgZ2V0RmlsZUZyb21FdmVudChldmVudCk7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHg6IHNjZW5lWCxcbiAgICAgICAgeTogc2NlbmVZXG4gICAgICB9ID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKGlzU3VwcG9ydGVkSW1hZ2VGaWxlKGZpbGUpKSB7XG4gICAgICAgICAgLy8gZmlyc3QgYXR0ZW1wdCB0byBkZWNvZGUgc2NlbmUgZnJvbSB0aGUgaW1hZ2UgaWYgaXQncyBlbWJlZGRlZFxuICAgICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgICAgICAgIGlmICgoZmlsZSA9PT0gbnVsbCB8fCBmaWxlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBmaWxlLnR5cGUpID09PSBNSU1FX1RZUEVTLnBuZyB8fCAoZmlsZSA9PT0gbnVsbCB8fCBmaWxlID09PSB2b2lkIDAgPyB2b2lkIDAgOiBmaWxlLnR5cGUpID09PSBNSU1FX1RZUEVTLnN2Zykge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3Qgc2NlbmUgPSB5aWVsZCBsb2FkRnJvbUJsb2IoZmlsZSwgdGhpcy5zdGF0ZSwgdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZmlsZUhhbmRsZSk7XG4gICAgICAgICAgICAgIHRoaXMuc3luY0FjdGlvblJlc3VsdChPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lKSwge1xuICAgICAgICAgICAgICAgIGFwcFN0YXRlOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHNjZW5lLmFwcFN0YXRlIHx8IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgICAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgcmVwbGFjZUZpbGVzOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgIGlmIChlcnJvci5uYW1lICE9PSBcIkVuY29kaW5nRXJyb3JcIikge1xuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSAvLyBpZiBubyBzY2VuZSBpcyBlbWJlZGRlZCBvciB3ZSBmYWlsIGZvciB3aGF0ZXZlciByZWFzb24sIGZhbGwgYmFja1xuICAgICAgICAgIC8vIHRvIGltcG9ydGluZyBhcyByZWd1bGFyIGltYWdlXG4gICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuICAgICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IHRoaXMuY3JlYXRlSW1hZ2VFbGVtZW50KHtcbiAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgIHNjZW5lWVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2VFbGVtZW50KGltYWdlRWxlbWVudCwgZmlsZSk7XG4gICAgICAgICAgdGhpcy5pbml0aWFsaXplSW1hZ2VEaW1lbnNpb25zKGltYWdlRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHtcbiAgICAgICAgICAgICAgW2ltYWdlRWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgICAgIH0sIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGxpYnJhcnlKU09OID0gZXZlbnQuZGF0YVRyYW5zZmVyLmdldERhdGEoTUlNRV9UWVBFUy5leGNhbGlkcmF3bGliKTtcblxuICAgICAgaWYgKGxpYnJhcnlKU09OICYmIHR5cGVvZiBsaWJyYXJ5SlNPTiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGxpYnJhcnlJdGVtcyA9IHBhcnNlTGlicmFyeUpTT04obGlicmFyeUpTT04pO1xuICAgICAgICAgIHRoaXMuYWRkRWxlbWVudHNGcm9tUGFzdGVPckxpYnJhcnkoe1xuICAgICAgICAgICAgZWxlbWVudHM6IGRpc3RyaWJ1dGVMaWJyYXJ5SXRlbXNPblNxdWFyZUdyaWQobGlicmFyeUl0ZW1zKSxcbiAgICAgICAgICAgIHBvc2l0aW9uOiBldmVudCxcbiAgICAgICAgICAgIGZpbGVzOiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGZpbGUpIHtcbiAgICAgICAgLy8gYXRldG1wdCB0byBwYXJzZSBhbiBleGNhbGlkcmF3L2V4Y2FsaWRyYXdsaWIgZmlsZVxuICAgICAgICB5aWVsZCB0aGlzLmxvYWRGaWxlVG9DYW52YXMoZmlsZSwgZmlsZUhhbmRsZSk7XG4gICAgICB9XG5cbiAgICAgIGlmICgoX20gPSAoX2wgPSBldmVudC5kYXRhVHJhbnNmZXIpID09PSBudWxsIHx8IF9sID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfbC50eXBlcykgPT09IG51bGwgfHwgX20gPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9tLmluY2x1ZGVzKFwidGV4dC9wbGFpblwiKSkge1xuICAgICAgICBjb25zdCB0ZXh0ID0gKF9vID0gZXZlbnQuZGF0YVRyYW5zZmVyKSA9PT0gbnVsbCB8fCBfbyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX28uZ2V0RGF0YShcInRleHRcIik7XG5cbiAgICAgICAgaWYgKHRleHQgJiYgZW1iZWRkYWJsZVVSTFZhbGlkYXRvcih0ZXh0LCB0aGlzLnByb3BzLnZhbGlkYXRlRW1iZWRkYWJsZSkgJiYgKC9eKGh0dHB8aHR0cHMpOlxcL1xcL1teXFxzLyQuPyNdLlteXFxzXSokLy50ZXN0KHRleHQpIHx8ICgoX3AgPSBnZXRFbWJlZExpbmsodGV4dCkpID09PSBudWxsIHx8IF9wID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfcC50eXBlKSA9PT0gXCJ2aWRlb1wiKSkge1xuICAgICAgICAgIGNvbnN0IGVtYmVkZGFibGUgPSB0aGlzLmluc2VydEVtYmVkZGFibGVFbGVtZW50KHtcbiAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgIHNjZW5lWSxcbiAgICAgICAgICAgIGxpbms6IG5vcm1hbGl6ZUxpbmsodGV4dClcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmIChlbWJlZGRhYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgW2VtYmVkZGFibGUuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5sb2FkRmlsZVRvQ2FudmFzID0gKGZpbGUsIGZpbGVIYW5kbGUpID0+IF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGZpbGUgPSB5aWVsZCBub3JtYWxpemVGaWxlKGZpbGUpO1xuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXQgPSB5aWVsZCBsb2FkU2NlbmVPckxpYnJhcnlGcm9tQmxvYihmaWxlLCB0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBmaWxlSGFuZGxlKTtcblxuICAgICAgICBpZiAocmV0LnR5cGUgPT09IE1JTUVfVFlQRVMuZXhjYWxpZHJhdykge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgaXNMb2FkaW5nOiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5zeW5jQWN0aW9uUmVzdWx0KE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcmV0LmRhdGEpLCB7XG4gICAgICAgICAgICBhcHBTdGF0ZTogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCByZXQuZGF0YS5hcHBTdGF0ZSB8fCB0aGlzLnN0YXRlKSwge1xuICAgICAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHJlcGxhY2VGaWxlczogdHJ1ZSxcbiAgICAgICAgICAgIGNvbW1pdFRvSGlzdG9yeTogdHJ1ZVxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfSBlbHNlIGlmIChyZXQudHlwZSA9PT0gTUlNRV9UWVBFUy5leGNhbGlkcmF3bGliKSB7XG4gICAgICAgICAgeWllbGQgdGhpcy5saWJyYXJ5LnVwZGF0ZUxpYnJhcnkoe1xuICAgICAgICAgICAgbGlicmFyeUl0ZW1zOiBmaWxlLFxuICAgICAgICAgICAgbWVyZ2U6IHRydWUsXG4gICAgICAgICAgICBvcGVuTGlicmFyeU1lbnU6IHRydWVcbiAgICAgICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IHQoXCJlcnJvcnMuaW1wb3J0TGlicmFyeUVycm9yXCIpXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmhhbmRsZUNhbnZhc0NvbnRleHRNZW51ID0gZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKChcInBvaW50ZXJUeXBlXCIgaW4gZXZlbnQubmF0aXZlRXZlbnQgJiYgZXZlbnQubmF0aXZlRXZlbnQucG9pbnRlclR5cGUgPT09IFwidG91Y2hcIiB8fCBcInBvaW50ZXJUeXBlXCIgaW4gZXZlbnQubmF0aXZlRXZlbnQgJiYgZXZlbnQubmF0aXZlRXZlbnQucG9pbnRlclR5cGUgPT09IFwicGVuXCIgJiYgLy8gYWx3YXlzIGFsbG93IGlmIHVzZXIgdXNlcyBhIHBlbiBzZWNvbmRhcnkgYnV0dG9uXG4gICAgICBldmVudC5idXR0b24gIT09IFBPSU5URVJfQlVUVE9OLlNFQ09OREFSWSkgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoZXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEF0UG9zaXRpb24oeCwgeSwge1xuICAgICAgICBwcmVmZXJTZWxlY3RlZDogdHJ1ZSxcbiAgICAgICAgaW5jbHVkZUxvY2tlZEVsZW1lbnRzOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG4gICAgICBjb25zdCBpc0hpdHRpZ25Db21tb25Cb3VuZEJveCA9IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICB4LFxuICAgICAgICB5XG4gICAgICB9LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgIGNvbnN0IHR5cGUgPSBlbGVtZW50IHx8IGlzSGl0dGlnbkNvbW1vbkJvdW5kQm94ID8gXCJlbGVtZW50XCIgOiBcImNhbnZhc1wiO1xuICAgICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICBjb25zdCB7XG4gICAgICAgIHRvcDogb2Zmc2V0VG9wLFxuICAgICAgICBsZWZ0OiBvZmZzZXRMZWZ0XG4gICAgICB9ID0gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgY29uc3QgbGVmdCA9IGV2ZW50LmNsaWVudFggLSBvZmZzZXRMZWZ0O1xuICAgICAgY29uc3QgdG9wID0gZXZlbnQuY2xpZW50WSAtIG9mZnNldFRvcDtcbiAgICAgIHRyYWNrRXZlbnQoXCJjb250ZXh0TWVudVwiLCBcIm9wZW5Db250ZXh0TWVudVwiLCB0eXBlKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBlbGVtZW50ICYmICF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1tlbGVtZW50LmlkXSA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlKSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgIGVkaXRpbmdHcm91cElkOiB0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICBbZWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgfVxuICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgdGhpcy5zdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogaXNMaW5lYXJFbGVtZW50KGVsZW1lbnQpID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoZWxlbWVudCwgdGhpcy5zY2VuZSkgOiBudWxsXG4gICAgICB9KSA6IHRoaXMuc3RhdGUpLCB7XG4gICAgICAgIHNob3dIeXBlcmxpbmtQb3B1cDogZmFsc2VcbiAgICAgIH0pLCAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGNvbnRleHRNZW51OiB7XG4gICAgICAgICAgICB0b3AsXG4gICAgICAgICAgICBsZWZ0LFxuICAgICAgICAgICAgaXRlbXM6IHRoaXMuZ2V0Q29udGV4dE1lbnVJdGVtcyh0eXBlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZURyYWdOZXdHZW5lcmljRWxlbWVudCA9IChwb2ludGVyRG93blN0YXRlLCBldmVudCkgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZTtcblxuICAgICAgY29uc3QgZHJhZ2dpbmdFbGVtZW50ID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQ7XG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzO1xuXG4gICAgICBpZiAoIWRyYWdnaW5nRWxlbWVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJzZWxlY3Rpb25cIiAmJiB0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSAhPT0gXCJlcmFzZXJcIikge1xuICAgICAgICBkcmFnTmV3RWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55LCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckNvb3Jkcy54KSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSwgcG9pbnRlckNvb3Jkcy55KSwgc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCksIHNob3VsZFJlc2l6ZUZyb21DZW50ZXIoZXZlbnQpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICAgIGNvbnN0IGltYWdlID0gaXNJbml0aWFsaXplZEltYWdlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpICYmICgoX2EgPSB0aGlzLmltYWdlQ2FjaGUuZ2V0KGRyYWdnaW5nRWxlbWVudC5maWxlSWQpKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaW1hZ2UpO1xuICAgICAgICBjb25zdCBhc3BlY3RSYXRpbyA9IGltYWdlICYmICEoaW1hZ2UgaW5zdGFuY2VvZiBQcm9taXNlKSA/IGltYWdlLndpZHRoIC8gaW1hZ2UuaGVpZ2h0IDogbnVsbDtcbiAgICAgICAgdGhpcy5tYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgW2RyYWdnaW5nRWxlbWVudF0pO1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgc25hcE9mZnNldCxcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSA9IHNuYXBOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZSwgZXZlbnQsIHtcbiAgICAgICAgICB4OiBwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC54ICsgKChfYyA9IChfYiA9IHRoaXMuc3RhdGUub3JpZ2luU25hcE9mZnNldCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLngpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IDApLFxuICAgICAgICAgIHk6IHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnkgKyAoKF9lID0gKF9kID0gdGhpcy5zdGF0ZS5vcmlnaW5TbmFwT2Zmc2V0KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QueSkgIT09IG51bGwgJiYgX2UgIT09IHZvaWQgMCA/IF9lIDogMClcbiAgICAgICAgfSwge1xuICAgICAgICAgIHg6IGdyaWRYIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCxcbiAgICAgICAgICB5OiBncmlkWSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnlcbiAgICAgICAgfSk7XG4gICAgICAgIGdyaWRYICs9IHNuYXBPZmZzZXQueDtcbiAgICAgICAgZ3JpZFkgKz0gc25hcE9mZnNldC55O1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgfSk7XG4gICAgICAgIGRyYWdOZXdFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLngsIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnksIGdyaWRYLCBncmlkWSwgZGlzdGFuY2UocG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCwgZ3JpZFgpLCBkaXN0YW5jZShwb2ludGVyRG93blN0YXRlLm9yaWdpbkluR3JpZC55LCBncmlkWSksIGlzSW1hZ2VFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgPyAhc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCkgOiBzaG91bGRNYWludGFpbkFzcGVjdFJhdGlvKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCksIGFzcGVjdFJhdGlvLCB0aGlzLnN0YXRlLm9yaWdpblNuYXBPZmZzZXQpO1xuICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoW2RyYWdnaW5nRWxlbWVudF0pOyAvLyBoaWdobGlnaHQgZWxlbWVudHMgdGhhdCBhcmUgdG8gYmUgYWRkZWQgdG8gZnJhbWVzIG9uIGZyYW1lcyBjcmVhdGlvblxuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5tYXliZUhhbmRsZVJlc2l6ZSA9IChwb2ludGVyRG93blN0YXRlLCBldmVudCkgPT4ge1xuICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgIGNvbnN0IHNlbGVjdGVkRnJhbWVzID0gc2VsZWN0ZWRFbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG4gICAgICBjb25zdCB0cmFuc2Zvcm1IYW5kbGVUeXBlID0gcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuaGFuZGxlVHlwZTtcblxuICAgICAgaWYgKHNlbGVjdGVkRnJhbWVzLmxlbmd0aCA+IDAgJiYgdHJhbnNmb3JtSGFuZGxlVHlwZSA9PT0gXCJyb3RhdGlvblwiKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIC8vIFRPRE86IHJlbmFtZSB0aGlzIHN0YXRlIGZpZWxkIHRvIFwiaXNTY2FsaW5nXCIgdG8gZGlzdGluZ3Vpc2hcbiAgICAgICAgLy8gaXQgZnJvbSB0aGUgZ2VuZXJpYyBcImlzUmVzaXppbmdcIiB3aGljaCBpbmNsdWRlcyBzY2FsaW5nIGFuZFxuICAgICAgICAvLyByb3RhdGluZ1xuICAgICAgICBpc1Jlc2l6aW5nOiB0cmFuc2Zvcm1IYW5kbGVUeXBlICYmIHRyYW5zZm9ybUhhbmRsZVR5cGUgIT09IFwicm90YXRpb25cIixcbiAgICAgICAgaXNSb3RhdGluZzogdHJhbnNmb3JtSGFuZGxlVHlwZSA9PT0gXCJyb3RhdGlvblwiLFxuICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHM7XG4gICAgICBsZXQgW3Jlc2l6ZVgsIHJlc2l6ZVldID0gZ2V0R3JpZFBvaW50KHBvaW50ZXJDb29yZHMueCAtIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLm9mZnNldC54LCBwb2ludGVyQ29vcmRzLnkgLSBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5vZmZzZXQueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7XG4gICAgICBjb25zdCBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcCA9IG5ldyBNYXAoKTtcbiAgICAgIHNlbGVjdGVkRnJhbWVzLmZvckVhY2goZnJhbWUgPT4ge1xuICAgICAgICBjb25zdCBlbGVtZW50c0luRnJhbWUgPSBnZXRGcmFtZUVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLmlkKTtcbiAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgZnJhbWVFbGVtZW50c09mZnNldHNNYXAuc2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCwge1xuICAgICAgICAgICAgeDogZWxlbWVudC54IC0gZnJhbWUueCxcbiAgICAgICAgICAgIHk6IGVsZW1lbnQueSAtIGZyYW1lLnlcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTsgLy8gY2hlY2sgbmVlZGVkIGZvciBhdm9pZGluZyBmbGlja2VyaW5nIHdoZW4gYSBrZXkgZ2V0cyBwcmVzc2VkXG4gICAgICAvLyBkdXJpbmcgZHJhZ2dpbmdcblxuICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQpIHtcbiAgICAgICAgY29uc3QgW2dyaWRYLCBncmlkWV0gPSBnZXRHcmlkUG9pbnQocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnksIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICBjb25zdCBkcmFnT2Zmc2V0ID0ge1xuICAgICAgICAgIHg6IGdyaWRYIC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5JbkdyaWQueCxcbiAgICAgICAgICB5OiBncmlkWSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luSW5HcmlkLnlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3Qgb3JpZ2luYWxFbGVtZW50cyA9IFsuLi5wb2ludGVyRG93blN0YXRlLm9yaWdpbmFsRWxlbWVudHMudmFsdWVzKCldO1xuICAgICAgICB0aGlzLm1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHNuYXBPZmZzZXQsXG4gICAgICAgICAgc25hcExpbmVzXG4gICAgICAgIH0gPSBzbmFwUmVzaXppbmdFbGVtZW50cyhzZWxlY3RlZEVsZW1lbnRzLCBnZXRTZWxlY3RlZEVsZW1lbnRzKG9yaWdpbmFsRWxlbWVudHMsIHRoaXMuc3RhdGUpLCB0aGlzLnN0YXRlLCBldmVudCwgZHJhZ09mZnNldCwgdHJhbnNmb3JtSGFuZGxlVHlwZSk7XG4gICAgICAgIHJlc2l6ZVggKz0gc25hcE9mZnNldC54O1xuICAgICAgICByZXNpemVZICs9IHNuYXBPZmZzZXQueTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc25hcExpbmVzXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAodHJhbnNmb3JtRWxlbWVudHMocG9pbnRlckRvd25TdGF0ZSwgdHJhbnNmb3JtSGFuZGxlVHlwZSwgc2VsZWN0ZWRFbGVtZW50cywgcG9pbnRlckRvd25TdGF0ZS5yZXNpemUuYXJyb3dEaXJlY3Rpb24sIHNob3VsZFJvdGF0ZVdpdGhEaXNjcmV0ZUFuZ2xlKGV2ZW50KSwgc2hvdWxkUmVzaXplRnJvbUNlbnRlcihldmVudCksIHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID09PSAxICYmIGlzSW1hZ2VFbGVtZW50KHNlbGVjdGVkRWxlbWVudHNbMF0pID8gIXNob3VsZE1haW50YWluQXNwZWN0UmF0aW8oZXZlbnQpIDogc2hvdWxkTWFpbnRhaW5Bc3BlY3RSYXRpbyhldmVudCksIHJlc2l6ZVgsIHJlc2l6ZVksIHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmNlbnRlci54LCBwb2ludGVyRG93blN0YXRlLnJlc2l6ZS5jZW50ZXIueSwgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgdGhpcy5tYXliZVN1Z2dlc3RCaW5kaW5nRm9yQWxsKHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICBjb25zdCBlbGVtZW50c1RvSGlnaGxpZ2h0ID0gbmV3IFNldCgpO1xuICAgICAgICBzZWxlY3RlZEZyYW1lcy5mb3JFYWNoKGZyYW1lID0+IHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50c0luRnJhbWUgPSBnZXRGcmFtZUVsZW1lbnRzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGZyYW1lLmlkKTsgLy8ga2VlcCBlbGVtZW50cycgcG9zaXRpb25zIHJlbGF0aXZlIHRvIHRoZWlyIGZyYW1lcyBvbiBmcmFtZXMgcmVzaXppbmdcblxuICAgICAgICAgIGlmICh0cmFuc2Zvcm1IYW5kbGVUeXBlKSB7XG4gICAgICAgICAgICBpZiAodHJhbnNmb3JtSGFuZGxlVHlwZS5pbmNsdWRlcyhcIndcIikpIHtcbiAgICAgICAgICAgICAgZWxlbWVudHNJbkZyYW1lLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgdmFyIF9hLCBfYjtcblxuICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgeDogZnJhbWUueCArICgoKF9hID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS54KSB8fCAwKSxcbiAgICAgICAgICAgICAgICAgIHk6IGZyYW1lLnkgKyAoKChfYiA9IGZyYW1lRWxlbWVudHNPZmZzZXRzTWFwLmdldChmcmFtZS5pZCArIGVsZW1lbnQuaWQpKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IueSkgfHwgMClcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0cmFuc2Zvcm1IYW5kbGVUeXBlLmluY2x1ZGVzKFwiblwiKSkge1xuICAgICAgICAgICAgICBlbGVtZW50c0luRnJhbWUuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChlbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICB4OiBmcmFtZS54ICsgKCgoX2EgPSBmcmFtZUVsZW1lbnRzT2Zmc2V0c01hcC5nZXQoZnJhbWUuaWQgKyBlbGVtZW50LmlkKSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLngpIHx8IDApLFxuICAgICAgICAgICAgICAgICAgeTogZnJhbWUueSArICgoKF9iID0gZnJhbWVFbGVtZW50c09mZnNldHNNYXAuZ2V0KGZyYW1lLmlkICsgZWxlbWVudC5pZCkpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi55KSB8fCAwKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBnZXRFbGVtZW50c0luUmVzaXppbmdGcmFtZSh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBmcmFtZSwgdGhpcy5zdGF0ZSkuZm9yRWFjaChlbGVtZW50ID0+IGVsZW1lbnRzVG9IaWdobGlnaHQuYWRkKGVsZW1lbnQpKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVsZW1lbnRzVG9IaWdobGlnaHQ6IFsuLi5lbGVtZW50c1RvSGlnaGxpZ2h0XVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgdGhpcy5nZXRDb250ZXh0TWVudUl0ZW1zID0gdHlwZSA9PiB7XG4gICAgICBjb25zdCBvcHRpb25zID0gW107XG4gICAgICBvcHRpb25zLnB1c2goYWN0aW9uQ29weUFzUG5nLCBhY3Rpb25Db3B5QXNTdmcpOyAvLyBjYW52YXMgY29udGV4dE1lbnVcbiAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAgICAgaWYgKHR5cGUgPT09IFwiY2FudmFzXCIpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUudmlld01vZGVFbmFibGVkKSB7XG4gICAgICAgICAgcmV0dXJuIFsuLi5vcHRpb25zLCBhY3Rpb25Ub2dnbGVHcmlkTW9kZSwgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVG9nZ2xlVmlld01vZGUsIGFjdGlvblRvZ2dsZVN0YXRzXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbYWN0aW9uUGFzdGUsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkNvcHlBc1BuZywgYWN0aW9uQ29weUFzU3ZnLCBjb3B5VGV4dCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uU2VsZWN0QWxsLCBhY3Rpb25VbmxvY2tBbGxFbGVtZW50cywgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uVG9nZ2xlR3JpZE1vZGUsIGFjdGlvblRvZ2dsZU9iamVjdHNTbmFwTW9kZSwgYWN0aW9uVG9nZ2xlWmVuTW9kZSwgYWN0aW9uVG9nZ2xlVmlld01vZGUsIGFjdGlvblRvZ2dsZVN0YXRzXTtcbiAgICAgIH0gLy8gZWxlbWVudCBjb250ZXh0TWVudVxuICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbiAgICAgIG9wdGlvbnMucHVzaChjb3B5VGV4dCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgICByZXR1cm4gW2FjdGlvbkNvcHksIC4uLm9wdGlvbnNdO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gW2FjdGlvbkN1dCwgYWN0aW9uQ29weSwgYWN0aW9uUGFzdGUsIGFjdGlvblNlbGVjdEFsbEVsZW1lbnRzSW5GcmFtZSwgYWN0aW9uUmVtb3ZlQWxsRWxlbWVudHNGcm9tRnJhbWUsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIC4uLm9wdGlvbnMsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkNvcHlTdHlsZXMsIGFjdGlvblBhc3RlU3R5bGVzLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25Hcm91cCwgYWN0aW9uVW5iaW5kVGV4dCwgYWN0aW9uQmluZFRleHQsIGFjdGlvbldyYXBUZXh0SW5Db250YWluZXIsIGFjdGlvblVuZ3JvdXAsIENPTlRFWFRfTUVOVV9TRVBBUkFUT1IsIGFjdGlvbkFkZFRvTGlicmFyeSwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uU2VuZEJhY2t3YXJkLCBhY3Rpb25CcmluZ0ZvcndhcmQsIGFjdGlvblNlbmRUb0JhY2ssIGFjdGlvbkJyaW5nVG9Gcm9udCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uRmxpcEhvcml6b250YWwsIGFjdGlvbkZsaXBWZXJ0aWNhbCwgQ09OVEVYVF9NRU5VX1NFUEFSQVRPUiwgYWN0aW9uVG9nZ2xlTGluZWFyRWRpdG9yLCBhY3Rpb25MaW5rLCBhY3Rpb25EdXBsaWNhdGVTZWxlY3Rpb24sIGFjdGlvblRvZ2dsZUVsZW1lbnRMb2NrLCBDT05URVhUX01FTlVfU0VQQVJBVE9SLCBhY3Rpb25EZWxldGVTZWxlY3RlZF07XG4gICAgfTtcblxuICAgIHRoaXMuaGFuZGxlV2hlZWwgPSB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgaWYgKGlzUGFubmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZGVsdGFYLFxuICAgICAgICBkZWx0YVlcbiAgICAgIH0gPSBldmVudDsgLy8gbm90ZSB0aGF0IGV2ZW50LmN0cmxLZXkgaXMgbmVjZXNzYXJ5IHRvIGhhbmRsZSBwaW5jaCB6b29taW5nXG5cbiAgICAgIGlmIChldmVudC5tZXRhS2V5IHx8IGV2ZW50LmN0cmxLZXkpIHtcbiAgICAgICAgY29uc3Qgc2lnbiA9IE1hdGguc2lnbihkZWx0YVkpO1xuICAgICAgICBjb25zdCBNQVhfU1RFUCA9IFpPT01fU1RFUCAqIDEwMDtcbiAgICAgICAgY29uc3QgYWJzRGVsdGEgPSBNYXRoLmFicyhkZWx0YVkpO1xuICAgICAgICBsZXQgZGVsdGEgPSBkZWx0YVk7XG5cbiAgICAgICAgaWYgKGFic0RlbHRhID4gTUFYX1NURVApIHtcbiAgICAgICAgICBkZWx0YSA9IE1BWF9TVEVQICogc2lnbjtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBuZXdab29tID0gdGhpcy5zdGF0ZS56b29tLnZhbHVlIC0gZGVsdGEgLyAxMDA7IC8vIGluY3JlYXNlIHpvb20gc3RlcHMgdGhlIG1vcmUgem9vbWVkLWluIHdlIGFyZSAoYXBwbGllcyB0byA+MTAwJSBvbmx5KVxuXG4gICAgICAgIG5ld1pvb20gKz0gTWF0aC5sb2cxMChNYXRoLm1heCgxLCB0aGlzLnN0YXRlLnpvb20udmFsdWUpKSAqIC1zaWduICogLy8gcmVkdWNlZCBhbXBsaWZpY2F0aW9uIGZvciBzbWFsbCBkZWx0YXMgKHNtYWxsIG1vdmVtZW50cyBvbiBhIHRyYWNrcGFkKVxuICAgICAgICBNYXRoLm1pbigxLCBhYnNEZWx0YSAvIDIwKTtcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDYW52YXMoc3RhdGUgPT4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBnZXRTdGF0ZUZvclpvb20oe1xuICAgICAgICAgIHZpZXdwb3J0WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgICAgIHZpZXdwb3J0WTogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55LFxuICAgICAgICAgIG5leHRab29tOiBnZXROb3JtYWxpemVkWm9vbShuZXdab29tKVxuICAgICAgICB9LCBzdGF0ZSkpLCB7XG4gICAgICAgICAgc2hvdWxkQ2FjaGVJZ25vcmVab29tOiB0cnVlXG4gICAgICAgIH0pKTtcbiAgICAgICAgdGhpcy5yZXNldFNob3VsZENhY2hlSWdub3JlWm9vbURlYm91bmNlZCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIHNjcm9sbCBob3Jpem9udGFsbHkgd2hlbiBzaGlmdCBwcmVzc2VkXG5cblxuICAgICAgaWYgKGV2ZW50LnNoaWZ0S2V5KSB7XG4gICAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKCh7XG4gICAgICAgICAgem9vbSxcbiAgICAgICAgICBzY3JvbGxYXG4gICAgICAgIH0pID0+ICh7XG4gICAgICAgICAgLy8gb24gTWFjLCBzaGlmdCt3aGVlbCB0ZW5kcyB0byByZXN1bHQgaW4gZGVsdGFYXG4gICAgICAgICAgc2Nyb2xsWDogc2Nyb2xsWCAtIChkZWx0YVkgfHwgZGVsdGFYKSAvIHpvb20udmFsdWVcbiAgICAgICAgfSkpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKCh7XG4gICAgICAgIHpvb20sXG4gICAgICAgIHNjcm9sbFgsXG4gICAgICAgIHNjcm9sbFlcbiAgICAgIH0pID0+ICh7XG4gICAgICAgIHNjcm9sbFg6IHNjcm9sbFggLSBkZWx0YVggLyB6b29tLnZhbHVlLFxuICAgICAgICBzY3JvbGxZOiBzY3JvbGxZIC0gZGVsdGFZIC8gem9vbS52YWx1ZVxuICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5zYXZlUG9pbnRlciA9ICh4LCB5LCBidXR0b24pID0+IHtcbiAgICAgIHZhciBfYSwgX2I7XG5cbiAgICAgIGlmICgheCB8fCAheSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgeDogc2NlbmVYLFxuICAgICAgICB5OiBzY2VuZVlcbiAgICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICBjbGllbnRYOiB4LFxuICAgICAgICBjbGllbnRZOiB5XG4gICAgICB9LCB0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKGlzTmFOKHNjZW5lWCkgfHwgaXNOYU4oc2NlbmVZKSkgey8vIHNvbWV0aW1lcyB0aGUgcG9pbnRlciBnb2VzIG9mZiBzY3JlZW5cbiAgICAgIH1cblxuICAgICAgY29uc3QgcG9pbnRlciA9IHtcbiAgICAgICAgeDogc2NlbmVYLFxuICAgICAgICB5OiBzY2VuZVksXG4gICAgICAgIHRvb2w6IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIgPyBcImxhc2VyXCIgOiBcInBvaW50ZXJcIlxuICAgICAgfTtcbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpLm9uUG9pbnRlclVwZGF0ZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHtcbiAgICAgICAgcG9pbnRlcixcbiAgICAgICAgYnV0dG9uLFxuICAgICAgICBwb2ludGVyc01hcDogZ2VzdHVyZS5wb2ludGVyc1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIHRoaXMucmVzZXRTaG91bGRDYWNoZUlnbm9yZVpvb21EZWJvdW5jZWQgPSBkZWJvdW5jZSgoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMudW5tb3VudGVkKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSwgMzAwKTtcblxuICAgIHRoaXMudXBkYXRlRE9NUmVjdCA9IGNiID0+IHtcbiAgICAgIHZhciBfYTtcblxuICAgICAgaWYgKChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmN1cnJlbnQpIHtcbiAgICAgICAgY29uc3QgZXhjYWxpZHJhd0NvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgIGxlZnQ6IG9mZnNldExlZnQsXG4gICAgICAgICAgdG9wOiBvZmZzZXRUb3BcbiAgICAgICAgfSA9IGV4Y2FsaWRyYXdDb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB3aWR0aDogY3VycmVudFdpZHRoLFxuICAgICAgICAgIGhlaWdodDogY3VycmVudEhlaWdodCxcbiAgICAgICAgICBvZmZzZXRUb3A6IGN1cnJlbnRPZmZzZXRUb3AsXG4gICAgICAgICAgb2Zmc2V0TGVmdDogY3VycmVudE9mZnNldExlZnRcbiAgICAgICAgfSA9IHRoaXMuc3RhdGU7XG5cbiAgICAgICAgaWYgKHdpZHRoID09PSBjdXJyZW50V2lkdGggJiYgaGVpZ2h0ID09PSBjdXJyZW50SGVpZ2h0ICYmIG9mZnNldExlZnQgPT09IGN1cnJlbnRPZmZzZXRMZWZ0ICYmIG9mZnNldFRvcCA9PT0gY3VycmVudE9mZnNldFRvcCkge1xuICAgICAgICAgIGlmIChjYikge1xuICAgICAgICAgICAgY2IoKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgb2Zmc2V0TGVmdCxcbiAgICAgICAgICBvZmZzZXRUb3BcbiAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgIGNiICYmIGNiKCk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLnJlZnJlc2ggPSAoKSA9PiB7XG4gICAgICB0aGlzLnNldFN0YXRlKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZ2V0Q2FudmFzT2Zmc2V0cygpKSk7XG4gICAgfTtcblxuICAgIGNvbnN0IGRlZmF1bHRBcHBTdGF0ZSA9IGdldERlZmF1bHRBcHBTdGF0ZSgpO1xuICAgIGNvbnN0IHtcbiAgICAgIGV4Y2FsaWRyYXdSZWYsXG4gICAgICB2aWV3TW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIHplbk1vZGVFbmFibGVkID0gZmFsc2UsXG4gICAgICBncmlkTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIG9iamVjdHNTbmFwTW9kZUVuYWJsZWQgPSBmYWxzZSxcbiAgICAgIHRoZW1lID0gZGVmYXVsdEFwcFN0YXRlLnRoZW1lLFxuICAgICAgbmFtZSA9IGRlZmF1bHRBcHBTdGF0ZS5uYW1lXG4gICAgfSA9IHByb3BzO1xuICAgIHRoaXMuc3RhdGUgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBkZWZhdWx0QXBwU3RhdGUpLCB7XG4gICAgICB0aGVtZSxcbiAgICAgIGlzTG9hZGluZzogdHJ1ZVxuICAgIH0pLCB0aGlzLmdldENhbnZhc09mZnNldHMoKSksIHtcbiAgICAgIHZpZXdNb2RlRW5hYmxlZCxcbiAgICAgIHplbk1vZGVFbmFibGVkLFxuICAgICAgb2JqZWN0c1NuYXBNb2RlRW5hYmxlZCxcbiAgICAgIGdyaWRTaXplOiBncmlkTW9kZUVuYWJsZWQgPyBHUklEX1NJWkUgOiBudWxsLFxuICAgICAgbmFtZSxcbiAgICAgIHdpZHRoOiB3aW5kb3cuaW5uZXJXaWR0aCxcbiAgICAgIGhlaWdodDogd2luZG93LmlubmVySGVpZ2h0XG4gICAgfSk7XG4gICAgdGhpcy5pZCA9IG5hbm9pZCgpO1xuICAgIHRoaXMubGlicmFyeSA9IG5ldyBMaWJyYXJ5KHRoaXMpO1xuICAgIHRoaXMuc2NlbmUgPSBuZXcgU2NlbmUoKTtcbiAgICB0aGlzLmNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgdGhpcy5yYyA9IHJvdWdoLmNhbnZhcyh0aGlzLmNhbnZhcyk7XG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBSZW5kZXJlcih0aGlzLnNjZW5lKTtcblxuICAgIGlmIChleGNhbGlkcmF3UmVmKSB7XG4gICAgICBjb25zdCByZWFkeVByb21pc2UgPSBcImN1cnJlbnRcIiBpbiBleGNhbGlkcmF3UmVmICYmICgoX2EgPSBleGNhbGlkcmF3UmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5yZWFkeVByb21pc2UpIHx8IHJlc29sdmFibGVQcm9taXNlKCk7XG4gICAgICBjb25zdCBhcGkgPSB7XG4gICAgICAgIHJlYWR5OiB0cnVlLFxuICAgICAgICByZWFkeVByb21pc2UsXG4gICAgICAgIHVwZGF0ZVNjZW5lOiB0aGlzLnVwZGF0ZVNjZW5lLFxuICAgICAgICB1cGRhdGVMaWJyYXJ5OiB0aGlzLmxpYnJhcnkudXBkYXRlTGlicmFyeSxcbiAgICAgICAgYWRkRmlsZXM6IHRoaXMuYWRkRmlsZXMsXG4gICAgICAgIHJlc2V0U2NlbmU6IHRoaXMucmVzZXRTY2VuZSxcbiAgICAgICAgZ2V0U2NlbmVFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQ6IHRoaXMuZ2V0U2NlbmVFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQsXG4gICAgICAgIGhpc3Rvcnk6IHtcbiAgICAgICAgICBjbGVhcjogdGhpcy5yZXNldEhpc3RvcnlcbiAgICAgICAgfSxcbiAgICAgICAgc2Nyb2xsVG9Db250ZW50OiB0aGlzLnNjcm9sbFRvQ29udGVudCxcbiAgICAgICAgZ2V0U2NlbmVFbGVtZW50czogdGhpcy5nZXRTY2VuZUVsZW1lbnRzLFxuICAgICAgICBnZXRBcHBTdGF0ZTogKCkgPT4gdGhpcy5zdGF0ZSxcbiAgICAgICAgZ2V0RmlsZXM6ICgpID0+IHRoaXMuZmlsZXMsXG4gICAgICAgIHJlZnJlc2g6IHRoaXMucmVmcmVzaCxcbiAgICAgICAgc2V0VG9hc3Q6IHRoaXMuc2V0VG9hc3QsXG4gICAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgICBzZXRBY3RpdmVUb29sOiB0aGlzLnNldEFjdGl2ZVRvb2wsXG4gICAgICAgIHNldEN1cnNvcjogdGhpcy5zZXRDdXJzb3IsXG4gICAgICAgIHJlc2V0Q3Vyc29yOiB0aGlzLnJlc2V0Q3Vyc29yLFxuICAgICAgICB1cGRhdGVGcmFtZVJlbmRlcmluZzogdGhpcy51cGRhdGVGcmFtZVJlbmRlcmluZyxcbiAgICAgICAgdG9nZ2xlU2lkZWJhcjogdGhpcy50b2dnbGVTaWRlYmFyLFxuICAgICAgICBvbkNoYW5nZTogY2IgPT4gdGhpcy5vbkNoYW5nZUVtaXR0ZXIub24oY2IpLFxuICAgICAgICBvblBvaW50ZXJEb3duOiBjYiA9PiB0aGlzLm9uUG9pbnRlckRvd25FbWl0dGVyLm9uKGNiKSxcbiAgICAgICAgb25Qb2ludGVyVXA6IGNiID0+IHRoaXMub25Qb2ludGVyVXBFbWl0dGVyLm9uKGNiKVxuICAgICAgfTtcblxuICAgICAgaWYgKHR5cGVvZiBleGNhbGlkcmF3UmVmID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgZXhjYWxpZHJhd1JlZihhcGkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZXhjYWxpZHJhd1JlZi5jdXJyZW50ID0gYXBpO1xuICAgICAgfVxuXG4gICAgICByZWFkeVByb21pc2UucmVzb2x2ZShhcGkpO1xuICAgIH1cblxuICAgIHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlID0ge1xuICAgICAgY29udGFpbmVyOiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCxcbiAgICAgIGlkOiB0aGlzLmlkXG4gICAgfTtcbiAgICB0aGlzLmZvbnRzID0gbmV3IEZvbnRzKHtcbiAgICAgIHNjZW5lOiB0aGlzLnNjZW5lLFxuICAgICAgb25TY2VuZVVwZGF0ZWQ6IHRoaXMub25TY2VuZVVwZGF0ZWRcbiAgICB9KTtcbiAgICB0aGlzLmhpc3RvcnkgPSBuZXcgSGlzdG9yeSgpO1xuICAgIHRoaXMuYWN0aW9uTWFuYWdlciA9IG5ldyBBY3Rpb25NYW5hZ2VyKHRoaXMuc3luY0FjdGlvblJlc3VsdCwgKCkgPT4gdGhpcy5zdGF0ZSwgKCkgPT4gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgdGhpcyk7XG4gICAgdGhpcy5hY3Rpb25NYW5hZ2VyLnJlZ2lzdGVyQWxsKGFjdGlvbnMpO1xuICAgIHRoaXMuYWN0aW9uTWFuYWdlci5yZWdpc3RlckFjdGlvbihjcmVhdGVVbmRvQWN0aW9uKHRoaXMuaGlzdG9yeSkpO1xuICAgIHRoaXMuYWN0aW9uTWFuYWdlci5yZWdpc3RlckFjdGlvbihjcmVhdGVSZWRvQWN0aW9uKHRoaXMuaGlzdG9yeSkpO1xuICB9XG5cbiAgb25XaW5kb3dNZXNzYWdlKGV2ZW50KSB7XG4gICAgaWYgKGV2ZW50Lm9yaWdpbiAhPT0gXCJodHRwczovL3BsYXllci52aW1lby5jb21cIiAmJiBldmVudC5vcmlnaW4gIT09IFwiaHR0cHM6Ly93d3cueW91dHViZS5jb21cIikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGxldCBkYXRhID0gbnVsbDtcblxuICAgIHRyeSB7XG4gICAgICBkYXRhID0gSlNPTi5wYXJzZShldmVudC5kYXRhKTtcbiAgICB9IGNhdGNoIChlKSB7fVxuXG4gICAgaWYgKCFkYXRhKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgc3dpdGNoIChldmVudC5vcmlnaW4pIHtcbiAgICAgIGNhc2UgXCJodHRwczovL3BsYXllci52aW1lby5jb21cIjpcbiAgICAgICAgLy9BbGxvd2luZyBmb3IgbXVsdGlwbGUgaW5zdGFuY2VzIG9mIEV4Y2FsaWRyYXcgcnVubmluZyBpbiB0aGUgd2luZG93XG4gICAgICAgIGlmIChkYXRhLm1ldGhvZCA9PT0gXCJwYXVzZWRcIikge1xuICAgICAgICAgIGxldCBzb3VyY2UgPSBudWxsO1xuICAgICAgICAgIGNvbnN0IGlmcmFtZXMgPSBkb2N1bWVudC5ib2R5LnF1ZXJ5U2VsZWN0b3JBbGwoXCJpZnJhbWUuZXhjYWxpZHJhd19fZW1iZWRkYWJsZVwiKTtcblxuICAgICAgICAgIGlmICghaWZyYW1lcykge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZm9yIChjb25zdCBpZnJhbWUgb2YgaWZyYW1lcykge1xuICAgICAgICAgICAgaWYgKGlmcmFtZS5jb250ZW50V2luZG93ID09PSBldmVudC5zb3VyY2UpIHtcbiAgICAgICAgICAgICAgc291cmNlID0gaWZyYW1lLmNvbnRlbnRXaW5kb3c7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgc291cmNlID09PSBudWxsIHx8IHNvdXJjZSA9PT0gdm9pZCAwID8gdm9pZCAwIDogc291cmNlLnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIG1ldGhvZDogZGF0YS52YWx1ZSA/IFwicGxheVwiIDogXCJwYXVzZVwiLFxuICAgICAgICAgICAgdmFsdWU6IHRydWVcbiAgICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgXCJodHRwczovL3d3dy55b3V0dWJlLmNvbVwiOlxuICAgICAgICBpZiAoZGF0YS5ldmVudCA9PT0gXCJpbmZvRGVsaXZlcnlcIiAmJiBkYXRhLmluZm8gJiYgZGF0YS5pZCAmJiB0eXBlb2YgZGF0YS5pbmZvLnBsYXllclN0YXRlID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgY29uc3QgaWQgPSBkYXRhLmlkO1xuICAgICAgICAgIGNvbnN0IHBsYXllclN0YXRlID0gZGF0YS5pbmZvLnBsYXllclN0YXRlO1xuXG4gICAgICAgICAgaWYgKE9iamVjdC52YWx1ZXMoWU9VVFVCRV9TVEFURVMpLmluY2x1ZGVzKHBsYXllclN0YXRlKSkge1xuICAgICAgICAgICAgWU9VVFVCRV9WSURFT19TVEFURVMuc2V0KGlkLCBwbGF5ZXJTdGF0ZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlRW1iZWRkYWJsZVJlZihpZCwgcmVmKSB7XG4gICAgaWYgKHJlZikge1xuICAgICAgdGhpcy5pRnJhbWVSZWZzLnNldChpZCwgcmVmKTtcbiAgICB9XG4gIH1cblxuICBnZXRIVE1MSUZyYW1lRWxlbWVudChpZCkge1xuICAgIHJldHVybiB0aGlzLmlGcmFtZVJlZnMuZ2V0KGlkKTtcbiAgfVxuXG4gIGhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayhlbGVtZW50KSB7XG4gICAgdmFyIF9hLCBfYiwgX2MsIF9kO1xuXG4gICAgaWYgKCgoX2EgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSA9PT0gZWxlbWVudCAmJiAoKF9iID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc3RhdGUpID09PSBcImFjdGl2ZVwiKSB7XG4gICAgICByZXR1cm47XG4gICAgfSAvLyBUaGUgZGVsYXkgc2VydmVzIHR3byBwdXJwb3Nlc1xuICAgIC8vIDEuIFRvIHByZXZlbnQgZmlyc3QgY2xpY2sgcHJvcGFnYXRpbmcgdG8gaWZyYW1lIG9uIG1vYmlsZSxcbiAgICAvLyAgICBlbHNlIHRoZSBjbGljayB3aWxsIGltbWVkaWF0ZWx5IHN0YXJ0IGFuZCBzdG9wIHRoZSB2aWRlb1xuICAgIC8vIDIuIElmIHRoZSB1c2VyIGRvdWJsZSBjbGlja3MgdGhlIGZyYW1lIGNlbnRlciB0byBhY3RpdmF0ZSBpdFxuICAgIC8vICAgIHdpdGhvdXQgdGhlIGRlbGF5IHlvdXR1YmUgd2lsbCBpbW1lZGlhdGVseSBvcGVuIHRoZSB2aWRlb1xuICAgIC8vICAgIGluIGZ1bGxzY3JlZW4gbW9kZVxuXG5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBhY3RpdmVFbWJlZGRhYmxlOiB7XG4gICAgICAgICAgZWxlbWVudCxcbiAgICAgICAgICBzdGF0ZTogXCJhY3RpdmVcIlxuICAgICAgICB9LFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHtcbiAgICAgICAgICBbZWxlbWVudC5pZF06IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICBzZWxlY3Rpb25FbGVtZW50OiBudWxsXG4gICAgICB9KTtcbiAgICB9LCAxMDApO1xuICAgIGNvbnN0IGlmcmFtZSA9IHRoaXMuZ2V0SFRNTElGcmFtZUVsZW1lbnQoZWxlbWVudC5pZCk7XG5cbiAgICBpZiAoIShpZnJhbWUgPT09IG51bGwgfHwgaWZyYW1lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpZnJhbWUuY29udGVudFdpbmRvdykpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoaWZyYW1lLnNyYy5pbmNsdWRlcyhcInlvdXR1YmVcIikpIHtcbiAgICAgIGNvbnN0IHN0YXRlID0gWU9VVFVCRV9WSURFT19TVEFURVMuZ2V0KGVsZW1lbnQuaWQpO1xuXG4gICAgICBpZiAoIXN0YXRlKSB7XG4gICAgICAgIFlPVVRVQkVfVklERU9fU1RBVEVTLnNldChlbGVtZW50LmlkLCBZT1VUVUJFX1NUQVRFUy5VTlNUQVJURUQpO1xuICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgZXZlbnQ6IFwibGlzdGVuaW5nXCIsXG4gICAgICAgICAgaWQ6IGVsZW1lbnQuaWRcbiAgICAgICAgfSksIFwiKlwiKTtcbiAgICAgIH1cblxuICAgICAgc3dpdGNoIChzdGF0ZSkge1xuICAgICAgICBjYXNlIFlPVVRVQkVfU1RBVEVTLlBMQVlJTkc6XG4gICAgICAgIGNhc2UgWU9VVFVCRV9TVEFURVMuQlVGRkVSSU5HOlxuICAgICAgICAgIChfYyA9IGlmcmFtZS5jb250ZW50V2luZG93KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgZXZlbnQ6IFwiY29tbWFuZFwiLFxuICAgICAgICAgICAgZnVuYzogXCJwYXVzZVZpZGVvXCIsXG4gICAgICAgICAgICBhcmdzOiBcIlwiXG4gICAgICAgICAgfSksIFwiKlwiKTtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIChfZCA9IGlmcmFtZS5jb250ZW50V2luZG93KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgZXZlbnQ6IFwiY29tbWFuZFwiLFxuICAgICAgICAgICAgZnVuYzogXCJwbGF5VmlkZW9cIixcbiAgICAgICAgICAgIGFyZ3M6IFwiXCJcbiAgICAgICAgICB9KSwgXCIqXCIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChpZnJhbWUuc3JjLmluY2x1ZGVzKFwicGxheWVyLnZpbWVvLmNvbVwiKSkge1xuICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2UoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBtZXRob2Q6IFwicGF1c2VkXCIgLy92aWRlbyBwbGF5L3BhdXNlIGluIG9uV2luZG93TWVzc2FnZSBoYW5kbGVyXG5cbiAgICAgIH0pLCBcIipcIik7XG4gICAgfVxuICB9XG5cbiAgaXNFbWJlZGRhYmxlQ2VudGVyKGVsLCBldmVudCwgc2NlbmVYLCBzY2VuZVkpIHtcbiAgICB2YXIgX2EsIF9iO1xuXG4gICAgcmV0dXJuIGVsICYmICFldmVudC5hbHRLZXkgJiYgIWV2ZW50LnNoaWZ0S2V5ICYmICFldmVudC5tZXRhS2V5ICYmICFldmVudC5jdHJsS2V5ICYmICgoKF9hID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgIT09IGVsIHx8ICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiaG92ZXJcIiB8fCAhdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSAmJiBzY2VuZVggPj0gZWwueCArIGVsLndpZHRoIC8gMyAmJiBzY2VuZVggPD0gZWwueCArIDIgKiBlbC53aWR0aCAvIDMgJiYgc2NlbmVZID49IGVsLnkgKyBlbC5oZWlnaHQgLyAzICYmIHNjZW5lWSA8PSBlbC55ICsgMiAqIGVsLmhlaWdodCAvIDM7XG4gIH1cblxuICByZW5kZXJFbWJlZGRhYmxlcygpIHtcbiAgICBjb25zdCBzY2FsZSA9IHRoaXMuc3RhdGUuem9vbS52YWx1ZTtcbiAgICBjb25zdCBub3JtYWxpemVkV2lkdGggPSB0aGlzLnN0YXRlLndpZHRoO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRIZWlnaHQgPSB0aGlzLnN0YXRlLmhlaWdodDtcbiAgICBjb25zdCBlbWJlZGRhYmxlRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLmZpbHRlcihlbCA9PiBpc0VtYmVkZGFibGVFbGVtZW50KGVsKSAmJiAhIWVsLnZhbGlkYXRlZCk7XG4gICAgcmV0dXJuIF9qc3goX0ZyYWdtZW50LCB7XG4gICAgICBjaGlsZHJlbjogZW1iZWRkYWJsZUVsZW1lbnRzLm1hcChlbCA9PiB7XG4gICAgICAgIHZhciBfYSwgX2IsIF9jLCBfZCwgX2UsIF9mLCBfZywgX2g7XG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9ID0gc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzKHtcbiAgICAgICAgICBzY2VuZVg6IGVsLngsXG4gICAgICAgICAgc2NlbmVZOiBlbC55XG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBlbWJlZExpbmsgPSBnZXRFbWJlZExpbmsodG9WYWxpZFVSTChlbC5saW5rIHx8IFwiXCIpKTtcbiAgICAgICAgY29uc3QgaXNWaXNpYmxlID0gaXNFbGVtZW50SW5WaWV3cG9ydChlbCwgbm9ybWFsaXplZFdpZHRoLCBub3JtYWxpemVkSGVpZ2h0LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgaXNBY3RpdmUgPSAoKF9hID0gdGhpcy5zdGF0ZS5hY3RpdmVFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZWxlbWVudCkgPT09IGVsICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgPT09IFwiYWN0aXZlXCI7XG4gICAgICAgIGNvbnN0IGlzSG92ZXJlZCA9ICgoX2MgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5lbGVtZW50KSA9PT0gZWwgJiYgKChfZCA9IHRoaXMuc3RhdGUuYWN0aXZlRW1iZWRkYWJsZSkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLnN0YXRlKSA9PT0gXCJob3ZlclwiO1xuICAgICAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICBjbGFzc05hbWU6IGNsc3goXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlLWNvbnRhaW5lclwiLCB7XG4gICAgICAgICAgICBcImlzLWhvdmVyZWRcIjogaXNIb3ZlcmVkXG4gICAgICAgICAgfSksXG4gICAgICAgICAgc3R5bGU6IHtcbiAgICAgICAgICAgIHRyYW5zZm9ybTogaXNWaXNpYmxlID8gYHRyYW5zbGF0ZSgke3ggLSB0aGlzLnN0YXRlLm9mZnNldExlZnR9cHgsICR7eSAtIHRoaXMuc3RhdGUub2Zmc2V0VG9wfXB4KSBzY2FsZSgke3NjYWxlfSlgIDogXCJub25lXCIsXG4gICAgICAgICAgICBkaXNwbGF5OiBpc1Zpc2libGUgPyBcImJsb2NrXCIgOiBcIm5vbmVcIixcbiAgICAgICAgICAgIG9wYWNpdHk6IGVsLm9wYWNpdHkgLyAxMDAsXG4gICAgICAgICAgICBbXCItLWVtYmVkZGFibGUtcmFkaXVzXCJdOiBgJHtnZXRDb3JuZXJSYWRpdXMoTWF0aC5taW4oZWwud2lkdGgsIGVsLmhlaWdodCksIGVsKX1weGBcbiAgICAgICAgICB9XG4gICAgICAgIH0sIHtcbiAgICAgICAgICBjaGlsZHJlbjogX2pzeHMoXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAvL3RoaXMgaXMgYSBoYWNrIHRoYXQgYWRkcmVzc2VzIGlzc2Ugd2l0aCBlbWJlZGRlZCBleGNhbGlkcmF3LmNvbSBlbWJlZGRhYmxlXG4gICAgICAgICAgICAvL2h0dHBzOi8vZ2l0aHViLmNvbS9leGNhbGlkcmF3L2V4Y2FsaWRyYXcvcHVsbC82NjkxI2lzc3VlY29tbWVudC0xNjA3MzgzOTM4XG5cbiAgICAgICAgICAgIC8qcmVmPXsocmVmKSA9PiB7XG4gICAgICAgICAgICAgIGlmICghdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG4gICAgICAgICAgICAgIGNvbnN0IHNoID0gY29udGFpbmVyLnNjcm9sbEhlaWdodDtcbiAgICAgICAgICAgICAgY29uc3QgY2ggPSBjb250YWluZXIuY2xpZW50SGVpZ2h0O1xuICAgICAgICAgICAgICBpZiAoc2ggIT09IGNoKSB7XG4gICAgICAgICAgICAgICAgY29udGFpbmVyLnN0eWxlLmhlaWdodCA9IGAke3NofXB4YDtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgIGNvbnRhaW5lci5zdHlsZS5oZWlnaHQgPSBgMTAwJWA7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH19Ki9cbiAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlLWNvbnRhaW5lcl9faW5uZXJcIixcbiAgICAgICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICAgIHdpZHRoOiBpc1Zpc2libGUgPyBgJHtlbC53aWR0aH1weGAgOiAwLFxuICAgICAgICAgICAgICBoZWlnaHQ6IGlzVmlzaWJsZSA/IGAke2VsLmhlaWdodH1weGAgOiAwLFxuICAgICAgICAgICAgICB0cmFuc2Zvcm06IGlzVmlzaWJsZSA/IGByb3RhdGUoJHtlbC5hbmdsZX1yYWQpYCA6IFwibm9uZVwiLFxuICAgICAgICAgICAgICBwb2ludGVyRXZlbnRzOiBpc0FjdGl2ZSA/IFBPSU5URVJfRVZFTlRTLmVuYWJsZWQgOiBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgIGNoaWxkcmVuOiBbaXNIb3ZlcmVkICYmIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlLWhpbnRcIlxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICBjaGlsZHJlbjogdChcImJ1dHRvbnMuZW1iZWRkYWJsZUludGVyYWN0aW9uQnV0dG9uXCIpXG4gICAgICAgICAgICB9KSksIF9qc3goXCJkaXZcIiwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3X19lbWJlZGRhYmxlX19vdXRlclwiLFxuICAgICAgICAgICAgICBzdHlsZToge1xuICAgICAgICAgICAgICAgIHBhZGRpbmc6IGAke2VsLnN0cm9rZVdpZHRofXB4YFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgIGNoaWxkcmVuOiAoX2cgPSAoX2YgPSAoX2UgPSB0aGlzLnByb3BzKS5yZW5kZXJFbWJlZGRhYmxlKSA9PT0gbnVsbCB8fCBfZiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2YuY2FsbChfZSwgZWwsIHRoaXMuc3RhdGUpKSAhPT0gbnVsbCAmJiBfZyAhPT0gdm9pZCAwID8gX2cgOiBfanN4KFwiaWZyYW1lXCIsIHtcbiAgICAgICAgICAgICAgICByZWY6IHJlZiA9PiB0aGlzLnVwZGF0ZUVtYmVkZGFibGVSZWYoZWwuaWQsIHJlZiksXG4gICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImV4Y2FsaWRyYXdfX2VtYmVkZGFibGVcIixcbiAgICAgICAgICAgICAgICBzcmNEb2M6IChlbWJlZExpbmsgPT09IG51bGwgfHwgZW1iZWRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbWJlZExpbmsudHlwZSkgPT09IFwiZG9jdW1lbnRcIiA/IGVtYmVkTGluay5zcmNkb2ModGhpcy5zdGF0ZS50aGVtZSkgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgc3JjOiAoZW1iZWRMaW5rID09PSBudWxsIHx8IGVtYmVkTGluayA9PT0gdm9pZCAwID8gdm9pZCAwIDogZW1iZWRMaW5rLnR5cGUpICE9PSBcImRvY3VtZW50XCIgPyAoX2ggPSBlbWJlZExpbmsgPT09IG51bGwgfHwgZW1iZWRMaW5rID09PSB2b2lkIDAgPyB2b2lkIDAgOiBlbWJlZExpbmsubGluaykgIT09IG51bGwgJiYgX2ggIT09IHZvaWQgMCA/IF9oIDogXCJcIiA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAvLyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3EvMTg0NzAwMTVcbiAgICAgICAgICAgICAgICBzY3JvbGxpbmc6IFwibm9cIixcbiAgICAgICAgICAgICAgICByZWZlcnJlclBvbGljeTogXCJuby1yZWZlcnJlci13aGVuLWRvd25ncmFkZVwiLFxuICAgICAgICAgICAgICAgIHRpdGxlOiBcIkV4Y2FsaWRyYXcgRW1iZWRkZWQgQ29udGVudFwiLFxuICAgICAgICAgICAgICAgIGFsbG93OiBcImFjY2VsZXJvbWV0ZXI7IGF1dG9wbGF5OyBjbGlwYm9hcmQtd3JpdGU7IGVuY3J5cHRlZC1tZWRpYTsgZ3lyb3Njb3BlOyBwaWN0dXJlLWluLXBpY3R1cmVcIixcbiAgICAgICAgICAgICAgICBhbGxvd0Z1bGxTY3JlZW46IHRydWUsXG4gICAgICAgICAgICAgICAgc2FuZGJveDogXCJhbGxvdy1zYW1lLW9yaWdpbiBhbGxvdy1zY3JpcHRzIGFsbG93LWZvcm1zIGFsbG93LXBvcHVwcyBhbGxvdy1wb3B1cHMtdG8tZXNjYXBlLXNhbmRib3ggYWxsb3ctcHJlc2VudGF0aW9uIGFsbG93LWRvd25sb2Fkc1wiXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KSldXG4gICAgICAgICAgfSkpXG4gICAgICAgIH0pLCBlbC5pZCk7XG4gICAgICB9KVxuICAgIH0pO1xuICB9XG5cbiAgcmVuZGVyKCkge1xuICAgIHZhciBfYSwgX2IsIF9jO1xuXG4gICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICBjb25zdCB7XG4gICAgICByZW5kZXJUb3BSaWdodFVJLFxuICAgICAgcmVuZGVyQ3VzdG9tU3RhdHNcbiAgICB9ID0gdGhpcy5wcm9wcztcbiAgICBjb25zdCB2ZXJzaW9uTm9uY2UgPSB0aGlzLnNjZW5lLmdldFZlcnNpb25Ob25jZSgpO1xuICAgIGNvbnN0IHtcbiAgICAgIGNhbnZhc0VsZW1lbnRzLFxuICAgICAgdmlzaWJsZUVsZW1lbnRzXG4gICAgfSA9IHRoaXMucmVuZGVyZXIuZ2V0UmVuZGVyYWJsZUVsZW1lbnRzKHtcbiAgICAgIHZlcnNpb25Ob25jZSxcbiAgICAgIHpvb206IHRoaXMuc3RhdGUuem9vbSxcbiAgICAgIG9mZnNldExlZnQ6IHRoaXMuc3RhdGUub2Zmc2V0TGVmdCxcbiAgICAgIG9mZnNldFRvcDogdGhpcy5zdGF0ZS5vZmZzZXRUb3AsXG4gICAgICBzY3JvbGxYOiB0aGlzLnN0YXRlLnNjcm9sbFgsXG4gICAgICBzY3JvbGxZOiB0aGlzLnN0YXRlLnNjcm9sbFksXG4gICAgICBoZWlnaHQ6IHRoaXMuc3RhdGUuaGVpZ2h0LFxuICAgICAgd2lkdGg6IHRoaXMuc3RhdGUud2lkdGgsXG4gICAgICBlZGl0aW5nRWxlbWVudDogdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCxcbiAgICAgIHBlbmRpbmdJbWFnZUVsZW1lbnRJZDogdGhpcy5zdGF0ZS5wZW5kaW5nSW1hZ2VFbGVtZW50SWRcbiAgICB9KTtcbiAgICByZXR1cm4gX2pzeChcImRpdlwiLCBPYmplY3QuYXNzaWduKHtcbiAgICAgIGNsYXNzTmFtZTogY2xzeChcImV4Y2FsaWRyYXcgZXhjYWxpZHJhdy1jb250YWluZXJcIiwge1xuICAgICAgICBcImV4Y2FsaWRyYXctLXZpZXctbW9kZVwiOiB0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCxcbiAgICAgICAgXCJleGNhbGlkcmF3LS1tb2JpbGVcIjogdGhpcy5kZXZpY2UuZWRpdG9yLmlzTW9iaWxlXG4gICAgICB9KSxcbiAgICAgIHN0eWxlOiB7XG4gICAgICAgIFtcIi0tdWktcG9pbnRlckV2ZW50c1wiXTogdGhpcy5zdGF0ZS5zZWxlY3Rpb25FbGVtZW50IHx8IHRoaXMuc3RhdGUuZHJhZ2dpbmdFbGVtZW50IHx8IHRoaXMuc3RhdGUucmVzaXppbmdFbGVtZW50IHx8IHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIgJiYgLy8gdGVjaG5pY2FsbHkgd2UgY2FuIGp1c3QgdGVzdCBvbiB0aGlzIG9uY2Ugd2UgbWFrZSBpdCBtb3JlIHNhZmVcbiAgICAgICAgdGhpcy5zdGF0ZS5jdXJzb3JCdXR0b24gPT09IFwiZG93blwiIHx8IHRoaXMuc3RhdGUuZWRpdGluZ0VsZW1lbnQgJiYgIWlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPyBQT0lOVEVSX0VWRU5UUy5kaXNhYmxlZCA6IFBPSU5URVJfRVZFTlRTLmVuYWJsZWRcbiAgICAgIH0sXG4gICAgICByZWY6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZixcbiAgICAgIG9uRHJvcDogdGhpcy5oYW5kbGVBcHBPbkRyb3AsXG4gICAgICB0YWJJbmRleDogMCxcbiAgICAgIG9uS2V5RG93bjogdGhpcy5wcm9wcy5oYW5kbGVLZXlib2FyZEdsb2JhbGx5ID8gdW5kZWZpbmVkIDogdGhpcy5vbktleURvd25cbiAgICB9LCB7XG4gICAgICBjaGlsZHJlbjogX2pzeChBcHBDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgdmFsdWU6IHRoaXNcbiAgICAgIH0sIHtcbiAgICAgICAgY2hpbGRyZW46IF9qc3goQXBwUHJvcHNDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICB2YWx1ZTogdGhpcy5wcm9wc1xuICAgICAgICB9LCB7XG4gICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd0NvbnRhaW5lckNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgdmFsdWU6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclZhbHVlXG4gICAgICAgICAgfSwge1xuICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRGV2aWNlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmRldmljZVxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICBjaGlsZHJlbjogX2pzeChFeGNhbGlkcmF3U2V0QXBwU3RhdGVDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5zZXRBcHBTdGF0ZVxuICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgY2hpbGRyZW46IF9qc3goRXhjYWxpZHJhd0FwcFN0YXRlQ29udGV4dC5Qcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5zdGF0ZVxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBfanN4cyhFeGNhbGlkcmF3RWxlbWVudHNDb250ZXh0LlByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKClcbiAgICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IFtfanN4cyhFeGNhbGlkcmF3QWN0aW9uTWFuYWdlckNvbnRleHQuUHJvdmlkZXIsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmFjdGlvbk1hbmFnZXJcbiAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbX2pzeHMoTGF5ZXJVSSwgT2JqZWN0LmFzc2lnbih7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBmaWxlczogdGhpcy5maWxlcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldEFwcFN0YXRlOiB0aGlzLnNldEFwcFN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uTWFuYWdlcjogdGhpcy5hY3Rpb25NYW5hZ2VyLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkxvY2tUb2dnbGU6IHRoaXMudG9nZ2xlTG9jayxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUGVuTW9kZVRvZ2dsZTogdGhpcy50b2dnbGVQZW5Nb2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25IYW5kVG9vbFRvZ2dsZTogdGhpcy5vbkhhbmRUb29sVG9nZ2xlLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGFuZ0NvZGU6IGdldExhbmd1YWdlKCkuY29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlclRvcFJpZ2h0VUk6IHJlbmRlclRvcFJpZ2h0VUksXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJDdXN0b21TdGF0czogcmVuZGVyQ3VzdG9tU3RhdHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzaG93RXhpdFplbk1vZGVCdG46IHR5cGVvZiAoKF9hID0gdGhpcy5wcm9wcykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnplbk1vZGVFbmFibGVkKSA9PT0gXCJ1bmRlZmluZWRcIiAmJiB0aGlzLnN0YXRlLnplbk1vZGVFbmFibGVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgVUlPcHRpb25zOiB0aGlzLnByb3BzLlVJT3B0aW9ucyxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uRXhwb3J0SW1hZ2U6IHRoaXMub25FeHBvcnRJbWFnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlcldlbGNvbWVTY3JlZW46ICF0aGlzLnN0YXRlLmlzTG9hZGluZyAmJiB0aGlzLnN0YXRlLnNob3dXZWxjb21lU2NyZWVuICYmIHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiICYmICF0aGlzLnN0YXRlLnplbk1vZGVFbmFibGVkICYmICF0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcDogdGhpcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzQ29sbGFib3JhdGluZzogdGhpcy5wcm9wcy5pc0NvbGxhYm9yYXRpbmdcbiAgICAgICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW3RoaXMucHJvcHMuY2hpbGRyZW4sIHRoaXMuc3RhdGUub3BlbkRpYWxvZyA9PT0gXCJtZXJtYWlkXCIgJiYgX2pzeChNZXJtYWlkVG9FeGNhbGlkcmF3LCB7fSldXG4gICAgICAgICAgICAgICAgICAgICAgfSkpLCBfanN4KFwiZGl2XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3LXRleHRFZGl0b3JDb250YWluZXJcIlxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KFwiZGl2XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogXCJleGNhbGlkcmF3LWNvbnRleHRNZW51Q29udGFpbmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICB9KSwgX2pzeChcImRpdlwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU6IFwiZXhjYWxpZHJhdy1leWUtZHJvcHBlci1jb250YWluZXJcIlxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBfanN4KExhc2VyVG9vbE92ZXJsYXksIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hbmFnZXI6IHRoaXMubGFzZXJQYXRoTWFuYWdlclxuICAgICAgICAgICAgICAgICAgICAgIH0pLCBzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiAhdGhpcy5zdGF0ZS5jb250ZXh0TWVudSAmJiB0aGlzLnN0YXRlLnNob3dIeXBlcmxpbmtQb3B1cCAmJiBfanN4KEh5cGVybGluaywge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudDogc2VsZWN0ZWRFbGVtZW50c1swXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldEFwcFN0YXRlOiB0aGlzLnNldEFwcFN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25MaW5rT3BlbjogdGhpcy5wcm9wcy5vbkxpbmtPcGVuLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0VG9hc3Q6IHRoaXMuc2V0VG9hc3RcbiAgICAgICAgICAgICAgICAgICAgICB9LCBzZWxlY3RlZEVsZW1lbnRzWzBdLmlkKSwgdGhpcy5zdGF0ZS50b2FzdCAhPT0gbnVsbCAmJiBfanN4KFRvYXN0LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiB0aGlzLnN0YXRlLnRvYXN0Lm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkNsb3NlOiAoKSA9PiB0aGlzLnNldFRvYXN0KG51bGwpLFxuICAgICAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IHRoaXMuc3RhdGUudG9hc3QuZHVyYXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICBjbG9zYWJsZTogdGhpcy5zdGF0ZS50b2FzdC5jbG9zYWJsZVxuICAgICAgICAgICAgICAgICAgICAgIH0pLCB0aGlzLnN0YXRlLmNvbnRleHRNZW51ICYmIF9qc3goQ29udGV4dE1lbnUsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW1zOiB0aGlzLnN0YXRlLmNvbnRleHRNZW51Lml0ZW1zLFxuICAgICAgICAgICAgICAgICAgICAgICAgdG9wOiB0aGlzLnN0YXRlLmNvbnRleHRNZW51LnRvcCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxlZnQ6IHRoaXMuc3RhdGUuY29udGV4dE1lbnUubGVmdCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGlvbk1hbmFnZXI6IHRoaXMuYWN0aW9uTWFuYWdlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xvc2U6IGNhbGxiYWNrID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dE1lbnU6IG51bGxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSwgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayA9PT0gbnVsbCB8fCBjYWxsYmFjayA9PT0gdm9pZCAwID8gdm9pZCAwIDogY2FsbGJhY2soKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goU3RhdGljQ2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmM6IHRoaXMucmMsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogY2FudmFzRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB2aXNpYmxlRWxlbWVudHM6IHZpc2libGVFbGVtZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb25Ob25jZTogdmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uTm9uY2U6IChfYiA9IHRoaXMuc3RhdGUuc2VsZWN0aW9uRWxlbWVudCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnZlcnNpb25Ob25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcFN0YXRlOiB0aGlzLnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyQ29uZmlnOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlQ2FjaGU6IHRoaXMuaW1hZ2VDYWNoZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaXNFeHBvcnRpbmc6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJHcmlkOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSksIF9qc3goSW50ZXJhY3RpdmVDYW52YXMsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lclJlZjogdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzOiB0aGlzLmludGVyYWN0aXZlQ2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudHM6IGNhbnZhc0VsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZUVsZW1lbnRzOiB2aXNpYmxlRWxlbWVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRzOiBzZWxlY3RlZEVsZW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmVyc2lvbk5vbmNlOiB2ZXJzaW9uTm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25Ob25jZTogKF9jID0gdGhpcy5zdGF0ZS5zZWxlY3Rpb25FbGVtZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MudmVyc2lvbk5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGU6IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZW5kZXJJbnRlcmFjdGl2ZVNjZW5lQ2FsbGJhY2s6IHRoaXMucmVuZGVySW50ZXJhY3RpdmVTY2VuZUNhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlQ2FudmFzUmVmOiB0aGlzLmhhbmRsZUludGVyYWN0aXZlQ2FudmFzUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgb25Db250ZXh0TWVudTogdGhpcy5oYW5kbGVDYW52YXNDb250ZXh0TWVudSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlck1vdmU6IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlck1vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJVcDogdGhpcy5oYW5kbGVDYW52YXNQb2ludGVyVXAsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblBvaW50ZXJDYW5jZWw6IHRoaXMucmVtb3ZlUG9pbnRlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uVG91Y2hNb3ZlOiB0aGlzLmhhbmRsZVRvdWNoTW92ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUG9pbnRlckRvd246IHRoaXMuaGFuZGxlQ2FudmFzUG9pbnRlckRvd24sXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkRvdWJsZUNsaWNrOiB0aGlzLmhhbmRsZUNhbnZhc0RvdWJsZUNsaWNrXG4gICAgICAgICAgICAgICAgICAgICAgfSksIHRoaXMucmVuZGVyRnJhbWVOYW1lcygpXVxuICAgICAgICAgICAgICAgICAgICB9KSksIHRoaXMucmVuZGVyRW1iZWRkYWJsZXMoKV1cbiAgICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgIH0pKVxuICAgICAgICB9KSlcbiAgICAgIH0pKVxuICAgIH0pKTtcbiAgfVxuXG4gIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgIHZhciBfYTtcblxuICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XG4gICAgICB0aGlzLnVubW91bnRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyVmFsdWUuY29udGFpbmVyID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQ7XG5cbiAgICAgIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gRU5WLlRFU1QgfHwgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09IFwicHJvZHVjdGlvblwiKSB7XG4gICAgICAgIGNvbnN0IHNldFN0YXRlID0gdGhpcy5zZXRTdGF0ZS5iaW5kKHRoaXMpO1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh3aW5kb3cuaCwge1xuICAgICAgICAgIHN0YXRlOiB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICBnZXQ6ICgpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBzZXRTdGF0ZToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6ICguLi5hcmdzKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLnNldFN0YXRlKC4uLmFyZ3MpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgYXBwOiB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogdGhpc1xuICAgICAgICAgIH0sXG4gICAgICAgICAgaGlzdG9yeToge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHRoaXMuaGlzdG9yeVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2NlbmUuYWRkQ2FsbGJhY2sodGhpcy5vblNjZW5lVXBkYXRlZCk7XG4gICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXJzKCk7XG5cbiAgICAgIGlmICh0aGlzLnByb3BzLmF1dG9Gb2N1cyAmJiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkge1xuICAgICAgICB0aGlzLmZvY3VzQ29udGFpbmVyKCk7XG4gICAgICB9XG5cbiAgICAgIGlmICggLy8gYm91bmRpbmcgcmVjdHMgZG9uJ3Qgd29yayBpbiB0ZXN0cyBzbyB1cGRhdGluZ1xuICAgICAgLy8gdGhlIHN0YXRlIG9uIGluaXQgd291bGQgcmVzdWx0IGluIG1ha2luZyB0aGUgdGVzdCBlbnZpcm8gcnVuXG4gICAgICAvLyBpbiBtb2JpbGUgYnJlYWtwb2ludCAoMCB3aWR0aC9oZWlnaHQpLCBtYWtpbmcgZXZlcnl0aGluZyBmYWlsXG4gICAgICAhaXNUZXN0RW52KCkpIHtcbiAgICAgICAgdGhpcy5yZWZyZXNoVmlld3BvcnRCcmVha3BvaW50cygpO1xuICAgICAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cygpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3VwcG9ydHNSZXNpemVPYnNlcnZlciAmJiB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkge1xuICAgICAgICB0aGlzLnJlc2l6ZU9ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKCgpID0+IHtcbiAgICAgICAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cygpO1xuICAgICAgICAgIHRoaXMudXBkYXRlRE9NUmVjdCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgKF9hID0gdGhpcy5yZXNpemVPYnNlcnZlcikgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLm9ic2VydmUodGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzZWFyY2hQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2guc2xpY2UoMSkpO1xuXG4gICAgICBpZiAoc2VhcmNoUGFyYW1zLmhhcyhcIndlYi1zaGFyZS10YXJnZXRcIikpIHtcbiAgICAgICAgLy8gT2J0YWluIGEgZmlsZSB0aGF0IHdhcyBzaGFyZWQgdmlhIHRoZSBXZWIgU2hhcmUgVGFyZ2V0IEFQSS5cbiAgICAgICAgdGhpcy5yZXN0b3JlRmlsZUZyb21TaGFyZSgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy51cGRhdGVET01SZWN0KHRoaXMuaW5pdGlhbGl6ZVNjZW5lKTtcbiAgICAgIH0gLy8gbm90ZSB0aGF0IHRoaXMgY2hlY2sgc2VlbXMgdG8gYWx3YXlzIHBhc3MgaW4gbG9jYWxob3N0XG5cblxuICAgICAgaWYgKGlzQnJhdmUoKSAmJiAhaXNNZWFzdXJlVGV4dFN1cHBvcnRlZCgpKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yTWVzc2FnZTogX2pzeChCcmF2ZU1lYXN1cmVUZXh0RXJyb3IsIHt9KVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgIHZhciBfYTtcblxuICAgIHRoaXMucmVuZGVyZXIuZGVzdHJveSgpO1xuICAgIHRoaXMuc2NlbmUgPSBuZXcgU2NlbmUoKTtcbiAgICB0aGlzLnJlbmRlcmVyID0gbmV3IFJlbmRlcmVyKHRoaXMuc2NlbmUpO1xuICAgIHRoaXMuZmlsZXMgPSB7fTtcbiAgICB0aGlzLmltYWdlQ2FjaGUuY2xlYXIoKTtcbiAgICAoX2EgPSB0aGlzLnJlc2l6ZU9ic2VydmVyKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuZGlzY29ubmVjdCgpO1xuICAgIHRoaXMudW5tb3VudGVkID0gdHJ1ZTtcbiAgICB0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXJzKCk7XG4gICAgdGhpcy5zY2VuZS5kZXN0cm95KCk7XG4gICAgdGhpcy5saWJyYXJ5LmRlc3Ryb3koKTtcbiAgICB0aGlzLmxhc2VyUGF0aE1hbmFnZXIuZGVzdHJveSgpO1xuICAgIHRoaXMub25DaGFuZ2VFbWl0dGVyLmRlc3Ryb3koKTtcbiAgICBTaGFwZUNhY2hlLmRlc3Ryb3koKTtcbiAgICBTbmFwQ2FjaGUuZGVzdHJveSgpO1xuICAgIGNsZWFyVGltZW91dCh0b3VjaFRpbWVvdXQpO1xuICAgIGlzU29tZUVsZW1lbnRTZWxlY3RlZC5jbGVhckNhY2hlKCk7XG4gICAgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cy5jbGVhckNhY2hlKCk7XG4gICAgdG91Y2hUaW1lb3V0ID0gMDtcbiAgfVxuXG4gIHJlbW92ZUV2ZW50TGlzdGVuZXJzKCkge1xuICAgIHZhciBfYSwgX2IsIF9jLCBfZDtcblxuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9VUCwgdGhpcy5yZW1vdmVQb2ludGVyKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkNPUFksIHRoaXMub25Db3B5KTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBBU1RFLCB0aGlzLnBhc3RlRnJvbUNsaXBib2FyZCk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5DVVQsIHRoaXMub25DdXQpO1xuICAgIChfYSA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5XSEVFTCwgdGhpcy5vbldoZWVsKTtcbiAgICAoX2IgPSB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5TQ1JPTEwsIHRoaXMub25TY3JvbGwpO1xuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgdGhpcy5vbktleURvd24sIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1PVVNFX01PVkUsIHRoaXMudXBkYXRlQ3VycmVudEN1cnNvclBvc2l0aW9uLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfYyA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfYyA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2MucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9kID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX1NUQVJULCB0aGlzLm9uR2VzdHVyZVN0YXJ0LCBmYWxzZSk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0NIQU5HRSwgdGhpcy5vbkdlc3R1cmVDaGFuZ2UsIGZhbHNlKTtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULkdFU1RVUkVfRU5ELCB0aGlzLm9uR2VzdHVyZUVuZCwgZmFsc2UpO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gIH1cblxuICBhZGRFdmVudExpc3RlbmVycygpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lO1xuXG4gICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVycygpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKEVWRU5ULk1FU1NBR0UsIHRoaXMub25XaW5kb3dNZXNzYWdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCB0aGlzLnJlbW92ZVBvaW50ZXIpOyAvLyAjMzU1M1xuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5DT1BZLCB0aGlzLm9uQ29weSk7XG4gICAgKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULldIRUVMLCB0aGlzLm9uV2hlZWwsIHtcbiAgICAgIHBhc3NpdmU6IGZhbHNlXG4gICAgfSk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5oYW5kbGVLZXlib2FyZEdsb2JhbGx5KSB7XG4gICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULktFWURPV04sIHRoaXMub25LZXlEb3duLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5LRVlVUCwgdGhpcy5vbktleVVwLCB7XG4gICAgICBwYXNzaXZlOiB0cnVlXG4gICAgfSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5NT1VTRV9NT1ZFLCB0aGlzLnVwZGF0ZUN1cnJlbnRDdXJzb3JQb3NpdGlvbik7IC8vIHJlcmVuZGVyIHRleHQgZWxlbWVudHMgb24gZm9udCBsb2FkIHRvIGZpeCAjNjM3ICYmICMxNTUzXG5cbiAgICAoX2MgPSAoX2IgPSBkb2N1bWVudC5mb250cykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmFkZEV2ZW50TGlzdGVuZXIpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5jYWxsKF9iLCBcImxvYWRpbmdkb25lXCIsIGV2ZW50ID0+IHtcbiAgICAgIGNvbnN0IGxvYWRlZEZvbnRGYWNlcyA9IGV2ZW50LmZvbnRmYWNlcztcbiAgICAgIHRoaXMuZm9udHMub25Gb250c0xvYWRlZChsb2FkZWRGb250RmFjZXMpO1xuICAgIH0pOyAvLyBTYWZhcmktb25seSBkZXNrdG9wIHBpbmNoIHpvb21cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9TVEFSVCwgdGhpcy5vbkdlc3R1cmVTdGFydCwgZmFsc2UpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuR0VTVFVSRV9DSEFOR0UsIHRoaXMub25HZXN0dXJlQ2hhbmdlLCBmYWxzZSk7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5HRVNUVVJFX0VORCwgdGhpcy5vbkdlc3R1cmVFbmQsIGZhbHNlKTtcblxuICAgIGlmICh0aGlzLnN0YXRlLnZpZXdNb2RlRW5hYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUEFTVEUsIHRoaXMucGFzdGVGcm9tQ2xpcGJvYXJkKTtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkNVVCwgdGhpcy5vbkN1dCk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5kZXRlY3RTY3JvbGwpIHtcbiAgICAgIHRoaXMubmVhcmVzdFNjcm9sbGFibGVDb250YWluZXIgPSBnZXROZWFyZXN0U2Nyb2xsYWJsZUNvbnRhaW5lcih0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCk7XG4gICAgICB0aGlzLm5lYXJlc3RTY3JvbGxhYmxlQ29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuU0NST0xMLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICB9XG5cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5SRVNJWkUsIHRoaXMub25SZXNpemUsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5VTkxPQUQsIHRoaXMub25VbmxvYWQsIGZhbHNlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5CTFVSLCB0aGlzLm9uQmx1ciwgZmFsc2UpO1xuICAgIChfZCA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5EUkFHX09WRVIsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gICAgKF9lID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmLmN1cnJlbnQpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5hZGRFdmVudExpc3RlbmVyKEVWRU5ULkRST1AsIHRoaXMuZGlzYWJsZUV2ZW50LCBmYWxzZSk7XG4gIH1cblxuICBjb21wb25lbnREaWRVcGRhdGUocHJldlByb3BzLCBwcmV2U3RhdGUpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZjtcblxuICAgIHRoaXMudXBkYXRlRW1iZWRkYWJsZXMoKTtcblxuICAgIGlmICghdGhpcy5zdGF0ZS5zaG93V2VsY29tZVNjcmVlbiAmJiAhdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5sZW5ndGgpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzaG93V2VsY29tZVNjcmVlbjogdHJ1ZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy5VSU9wdGlvbnMuZG9ja2VkU2lkZWJhckJyZWFrcG9pbnQgIT09IHRoaXMucHJvcHMuVUlPcHRpb25zLmRvY2tlZFNpZGViYXJCcmVha3BvaW50KSB7XG4gICAgICB0aGlzLnJlZnJlc2hFZGl0b3JCcmVha3BvaW50cygpO1xuICAgIH1cblxuICAgIGlmIChwcmV2U3RhdGUuc2Nyb2xsWCAhPT0gdGhpcy5zdGF0ZS5zY3JvbGxYIHx8IHByZXZTdGF0ZS5zY3JvbGxZICE9PSB0aGlzLnN0YXRlLnNjcm9sbFkpIHtcbiAgICAgIChfYiA9IChfYSA9IHRoaXMucHJvcHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5vblNjcm9sbENoYW5nZSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmNhbGwoX2EsIHRoaXMuc3RhdGUuc2Nyb2xsWCwgdGhpcy5zdGF0ZS5zY3JvbGxZKTtcbiAgICB9XG5cbiAgICBpZiAoT2JqZWN0LmtleXModGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLmxlbmd0aCAmJiBpc0VyYXNlckFjdGl2ZSh0aGlzLnN0YXRlKSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCJcbiAgICAgICAgfSlcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlLmFjdGl2ZVRvb2wudHlwZSA9PT0gXCJlcmFzZXJcIiAmJiBwcmV2U3RhdGUudGhlbWUgIT09IHRoaXMuc3RhdGUudGhlbWUpIHtcbiAgICAgIHNldEVyYXNlckN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlLnRoZW1lKTtcbiAgICB9IC8vIEhpZGUgaHlwZXJsaW5rIHBvcHVwIGlmIHNob3duIHdoZW4gZWxlbWVudCB0eXBlIGlzIG5vdCBzZWxlY3Rpb25cblxuXG4gICAgaWYgKHByZXZTdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgIT09IFwic2VsZWN0aW9uXCIgJiYgdGhpcy5zdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXApIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGZhbHNlXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLmxhbmdDb2RlICE9PSB0aGlzLnByb3BzLmxhbmdDb2RlKSB7XG4gICAgICB0aGlzLnVwZGF0ZUxhbmd1YWdlKCk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy52aWV3TW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMudmlld01vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgdmlld01vZGVFbmFibGVkOiAhIXRoaXMucHJvcHMudmlld01vZGVFbmFibGVkXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlN0YXRlLnZpZXdNb2RlRW5hYmxlZCAhPT0gdGhpcy5zdGF0ZS52aWV3TW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICAgIHRoaXMuZGVzZWxlY3RFbGVtZW50cygpO1xuICAgIH1cblxuICAgIGlmIChwcmV2UHJvcHMuemVuTW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMuemVuTW9kZUVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB6ZW5Nb2RlRW5hYmxlZDogISF0aGlzLnByb3BzLnplbk1vZGVFbmFibGVkXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJldlByb3BzLnRoZW1lICE9PSB0aGlzLnByb3BzLnRoZW1lICYmIHRoaXMucHJvcHMudGhlbWUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB0aGVtZTogdGhpcy5wcm9wcy50aGVtZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZQcm9wcy5ncmlkTW9kZUVuYWJsZWQgIT09IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgZ3JpZFNpemU6IHRoaXMucHJvcHMuZ3JpZE1vZGVFbmFibGVkID8gR1JJRF9TSVpFIDogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucHJvcHMubmFtZSAmJiBwcmV2UHJvcHMubmFtZSAhPT0gdGhpcy5wcm9wcy5uYW1lKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgbmFtZTogdGhpcy5wcm9wcy5uYW1lXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAoX2MgPSB0aGlzLmV4Y2FsaWRyYXdDb250YWluZXJSZWYuY3VycmVudCkgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jLmNsYXNzTGlzdC50b2dnbGUoXCJ0aGVtZS0tZGFya1wiLCB0aGlzLnN0YXRlLnRoZW1lID09PSBcImRhcmtcIik7XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudC5lbGVtZW50SWRdKSB7XG4gICAgICAvLyBkZWZlciBzbyB0aGF0IHRoZSBjb21taXRUb0hpc3RvcnkgZmxhZyBpc24ndCByZXNldCB2aWEgY3VycmVudCB1cGRhdGVcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAvLyBleGVjdXRlIG9ubHkgaWYgdGhlIGNvbmRpdGlvbiBzdGlsbCBob2xkcyB3aGVuIHRoZSBkZWZlcnJlZCBjYWxsYmFja1xuICAgICAgICAvLyBleGVjdXRlcyAoaXQgY2FuIGJlIHNjaGVkdWxlZCBtdWx0aXBsZSB0aW1lcyBkZXBlbmRpbmcgb24gaG93XG4gICAgICAgIC8vIG1hbnkgdGltZXMgdGhlIGNvbXBvbmVudCByZW5kZXJzKVxuICAgICAgICB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50ICYmIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgIH0pO1xuICAgIH0gLy8gZmFpbHNhZmUgaW4gY2FzZSB0aGUgc3RhdGUgaXMgYmVpbmcgdXBkYXRlZCBpbiBpbmNvcnJlY3Qgb3JkZXIgcmVzdWx0aW5nXG4gICAgLy8gaW4gdGhlIGVkaXRpbmdFbGVtZW50IGJlaW5nIG5vdyBhIGRlbGV0ZWQgZWxlbWVudFxuXG5cbiAgICBpZiAoKF9kID0gdGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPT09IG51bGwgfHwgX2QgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9kLmlzRGVsZXRlZCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGVkaXRpbmdFbGVtZW50OiBudWxsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzW3RoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LmVsZW1lbnRJZF0pIHtcbiAgICAgIC8vIFRvIG1ha2Ugc3VyZSBgc2VsZWN0ZWRMaW5lYXJFbGVtZW50YCBpcyBpbiBzeW5jIHdpdGggYHNlbGVjdGVkRWxlbWVudElkc2AsIGhvd2V2ZXIgdGhpcyBzaG91bGRuJ3QgYmUgbmVlZGVkIG9uY2VcbiAgICAgIC8vIHdlIGhhdmUgYSBzaW5nbGUgQVBJIHRvIHVwZGF0ZSBgc2VsZWN0ZWRFbGVtZW50SWRzYFxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogbnVsbFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3Qge1xuICAgICAgbXVsdGlFbGVtZW50XG4gICAgfSA9IHByZXZTdGF0ZTtcblxuICAgIGlmIChwcmV2U3RhdGUuYWN0aXZlVG9vbCAhPT0gdGhpcy5zdGF0ZS5hY3RpdmVUb29sICYmIG11bHRpRWxlbWVudCAhPSBudWxsICYmIGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgJiYgaXNCaW5kaW5nRWxlbWVudChtdWx0aUVsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgbWF5YmVCaW5kTGluZWFyRWxlbWVudChtdWx0aUVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUsIHR1cGxlVG9Db29ycyhMaW5lYXJFbGVtZW50RWRpdG9yLmdldFBvaW50QXRJbmRleEdsb2JhbENvb3JkaW5hdGVzKG11bHRpRWxlbWVudCwgLTEpKSk7XG4gICAgfVxuXG4gICAgdGhpcy5oaXN0b3J5LnJlY29yZCh0aGlzLnN0YXRlLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpKTsgLy8gRG8gbm90IG5vdGlmeSBjb25zdW1lcnMgaWYgd2UncmUgc3RpbGwgbG9hZGluZyB0aGUgc2NlbmUuIEFtb25nIG90aGVyXG4gICAgLy8gcG90ZW50aWFsIGlzc3VlcywgdGhpcyBmaXhlcyBhIGNhc2Ugd2hlcmUgdGhlIHRhYiBpc24ndCBmb2N1c2VkIGR1cmluZ1xuICAgIC8vIGluaXQsIHdoaWNoIHdvdWxkIHRyaWdnZXIgb25DaGFuZ2Ugd2l0aCBlbXB0eSBlbGVtZW50cywgd2hpY2ggd291bGQgdGhlblxuICAgIC8vIG92ZXJyaWRlIHdoYXRldmVyIGlzIGluIGxvY2FsU3RvcmFnZSBjdXJyZW50bHkuXG5cbiAgICBpZiAoIXRoaXMuc3RhdGUuaXNMb2FkaW5nKSB7XG4gICAgICAoX2YgPSAoX2UgPSB0aGlzLnByb3BzKS5vbkNoYW5nZSkgPT09IG51bGwgfHwgX2YgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9mLmNhbGwoX2UsIHRoaXMuc2NlbmUuZ2V0RWxlbWVudHNJbmNsdWRpbmdEZWxldGVkKCksIHRoaXMuc3RhdGUsIHRoaXMuZmlsZXMpO1xuICAgICAgdGhpcy5vbkNoYW5nZUVtaXR0ZXIudHJpZ2dlcih0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzLnN0YXRlLCB0aGlzLmZpbGVzKTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgcmVzZXRUYXBUd2ljZSgpIHtcbiAgICBkaWRUYXBUd2ljZSA9IGZhbHNlO1xuICB9IC8vIFRPRE8gcmV3cml0ZSB0aGlzIHRvIHBhc3RlIGJvdGggdGV4dCAmIGltYWdlcyBhdCB0aGUgc2FtZSB0aW1lIGlmXG4gIC8vIHBhc3RlZCBkYXRhIGNvbnRhaW5zIGJvdGhcblxuXG4gIGFkZEVsZW1lbnRzRnJvbU1peGVkQ29udGVudFBhc3RlKG1peGVkQ29udGVudCwge1xuICAgIGlzUGxhaW5QYXN0ZSxcbiAgICBzY2VuZVgsXG4gICAgc2NlbmVZXG4gIH0pIHtcbiAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgaWYgKCFpc1BsYWluUGFzdGUgJiYgbWl4ZWRDb250ZW50LnNvbWUobm9kZSA9PiBub2RlLnR5cGUgPT09IFwiaW1hZ2VVcmxcIikpIHtcbiAgICAgICAgY29uc3QgaW1hZ2VVUkxzID0gbWl4ZWRDb250ZW50LmZpbHRlcihub2RlID0+IG5vZGUudHlwZSA9PT0gXCJpbWFnZVVybFwiKS5tYXAobm9kZSA9PiBub2RlLnZhbHVlKTtcbiAgICAgICAgY29uc3QgcmVzcG9uc2VzID0geWllbGQgUHJvbWlzZS5hbGwoaW1hZ2VVUkxzLm1hcCh1cmwgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBmaWxlOiB5aWVsZCBJbWFnZVVSTFRvRmlsZSh1cmwpXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICB9KSkpO1xuICAgICAgICBsZXQgeSA9IHNjZW5lWTtcbiAgICAgICAgbGV0IGZpcnN0SW1hZ2VZT2Zmc2V0RG9uZSA9IGZhbHNlO1xuICAgICAgICBjb25zdCBuZXh0U2VsZWN0ZWRJZHMgPSB7fTtcblxuICAgICAgICBmb3IgKGNvbnN0IHJlc3BvbnNlIG9mIHJlc3BvbnNlcykge1xuICAgICAgICAgIGlmIChyZXNwb25zZS5maWxlKSB7XG4gICAgICAgICAgICBjb25zdCBpbWFnZUVsZW1lbnQgPSB0aGlzLmNyZWF0ZUltYWdlRWxlbWVudCh7XG4gICAgICAgICAgICAgIHNjZW5lWCxcbiAgICAgICAgICAgICAgc2NlbmVZOiB5XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnN0IGluaXRpYWxpemVkSW1hZ2VFbGVtZW50ID0geWllbGQgdGhpcy5pbnNlcnRJbWFnZUVsZW1lbnQoaW1hZ2VFbGVtZW50LCByZXNwb25zZS5maWxlKTtcblxuICAgICAgICAgICAgaWYgKGluaXRpYWxpemVkSW1hZ2VFbGVtZW50KSB7XG4gICAgICAgICAgICAgIC8vIHZlcnRpY2FsbHkgY2VudGVyIGZpcnN0IGltYWdlIGluIHRoZSBiYXRjaFxuICAgICAgICAgICAgICBpZiAoIWZpcnN0SW1hZ2VZT2Zmc2V0RG9uZSkge1xuICAgICAgICAgICAgICAgIGZpcnN0SW1hZ2VZT2Zmc2V0RG9uZSA9IHRydWU7XG4gICAgICAgICAgICAgICAgeSAtPSBpbml0aWFsaXplZEltYWdlRWxlbWVudC5oZWlnaHQgLyAyO1xuICAgICAgICAgICAgICB9IC8vIGhhY2sgdG8gcmVzZXQgdGhlIGB5YCBjb29yZCBiZWNhdXNlIHdlIHZlcnRpY2FsbHkgY2VudGVyIGR1cmluZ1xuICAgICAgICAgICAgICAvLyBpbnNlcnRJbWFnZUVsZW1lbnRcblxuXG4gICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoaW5pdGlhbGl6ZWRJbWFnZUVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICB5XG4gICAgICAgICAgICAgIH0sIGZhbHNlKTtcbiAgICAgICAgICAgICAgeSA9IGltYWdlRWxlbWVudC55ICsgaW1hZ2VFbGVtZW50LmhlaWdodCArIDI1O1xuICAgICAgICAgICAgICBuZXh0U2VsZWN0ZWRJZHNbaW1hZ2VFbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRJZHMsIHRoaXMuc3RhdGUpXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBlcnJvciA9IHJlc3BvbnNlcy5maW5kKHJlc3BvbnNlID0+ICEhcmVzcG9uc2UuZXJyb3JNZXNzYWdlKTtcblxuICAgICAgICBpZiAoZXJyb3IgJiYgZXJyb3IuZXJyb3JNZXNzYWdlKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVycm9yLmVycm9yTWVzc2FnZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB0ZXh0Tm9kZXMgPSBtaXhlZENvbnRlbnQuZmlsdGVyKG5vZGUgPT4gbm9kZS50eXBlID09PSBcInRleHRcIik7XG5cbiAgICAgICAgaWYgKHRleHROb2Rlcy5sZW5ndGgpIHtcbiAgICAgICAgICB0aGlzLmFkZFRleHRGcm9tUGFzdGUodGV4dE5vZGVzLm1hcChub2RlID0+IG5vZGUudmFsdWUpLmpvaW4oXCJcXG5cXG5cIiksIGlzUGxhaW5QYXN0ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGFkZFRleHRGcm9tUGFzdGUodGV4dCwgaXNQbGFpblBhc3RlID0gZmFsc2UpIHtcbiAgICBjb25zdCB7XG4gICAgICB4LFxuICAgICAgeVxuICAgIH0gPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgY2xpZW50WDogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi54LFxuICAgICAgY2xpZW50WTogdGhpcy5sYXN0Vmlld3BvcnRQb3NpdGlvbi55XG4gICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgY29uc3QgdGV4dEVsZW1lbnRQcm9wcyA9IHtcbiAgICAgIHgsXG4gICAgICB5LFxuICAgICAgc3Ryb2tlQ29sb3I6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1TdHJva2VDb2xvcixcbiAgICAgIGJhY2tncm91bmRDb2xvcjogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUJhY2tncm91bmRDb2xvcixcbiAgICAgIGZpbGxTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbUZpbGxTdHlsZSxcbiAgICAgIHN0cm9rZVdpZHRoOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtU3Ryb2tlV2lkdGgsXG4gICAgICBzdHJva2VTdHlsZTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbVN0cm9rZVN0eWxlLFxuICAgICAgcm91bmRuZXNzOiBudWxsLFxuICAgICAgcm91Z2huZXNzOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtUm91Z2huZXNzLFxuICAgICAgb3BhY2l0eTogdGhpcy5zdGF0ZS5jdXJyZW50SXRlbU9wYWNpdHksXG4gICAgICB0ZXh0LFxuICAgICAgZm9udFNpemU6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250U2l6ZSxcbiAgICAgIGZvbnRGYW1pbHk6IHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Gb250RmFtaWx5LFxuICAgICAgdGV4dEFsaWduOiB0aGlzLnN0YXRlLmN1cnJlbnRJdGVtVGV4dEFsaWduLFxuICAgICAgdmVydGljYWxBbGlnbjogREVGQVVMVF9WRVJUSUNBTF9BTElHTixcbiAgICAgIGxvY2tlZDogZmFsc2VcbiAgICB9O1xuICAgIGNvbnN0IExJTkVfR0FQID0gMTA7XG4gICAgbGV0IGN1cnJlbnRZID0geTtcbiAgICBjb25zdCBsaW5lcyA9IGlzUGxhaW5QYXN0ZSA/IFt0ZXh0XSA6IHRleHQuc3BsaXQoXCJcXG5cIik7XG4gICAgY29uc3QgdGV4dEVsZW1lbnRzID0gbGluZXMucmVkdWNlKChhY2MsIGxpbmUsIGlkeCkgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICBjb25zdCB0ZXh0ID0gbGluZS50cmltKCk7XG4gICAgICBjb25zdCBsaW5lSGVpZ2h0ID0gZ2V0RGVmYXVsdExpbmVIZWlnaHQodGV4dEVsZW1lbnRQcm9wcy5mb250RmFtaWx5KTtcblxuICAgICAgaWYgKHRleHQubGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IHRvcExheWVyRnJhbWUgPSB0aGlzLmdldFRvcExheWVyRnJhbWVBdFNjZW5lQ29vcmRzKHtcbiAgICAgICAgICB4LFxuICAgICAgICAgIHk6IGN1cnJlbnRZXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBlbGVtZW50ID0gbmV3VGV4dEVsZW1lbnQoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0ZXh0RWxlbWVudFByb3BzKSwge1xuICAgICAgICAgIHgsXG4gICAgICAgICAgeTogY3VycmVudFksXG4gICAgICAgICAgdGV4dCxcbiAgICAgICAgICBsaW5lSGVpZ2h0LFxuICAgICAgICAgIGZyYW1lSWQ6IHRvcExheWVyRnJhbWUgPyB0b3BMYXllckZyYW1lLmlkIDogbnVsbFxuICAgICAgICB9KSk7XG4gICAgICAgIGFjYy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICBjdXJyZW50WSArPSBlbGVtZW50LmhlaWdodCArIExJTkVfR0FQO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcHJldkxpbmUgPSAoX2EgPSBsaW5lc1tpZHggLSAxXSkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnRyaW0oKTsgLy8gYWRkIHBhcmFncmFwaCBvbmx5IGlmIHByZXZpb3VzIGxpbmUgd2FzIG5vdCBlbXB0eSwgSU9XIGRvbid0IGFkZFxuICAgICAgICAvLyBtb3JlIHRoYW4gb25lIGVtcHR5IGxpbmVcblxuICAgICAgICBpZiAocHJldkxpbmUpIHtcbiAgICAgICAgICBjdXJyZW50WSArPSBnZXRMaW5lSGVpZ2h0SW5QeCh0ZXh0RWxlbWVudFByb3BzLmZvbnRTaXplLCBsaW5lSGVpZ2h0KSArIExJTkVfR0FQO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwgW10pO1xuXG4gICAgaWYgKHRleHRFbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBmcmFtZUlkID0gdGV4dEVsZW1lbnRzWzBdLmZyYW1lSWQ7XG5cbiAgICBpZiAoZnJhbWVJZCkge1xuICAgICAgdGhpcy5zY2VuZS5pbnNlcnRFbGVtZW50c0F0SW5kZXgodGV4dEVsZW1lbnRzLCB0aGlzLnNjZW5lLmdldEVsZW1lbnRJbmRleChmcmFtZUlkKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCAuLi50ZXh0RWxlbWVudHNdKTtcbiAgICB9XG5cbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoT2JqZWN0LmZyb21FbnRyaWVzKHRleHRFbGVtZW50cy5tYXAoZWwgPT4gW2VsLmlkLCB0cnVlXSkpLCB0aGlzLnN0YXRlKVxuICAgIH0pO1xuXG4gICAgaWYgKCFpc1BsYWluUGFzdGUgJiYgdGV4dEVsZW1lbnRzLmxlbmd0aCA+IDEgJiYgUExBSU5fUEFTVEVfVE9BU1RfU0hPV04gPT09IGZhbHNlICYmICF0aGlzLmRldmljZS5lZGl0b3IuaXNNb2JpbGUpIHtcbiAgICAgIHRoaXMuc2V0VG9hc3Qoe1xuICAgICAgICBtZXNzYWdlOiB0KFwidG9hc3QucGFzdGVBc1NpbmdsZUVsZW1lbnRcIiwge1xuICAgICAgICAgIHNob3J0Y3V0OiBnZXRTaG9ydGN1dEtleShcIkN0cmxPckNtZCtTaGlmdCtWXCIpXG4gICAgICAgIH0pLFxuICAgICAgICBkdXJhdGlvbjogNTAwMFxuICAgICAgfSk7XG4gICAgICBQTEFJTl9QQVNURV9UT0FTVF9TSE9XTiA9IHRydWU7XG4gICAgfVxuXG4gICAgdGhpcy5oaXN0b3J5LnJlc3VtZVJlY29yZGluZygpO1xuICB9XG5cbiAgaGFuZGxlVGV4dFd5c2l3eWcoZWxlbWVudCwge1xuICAgIGlzRXhpc3RpbmdFbGVtZW50ID0gZmFsc2VcbiAgfSkge1xuICAgIGNvbnN0IHVwZGF0ZUVsZW1lbnQgPSAodGV4dCwgb3JpZ2luYWxUZXh0LCBpc0RlbGV0ZWQpID0+IHtcbiAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKFsuLi50aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLm1hcChfZWxlbWVudCA9PiB7XG4gICAgICAgIGlmIChfZWxlbWVudC5pZCA9PT0gZWxlbWVudC5pZCAmJiBpc1RleHRFbGVtZW50KF9lbGVtZW50KSkge1xuICAgICAgICAgIHJldHVybiB1cGRhdGVUZXh0RWxlbWVudChfZWxlbWVudCwge1xuICAgICAgICAgICAgdGV4dCxcbiAgICAgICAgICAgIGlzRGVsZXRlZCxcbiAgICAgICAgICAgIG9yaWdpbmFsVGV4dFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF9lbGVtZW50O1xuICAgICAgfSldKTtcbiAgICB9O1xuXG4gICAgdGV4dFd5c2l3eWcoe1xuICAgICAgaWQ6IGVsZW1lbnQuaWQsXG4gICAgICBjYW52YXM6IHRoaXMuY2FudmFzLFxuICAgICAgZ2V0Vmlld3BvcnRDb29yZHM6ICh4LCB5KSA9PiB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB4OiB2aWV3cG9ydFgsXG4gICAgICAgICAgeTogdmlld3BvcnRZXG4gICAgICAgIH0gPSBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMoe1xuICAgICAgICAgIHNjZW5lWDogeCxcbiAgICAgICAgICBzY2VuZVk6IHlcbiAgICAgICAgfSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIHJldHVybiBbdmlld3BvcnRYIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LCB2aWV3cG9ydFkgLSB0aGlzLnN0YXRlLm9mZnNldFRvcF07XG4gICAgICB9LFxuICAgICAgb25DaGFuZ2U6IHdpdGhCYXRjaGVkVXBkYXRlcyh0ZXh0ID0+IHtcbiAgICAgICAgdXBkYXRlRWxlbWVudCh0ZXh0LCB0ZXh0LCBmYWxzZSk7XG5cbiAgICAgICAgaWYgKGlzTm9uRGVsZXRlZEVsZW1lbnQoZWxlbWVudCkpIHtcbiAgICAgICAgICB1cGRhdGVCb3VuZEVsZW1lbnRzKGVsZW1lbnQpO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICAgIG9uU3VibWl0OiB3aXRoQmF0Y2hlZFVwZGF0ZXMoKHtcbiAgICAgICAgdGV4dCxcbiAgICAgICAgdmlhS2V5Ym9hcmQsXG4gICAgICAgIG9yaWdpbmFsVGV4dFxuICAgICAgfSkgPT4ge1xuICAgICAgICBjb25zdCBpc0RlbGV0ZWQgPSAhdGV4dC50cmltKCk7XG4gICAgICAgIHVwZGF0ZUVsZW1lbnQodGV4dCwgb3JpZ2luYWxUZXh0LCBpc0RlbGV0ZWQpOyAvLyBzZWxlY3QgdGhlIGNyZWF0ZWQgdGV4dCBlbGVtZW50IG9ubHkgaWYgc3VibWl0dGluZyB2aWEga2V5Ym9hcmRcbiAgICAgICAgLy8gKHdoZW4gc3VibWl0dGluZyB2aWEgY2xpY2sgaXQgc2hvdWxkIGFjdCBhcyBzaWduYWwgdG8gZGVzZWxlY3QpXG5cbiAgICAgICAgaWYgKCFpc0RlbGV0ZWQgJiYgdmlhS2V5Ym9hcmQpIHtcbiAgICAgICAgICBjb25zdCBlbGVtZW50SWRUb1NlbGVjdCA9IGVsZW1lbnQuY29udGFpbmVySWQgPyBlbGVtZW50LmNvbnRhaW5lcklkIDogZWxlbWVudC5pZDtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiAoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgIFtlbGVtZW50SWRUb1NlbGVjdF06IHRydWVcbiAgICAgICAgICAgIH0pLCBwcmV2U3RhdGUpXG4gICAgICAgICAgfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzRGVsZXRlZCkge1xuICAgICAgICAgIGZpeEJpbmRpbmdzQWZ0ZXJEZWxldGlvbih0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBbZWxlbWVudF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFpc0RlbGV0ZWQgfHwgaXNFeGlzdGluZ0VsZW1lbnQpIHtcbiAgICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgZWRpdGluZ0VsZW1lbnQ6IG51bGxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgICBzZXRDdXJzb3JGb3JTaGFwZSh0aGlzLmludGVyYWN0aXZlQ2FudmFzLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZm9jdXNDb250YWluZXIoKTtcbiAgICAgIH0pLFxuICAgICAgZWxlbWVudCxcbiAgICAgIGV4Y2FsaWRyYXdDb250YWluZXI6IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50LFxuICAgICAgYXBwOiB0aGlzXG4gICAgfSk7IC8vIGRlc2VsZWN0IGFsbCBvdGhlciBlbGVtZW50cyB3aGVuIGluc2VydGluZyB0ZXh0XG5cbiAgICB0aGlzLmRlc2VsZWN0RWxlbWVudHMoKTsgLy8gZG8gYW4gaW5pdGlhbCB1cGRhdGUgdG8gcmUtaW5pdGlhbGl6ZSBlbGVtZW50IHBvc2l0aW9uIHNpbmNlIHdlIHdlcmVcbiAgICAvLyBtb2RpZnlpbmcgZWxlbWVudCdzIHgveSBmb3Igc2FrZSBvZiBlZGl0b3IgKGNhc2U6IHN5bmNpbmcgdG8gcmVtb3RlKVxuXG4gICAgdXBkYXRlRWxlbWVudChlbGVtZW50LnRleHQsIGVsZW1lbnQub3JpZ2luYWxUZXh0LCBmYWxzZSk7XG4gIH1cblxuICBkZXNlbGVjdEVsZW1lbnRzKCkge1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7fSwgdGhpcy5zdGF0ZSksXG4gICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgIGVkaXRpbmdHcm91cElkOiBudWxsLFxuICAgICAgYWN0aXZlRW1iZWRkYWJsZTogbnVsbFxuICAgIH0pO1xuICB9XG5cbiAgZ2V0VGV4dEVsZW1lbnRBdFBvc2l0aW9uKHgsIHkpIHtcbiAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50QXRQb3NpdGlvbih4LCB5LCB7XG4gICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZVxuICAgIH0pO1xuXG4gICAgaWYgKGVsZW1lbnQgJiYgaXNUZXh0RWxlbWVudChlbGVtZW50KSAmJiAhZWxlbWVudC5pc0RlbGV0ZWQpIHtcbiAgICAgIHJldHVybiBlbGVtZW50O1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZ2V0RWxlbWVudEF0UG9zaXRpb24oeCwgeSwgb3B0cykge1xuICAgIGNvbnN0IGFsbEhpdEVsZW1lbnRzID0gdGhpcy5nZXRFbGVtZW50c0F0UG9zaXRpb24oeCwgeSwgb3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLmluY2x1ZGVCb3VuZFRleHRFbGVtZW50LCBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuaW5jbHVkZUxvY2tlZEVsZW1lbnRzKTtcblxuICAgIGlmIChhbGxIaXRFbGVtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICBpZiAob3B0cyA9PT0gbnVsbCB8fCBvcHRzID09PSB2b2lkIDAgPyB2b2lkIDAgOiBvcHRzLnByZWZlclNlbGVjdGVkKSB7XG4gICAgICAgIGZvciAobGV0IGluZGV4ID0gYWxsSGl0RWxlbWVudHMubGVuZ3RoIC0gMTsgaW5kZXggPiAtMTsgaW5kZXgtLSkge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1thbGxIaXRFbGVtZW50c1tpbmRleF0uaWRdKSB7XG4gICAgICAgICAgICByZXR1cm4gYWxsSGl0RWxlbWVudHNbaW5kZXhdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50V2l0aEhpZ2hlc3RaSW5kZXggPSBhbGxIaXRFbGVtZW50c1thbGxIaXRFbGVtZW50cy5sZW5ndGggLSAxXTsgLy8gSWYgd2UncmUgaGl0dGluZyBlbGVtZW50IHdpdGggaGlnaGVzdCB6LWluZGV4IG9ubHkgb24gaXRzIGJvdW5kaW5nIGJveFxuICAgICAgLy8gd2hpbGUgYWxzbyBoaXR0aW5nIG90aGVyIGVsZW1lbnQgZmlndXJlLCB0aGUgbGF0dGVyIHNob3VsZCBiZSBjb25zaWRlcmVkLlxuXG4gICAgICByZXR1cm4gaXNIaXR0aW5nRWxlbWVudEJvdW5kaW5nQm94V2l0aG91dEhpdHRpbmdFbGVtZW50KGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgeCwgeSkgPyBhbGxIaXRFbGVtZW50c1thbGxIaXRFbGVtZW50cy5sZW5ndGggLSAyXSA6IGVsZW1lbnRXaXRoSGlnaGVzdFpJbmRleDtcbiAgICB9XG5cbiAgICBpZiAoYWxsSGl0RWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICByZXR1cm4gYWxsSGl0RWxlbWVudHNbMF07XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBnZXRFbGVtZW50c0F0UG9zaXRpb24oeCwgeSwgaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgPSBmYWxzZSwgaW5jbHVkZUxvY2tlZEVsZW1lbnRzID0gZmFsc2UpIHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGluY2x1ZGVCb3VuZFRleHRFbGVtZW50ICYmIGluY2x1ZGVMb2NrZWRFbGVtZW50cyA/IHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkgOiB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLmZpbHRlcihlbGVtZW50ID0+IChpbmNsdWRlTG9ja2VkRWxlbWVudHMgfHwgIWVsZW1lbnQubG9ja2VkKSAmJiAoaW5jbHVkZUJvdW5kVGV4dEVsZW1lbnQgfHwgIShpc1RleHRFbGVtZW50KGVsZW1lbnQpICYmIGVsZW1lbnQuY29udGFpbmVySWQpKSk7XG4gICAgcmV0dXJuIGdldEVsZW1lbnRzQXRQb3NpdGlvbihlbGVtZW50cywgZWxlbWVudCA9PiBoaXRUZXN0KGVsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuZnJhbWVOYW1lQm91bmRzQ2FjaGUsIHgsIHkpKS5maWx0ZXIoZWxlbWVudCA9PiB7XG4gICAgICAvLyBoaXR0aW5nIGEgZnJhbWUncyBlbGVtZW50IGZyb20gb3V0c2lkZSB0aGUgZnJhbWUgaXMgbm90IGNvbnNpZGVyZWQgYSBoaXRcbiAgICAgIGNvbnN0IGNvbnRhaW5pbmdGcmFtZSA9IGdldENvbnRhaW5pbmdGcmFtZShlbGVtZW50KTtcbiAgICAgIHJldHVybiBjb250YWluaW5nRnJhbWUgJiYgdGhpcy5zdGF0ZS5mcmFtZVJlbmRlcmluZy5lbmFibGVkICYmIHRoaXMuc3RhdGUuZnJhbWVSZW5kZXJpbmcuY2xpcCA/IGlzQ3Vyc29ySW5GcmFtZSh7XG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0sIGNvbnRhaW5pbmdGcmFtZSkgOiB0cnVlO1xuICAgIH0pO1xuICB9XG5cbiAgaGFuZGxlSG92ZXJTZWxlY3RlZExpbmVhckVsZW1lbnQobGluZWFyRWxlbWVudEVkaXRvciwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmdldEVsZW1lbnQobGluZWFyRWxlbWVudEVkaXRvci5lbGVtZW50SWQpO1xuICAgIGNvbnN0IGJvdW5kVGV4dEVsZW1lbnQgPSBnZXRCb3VuZFRleHRFbGVtZW50KGVsZW1lbnQpO1xuXG4gICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICBsZXQgaG92ZXJQb2ludEluZGV4ID0gLTE7XG4gICAgICBsZXQgc2VnbWVudE1pZFBvaW50SG92ZXJlZENvb3JkcyA9IG51bGw7XG5cbiAgICAgIGlmIChpc0hpdHRpbmdFbGVtZW50Tm90Q29uc2lkZXJpbmdCb3VuZGluZ0JveChlbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBbc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWV0pKSB7XG4gICAgICAgIGhvdmVyUG9pbnRJbmRleCA9IExpbmVhckVsZW1lbnRFZGl0b3IuZ2V0UG9pbnRJbmRleFVuZGVyQ3Vyc29yKGVsZW1lbnQsIHRoaXMuc3RhdGUuem9vbSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSk7XG4gICAgICAgIHNlZ21lbnRNaWRQb2ludEhvdmVyZWRDb29yZHMgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmdldFNlZ21lbnRNaWRwb2ludEhpdENvb3JkcyhsaW5lYXJFbGVtZW50RWRpdG9yLCB7XG4gICAgICAgICAgeDogc2NlbmVQb2ludGVyWCxcbiAgICAgICAgICB5OiBzY2VuZVBvaW50ZXJZXG4gICAgICAgIH0sIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgIGlmIChob3ZlclBvaW50SW5kZXggPj0gMCB8fCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzKSB7XG4gICAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLlBPSU5URVIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5NT1ZFKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzaG91bGRTaG93Qm91bmRpbmdCb3goW2VsZW1lbnRdLCB0aGlzLnN0YXRlKSAmJiBpc0hpdHRpbmdFbGVtZW50Qm91bmRpbmdCb3hXaXRob3V0SGl0dGluZ0VsZW1lbnQoZWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgfSBlbHNlIGlmIChib3VuZFRleHRFbGVtZW50ICYmIGhpdFRlc3QoYm91bmRUZXh0RWxlbWVudCwgdGhpcy5zdGF0ZSwgdGhpcy5mcmFtZU5hbWVCb3VuZHNDYWNoZSwgc2NlbmVQb2ludGVyWCwgc2NlbmVQb2ludGVyWSkpIHtcbiAgICAgICAgc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIENVUlNPUl9UWVBFLk1PVkUpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaG92ZXJQb2ludEluZGV4ICE9PSBob3ZlclBvaW50SW5kZXgpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgaG92ZXJQb2ludEluZGV4XG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghTGluZWFyRWxlbWVudEVkaXRvci5hcmVQb2ludHNFcXVhbCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5zZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzLCBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzKSkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICBzZWdtZW50TWlkUG9pbnRIb3ZlcmVkQ29vcmRzXG4gICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHNldEN1cnNvcih0aGlzLmludGVyYWN0aXZlQ2FudmFzLCBDVVJTT1JfVFlQRS5BVVRPKTtcbiAgICB9XG4gIH1cblxuICBtYXliZUNsZWFudXBBZnRlck1pc3NpbmdQb2ludGVyVXAoZXZlbnQpIHtcbiAgICBpZiAobGFzdFBvaW50ZXJVcCAhPT0gbnVsbCkge1xuICAgICAgLy8gVW5mb3J0dW5hdGVseSwgc29tZXRpbWVzIHdlIGRvbid0IGdldCBhIHBvaW50ZXJ1cCBhZnRlciBhIHBvaW50ZXJkb3duLFxuICAgICAgLy8gdGhpcyBjYW4gaGFwcGVuIHdoZW4gYSBjb250ZXh0dWFsIG1lbnUgb3IgYWxlcnQgaXMgdHJpZ2dlcmVkLiBJbiBvcmRlciB0byBhdm9pZFxuICAgICAgLy8gYmVpbmcgaW4gYSB3ZWlyZCBzdGF0ZSwgd2UgY2xlYW4gdXAgb24gdGhlIG5leHQgcG9pbnRlcmRvd25cbiAgICAgIGxhc3RQb2ludGVyVXAoZXZlbnQpO1xuICAgIH1cbiAgfVxuXG4gIHVwZGF0ZUdlc3R1cmVPblBvaW50ZXJEb3duKGV2ZW50KSB7XG4gICAgZ2VzdHVyZS5wb2ludGVycy5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICB4OiBldmVudC5jbGllbnRYLFxuICAgICAgeTogZXZlbnQuY2xpZW50WVxuICAgIH0pO1xuXG4gICAgaWYgKGdlc3R1cmUucG9pbnRlcnMuc2l6ZSA9PT0gMikge1xuICAgICAgZ2VzdHVyZS5sYXN0Q2VudGVyID0gZ2V0Q2VudGVyKGdlc3R1cmUucG9pbnRlcnMpO1xuICAgICAgZ2VzdHVyZS5pbml0aWFsU2NhbGUgPSB0aGlzLnN0YXRlLnpvb20udmFsdWU7XG4gICAgICBnZXN0dXJlLmluaXRpYWxEaXN0YW5jZSA9IGdldERpc3RhbmNlKEFycmF5LmZyb20oZ2VzdHVyZS5wb2ludGVycy52YWx1ZXMoKSkpO1xuICAgIH1cbiAgfVxuXG4gIGluaXRpYWxQb2ludGVyRG93blN0YXRlKGV2ZW50KSB7XG4gICAgY29uc3Qgb3JpZ2luID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcbiAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpO1xuICAgIGNvbnN0IFttaW5YLCBtaW5ZLCBtYXhYLCBtYXhZXSA9IGdldENvbW1vbkJvdW5kcyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICByZXR1cm4ge1xuICAgICAgb3JpZ2luLFxuICAgICAgd2l0aENtZE9yQ3RybDogZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0sXG4gICAgICBvcmlnaW5JbkdyaWQ6IHR1cGxlVG9Db29ycyhnZXRHcmlkUG9pbnQob3JpZ2luLngsIG9yaWdpbi55LCBldmVudFtLRVlTLkNUUkxfT1JfQ01EXSA/IG51bGwgOiB0aGlzLnN0YXRlLmdyaWRTaXplKSksXG4gICAgICBzY3JvbGxiYXJzOiBpc092ZXJTY3JvbGxCYXJzKGN1cnJlbnRTY3JvbGxCYXJzLCBldmVudC5jbGllbnRYIC0gdGhpcy5zdGF0ZS5vZmZzZXRMZWZ0LCBldmVudC5jbGllbnRZIC0gdGhpcy5zdGF0ZS5vZmZzZXRUb3ApLFxuICAgICAgLy8gd2UgbmVlZCB0byBkdXBsaWNhdGUgYmVjYXVzZSB3ZSdsbCBiZSB1cGRhdGluZyB0aGlzIHN0YXRlXG4gICAgICBsYXN0Q29vcmRzOiBPYmplY3QuYXNzaWduKHt9LCBvcmlnaW4pLFxuICAgICAgb3JpZ2luYWxFbGVtZW50czogdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKS5yZWR1Y2UoKGFjYywgZWxlbWVudCkgPT4ge1xuICAgICAgICBhY2Muc2V0KGVsZW1lbnQuaWQsIGRlZXBDb3B5RWxlbWVudChlbGVtZW50KSk7XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCBuZXcgTWFwKCkpLFxuICAgICAgcmVzaXplOiB7XG4gICAgICAgIGhhbmRsZVR5cGU6IGZhbHNlLFxuICAgICAgICBpc1Jlc2l6aW5nOiBmYWxzZSxcbiAgICAgICAgb2Zmc2V0OiB7XG4gICAgICAgICAgeDogMCxcbiAgICAgICAgICB5OiAwXG4gICAgICAgIH0sXG4gICAgICAgIGFycm93RGlyZWN0aW9uOiBcIm9yaWdpblwiLFxuICAgICAgICBjZW50ZXI6IHtcbiAgICAgICAgICB4OiAobWF4WCArIG1pblgpIC8gMixcbiAgICAgICAgICB5OiAobWF4WSArIG1pblkpIC8gMlxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgaGl0OiB7XG4gICAgICAgIGVsZW1lbnQ6IG51bGwsXG4gICAgICAgIGFsbEhpdEVsZW1lbnRzOiBbXSxcbiAgICAgICAgd2FzQWRkZWRUb1NlbGVjdGlvbjogZmFsc2UsXG4gICAgICAgIGhhc0JlZW5EdXBsaWNhdGVkOiBmYWxzZSxcbiAgICAgICAgaGFzSGl0Q29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHM6IHRoaXMuaXNIaXR0aW5nQ29tbW9uQm91bmRpbmdCb3hPZlNlbGVjdGVkRWxlbWVudHMob3JpZ2luLCBzZWxlY3RlZEVsZW1lbnRzKVxuICAgICAgfSxcbiAgICAgIGRyYWc6IHtcbiAgICAgICAgaGFzT2NjdXJyZWQ6IGZhbHNlLFxuICAgICAgICBvZmZzZXQ6IG51bGxcbiAgICAgIH0sXG4gICAgICBldmVudExpc3RlbmVyczoge1xuICAgICAgICBvbk1vdmU6IG51bGwsXG4gICAgICAgIG9uVXA6IG51bGwsXG4gICAgICAgIG9uS2V5VXA6IG51bGwsXG4gICAgICAgIG9uS2V5RG93bjogbnVsbFxuICAgICAgfSxcbiAgICAgIGJveFNlbGVjdGlvbjoge1xuICAgICAgICBoYXNPY2N1cnJlZDogZmFsc2VcbiAgICAgIH0sXG4gICAgICBlbGVtZW50SWRzVG9FcmFzZToge31cbiAgICB9O1xuICB9IC8vIFJldHVybnMgd2hldGhlciB0aGUgZXZlbnQgaXMgYSBkcmFnZ2luZyBhIHNjcm9sbGJhclxuXG5cbiAgaGFuZGxlRHJhZ2dpbmdTY3JvbGxCYXIoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICBpZiAoIShwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVyRWl0aGVyICYmICF0aGlzLnN0YXRlLm11bHRpRWxlbWVudCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpc0RyYWdnaW5nU2Nyb2xsQmFyID0gdHJ1ZTtcbiAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IGV2ZW50LmNsaWVudFg7XG4gICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSBldmVudC5jbGllbnRZO1xuICAgIGNvbnN0IG9uUG9pbnRlck1vdmUgPSB3aXRoQmF0Y2hlZFVwZGF0ZXNUaHJvdHRsZWQoZXZlbnQgPT4ge1xuICAgICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0O1xuXG4gICAgICBpZiAoISh0YXJnZXQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmhhbmRsZVBvaW50ZXJNb3ZlT3ZlclNjcm9sbGJhcnMoZXZlbnQsIHBvaW50ZXJEb3duU3RhdGUpO1xuICAgIH0pO1xuICAgIGNvbnN0IG9uUG9pbnRlclVwID0gd2l0aEJhdGNoZWRVcGRhdGVzKCgpID0+IHtcbiAgICAgIGlzRHJhZ2dpbmdTY3JvbGxCYXIgPSBmYWxzZTtcbiAgICAgIHNldEN1cnNvckZvclNoYXBlKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMsIHRoaXMuc3RhdGUpO1xuICAgICAgbGFzdFBvaW50ZXJVcCA9IG51bGw7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgY3Vyc29yQnV0dG9uOiBcInVwXCJcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zYXZlUG9pbnRlcihldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZLCBcInVwXCIpO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKEVWRU5ULlBPSU5URVJfVVAsIG9uUG9pbnRlclVwKTtcbiAgICAgIG9uUG9pbnRlck1vdmUuZmx1c2goKTtcbiAgICB9KTtcbiAgICBsYXN0UG9pbnRlclVwID0gb25Qb2ludGVyVXA7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBvblBvaW50ZXJNb3ZlKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBvblBvaW50ZXJVcCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBpc0FTZWxlY3RlZEVsZW1lbnQoaGl0RWxlbWVudCkge1xuICAgIHJldHVybiBoaXRFbGVtZW50ICE9IG51bGwgJiYgdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF07XG4gIH1cblxuICBpc0hpdHRpbmdDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cyhwb2ludCwgc2VsZWN0ZWRFbGVtZW50cykge1xuICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA8IDIpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IC8vIEhvdyBtYW55IHBpeGVscyBvZmYgdGhlIHNoYXBlIGJvdW5kYXJ5IHdlIHN0aWxsIGNvbnNpZGVyIGEgaGl0XG5cblxuICAgIGNvbnN0IHRocmVzaG9sZCA9IDEwIC8gdGhpcy5zdGF0ZS56b29tLnZhbHVlO1xuICAgIGNvbnN0IFt4MSwgeTEsIHgyLCB5Ml0gPSBnZXRDb21tb25Cb3VuZHMoc2VsZWN0ZWRFbGVtZW50cyk7XG4gICAgcmV0dXJuIHBvaW50LnggPiB4MSAtIHRocmVzaG9sZCAmJiBwb2ludC54IDwgeDIgKyB0aHJlc2hvbGQgJiYgcG9pbnQueSA+IHkxIC0gdGhyZXNob2xkICYmIHBvaW50LnkgPCB5MiArIHRocmVzaG9sZDtcbiAgfVxuXG4gIGdldEN1cnJlbnRJdGVtUm91bmRuZXNzKGVsZW1lbnRUeXBlKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuY3VycmVudEl0ZW1Sb3VuZG5lc3MgPT09IFwicm91bmRcIiA/IHtcbiAgICAgIHR5cGU6IGlzVXNpbmdBZGFwdGl2ZVJhZGl1cyhlbGVtZW50VHlwZSkgPyBST1VORE5FU1MuQURBUFRJVkVfUkFESVVTIDogUk9VTkRORVNTLlBST1BPUlRJT05BTF9SQURJVVNcbiAgICB9IDogbnVsbDtcbiAgfVxuXG4gIG1heWJlQ2FjaGVSZWZlcmVuY2VTbmFwUG9pbnRzKGV2ZW50LCBzZWxlY3RlZEVsZW1lbnRzLCByZWNvbXB1dGVBbnl3YXlzID0gZmFsc2UpIHtcbiAgICBpZiAoaXNTbmFwcGluZ0VuYWJsZWQoe1xuICAgICAgZXZlbnQsXG4gICAgICBhcHBTdGF0ZTogdGhpcy5zdGF0ZSxcbiAgICAgIHNlbGVjdGVkRWxlbWVudHNcbiAgICB9KSAmJiAocmVjb21wdXRlQW55d2F5cyB8fCAhU25hcENhY2hlLmdldFJlZmVyZW5jZVNuYXBQb2ludHMoKSkpIHtcbiAgICAgIFNuYXBDYWNoZS5zZXRSZWZlcmVuY2VTbmFwUG9pbnRzKGdldFJlZmVyZW5jZVNuYXBQb2ludHModGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgc2VsZWN0ZWRFbGVtZW50cywgdGhpcy5zdGF0ZSkpO1xuICAgIH1cbiAgfVxuXG4gIG1heWJlQ2FjaGVWaXNpYmxlR2FwcyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgcmVjb21wdXRlQW55d2F5cyA9IGZhbHNlKSB7XG4gICAgaWYgKGlzU25hcHBpbmdFbmFibGVkKHtcbiAgICAgIGV2ZW50LFxuICAgICAgYXBwU3RhdGU6IHRoaXMuc3RhdGUsXG4gICAgICBzZWxlY3RlZEVsZW1lbnRzXG4gICAgfSkgJiYgKHJlY29tcHV0ZUFueXdheXMgfHwgIVNuYXBDYWNoZS5nZXRWaXNpYmxlR2FwcygpKSkge1xuICAgICAgU25hcENhY2hlLnNldFZpc2libGVHYXBzKGdldFZpc2libGVHYXBzKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHNlbGVjdGVkRWxlbWVudHMsIHRoaXMuc3RhdGUpKTtcbiAgICB9XG4gIH1cblxuICBvbktleURvd25Gcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGV2ZW50ID0+IHtcbiAgICAgIGlmICh0aGlzLm1heWJlSGFuZGxlUmVzaXplKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubWF5YmVEcmFnTmV3R2VuZXJpY0VsZW1lbnQocG9pbnRlckRvd25TdGF0ZSwgZXZlbnQpO1xuICAgIH0pO1xuICB9XG5cbiAgb25LZXlVcEZyb21Qb2ludGVyRG93bkhhbmRsZXIocG9pbnRlckRvd25TdGF0ZSkge1xuICAgIHJldHVybiB3aXRoQmF0Y2hlZFVwZGF0ZXMoZXZlbnQgPT4ge1xuICAgICAgLy8gUHJldmVudHMgZm9jdXMgZnJvbSBlc2NhcGluZyBleGNhbGlkcmF3IHRhYlxuICAgICAgZXZlbnQua2V5ID09PSBLRVlTLkFMVCAmJiBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICBpZiAodGhpcy5tYXliZUhhbmRsZVJlc2l6ZShwb2ludGVyRG93blN0YXRlLCBldmVudCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uUG9pbnRlck1vdmVGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzVGhyb3R0bGVkKGV2ZW50ID0+IHtcbiAgICAgIHZhciBfYSwgX2I7IC8vIFdlIG5lZWQgdG8gaW5pdGlhbGl6ZSBkcmFnT2Zmc2V0WFkgb25seSBhZnRlciB3ZSd2ZSB1cGRhdGVkXG4gICAgICAvLyBgc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzYCBvbiBwb2ludGVyRG93bi4gRG9pbmcgaXQgaGVyZSBpbiBwb2ludGVyTW92ZVxuICAgICAgLy8gZXZlbnQgaGFuZGxlciBzaG91bGQgaG9wZWZ1bGx5IGVuc3VyZSB3ZSdyZSBhbHJlYWR5IHdvcmtpbmcgd2l0aFxuICAgICAgLy8gdGhlIHVwZGF0ZWQgc3RhdGUuXG5cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5vZmZzZXQgPT09IG51bGwpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLm9mZnNldCA9IHR1cGxlVG9Db29ycyhnZXREcmFnT2Zmc2V0WFkodGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldDtcblxuICAgICAgaWYgKCEodGFyZ2V0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGV2ZW50LCB0aGlzLnN0YXRlKTtcblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlRXJhc2VyKGV2ZW50LCBwb2ludGVyRG93blN0YXRlLCBwb2ludGVyQ29vcmRzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGFzZXJcIikge1xuICAgICAgICB0aGlzLmxhc2VyUGF0aE1hbmFnZXIuYWRkUG9pbnRUb1BhdGgocG9pbnRlckNvb3Jkcy54LCBwb2ludGVyQ29vcmRzLnkpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBbZ3JpZFgsIGdyaWRZXSA9IGdldEdyaWRQb2ludChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0gPyBudWxsIDogdGhpcy5zdGF0ZS5ncmlkU2l6ZSk7IC8vIGZvciBhcnJvd3MvbGluZXMsIGRvbid0IHN0YXJ0IGRyYWdnaW5nIHVudGlsIGEgZ2l2ZW4gdGhyZXNob2xkXG4gICAgICAvLyB0byBlbnN1cmUgd2UgZG9uJ3QgY3JlYXRlIGEgMi1wb2ludCBhcnJvdyBieSBtaXN0YWtlIHdoZW5cbiAgICAgIC8vIHVzZXIgY2xpY2tzIG1vdXNlIGluIGEgd2F5IHRoYXQgaXQgbW92ZXMgYSB0aW55IGJpdCAodGh1c1xuICAgICAgLy8gdHJpZ2dlcmluZyBwb2ludGVybW92ZSlcblxuICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcImFycm93XCIgfHwgdGhpcy5zdGF0ZS5hY3RpdmVUb29sLnR5cGUgPT09IFwibGluZVwiKSkge1xuICAgICAgICBpZiAoZGlzdGFuY2UyZChwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCwgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueSkgPCBEUkFHR0lOR19USFJFU0hPTEQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmlzUmVzaXppbmcpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuXG4gICAgICAgIGlmICh0aGlzLm1heWJlSGFuZGxlUmVzaXplKHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICBjb25zdCBsaW5lYXJFbGVtZW50RWRpdG9yID0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCB8fCB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudDtcblxuICAgICAgICBpZiAoTGluZWFyRWxlbWVudEVkaXRvci5zaG91bGRBZGRNaWRwb2ludCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCwgcG9pbnRlckNvb3JkcywgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgICBjb25zdCByZXQgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmFkZE1pZHBvaW50KHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LCBwb2ludGVyQ29vcmRzLCB0aGlzLnN0YXRlLCAhZXZlbnRbS0VZUy5DVFJMX09SX0NNRF0pO1xuXG4gICAgICAgICAgaWYgKCFyZXQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9IC8vIFNpbmNlIHdlIGFyZSByZWFkaW5nIGZyb20gcHJldmlvdXMgc3RhdGUgd2hpY2ggaXMgbm90IHBvc3NpYmxlIHdpdGhcbiAgICAgICAgICAvLyBhdXRvbWF0aWMgYmF0Y2hpbmcgaW4gUmVhY3QgMTggaGVuY2UgdXNpbmcgZmx1c2ggc3luYyB0byBzeW5jaHJvbm91c2x5XG4gICAgICAgICAgLy8gdXBkYXRlIHRoZSBzdGF0ZS4gQ2hlY2sgaHR0cHM6Ly9naXRodWIuY29tL2V4Y2FsaWRyYXcvZXhjYWxpZHJhdy9wdWxsLzU1MDggZm9yIG1vcmUgZGV0YWlscy5cblxuXG4gICAgICAgICAgZmx1c2hTeW5jKCgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICAgICAgICBwb2ludGVyRG93blN0YXRlOiByZXQucG9pbnRlckRvd25TdGF0ZSxcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkUG9pbnRzSW5kaWNlczogcmV0LnNlbGVjdGVkUG9pbnRzSW5kaWNlc1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBlZGl0aW5nTGluZWFyRWxlbWVudDogT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZTogcmV0LnBvaW50ZXJEb3duU3RhdGUsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IHJldC5zZWxlY3RlZFBvaW50c0luZGljZXNcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAobGluZWFyRWxlbWVudEVkaXRvci5wb2ludGVyRG93blN0YXRlLnNlZ21lbnRNaWRwb2ludC52YWx1ZSAhPT0gbnVsbCAmJiAhbGluZWFyRWxlbWVudEVkaXRvci5wb2ludGVyRG93blN0YXRlLnNlZ21lbnRNaWRwb2ludC5hZGRlZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRpZERyYWcgPSBMaW5lYXJFbGVtZW50RWRpdG9yLmhhbmRsZVBvaW50RHJhZ2dpbmcoZXZlbnQsIHRoaXMuc3RhdGUsIHBvaW50ZXJDb29yZHMueCwgcG9pbnRlckNvb3Jkcy55LCAoZWxlbWVudCwgcG9pbnRzU2NlbmVDb29yZHMpID0+IHtcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdzRm9yTGluZWFyRWxlbWVudEF0Q29vcmRzKGVsZW1lbnQsIHBvaW50c1NjZW5lQ29vcmRzKTtcbiAgICAgICAgfSwgbGluZWFyRWxlbWVudEVkaXRvcik7XG5cbiAgICAgICAgaWYgKGRpZERyYWcpIHtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueCA9IHBvaW50ZXJDb29yZHMueDtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueSA9IHBvaW50ZXJDb29yZHMueTtcbiAgICAgICAgICBwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgPSB0cnVlO1xuXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgJiYgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpLCB7XG4gICAgICAgICAgICAgICAgaXNEcmFnZ2luZzogdHJ1ZVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5pc0RyYWdnaW5nKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSwge1xuICAgICAgICAgICAgICAgIGlzRHJhZ2dpbmc6IHRydWVcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNIaXRBU2VsZWN0ZWRFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5oaXQuYWxsSGl0RWxlbWVudHMuc29tZShlbGVtZW50ID0+IHRoaXMuaXNBU2VsZWN0ZWRFbGVtZW50KGVsZW1lbnQpKTtcbiAgICAgIGNvbnN0IGlzU2VsZWN0aW5nUG9pbnRzSW5MaW5lRWRpdG9yID0gdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCAmJiBldmVudC5zaGlmdEtleSAmJiB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCA9PT0gKChfYSA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pZCk7XG5cbiAgICAgIGlmICgoaGFzSGl0QVNlbGVjdGVkRWxlbWVudCB8fCBwb2ludGVyRG93blN0YXRlLmhpdC5oYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cykgJiYgIWlzU2VsZWN0aW5nUG9pbnRzSW5MaW5lRWRpdG9yKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkRWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMuZXZlcnkoZWxlbWVudCA9PiBlbGVtZW50LmxvY2tlZCkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZWxlY3RlZEVsZW1lbnRzSGFzQUZyYW1lID0gc2VsZWN0ZWRFbGVtZW50cy5maW5kKGUgPT4gaXNGcmFtZUVsZW1lbnQoZSkpO1xuICAgICAgICBjb25zdCB0b3BMYXllckZyYW1lID0gdGhpcy5nZXRUb3BMYXllckZyYW1lQXRTY2VuZUNvb3Jkcyhwb2ludGVyQ29vcmRzKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZnJhbWVUb0hpZ2hsaWdodDogdG9wTGF5ZXJGcmFtZSAmJiAhc2VsZWN0ZWRFbGVtZW50c0hhc0FGcmFtZSA/IHRvcExheWVyRnJhbWUgOiBudWxsXG4gICAgICAgIH0pOyAvLyBNYXJraW5nIHRoYXQgY2xpY2sgd2FzIHVzZWQgZm9yIGRyYWdnaW5nIHRvIGNoZWNrXG4gICAgICAgIC8vIGlmIGVsZW1lbnRzIHNob3VsZCBiZSBkZXNlbGVjdGVkIG9uIHBvaW50ZXJ1cFxuXG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCA9IHRydWU7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHNlbGVjdGVkRWxlbWVudHNBcmVCZWluZ0RyYWdnZWQ6IHRydWVcbiAgICAgICAgfSk7IC8vIHByZXZlbnQgZHJhZ2dpbmcgZXZlbiBpZiB3ZSdyZSBubyBsb25nZXIgaG9sZGluZyBjbWQvY3RybCBvdGhlcndpc2VcbiAgICAgICAgLy8gaXQgd291bGQgaGF2ZSB3ZWlyZCByZXN1bHRzIChzdHVmZiBqdW1waW5nIGFsbCBvdmVyIHRoZSBzY3JlZW4pXG4gICAgICAgIC8vIENoZWNraW5nIGZvciBlZGl0aW5nRWxlbWVudCB0byBhdm9pZCBqdW1wIHdoaWxlIGVkaXRpbmcgb24gbW9iaWxlICM2NTAzXG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRWxlbWVudHMubGVuZ3RoID4gMCAmJiAhcG9pbnRlckRvd25TdGF0ZS53aXRoQ21kT3JDdHJsICYmICF0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50ICYmICgoX2IgPSB0aGlzLnN0YXRlLmFjdGl2ZUVtYmVkZGFibGUpID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYi5zdGF0ZSkgIT09IFwiYWN0aXZlXCIpIHtcbiAgICAgICAgICBjb25zdCBkcmFnT2Zmc2V0ID0ge1xuICAgICAgICAgICAgeDogcG9pbnRlckNvb3Jkcy54IC0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW4ueCxcbiAgICAgICAgICAgIHk6IHBvaW50ZXJDb29yZHMueSAtIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luLnlcbiAgICAgICAgICB9O1xuICAgICAgICAgIGNvbnN0IG9yaWdpbmFsRWxlbWVudHMgPSBbLi4ucG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLnZhbHVlcygpXTsgLy8gV2Ugb25seSBkcmFnIGluIG9uZSBkaXJlY3Rpb24gaWYgc2hpZnQgaXMgcHJlc3NlZFxuXG4gICAgICAgICAgY29uc3QgbG9ja0RpcmVjdGlvbiA9IGV2ZW50LnNoaWZ0S2V5O1xuXG4gICAgICAgICAgaWYgKGxvY2tEaXJlY3Rpb24pIHtcbiAgICAgICAgICAgIGNvbnN0IGRpc3RhbmNlWCA9IE1hdGguYWJzKGRyYWdPZmZzZXQueCk7XG4gICAgICAgICAgICBjb25zdCBkaXN0YW5jZVkgPSBNYXRoLmFicyhkcmFnT2Zmc2V0LnkpO1xuICAgICAgICAgICAgY29uc3QgbG9ja1ggPSBsb2NrRGlyZWN0aW9uICYmIGRpc3RhbmNlWCA8IGRpc3RhbmNlWTtcbiAgICAgICAgICAgIGNvbnN0IGxvY2tZID0gbG9ja0RpcmVjdGlvbiAmJiBkaXN0YW5jZVggPiBkaXN0YW5jZVk7XG5cbiAgICAgICAgICAgIGlmIChsb2NrWCkge1xuICAgICAgICAgICAgICBkcmFnT2Zmc2V0LnggPSAwO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAobG9ja1kpIHtcbiAgICAgICAgICAgICAgZHJhZ09mZnNldC55ID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IC8vIFNuYXAgY2FjaGUgKm11c3QqIGJlIHN5bmNocm9ub3VzbHkgcG9wdXBsYXRlZCBiZWZvcmUgaW5pdGlhbCBkcmFnLFxuICAgICAgICAgIC8vIG90aGVyd2lzZSB0aGUgZmlyc3QgZHJhZyBldmVuIHdpbGwgbm90IHNuYXAsIGNhdXNpbmcgYSBqdW1wIGJlZm9yZVxuICAgICAgICAgIC8vIGl0IHNuYXBzIHRvIGl0cyBwb3NpdGlvbiBpZiBwcmV2aW91c2x5IHNuYXBwZWQgYWxyZWFkeS5cblxuXG4gICAgICAgICAgdGhpcy5tYXliZUNhY2hlVmlzaWJsZUdhcHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICAgIHRoaXMubWF5YmVDYWNoZVJlZmVyZW5jZVNuYXBQb2ludHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMpO1xuICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgIHNuYXBPZmZzZXQsXG4gICAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgICB9ID0gc25hcERyYWdnZWRFbGVtZW50cyhnZXRTZWxlY3RlZEVsZW1lbnRzKG9yaWdpbmFsRWxlbWVudHMsIHRoaXMuc3RhdGUpLCBkcmFnT2Zmc2V0LCB0aGlzLnN0YXRlLCBldmVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzbmFwTGluZXNcbiAgICAgICAgICB9KTsgLy8gd2hlbiB3ZSdyZSBlZGl0aW5nIHRoZSBuYW1lIG9mIGEgZnJhbWUsIHdlIHdhbnQgdGhlIHVzZXIgdG8gYmVcbiAgICAgICAgICAvLyBhYmxlIHRvIHNlbGVjdCBhbmQgaW50ZXJhY3Qgd2l0aCB0aGUgdGV4dCBpbnB1dFxuXG4gICAgICAgICAgIXRoaXMuc3RhdGUuZWRpdGluZ0ZyYW1lICYmIGRyYWdTZWxlY3RlZEVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUsIHNlbGVjdGVkRWxlbWVudHMsIGRyYWdPZmZzZXQsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUsIHNuYXBPZmZzZXQsIGV2ZW50W0tFWVMuQ1RSTF9PUl9DTURdID8gbnVsbCA6IHRoaXMuc3RhdGUuZ3JpZFNpemUpO1xuICAgICAgICAgIHRoaXMubWF5YmVTdWdnZXN0QmluZGluZ0ZvckFsbChzZWxlY3RlZEVsZW1lbnRzKTsgLy8gV2UgZHVwbGljYXRlIHRoZSBzZWxlY3RlZCBlbGVtZW50IGlmIGFsdCBpcyBwcmVzc2VkIG9uIHBvaW50ZXIgbW92ZVxuXG4gICAgICAgICAgaWYgKGV2ZW50LmFsdEtleSAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQpIHtcbiAgICAgICAgICAgIC8vIE1vdmUgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBlbGVtZW50cyB0byB0aGUgdG9wIG9mIHRoZSB6IGluZGV4IHN0YWNrLCBhbmRcbiAgICAgICAgICAgIC8vIHB1dCB0aGUgZHVwbGljYXRlcyB3aGVyZSB0aGUgc2VsZWN0ZWQgZWxlbWVudHMgdXNlZCB0byBiZS5cbiAgICAgICAgICAgIC8vICh0aGUgb3JpZ2luIHBvaW50IHdoZXJlIHRoZSBkcmFnZ2luZyBzdGFydGVkKVxuICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5oaXQuaGFzQmVlbkR1cGxpY2F0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29uc3QgbmV4dEVsZW1lbnRzID0gW107XG4gICAgICAgICAgICBjb25zdCBlbGVtZW50c1RvQXBwZW5kID0gW107XG4gICAgICAgICAgICBjb25zdCBncm91cElkTWFwID0gbmV3IE1hcCgpO1xuICAgICAgICAgICAgY29uc3Qgb2xkSWRUb0R1cGxpY2F0ZWRJZCA9IG5ldyBNYXAoKTtcbiAgICAgICAgICAgIGNvbnN0IGhpdEVsZW1lbnQgPSBwb2ludGVyRG93blN0YXRlLmhpdC5lbGVtZW50O1xuICAgICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50SWRzID0gbmV3IFNldCh0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHMoe1xuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IHRoaXMuc3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzLFxuICAgICAgICAgICAgICBpbmNsdWRlQm91bmRUZXh0RWxlbWVudDogdHJ1ZSxcbiAgICAgICAgICAgICAgaW5jbHVkZUVsZW1lbnRzSW5GcmFtZXM6IHRydWVcbiAgICAgICAgICAgIH0pLm1hcChlbGVtZW50ID0+IGVsZW1lbnQuaWQpKTtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgIGlmIChzZWxlY3RlZEVsZW1lbnRJZHMuaGFzKGVsZW1lbnQuaWQpIHx8IC8vIGNhc2U6IHRoZSBzdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMgbWlnaHQgbm90IGhhdmUgYmVlblxuICAgICAgICAgICAgICAvLyB1cGRhdGVkIHlldCBieSB0aGUgdGltZSB0aGlzIG1vdXNlbW92ZSBldmVudCBpcyBmaXJlZFxuICAgICAgICAgICAgICBlbGVtZW50LmlkID09PSAoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmlkKSAmJiBwb2ludGVyRG93blN0YXRlLmhpdC53YXNBZGRlZFRvU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZHVwbGljYXRlZEVsZW1lbnQgPSBkdXBsaWNhdGVFbGVtZW50KHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQsIGdyb3VwSWRNYXAsIGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IG9yaWdFbGVtZW50ID0gcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLmdldChlbGVtZW50LmlkKTtcbiAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGR1cGxpY2F0ZWRFbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICB4OiBvcmlnRWxlbWVudC54LFxuICAgICAgICAgICAgICAgICAgeTogb3JpZ0VsZW1lbnQueVxuICAgICAgICAgICAgICAgIH0pOyAvLyBwdXQgZHVwbGljYXRlZCBlbGVtZW50IHRvIHBvaW50ZXJEb3duU3RhdGUub3JpZ2luYWxFbGVtZW50c1xuICAgICAgICAgICAgICAgIC8vIHNvIHRoYXQgd2UgY2FuIHNuYXAgdG8gdGhlIGR1cGxpY2F0ZWQgZWxlbWVudCB3aXRob3V0IHJlbGVhc2luZ1xuXG4gICAgICAgICAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5vcmlnaW5hbEVsZW1lbnRzLnNldChkdXBsaWNhdGVkRWxlbWVudC5pZCwgZHVwbGljYXRlZEVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIG5leHRFbGVtZW50cy5wdXNoKGR1cGxpY2F0ZWRFbGVtZW50KTtcbiAgICAgICAgICAgICAgICBlbGVtZW50c1RvQXBwZW5kLnB1c2goZWxlbWVudCk7XG4gICAgICAgICAgICAgICAgb2xkSWRUb0R1cGxpY2F0ZWRJZC5zZXQoZWxlbWVudC5pZCwgZHVwbGljYXRlZEVsZW1lbnQuaWQpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG5leHRFbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IG5leHRTY2VuZUVsZW1lbnRzID0gWy4uLm5leHRFbGVtZW50cywgLi4uZWxlbWVudHNUb0FwcGVuZF07XG4gICAgICAgICAgICBiaW5kVGV4dFRvU2hhcGVBZnRlckR1cGxpY2F0aW9uKG5leHRFbGVtZW50cywgZWxlbWVudHNUb0FwcGVuZCwgb2xkSWRUb0R1cGxpY2F0ZWRJZCk7XG4gICAgICAgICAgICBmaXhCaW5kaW5nc0FmdGVyRHVwbGljYXRpb24obmV4dFNjZW5lRWxlbWVudHMsIGVsZW1lbnRzVG9BcHBlbmQsIG9sZElkVG9EdXBsaWNhdGVkSWQsIFwiZHVwbGljYXRlc1NlcnZlQXNPbGRcIik7XG4gICAgICAgICAgICBiaW5kRWxlbWVudHNUb0ZyYW1lc0FmdGVyRHVwbGljYXRpb24obmV4dFNjZW5lRWxlbWVudHMsIGVsZW1lbnRzVG9BcHBlbmQsIG9sZElkVG9EdXBsaWNhdGVkSWQpO1xuICAgICAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMobmV4dFNjZW5lRWxlbWVudHMpO1xuICAgICAgICAgICAgdGhpcy5tYXliZUNhY2hlVmlzaWJsZUdhcHMoZXZlbnQsIHNlbGVjdGVkRWxlbWVudHMsIHRydWUpO1xuICAgICAgICAgICAgdGhpcy5tYXliZUNhY2hlUmVmZXJlbmNlU25hcFBvaW50cyhldmVudCwgc2VsZWN0ZWRFbGVtZW50cywgdHJ1ZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9IC8vIEl0IGlzIHZlcnkgaW1wb3J0YW50IHRvIHJlYWQgdGhpcy5zdGF0ZSB3aXRoaW4gZWFjaCBtb3ZlIGV2ZW50LFxuICAgICAgLy8gb3RoZXJ3aXNlIHdlIHdvdWxkIHJlYWQgYSBzdGFsZSBvbmUhXG5cblxuICAgICAgY29uc3QgZHJhZ2dpbmdFbGVtZW50ID0gdGhpcy5zdGF0ZS5kcmFnZ2luZ0VsZW1lbnQ7XG5cbiAgICAgIGlmICghZHJhZ2dpbmdFbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC50eXBlID09PSBcImZyZWVkcmF3XCIpIHtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgY29uc3QgZHggPSBwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgY29uc3QgZHkgPSBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcbiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9pbnRzLmxlbmd0aCA+IDAgJiYgcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXTtcbiAgICAgICAgY29uc3QgZGlzY2FyZFBvaW50ID0gbGFzdFBvaW50ICYmIGxhc3RQb2ludFswXSA9PT0gZHggJiYgbGFzdFBvaW50WzFdID09PSBkeTtcblxuICAgICAgICBpZiAoIWRpc2NhcmRQb2ludCkge1xuICAgICAgICAgIGNvbnN0IHByZXNzdXJlcyA9IGRyYWdnaW5nRWxlbWVudC5zaW11bGF0ZVByZXNzdXJlID8gZHJhZ2dpbmdFbGVtZW50LnByZXNzdXJlcyA6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucHJlc3N1cmVzLCBldmVudC5wcmVzc3VyZV07XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cywgW2R4LCBkeV1dLFxuICAgICAgICAgICAgcHJlc3N1cmVzXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoaXNMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgcG9pbnRzID0gZHJhZ2dpbmdFbGVtZW50LnBvaW50cztcbiAgICAgICAgbGV0IGR4ID0gZ3JpZFggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgbGV0IGR5ID0gZ3JpZFkgLSBkcmFnZ2luZ0VsZW1lbnQueTtcblxuICAgICAgICBpZiAoc2hvdWxkUm90YXRlV2l0aERpc2NyZXRlQW5nbGUoZXZlbnQpICYmIHBvaW50cy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICAoe1xuICAgICAgICAgICAgd2lkdGg6IGR4LFxuICAgICAgICAgICAgaGVpZ2h0OiBkeVxuICAgICAgICAgIH0gPSBnZXRMb2NrZWRMaW5lYXJDdXJzb3JBbGlnblNpemUoZHJhZ2dpbmdFbGVtZW50LngsIGRyYWdnaW5nRWxlbWVudC55LCBwb2ludGVyQ29vcmRzLngsIHBvaW50ZXJDb29yZHMueSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBvaW50cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4ucG9pbnRzLCBbZHgsIGR5XV1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChwb2ludHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICAgIHBvaW50czogWy4uLnBvaW50cy5zbGljZSgwLCAtMSksIFtkeCwgZHldXVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQmluZGluZ0VsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBmYWxzZSkpIHtcbiAgICAgICAgICAvLyBXaGVuIGNyZWF0aW5nIGEgbGluZWFyIGVsZW1lbnQgYnkgZHJhZ2dpbmdcbiAgICAgICAgICB0aGlzLm1heWJlU3VnZ2VzdEJpbmRpbmdzRm9yTGluZWFyRWxlbWVudEF0Q29vcmRzKGRyYWdnaW5nRWxlbWVudCwgW3BvaW50ZXJDb29yZHNdLCB0aGlzLnN0YXRlLnN0YXJ0Qm91bmRFbGVtZW50KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSBwb2ludGVyQ29vcmRzLng7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUubGFzdENvb3Jkcy55ID0gcG9pbnRlckNvb3Jkcy55O1xuICAgICAgICB0aGlzLm1heWJlRHJhZ05ld0dlbmVyaWNFbGVtZW50KHBvaW50ZXJEb3duU3RhdGUsIGV2ZW50KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuc3RhdGUuYWN0aXZlVG9vbC50eXBlID09PSBcInNlbGVjdGlvblwiKSB7XG4gICAgICAgIHBvaW50ZXJEb3duU3RhdGUuYm94U2VsZWN0aW9uLmhhc09jY3VycmVkID0gdHJ1ZTtcbiAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpOyAvLyBib3gtc2VsZWN0IGxpbmUgZWRpdG9yIHBvaW50c1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgTGluZWFyRWxlbWVudEVkaXRvci5oYW5kbGVCb3hTZWxlY3Rpb24oZXZlbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2V0U3RhdGUuYmluZCh0aGlzKSk7IC8vIHJlZ3VsYXIgYm94LXNlbGVjdFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxldCBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IHRydWU7XG5cbiAgICAgICAgICBpZiAoIWV2ZW50LnNoaWZ0S2V5ICYmIGlzU29tZUVsZW1lbnRTZWxlY3RlZChlbGVtZW50cywgdGhpcy5zdGF0ZSkpIHtcbiAgICAgICAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLndpdGhDbWRPckN0cmwgJiYgcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHByZXZTdGF0ZSA9PiBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczoge1xuICAgICAgICAgICAgICAgICAgW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzaG91bGRSZXVzZVNlbGVjdGlvbiA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uID0gZ2V0RWxlbWVudHNXaXRoaW5TZWxlY3Rpb24oZWxlbWVudHMsIGRyYWdnaW5nRWxlbWVudCk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgY29uc3QgbmV4dFNlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2hvdWxkUmV1c2VTZWxlY3Rpb24gJiYgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLnJlZHVjZSgoYWNjLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgIGFjY1tlbGVtZW50LmlkXSA9IHRydWU7XG4gICAgICAgICAgICAgIHJldHVybiBhY2M7XG4gICAgICAgICAgICB9LCB7fSkpO1xuXG4gICAgICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudCkge1xuICAgICAgICAgICAgICAvLyBpZiB1c2luZyBjdHJsL2NtZCwgc2VsZWN0IHRoZSBoaXRFbGVtZW50IG9ubHkgaWYgd2VcbiAgICAgICAgICAgICAgLy8gaGF2ZW4ndCBib3gtc2VsZWN0ZWQgYW55dGhpbmcgZWxzZVxuICAgICAgICAgICAgICBpZiAoIWVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbcG9pbnRlckRvd25TdGF0ZS5oaXQuZWxlbWVudC5pZF0gPSB0cnVlO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW3BvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXZTdGF0ZSA9ICFzaG91bGRSZXVzZVNlbGVjdGlvbiA/IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlKSwge1xuICAgICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiB7fSxcbiAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IG51bGxcbiAgICAgICAgICAgIH0pIDogcHJldlN0YXRlO1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbmV4dFNlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgLy8gc2VsZWN0IGxpbmVhciBlbGVtZW50IG9ubHkgd2hlbiB3ZSBoYXZlbid0IGJveC1zZWxlY3RlZCBhbnl0aGluZyBlbHNlXG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogZWxlbWVudHNXaXRoaW5TZWxlY3Rpb24ubGVuZ3RoID09PSAxICYmIGlzTGluZWFyRWxlbWVudChlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihlbGVtZW50c1dpdGhpblNlbGVjdGlvblswXSwgdGhpcy5zY2VuZSkgOiBudWxsLFxuICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uLmxlbmd0aCA9PT0gMSAmJiAoZWxlbWVudHNXaXRoaW5TZWxlY3Rpb25bMF0ubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGVsZW1lbnRzV2l0aGluU2VsZWN0aW9uWzBdKSkgPyBcImluZm9cIiA6IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9IC8vIFJldHVybnMgd2hldGhlciB0aGUgcG9pbnRlciBtb3ZlIGhhcHBlbmVkIG92ZXIgZWl0aGVyIHNjcm9sbGJhclxuXG5cbiAgaGFuZGxlUG9pbnRlck1vdmVPdmVyU2Nyb2xsYmFycyhldmVudCwgcG9pbnRlckRvd25TdGF0ZSkge1xuICAgIGlmIChwb2ludGVyRG93blN0YXRlLnNjcm9sbGJhcnMuaXNPdmVySG9yaXpvbnRhbCkge1xuICAgICAgY29uc3QgeCA9IGV2ZW50LmNsaWVudFg7XG4gICAgICBjb25zdCBkeCA9IHggLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueDtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWDogdGhpcy5zdGF0ZS5zY3JvbGxYIC0gZHggLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnggPSB4O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaWYgKHBvaW50ZXJEb3duU3RhdGUuc2Nyb2xsYmFycy5pc092ZXJWZXJ0aWNhbCkge1xuICAgICAgY29uc3QgeSA9IGV2ZW50LmNsaWVudFk7XG4gICAgICBjb25zdCBkeSA9IHkgLSBwb2ludGVyRG93blN0YXRlLmxhc3RDb29yZHMueTtcbiAgICAgIHRoaXMudHJhbnNsYXRlQ2FudmFzKHtcbiAgICAgICAgc2Nyb2xsWTogdGhpcy5zdGF0ZS5zY3JvbGxZIC0gZHkgLyB0aGlzLnN0YXRlLnpvb20udmFsdWVcbiAgICAgIH0pO1xuICAgICAgcG9pbnRlckRvd25TdGF0ZS5sYXN0Q29vcmRzLnkgPSB5O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgb25Qb2ludGVyVXBGcm9tUG9pbnRlckRvd25IYW5kbGVyKHBvaW50ZXJEb3duU3RhdGUpIHtcbiAgICByZXR1cm4gd2l0aEJhdGNoZWRVcGRhdGVzKGNoaWxkRXZlbnQgPT4ge1xuICAgICAgdmFyIF9hLCBfYiwgX2MsIF9kLCBfZSwgX2Y7XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSkge1xuICAgICAgICBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZS5mbHVzaCgpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7XG4gICAgICAgIGRyYWdnaW5nRWxlbWVudCxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50LFxuICAgICAgICBtdWx0aUVsZW1lbnQsXG4gICAgICAgIGFjdGl2ZVRvb2wsXG4gICAgICAgIGlzUmVzaXppbmcsXG4gICAgICAgIGlzUm90YXRpbmdcbiAgICAgIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzUmVzaXppbmc6IGZhbHNlLFxuICAgICAgICBpc1JvdGF0aW5nOiBmYWxzZSxcbiAgICAgICAgcmVzaXppbmdFbGVtZW50OiBudWxsLFxuICAgICAgICBzZWxlY3Rpb25FbGVtZW50OiBudWxsLFxuICAgICAgICBmcmFtZVRvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBlbGVtZW50c1RvSGlnaGxpZ2h0OiBudWxsLFxuICAgICAgICBjdXJzb3JCdXR0b246IFwidXBcIixcbiAgICAgICAgLy8gdGV4dCBlbGVtZW50cyBhcmUgcmVzZXQgb24gZmluYWxpemUsIGFuZCByZXNldHRpbmcgb24gcG9pbnRlcnVwXG4gICAgICAgIC8vIG1heSBjYXVzZSBpc3N1ZXMgd2l0aCBkb3VibGUgdGFwc1xuICAgICAgICBlZGl0aW5nRWxlbWVudDogbXVsdGlFbGVtZW50IHx8IGlzVGV4dEVsZW1lbnQodGhpcy5zdGF0ZS5lZGl0aW5nRWxlbWVudCkgPyB0aGlzLnN0YXRlLmVkaXRpbmdFbGVtZW50IDogbnVsbCxcbiAgICAgICAgc25hcExpbmVzOiBbXSxcbiAgICAgICAgb3JpZ2luU25hcE9mZnNldDogbnVsbFxuICAgICAgfSk7XG4gICAgICBTbmFwQ2FjaGUuc2V0UmVmZXJlbmNlU25hcFBvaW50cyhudWxsKTtcbiAgICAgIFNuYXBDYWNoZS5zZXRWaXNpYmxlR2FwcyhudWxsKTtcbiAgICAgIHRoaXMuc2F2ZVBvaW50ZXIoY2hpbGRFdmVudC5jbGllbnRYLCBjaGlsZEV2ZW50LmNsaWVudFksIFwidXBcIik7XG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgc2VsZWN0ZWRFbGVtZW50c0FyZUJlaW5nRHJhZ2dlZDogZmFsc2VcbiAgICAgIH0pOyAvLyBIYW5kbGUgZW5kIG9mIGRyYWdnaW5nIGEgcG9pbnQgb2YgYSBsaW5lYXIgZWxlbWVudCwgbWlnaHQgY2xvc2UgYSBsb29wXG4gICAgICAvLyBhbmQgc2V0cyBiaW5kaW5nIGVsZW1lbnRcblxuICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmJveFNlbGVjdGlvbi5oYXNPY2N1cnJlZCAmJiAoKF9iID0gKF9hID0gcG9pbnRlckRvd25TdGF0ZS5oaXQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuaWQpICE9PSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50LmVsZW1lbnRJZCkge1xuICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBlZGl0aW5nTGluZWFyRWxlbWVudCA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlclVwKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQsIHRoaXMuc3RhdGUpO1xuXG4gICAgICAgICAgaWYgKGVkaXRpbmdMaW5lYXJFbGVtZW50ICE9PSB0aGlzLnN0YXRlLmVkaXRpbmdMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0xpbmVhckVsZW1lbnQsXG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50KSB7XG4gICAgICAgIGlmICgoKF9kID0gKF9jID0gcG9pbnRlckRvd25TdGF0ZS5oaXQpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5lbGVtZW50KSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2QuaWQpICE9PSB0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5lbGVtZW50SWQpIHtcbiAgICAgICAgICBjb25zdCBzZWxlY3RlZEVMZW1lbnRzID0gdGhpcy5zY2VuZS5nZXRTZWxlY3RlZEVsZW1lbnRzKHRoaXMuc3RhdGUpOyAvLyBzZXQgc2VsZWN0ZWRMaW5lYXJFbGVtZW50IHRvIG51bGwgaWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSBlbGVtZW50IHNlbGVjdGVkIHNpbmNlIHdlIGRvbid0IHdhbnQgdG8gc2hvdyBsaW5lYXIgZWxlbWVudCBoYW5kbGVzXG5cbiAgICAgICAgICBpZiAoc2VsZWN0ZWRFTGVtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBudWxsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudEVkaXRvciA9IExpbmVhckVsZW1lbnRFZGl0b3IuaGFuZGxlUG9pbnRlclVwKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICBjb25zdCB7XG4gICAgICAgICAgICBzdGFydEJpbmRpbmdFbGVtZW50LFxuICAgICAgICAgICAgZW5kQmluZGluZ0VsZW1lbnRcbiAgICAgICAgICB9ID0gbGluZWFyRWxlbWVudEVkaXRvcjtcbiAgICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KGxpbmVhckVsZW1lbnRFZGl0b3IuZWxlbWVudElkKTtcblxuICAgICAgICAgIGlmIChpc0JpbmRpbmdFbGVtZW50KGVsZW1lbnQpKSB7XG4gICAgICAgICAgICBiaW5kT3JVbmJpbmRMaW5lYXJFbGVtZW50KGVsZW1lbnQsIHN0YXJ0QmluZGluZ0VsZW1lbnQsIGVuZEJpbmRpbmdFbGVtZW50KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAobGluZWFyRWxlbWVudEVkaXRvciAhPT0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgbGluZWFyRWxlbWVudEVkaXRvciksIHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZFBvaW50c0luZGljZXM6IG51bGxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxhc3RQb2ludGVyVXAgPSBudWxsO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuUE9JTlRFUl9NT1ZFLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uTW92ZSk7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihFVkVOVC5QT0lOVEVSX1VQLCBwb2ludGVyRG93blN0YXRlLmV2ZW50TGlzdGVuZXJzLm9uVXApO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZRE9XTiwgcG9pbnRlckRvd25TdGF0ZS5ldmVudExpc3RlbmVycy5vbktleURvd24pO1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoRVZFTlQuS0VZVVAsIHBvaW50ZXJEb3duU3RhdGUuZXZlbnRMaXN0ZW5lcnMub25LZXlVcCk7XG5cbiAgICAgIGlmICh0aGlzLnN0YXRlLnBlbmRpbmdJbWFnZUVsZW1lbnRJZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nSW1hZ2VFbGVtZW50SWQ6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMub25Qb2ludGVyVXBFbWl0dGVyLnRyaWdnZXIodGhpcy5zdGF0ZS5hY3RpdmVUb29sLCBwb2ludGVyRG93blN0YXRlLCBjaGlsZEV2ZW50KTtcblxuICAgICAgaWYgKChkcmFnZ2luZ0VsZW1lbnQgPT09IG51bGwgfHwgZHJhZ2dpbmdFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBkcmFnZ2luZ0VsZW1lbnQudHlwZSkgPT09IFwiZnJlZWRyYXdcIikge1xuICAgICAgICBjb25zdCBwb2ludGVyQ29vcmRzID0gdmlld3BvcnRDb29yZHNUb1NjZW5lQ29vcmRzKGNoaWxkRXZlbnQsIHRoaXMuc3RhdGUpO1xuICAgICAgICBjb25zdCBwb2ludHMgPSBkcmFnZ2luZ0VsZW1lbnQucG9pbnRzO1xuICAgICAgICBsZXQgZHggPSBwb2ludGVyQ29vcmRzLnggLSBkcmFnZ2luZ0VsZW1lbnQueDtcbiAgICAgICAgbGV0IGR5ID0gcG9pbnRlckNvb3Jkcy55IC0gZHJhZ2dpbmdFbGVtZW50Lnk7IC8vIEFsbG93cyBkb3RzIHRvIGF2b2lkIGJlaW5nIGZsYWdnZWQgYXMgaW5maW5pdGVseSBzbWFsbFxuXG4gICAgICAgIGlmIChkeCA9PT0gcG9pbnRzWzBdWzBdICYmIGR5ID09PSBwb2ludHNbMF1bMV0pIHtcbiAgICAgICAgICBkeSArPSAwLjAwMDE7XG4gICAgICAgICAgZHggKz0gMC4wMDAxO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcHJlc3N1cmVzID0gZHJhZ2dpbmdFbGVtZW50LnNpbXVsYXRlUHJlc3N1cmUgPyBbXSA6IFsuLi5kcmFnZ2luZ0VsZW1lbnQucHJlc3N1cmVzLCBjaGlsZEV2ZW50LnByZXNzdXJlXTtcbiAgICAgICAgbXV0YXRlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHtcbiAgICAgICAgICBwb2ludHM6IFsuLi5wb2ludHMsIFtkeCwgZHldXSxcbiAgICAgICAgICBwcmVzc3VyZXMsXG4gICAgICAgICAgbGFzdENvbW1pdHRlZFBvaW50OiBbZHgsIGR5XVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0ltYWdlRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQpKSB7XG4gICAgICAgIGNvbnN0IGltYWdlRWxlbWVudCA9IGRyYWdnaW5nRWxlbWVudDtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUltYWdlRGltZW5zaW9ucyhpbWFnZUVsZW1lbnQpO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyh7XG4gICAgICAgICAgICAgIFtpbWFnZUVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICB9LCB0aGlzLnN0YXRlKVxuICAgICAgICAgIH0sICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuYWN0aW9uTWFuYWdlci5leGVjdXRlQWN0aW9uKGFjdGlvbkZpbmFsaXplKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbHRlcihlbCA9PiBlbC5pZCAhPT0gaW1hZ2VFbGVtZW50LmlkKSk7XG4gICAgICAgICAgdGhpcy5hY3Rpb25NYW5hZ2VyLmV4ZWN1dGVBY3Rpb24oYWN0aW9uRmluYWxpemUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNMaW5lYXJFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkpIHtcbiAgICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudC5wb2ludHMubGVuZ3RoID4gMSkge1xuICAgICAgICAgIHRoaXMuaGlzdG9yeS5yZXN1bWVSZWNvcmRpbmcoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHBvaW50ZXJDb29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoY2hpbGRFdmVudCwgdGhpcy5zdGF0ZSk7XG5cbiAgICAgICAgaWYgKCFwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgJiYgZHJhZ2dpbmdFbGVtZW50ICYmICFtdWx0aUVsZW1lbnQpIHtcbiAgICAgICAgICBtdXRhdGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCwge1xuICAgICAgICAgICAgcG9pbnRzOiBbLi4uZHJhZ2dpbmdFbGVtZW50LnBvaW50cywgW3BvaW50ZXJDb29yZHMueCAtIGRyYWdnaW5nRWxlbWVudC54LCBwb2ludGVyQ29vcmRzLnkgLSBkcmFnZ2luZ0VsZW1lbnQueV1dXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBtdWx0aUVsZW1lbnQ6IGRyYWdnaW5nRWxlbWVudCxcbiAgICAgICAgICAgIGVkaXRpbmdFbGVtZW50OiB0aGlzLnN0YXRlLmRyYWdnaW5nRWxlbWVudFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKHBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiAhbXVsdGlFbGVtZW50KSB7XG4gICAgICAgICAgaWYgKGlzQmluZGluZ0VuYWJsZWQodGhpcy5zdGF0ZSkgJiYgaXNCaW5kaW5nRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIGZhbHNlKSkge1xuICAgICAgICAgICAgbWF5YmVCaW5kTGluZWFyRWxlbWVudChkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc3RhdGUsIHRoaXMuc2NlbmUsIHBvaW50ZXJDb29yZHMpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdLFxuICAgICAgICAgICAgc3RhcnRCb3VuZEVsZW1lbnQ6IG51bGxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmICghYWN0aXZlVG9vbC5sb2NrZWQpIHtcbiAgICAgICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgICAgICBhY3RpdmVUb29sOiB1cGRhdGVBY3RpdmVUb29sKHRoaXMuc3RhdGUsIHtcbiAgICAgICAgICAgICAgICB0eXBlOiBcInNlbGVjdGlvblwiXG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgICAgICBbZHJhZ2dpbmdFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9KSwgcHJldlN0YXRlKSxcbiAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihkcmFnZ2luZ0VsZW1lbnQsIHRoaXMuc2NlbmUpXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUocHJldlN0YXRlID0+ICh7XG4gICAgICAgICAgICAgIGRyYWdnaW5nRWxlbWVudDogbnVsbFxuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGFjdGl2ZVRvb2wudHlwZSAhPT0gXCJzZWxlY3Rpb25cIiAmJiBkcmFnZ2luZ0VsZW1lbnQgJiYgaXNJbnZpc2libHlTbWFsbEVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50KSkge1xuICAgICAgICAvLyByZW1vdmUgaW52aXNpYmxlIGVsZW1lbnQgd2hpY2ggd2FzIGFkZGVkIGluIG9uUG9pbnRlckRvd25cbiAgICAgICAgdGhpcy5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHModGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKS5maWx0ZXIoZWwgPT4gZWwuaWQgIT09IGRyYWdnaW5nRWxlbWVudC5pZCkpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRyYWdnaW5nRWxlbWVudCkge1xuICAgICAgICBpZiAocG9pbnRlckRvd25TdGF0ZS5kcmFnLmhhc09jY3VycmVkKSB7XG4gICAgICAgICAgY29uc3Qgc2NlbmVDb29yZHMgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoY2hpbGRFdmVudCwgdGhpcy5zdGF0ZSk7IC8vIHdoZW4gZWRpdGluZyB0aGUgcG9pbnRzIG9mIGEgbGluZWFyIGVsZW1lbnQsIHdlIGNoZWNrIGlmIHRoZVxuICAgICAgICAgIC8vIGxpbmVhciBlbGVtZW50IHN0aWxsIGlzIGluIHRoZSBmcmFtZSBhZnRlcndhcmRzXG4gICAgICAgICAgLy8gaWYgbm90LCB0aGUgbGluZWFyIGVsZW1lbnQgd2lsbCBiZSByZW1vdmVkIGZyb20gaXRzIGZyYW1lIChpZiBhbnkpXG5cbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQgJiYgdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQuaXNEcmFnZ2luZykge1xuICAgICAgICAgICAgY29uc3QgbGluZWFyRWxlbWVudCA9IHRoaXMuc2NlbmUuZ2V0RWxlbWVudCh0aGlzLnN0YXRlLnNlbGVjdGVkTGluZWFyRWxlbWVudC5lbGVtZW50SWQpO1xuXG4gICAgICAgICAgICBpZiAobGluZWFyRWxlbWVudCA9PT0gbnVsbCB8fCBsaW5lYXJFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBsaW5lYXJFbGVtZW50LmZyYW1lSWQpIHtcbiAgICAgICAgICAgICAgY29uc3QgZnJhbWUgPSBnZXRDb250YWluaW5nRnJhbWUobGluZWFyRWxlbWVudCk7XG5cbiAgICAgICAgICAgICAgaWYgKGZyYW1lICYmIGxpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWVsZW1lbnRPdmVybGFwc1dpdGhGcmFtZShsaW5lYXJFbGVtZW50LCBmcmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgbGluZWFyIGVsZW1lbnQgZnJvbSBhbGwgZ3JvdXBzXG4gICAgICAgICAgICAgICAgICAvLyBiZWZvcmUgcmVtb3ZpbmcgaXQgZnJvbSB0aGUgZnJhbWUgYXMgd2VsbFxuICAgICAgICAgICAgICAgICAgbXV0YXRlRWxlbWVudChsaW5lYXJFbGVtZW50LCB7XG4gICAgICAgICAgICAgICAgICAgIGdyb3VwSWRzOiBbXVxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhyZW1vdmVFbGVtZW50c0Zyb21GcmFtZSh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBbbGluZWFyRWxlbWVudF0sIHRoaXMuc3RhdGUpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdXBkYXRlIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gc2VsZWN0ZWQgZWxlbWVudHMgYW5kIGZyYW1lc1xuICAgICAgICAgICAgY29uc3QgdG9wTGF5ZXJGcmFtZSA9IHRoaXMuZ2V0VG9wTGF5ZXJGcmFtZUF0U2NlbmVDb29yZHMoc2NlbmVDb29yZHMpO1xuICAgICAgICAgICAgY29uc3Qgc2VsZWN0ZWRFbGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTtcbiAgICAgICAgICAgIGxldCBuZXh0RWxlbWVudHMgPSB0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuXG4gICAgICAgICAgICBjb25zdCB1cGRhdGVHcm91cElkc0FmdGVyRWRpdGluZ0dyb3VwID0gZWxlbWVudHMgPT4ge1xuICAgICAgICAgICAgICBpZiAoZWxlbWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50cykge1xuICAgICAgICAgICAgICAgICAgY29uc3QgaW5kZXggPSBlbGVtZW50Lmdyb3VwSWRzLmluZGV4T2YodGhpcy5zdGF0ZS5lZGl0aW5nR3JvdXBJZCk7XG4gICAgICAgICAgICAgICAgICBtdXRhdGVFbGVtZW50KGVsZW1lbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZHM6IGVsZW1lbnQuZ3JvdXBJZHMuc2xpY2UoMCwgaW5kZXgpXG4gICAgICAgICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzLmZvckVhY2goZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC5ncm91cElkcy5sZW5ndGggJiYgZ2V0RWxlbWVudHNJbkdyb3VwKG5leHRFbGVtZW50cywgZWxlbWVudC5ncm91cElkc1tlbGVtZW50Lmdyb3VwSWRzLmxlbmd0aCAtIDFdKS5sZW5ndGggPCAyKSB7XG4gICAgICAgICAgICAgICAgICAgIG11dGF0ZUVsZW1lbnQoZWxlbWVudCwge1xuICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWRzOiBbXVxuICAgICAgICAgICAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAodG9wTGF5ZXJGcmFtZSAmJiAhdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbdG9wTGF5ZXJGcmFtZS5pZF0pIHtcbiAgICAgICAgICAgICAgY29uc3QgZWxlbWVudHNUb0FkZCA9IHNlbGVjdGVkRWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC5mcmFtZUlkICE9PSB0b3BMYXllckZyYW1lLmlkICYmIGlzRWxlbWVudEluRnJhbWUoZWxlbWVudCwgbmV4dEVsZW1lbnRzLCB0aGlzLnN0YXRlKSk7XG5cbiAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0dyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICB1cGRhdGVHcm91cElkc0FmdGVyRWRpdGluZ0dyb3VwKGVsZW1lbnRzVG9BZGQpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgbmV4dEVsZW1lbnRzID0gYWRkRWxlbWVudHNUb0ZyYW1lKG5leHRFbGVtZW50cywgZWxlbWVudHNUb0FkZCwgdG9wTGF5ZXJGcmFtZSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCF0b3BMYXllckZyYW1lKSB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmdHcm91cElkKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZWxlbWVudHNUb1JlbW92ZSA9IHNlbGVjdGVkRWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC5mcmFtZUlkICYmICFpc0VsZW1lbnRJbkZyYW1lKGVsZW1lbnQsIG5leHRFbGVtZW50cywgdGhpcy5zdGF0ZSkpO1xuICAgICAgICAgICAgICAgIHVwZGF0ZUdyb3VwSWRzQWZ0ZXJFZGl0aW5nR3JvdXAoZWxlbWVudHNUb1JlbW92ZSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbmV4dEVsZW1lbnRzID0gdXBkYXRlRnJhbWVNZW1iZXJzaGlwT2ZTZWxlY3RlZEVsZW1lbnRzKG5leHRFbGVtZW50cywgdGhpcy5zdGF0ZSwgdGhpcyk7XG4gICAgICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0RWxlbWVudHMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkcmFnZ2luZ0VsZW1lbnQudHlwZSA9PT0gXCJmcmFtZVwiKSB7XG4gICAgICAgICAgY29uc3QgZWxlbWVudHNJbnNpZGVGcmFtZSA9IGdldEVsZW1lbnRzSW5OZXdGcmFtZSh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBkcmFnZ2luZ0VsZW1lbnQpO1xuICAgICAgICAgIHRoaXMuc2NlbmUucmVwbGFjZUFsbEVsZW1lbnRzKGFkZEVsZW1lbnRzVG9GcmFtZSh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCBlbGVtZW50c0luc2lkZUZyYW1lLCBkcmFnZ2luZ0VsZW1lbnQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIG11dGF0ZUVsZW1lbnQoZHJhZ2dpbmdFbGVtZW50LCBnZXROb3JtYWxpemVkRGltZW5zaW9ucyhkcmFnZ2luZ0VsZW1lbnQpKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHJlc2l6aW5nRWxlbWVudCkge1xuICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChyZXNpemluZ0VsZW1lbnQgJiYgaXNJbnZpc2libHlTbWFsbEVsZW1lbnQocmVzaXppbmdFbGVtZW50KSkge1xuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLmZpbHRlcihlbCA9PiBlbC5pZCAhPT0gcmVzaXppbmdFbGVtZW50LmlkKSk7XG4gICAgICB9IC8vIGhhbmRsZSBmcmFtZSBtZW1iZXJzaGlwIGZvciByZXNpemluZyBmcmFtZXMgYW5kL29yIHNlbGVjdGVkIGVsZW1lbnRzXG5cblxuICAgICAgaWYgKHBvaW50ZXJEb3duU3RhdGUucmVzaXplLmlzUmVzaXppbmcpIHtcbiAgICAgICAgbGV0IG5leHRFbGVtZW50cyA9IHVwZGF0ZUZyYW1lTWVtYmVyc2hpcE9mU2VsZWN0ZWRFbGVtZW50cyh0aGlzLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpLCB0aGlzLnN0YXRlLCB0aGlzKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRGcmFtZXMgPSB0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSkuZmlsdGVyKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuXG4gICAgICAgIGZvciAoY29uc3QgZnJhbWUgb2Ygc2VsZWN0ZWRGcmFtZXMpIHtcbiAgICAgICAgICBuZXh0RWxlbWVudHMgPSByZXBsYWNlQWxsRWxlbWVudHNJbkZyYW1lKG5leHRFbGVtZW50cywgZ2V0RWxlbWVudHNJblJlc2l6aW5nRnJhbWUodGhpcy5zY2VuZS5nZXRFbGVtZW50c0luY2x1ZGluZ0RlbGV0ZWQoKSwgZnJhbWUsIHRoaXMuc3RhdGUpLCBmcmFtZSwgdGhpcy5zdGF0ZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNjZW5lLnJlcGxhY2VBbGxFbGVtZW50cyhuZXh0RWxlbWVudHMpO1xuICAgICAgfSAvLyBDb2RlIGJlbG93IGhhbmRsZXMgc2VsZWN0aW9uIHdoZW4gZWxlbWVudChzKSB3ZXJlbid0XG4gICAgICAvLyBkcmFnIG9yIGFkZGVkIHRvIHNlbGVjdGlvbiBvbiBwb2ludGVyIGRvd24gcGhhc2UuXG5cblxuICAgICAgY29uc3QgaGl0RWxlbWVudCA9IHBvaW50ZXJEb3duU3RhdGUuaGl0LmVsZW1lbnQ7XG5cbiAgICAgIGlmICgoKF9lID0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpID09PSBudWxsIHx8IF9lID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZS5lbGVtZW50SWQpICE9PSAoaGl0RWxlbWVudCA9PT0gbnVsbCB8fCBoaXRFbGVtZW50ID09PSB2b2lkIDAgPyB2b2lkIDAgOiBoaXRFbGVtZW50LmlkKSAmJiBpc0xpbmVhckVsZW1lbnQoaGl0RWxlbWVudCkpIHtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRFTGVtZW50cyA9IHRoaXMuc2NlbmUuZ2V0U2VsZWN0ZWRFbGVtZW50cyh0aGlzLnN0YXRlKTsgLy8gc2V0IHNlbGVjdGVkTGluZWFyRWxlbWVudCB3aGVuIG5vIG90aGVyIGVsZW1lbnQgc2VsZWN0ZWQgZXhjZXB0XG4gICAgICAgIC8vIHRoZSBvbmUgd2UndmUgaGl0XG5cbiAgICAgICAgaWYgKHNlbGVjdGVkRUxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZWxlY3RlZExpbmVhckVsZW1lbnQ6IG5ldyBMaW5lYXJFbGVtZW50RWRpdG9yKGhpdEVsZW1lbnQsIHRoaXMuc2NlbmUpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGlzRXJhc2VyQWN0aXZlKHRoaXMuc3RhdGUpKSB7XG4gICAgICAgIGNvbnN0IGRyYWdnZWREaXN0YW5jZSA9IGRpc3RhbmNlMmQodGhpcy5sYXN0UG9pbnRlckRvd25FdmVudC5jbGllbnRYLCB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50LmNsaWVudFksIHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LmNsaWVudFgsIHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LmNsaWVudFkpO1xuXG4gICAgICAgIGlmIChkcmFnZ2VkRGlzdGFuY2UgPT09IDApIHtcbiAgICAgICAgICBjb25zdCBzY2VuZVBvaW50ZXIgPSB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMoe1xuICAgICAgICAgICAgY2xpZW50WDogdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQuY2xpZW50WCxcbiAgICAgICAgICAgIGNsaWVudFk6IHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LmNsaWVudFlcbiAgICAgICAgICB9LCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICBjb25zdCBoaXRFbGVtZW50cyA9IHRoaXMuZ2V0RWxlbWVudHNBdFBvc2l0aW9uKHNjZW5lUG9pbnRlci54LCBzY2VuZVBvaW50ZXIueSk7XG4gICAgICAgICAgaGl0RWxlbWVudHMuZm9yRWFjaChoaXRFbGVtZW50ID0+IHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2VbaGl0RWxlbWVudC5pZF0gPSB7XG4gICAgICAgICAgICBlcmFzZTogdHJ1ZSxcbiAgICAgICAgICAgIG9wYWNpdHk6IGhpdEVsZW1lbnQub3BhY2l0eVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lcmFzZUVsZW1lbnRzKHBvaW50ZXJEb3duU3RhdGUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKHBvaW50ZXJEb3duU3RhdGUuZWxlbWVudElkc1RvRXJhc2UpLmxlbmd0aCkge1xuICAgICAgICB0aGlzLnJlc3RvcmVSZWFkeVRvRXJhc2VFbGVtZW50cyhwb2ludGVyRG93blN0YXRlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgIXBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiAhcG9pbnRlckRvd25TdGF0ZS5oaXQud2FzQWRkZWRUb1NlbGVjdGlvbiAmJiAoIC8vIGlmIHdlJ3JlIGVkaXRpbmcgYSBsaW5lLCBwb2ludGVydXAgc2hvdWxkbid0IHN3aXRjaCBzZWxlY3Rpb24gaWZcbiAgICAgIC8vIGJveCBzZWxlY3RlZFxuICAgICAgIXRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQgfHwgIXBvaW50ZXJEb3duU3RhdGUuYm94U2VsZWN0aW9uLmhhc09jY3VycmVkKSkge1xuICAgICAgICAvLyB3aGVuIGluc2lkZSBsaW5lIGVkaXRvciwgc2hpZnQgc2VsZWN0cyBwb2ludHMgaW5zdGVhZFxuICAgICAgICBpZiAoY2hpbGRFdmVudC5zaGlmdEtleSAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nTGluZWFyRWxlbWVudCkge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmlkXSkge1xuICAgICAgICAgICAgaWYgKGlzU2VsZWN0ZWRWaWFHcm91cCh0aGlzLnN0YXRlLCBoaXRFbGVtZW50KSkge1xuICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKF9wcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKHt9LCBfcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyk7IC8vIFdlIHdhbnQgdG8gdW5zZWxlY3QgYWxsIGdyb3VwcyBoaXRFbGVtZW50IGlzIHBhcnQgb2ZcbiAgICAgICAgICAgICAgICAvLyBhcyB3ZWxsIGFzIGFsbCBlbGVtZW50cyB0aGF0IGFyZSBwYXJ0IG9mIHRoZSBncm91cHNcbiAgICAgICAgICAgICAgICAvLyBoaXRFbGVtZW50IGlzIHBhcnQgb2ZcblxuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZ3JvdXBlZEVsZW1lbnQgb2YgaGl0RWxlbWVudC5ncm91cElkcy5mbGF0TWFwKGdyb3VwSWQgPT4gZ2V0RWxlbWVudHNJbkdyb3VwKHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIGdyb3VwSWQpKSkge1xuICAgICAgICAgICAgICAgICAgZGVsZXRlIG5leHRTZWxlY3RlZEVsZW1lbnRJZHNbZ3JvdXBlZEVsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEdyb3VwSWRzOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIF9wcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwgaGl0RWxlbWVudC5ncm91cElkcy5tYXAoZ0lkID0+ICh7XG4gICAgICAgICAgICAgICAgICAgIFtnSWRdOiBmYWxzZVxuICAgICAgICAgICAgICAgICAgfSkpLnJlZHVjZSgocHJldiwgYWNjKSA9PiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXYpLCBhY2MpLCB7fSkpLFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhuZXh0U2VsZWN0ZWRFbGVtZW50SWRzLCBfcHJldlN0YXRlKVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIH0pOyAvLyBpZiBub3QgZ3JhZ2dpbmcgYSBsaW5lYXIgZWxlbWVudCBwb2ludCAob3V0c2lkZSBlZGl0b3IpXG4gICAgICAgICAgICB9IGVsc2UgaWYgKCEoKF9mID0gdGhpcy5zdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpID09PSBudWxsIHx8IF9mID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZi5pc0RyYWdnaW5nKSkge1xuICAgICAgICAgICAgICAvLyByZW1vdmUgZWxlbWVudCBmcm9tIHNlbGVjdGlvbiB3aGlsZVxuICAgICAgICAgICAgICAvLyBrZWVwaW5nIHByZXYgZWxlbWVudHMgc2VsZWN0ZWRcbiAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5ld1NlbGVjdGVkRWxlbWVudElkcyA9IE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXdTZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5pZF07XG4gICAgICAgICAgICAgICAgY29uc3QgbmV3U2VsZWN0ZWRFbGVtZW50cyA9IGdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwge1xuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBuZXdTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQsXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5ld1NlbGVjdGVkRWxlbWVudElkc1xuICAgICAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgICAgICAvLyBzZXQgc2VsZWN0ZWRMaW5lYXJFbGVtZW50IG9ubHkgaWYgdGhhdHMgdGhlIG9ubHkgZWxlbWVudCBzZWxlY3RlZFxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRMaW5lYXJFbGVtZW50OiBuZXdTZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMSAmJiBpc0xpbmVhckVsZW1lbnQobmV3U2VsZWN0ZWRFbGVtZW50c1swXSkgPyBuZXcgTGluZWFyRWxlbWVudEVkaXRvcihuZXdTZWxlY3RlZEVsZW1lbnRzWzBdLCB0aGlzLnNjZW5lKSA6IHByZXZTdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnRcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChoaXRFbGVtZW50LmZyYW1lSWQgJiYgdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNbaGl0RWxlbWVudC5mcmFtZUlkXSkge1xuICAgICAgICAgICAgLy8gd2hlbiBoaXRFbGVtZW50IGlzIHBhcnQgb2YgYSBzZWxlY3RlZCBmcmFtZSwgZGVzZWxlY3QgdGhlIGZyYW1lXG4gICAgICAgICAgICAvLyB0byBhdm9pZCBmcmFtZSBhbmQgY29udGFpbmluZyBlbGVtZW50cyBzZWxlY3RlZCBzaW11bHRhbmVvdXNseVxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgICB2YXIgX2EsIF9iO1xuXG4gICAgICAgICAgICAgIGNvbnN0IG5leHRTZWxlY3RlZEVsZW1lbnRJZHMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZTdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHMpLCB7XG4gICAgICAgICAgICAgICAgW2hpdEVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH0pOyAvLyBkZXNlbGVjdCB0aGUgZnJhbWVcblxuICAgICAgICAgICAgICBkZWxldGUgbmV4dFNlbGVjdGVkRWxlbWVudElkc1toaXRFbGVtZW50LmZyYW1lSWRdOyAvLyBkZXNlbGVjdCBncm91cHMgY29udGFpbmluZyB0aGUgZnJhbWVcblxuICAgICAgICAgICAgICAoKF9iID0gKF9hID0gdGhpcy5zY2VuZS5nZXRFbGVtZW50KGhpdEVsZW1lbnQuZnJhbWVJZCkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5ncm91cElkcykgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogW10pLmZsYXRNYXAoZ2lkID0+IGdldEVsZW1lbnRzSW5Hcm91cCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCBnaWQpKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBuZXh0U2VsZWN0ZWRFbGVtZW50SWRzW2VsZW1lbnQuaWRdO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgc2VsZWN0R3JvdXBzRm9yU2VsZWN0ZWRFbGVtZW50cyh7XG4gICAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG5leHRTZWxlY3RlZEVsZW1lbnRJZHNcbiAgICAgICAgICAgICAgfSwgdGhpcy5zY2VuZS5nZXROb25EZWxldGVkRWxlbWVudHMoKSwgcHJldlN0YXRlLCB0aGlzKSksIHtcbiAgICAgICAgICAgICAgICBzaG93SHlwZXJsaW5rUG9wdXA6IGhpdEVsZW1lbnQubGluayB8fCBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpID8gXCJpbmZvXCIgOiBmYWxzZVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBhZGQgZWxlbWVudCB0byBzZWxlY3Rpb24gd2hpbGUga2VlcGluZyBwcmV2IGVsZW1lbnRzIHNlbGVjdGVkXG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKF9wcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiBtYWtlTmV4dFNlbGVjdGVkRWxlbWVudElkcyhPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIF9wcmV2U3RhdGUuc2VsZWN0ZWRFbGVtZW50SWRzKSwge1xuICAgICAgICAgICAgICAgIFtoaXRFbGVtZW50LmlkXTogdHJ1ZVxuICAgICAgICAgICAgICB9KSwgX3ByZXZTdGF0ZSlcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4ge1xuICAgICAgICAgICAgdmFyIF9hO1xuXG4gICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LCBzZWxlY3RHcm91cHNGb3JTZWxlY3RlZEVsZW1lbnRzKHtcbiAgICAgICAgICAgICAgZWRpdGluZ0dyb3VwSWQ6IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCxcbiAgICAgICAgICAgICAgc2VsZWN0ZWRFbGVtZW50SWRzOiB7XG4gICAgICAgICAgICAgICAgW2hpdEVsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIHRoaXMuc2NlbmUuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCksIHByZXZTdGF0ZSwgdGhpcykpLCB7XG4gICAgICAgICAgICAgIHNlbGVjdGVkTGluZWFyRWxlbWVudDogaXNMaW5lYXJFbGVtZW50KGhpdEVsZW1lbnQpICYmIC8vIERvbid0IHNldCBgc2VsZWN0ZWRMaW5lYXJFbGVtZW50YCBpZiBpdHMgc2FtZSBhcyB0aGUgaGl0RWxlbWVudCwgdGhpcyBpcyBtYWlubHkgdG8gcHJldmVudCByZXNldHRpbmcgdGhlIGBob3ZlclBvaW50SW5kZXhgIHRvIC0xLlxuICAgICAgICAgICAgICAvLyBGdXR1cmUgd2Ugc2hvdWxkIHVwZGF0ZSB0aGUgQVBJIHRvIHRha2UgY2FyZSBvZiBzZXR0aW5nIHRoZSBjb3JyZWN0IGBob3ZlclBvaW50SW5kZXhgIHdoZW4gaW5pdGlhbGl6ZWRcbiAgICAgICAgICAgICAgKChfYSA9IHByZXZTdGF0ZS5zZWxlY3RlZExpbmVhckVsZW1lbnQpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5lbGVtZW50SWQpICE9PSBoaXRFbGVtZW50LmlkID8gbmV3IExpbmVhckVsZW1lbnRFZGl0b3IoaGl0RWxlbWVudCwgdGhpcy5zY2VuZSkgOiBwcmV2U3RhdGUuc2VsZWN0ZWRMaW5lYXJFbGVtZW50XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIXBvaW50ZXJEb3duU3RhdGUuZHJhZy5oYXNPY2N1cnJlZCAmJiAhdGhpcy5zdGF0ZS5pc1Jlc2l6aW5nICYmIChoaXRFbGVtZW50ICYmIGlzSGl0dGluZ0VsZW1lbnRCb3VuZGluZ0JveFdpdGhvdXRIaXR0aW5nRWxlbWVudChoaXRFbGVtZW50LCB0aGlzLnN0YXRlLCB0aGlzLmZyYW1lTmFtZUJvdW5kc0NhY2hlLCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSB8fCAhaGl0RWxlbWVudCAmJiBwb2ludGVyRG93blN0YXRlLmhpdC5oYXNIaXRDb21tb25Cb3VuZGluZ0JveE9mU2VsZWN0ZWRFbGVtZW50cykpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWRpdGluZ0xpbmVhckVsZW1lbnQpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVkaXRpbmdMaW5lYXJFbGVtZW50OiBudWxsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRGVzZWxlY3Qgc2VsZWN0ZWQgZWxlbWVudHNcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAgICAgICBlZGl0aW5nR3JvdXBJZDogbnVsbCxcbiAgICAgICAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKCFhY3RpdmVUb29sLmxvY2tlZCAmJiBhY3RpdmVUb29sLnR5cGUgIT09IFwiZnJlZWRyYXdcIiAmJiBkcmFnZ2luZ0VsZW1lbnQgJiYgZHJhZ2dpbmdFbGVtZW50LnR5cGUgIT09IFwic2VsZWN0aW9uXCIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJldlN0YXRlLnNlbGVjdGVkRWxlbWVudElkcyksIHtcbiAgICAgICAgICAgIFtkcmFnZ2luZ0VsZW1lbnQuaWRdOiB0cnVlXG4gICAgICAgICAgfSksIHByZXZTdGF0ZSksXG4gICAgICAgICAgc2hvd0h5cGVybGlua1BvcHVwOiBpc0VtYmVkZGFibGVFbGVtZW50KGRyYWdnaW5nRWxlbWVudCkgJiYgIWRyYWdnaW5nRWxlbWVudC5saW5rID8gXCJlZGl0b3JcIiA6IHByZXZTdGF0ZS5zaG93SHlwZXJsaW5rUG9wdXBcbiAgICAgICAgfSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aXZlVG9vbC50eXBlICE9PSBcInNlbGVjdGlvblwiIHx8IGlzU29tZUVsZW1lbnRTZWxlY3RlZCh0aGlzLnNjZW5lLmdldE5vbkRlbGV0ZWRFbGVtZW50cygpLCB0aGlzLnN0YXRlKSkge1xuICAgICAgICB0aGlzLmhpc3RvcnkucmVzdW1lUmVjb3JkaW5nKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChwb2ludGVyRG93blN0YXRlLmRyYWcuaGFzT2NjdXJyZWQgfHwgaXNSZXNpemluZyB8fCBpc1JvdGF0aW5nKSB7XG4gICAgICAgIChpc0JpbmRpbmdFbmFibGVkKHRoaXMuc3RhdGUpID8gYmluZE9yVW5iaW5kU2VsZWN0ZWRFbGVtZW50cyA6IHVuYmluZExpbmVhckVsZW1lbnRzKSh0aGlzLnNjZW5lLmdldFNlbGVjdGVkRWxlbWVudHModGhpcy5zdGF0ZSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aXZlVG9vbC50eXBlID09PSBcImxhc2VyXCIpIHtcbiAgICAgICAgdGhpcy5sYXNlclBhdGhNYW5hZ2VyLmVuZFBhdGgoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWFjdGl2ZVRvb2wubG9ja2VkICYmIGFjdGl2ZVRvb2wudHlwZSAhPT0gXCJmcmVlZHJhd1wiKSB7XG4gICAgICAgIHJlc2V0Q3Vyc29yKHRoaXMuaW50ZXJhY3RpdmVDYW52YXMpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBkcmFnZ2luZ0VsZW1lbnQ6IG51bGwsXG4gICAgICAgICAgc3VnZ2VzdGVkQmluZGluZ3M6IFtdLFxuICAgICAgICAgIGFjdGl2ZVRvb2w6IHVwZGF0ZUFjdGl2ZVRvb2wodGhpcy5zdGF0ZSwge1xuICAgICAgICAgICAgdHlwZTogXCJzZWxlY3Rpb25cIlxuICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgZHJhZ2dpbmdFbGVtZW50OiBudWxsLFxuICAgICAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzOiBbXVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGhpdEVsZW1lbnQgJiYgdGhpcy5sYXN0UG9pbnRlclVwRXZlbnQgJiYgdGhpcy5sYXN0UG9pbnRlckRvd25FdmVudCAmJiB0aGlzLmxhc3RQb2ludGVyVXBFdmVudC50aW1lU3RhbXAgLSB0aGlzLmxhc3RQb2ludGVyRG93bkV2ZW50LnRpbWVTdGFtcCA8IDMwMCAmJiBnZXN0dXJlLnBvaW50ZXJzLnNpemUgPD0gMSAmJiBpc0VtYmVkZGFibGVFbGVtZW50KGhpdEVsZW1lbnQpICYmIHRoaXMuaXNFbWJlZGRhYmxlQ2VudGVyKGhpdEVsZW1lbnQsIHRoaXMubGFzdFBvaW50ZXJVcEV2ZW50LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi54LCBwb2ludGVyRG93blN0YXRlLm9yaWdpbi55KSkge1xuICAgICAgICB0aGlzLmhhbmRsZUVtYmVkZGFibGVDZW50ZXJDbGljayhoaXRFbGVtZW50KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIG1heWJlU3VnZ2VzdEJpbmRpbmdGb3JBbGwoc2VsZWN0ZWRFbGVtZW50cykge1xuICAgIGlmIChzZWxlY3RlZEVsZW1lbnRzLmxlbmd0aCA+IDUwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgc3VnZ2VzdGVkQmluZGluZ3MgPSBnZXRFbGlnaWJsZUVsZW1lbnRzRm9yQmluZGluZyhzZWxlY3RlZEVsZW1lbnRzKTtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIHN1Z2dlc3RlZEJpbmRpbmdzXG4gICAgfSk7XG4gIH1cblxuICBjbGVhclNlbGVjdGlvbihoaXRFbGVtZW50KSB7XG4gICAgdGhpcy5zZXRTdGF0ZShwcmV2U3RhdGUgPT4gKHtcbiAgICAgIHNlbGVjdGVkRWxlbWVudElkczogbWFrZU5leHRTZWxlY3RlZEVsZW1lbnRJZHMoe30sIHByZXZTdGF0ZSksXG4gICAgICBhY3RpdmVFbWJlZGRhYmxlOiBudWxsLFxuICAgICAgc2VsZWN0ZWRHcm91cElkczoge30sXG4gICAgICAvLyBDb250aW51ZSBlZGl0aW5nIHRoZSBzYW1lIGdyb3VwIGlmIHRoZSB1c2VyIHNlbGVjdGVkIGEgZGlmZmVyZW50XG4gICAgICAvLyBlbGVtZW50IGZyb20gaXRcbiAgICAgIGVkaXRpbmdHcm91cElkOiBwcmV2U3RhdGUuZWRpdGluZ0dyb3VwSWQgJiYgaGl0RWxlbWVudCAhPSBudWxsICYmIGlzRWxlbWVudEluR3JvdXAoaGl0RWxlbWVudCwgcHJldlN0YXRlLmVkaXRpbmdHcm91cElkKSA/IHByZXZTdGF0ZS5lZGl0aW5nR3JvdXBJZCA6IG51bGxcbiAgICB9KSk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBzZWxlY3RlZEVsZW1lbnRJZHM6IG1ha2VOZXh0U2VsZWN0ZWRFbGVtZW50SWRzKHt9LCB0aGlzLnN0YXRlKSxcbiAgICAgIGFjdGl2ZUVtYmVkZGFibGU6IG51bGwsXG4gICAgICBwcmV2aW91c1NlbGVjdGVkRWxlbWVudElkczogdGhpcy5zdGF0ZS5zZWxlY3RlZEVsZW1lbnRJZHNcbiAgICB9KTtcbiAgfVxuXG4gIGdldFRleHRXeXNpd3lnU25hcHBlZFRvQ2VudGVyUG9zaXRpb24oeCwgeSwgYXBwU3RhdGUsIGNvbnRhaW5lcikge1xuICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgIGxldCBlbGVtZW50Q2VudGVyWCA9IGNvbnRhaW5lci54ICsgY29udGFpbmVyLndpZHRoIC8gMjtcbiAgICAgIGxldCBlbGVtZW50Q2VudGVyWSA9IGNvbnRhaW5lci55ICsgY29udGFpbmVyLmhlaWdodCAvIDI7XG4gICAgICBjb25zdCBlbGVtZW50Q2VudGVyID0gZ2V0Q29udGFpbmVyQ2VudGVyKGNvbnRhaW5lciwgYXBwU3RhdGUpO1xuXG4gICAgICBpZiAoZWxlbWVudENlbnRlcikge1xuICAgICAgICBlbGVtZW50Q2VudGVyWCA9IGVsZW1lbnRDZW50ZXIueDtcbiAgICAgICAgZWxlbWVudENlbnRlclkgPSBlbGVtZW50Q2VudGVyLnk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRpc3RhbmNlVG9DZW50ZXIgPSBNYXRoLmh5cG90KHggLSBlbGVtZW50Q2VudGVyWCwgeSAtIGVsZW1lbnRDZW50ZXJZKTtcbiAgICAgIGNvbnN0IGlzU25hcHBlZFRvQ2VudGVyID0gZGlzdGFuY2VUb0NlbnRlciA8IFRFWFRfVE9fQ0VOVEVSX1NOQVBfVEhSRVNIT0xEO1xuXG4gICAgICBpZiAoaXNTbmFwcGVkVG9DZW50ZXIpIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHg6IHZpZXdwb3J0WCxcbiAgICAgICAgICB5OiB2aWV3cG9ydFlcbiAgICAgICAgfSA9IHNjZW5lQ29vcmRzVG9WaWV3cG9ydENvb3Jkcyh7XG4gICAgICAgICAgc2NlbmVYOiBlbGVtZW50Q2VudGVyWCxcbiAgICAgICAgICBzY2VuZVk6IGVsZW1lbnRDZW50ZXJZXG4gICAgICAgIH0sIGFwcFN0YXRlKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB2aWV3cG9ydFgsXG4gICAgICAgICAgdmlld3BvcnRZLFxuICAgICAgICAgIGVsZW1lbnRDZW50ZXJYLFxuICAgICAgICAgIGVsZW1lbnRDZW50ZXJZXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZ2V0Q2FudmFzT2Zmc2V0cygpIHtcbiAgICB2YXIgX2E7XG5cbiAgICBpZiAoKF9hID0gdGhpcy5leGNhbGlkcmF3Q29udGFpbmVyUmVmKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuY3VycmVudCkge1xuICAgICAgY29uc3QgZXhjYWxpZHJhd0NvbnRhaW5lciA9IHRoaXMuZXhjYWxpZHJhd0NvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgICAgY29uc3Qge1xuICAgICAgICBsZWZ0LFxuICAgICAgICB0b3BcbiAgICAgIH0gPSBleGNhbGlkcmF3Q29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgb2Zmc2V0TGVmdDogbGVmdCxcbiAgICAgICAgb2Zmc2V0VG9wOiB0b3BcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIG9mZnNldExlZnQ6IDAsXG4gICAgICBvZmZzZXRUb3A6IDBcbiAgICB9O1xuICB9XG5cbiAgdXBkYXRlTGFuZ3VhZ2UoKSB7XG4gICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgICAgIGNvbnN0IGN1cnJlbnRMYW5nID0gbGFuZ3VhZ2VzLmZpbmQobGFuZyA9PiBsYW5nLmNvZGUgPT09IHRoaXMucHJvcHMubGFuZ0NvZGUpIHx8IGRlZmF1bHRMYW5nO1xuICAgICAgeWllbGQgc2V0TGFuZ3VhZ2UoY3VycmVudExhbmcpO1xuICAgICAgdGhpcy5zZXRBcHBTdGF0ZSh7fSk7XG4gICAgfSk7XG4gIH1cblxufVxuXG5BcHAuZGVmYXVsdFByb3BzID0ge1xuICAvLyBuZWVkZWQgZm9yIHRlc3RzIHRvIHBhc3Mgc2luY2Ugd2UgZGlyZWN0bHkgcmVuZGVyIEFwcCBpbiBtYW55IHRlc3RzXG4gIFVJT3B0aW9uczogREVGQVVMVF9VSV9PUFRJT05TXG59O1xuXG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IEVOVi5URVNUIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcInByb2R1Y3Rpb25cIikge1xuICB3aW5kb3cuaCA9IHdpbmRvdy5oIHx8IHt9O1xuICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh3aW5kb3cuaCwge1xuICAgIGVsZW1lbnRzOiB7XG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG5cbiAgICAgIGdldCgpIHtcbiAgICAgICAgdmFyIF9hO1xuXG4gICAgICAgIHJldHVybiAoX2EgPSB0aGlzLmFwcCkgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLnNjZW5lLmdldEVsZW1lbnRzSW5jbHVkaW5nRGVsZXRlZCgpO1xuICAgICAgfSxcblxuICAgICAgc2V0KGVsZW1lbnRzKSB7XG4gICAgICAgIHZhciBfYTtcblxuICAgICAgICByZXR1cm4gKF9hID0gdGhpcy5hcHApID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5zY2VuZS5yZXBsYWNlQWxsRWxlbWVudHMoZWxlbWVudHMpO1xuICAgICAgfVxuXG4gICAgfVxuICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgQXBwOyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../../components/App.tsx\n");
2533
2533
 
2534
2534
  /***/ }),
2535
2535
 
@@ -4355,7 +4355,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
4355
4355
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4356
4356
 
4357
4357
  "use strict";
4358
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Button\": () => (/* reexport safe */ _components_Button__WEBPACK_IMPORTED_MODULE_22__.Button),\n/* harmony export */ \"DefaultSidebar\": () => (/* reexport safe */ _components_DefaultSidebar__WEBPACK_IMPORTED_MODULE_23__.DefaultSidebar),\n/* harmony export */ \"Excalidraw\": () => (/* binding */ Excalidraw),\n/* harmony export */ \"FONT_FAMILY\": () => (/* reexport safe */ _constants__WEBPACK_IMPORTED_MODULE_8__.FONT_FAMILY),\n/* harmony export */ \"Footer\": () => (/* reexport safe */ _components_footer_FooterCenter__WEBPACK_IMPORTED_MODULE_10__[\"default\"]),\n/* harmony export */ \"LiveCollaborationTrigger\": () => (/* reexport safe */ _components_live_collaboration_LiveCollaborationTrigger__WEBPACK_IMPORTED_MODULE_13__[\"default\"]),\n/* harmony export */ \"MIME_TYPES\": () => (/* reexport safe */ _constants__WEBPACK_IMPORTED_MODULE_8__.MIME_TYPES),\n/* harmony export */ \"MainMenu\": () => (/* reexport safe */ _components_main_menu_MainMenu__WEBPACK_IMPORTED_MODULE_11__[\"default\"]),\n/* harmony export */ \"Sidebar\": () => (/* reexport safe */ _components_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_21__.Sidebar),\n/* harmony export */ \"THEME\": () => (/* reexport safe */ _constants__WEBPACK_IMPORTED_MODULE_8__.THEME),\n/* harmony export */ \"WelcomeScreen\": () => (/* reexport safe */ _components_welcome_screen_WelcomeScreen__WEBPACK_IMPORTED_MODULE_12__[\"default\"]),\n/* harmony export */ \"bumpVersion\": () => (/* reexport safe */ _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.bumpVersion),\n/* harmony export */ \"convertToExcalidrawElements\": () => (/* reexport safe */ _data_transform__WEBPACK_IMPORTED_MODULE_25__.convertToExcalidrawElements),\n/* harmony export */ \"defaultLang\": () => (/* reexport safe */ _i18n__WEBPACK_IMPORTED_MODULE_7__.defaultLang),\n/* harmony export */ \"elementPartiallyOverlapsWithOrContainsBBox\": () => (/* reexport safe */ _withinBounds__WEBPACK_IMPORTED_MODULE_27__.elementPartiallyOverlapsWithOrContainsBBox),\n/* harmony export */ \"elementsOverlappingBBox\": () => (/* reexport safe */ _withinBounds__WEBPACK_IMPORTED_MODULE_27__.elementsOverlappingBBox),\n/* harmony export */ \"exportToBlob\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.exportToBlob),\n/* harmony export */ \"exportToCanvas\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.exportToCanvas),\n/* harmony export */ \"exportToClipboard\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.exportToClipboard),\n/* harmony export */ \"exportToSvg\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.exportToSvg),\n/* harmony export */ \"getCommonBounds\": () => (/* reexport safe */ _element_bounds__WEBPACK_IMPORTED_MODULE_26__.getCommonBounds),\n/* harmony export */ \"getFreeDrawSvgPath\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.getFreeDrawSvgPath),\n/* harmony export */ \"getNonDeletedElements\": () => (/* reexport safe */ _element__WEBPACK_IMPORTED_MODULE_15__.getNonDeletedElements),\n/* harmony export */ \"getSceneVersion\": () => (/* reexport safe */ _element__WEBPACK_IMPORTED_MODULE_15__.getSceneVersion),\n/* harmony export */ \"isElementInsideBBox\": () => (/* reexport safe */ _withinBounds__WEBPACK_IMPORTED_MODULE_27__.isElementInsideBBox),\n/* harmony export */ \"isInvisiblySmallElement\": () => (/* reexport safe */ _element__WEBPACK_IMPORTED_MODULE_15__.isInvisiblySmallElement),\n/* harmony export */ \"isLinearElement\": () => (/* reexport safe */ _element_typeChecks__WEBPACK_IMPORTED_MODULE_18__.isLinearElement),\n/* harmony export */ \"languages\": () => (/* reexport safe */ _i18n__WEBPACK_IMPORTED_MODULE_7__.languages),\n/* harmony export */ \"loadFromBlob\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.loadFromBlob),\n/* harmony export */ \"loadLibraryFromBlob\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.loadLibraryFromBlob),\n/* harmony export */ \"loadSceneOrLibraryFromBlob\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.loadSceneOrLibraryFromBlob),\n/* harmony export */ \"mergeLibraryItems\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.mergeLibraryItems),\n/* harmony export */ \"mutateElement\": () => (/* reexport safe */ _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement),\n/* harmony export */ \"newElementWith\": () => (/* reexport safe */ _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith),\n/* harmony export */ \"normalizeLink\": () => (/* reexport safe */ _data_url__WEBPACK_IMPORTED_MODULE_24__.normalizeLink),\n/* harmony export */ \"parseLibraryTokensFromUrl\": () => (/* reexport safe */ _data_library__WEBPACK_IMPORTED_MODULE_20__.parseLibraryTokensFromUrl),\n/* harmony export */ \"restore\": () => (/* reexport safe */ _data_restore__WEBPACK_IMPORTED_MODULE_16__.restore),\n/* harmony export */ \"restoreAppState\": () => (/* reexport safe */ _data_restore__WEBPACK_IMPORTED_MODULE_16__.restoreAppState),\n/* harmony export */ \"restoreElements\": () => (/* reexport safe */ _data_restore__WEBPACK_IMPORTED_MODULE_16__.restoreElements),\n/* harmony export */ \"restoreLibraryItems\": () => (/* reexport safe */ _data_restore__WEBPACK_IMPORTED_MODULE_16__.restoreLibraryItems),\n/* harmony export */ \"sceneCoordsToViewportCoords\": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_4__.sceneCoordsToViewportCoords),\n/* harmony export */ \"serializeAsJSON\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.serializeAsJSON),\n/* harmony export */ \"serializeLibraryAsJSON\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.serializeLibraryAsJSON),\n/* harmony export */ \"useDevice\": () => (/* reexport safe */ _components_App__WEBPACK_IMPORTED_MODULE_3__.useDevice),\n/* harmony export */ \"useHandleLibrary\": () => (/* reexport safe */ _data_library__WEBPACK_IMPORTED_MODULE_20__.useHandleLibrary),\n/* harmony export */ \"useI18n\": () => (/* reexport safe */ _i18n__WEBPACK_IMPORTED_MODULE_7__.useI18n),\n/* harmony export */ \"viewportCoordsToSceneCoords\": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_4__.viewportCoordsToSceneCoords)\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 _components_InitializeApp__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../components/InitializeApp */ \"../../components/InitializeApp.tsx\");\n/* harmony import */ var _components_App__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../components/App */ \"../../components/App.tsx\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../utils */ \"../../utils.ts\");\n/* harmony import */ var _css_app_scss__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../css/app.scss */ \"../../css/app.scss\");\n/* harmony import */ var _css_styles_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../css/styles.scss */ \"../../css/styles.scss\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../i18n */ \"../../i18n.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../constants */ \"../../constants.ts\");\n/* harmony import */ var jotai__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! jotai */ \"../../../node_modules/jotai/esm/index.mjs\");\n/* harmony import */ var _jotai__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../jotai */ \"../../jotai.ts\");\n/* harmony import */ var _components_footer_FooterCenter__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../components/footer/FooterCenter */ \"../../components/footer/FooterCenter.tsx\");\n/* harmony import */ var _components_main_menu_MainMenu__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../components/main-menu/MainMenu */ \"../../components/main-menu/MainMenu.tsx\");\n/* harmony import */ var _components_welcome_screen_WelcomeScreen__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../components/welcome-screen/WelcomeScreen */ \"../../components/welcome-screen/WelcomeScreen.tsx\");\n/* harmony import */ var _components_live_collaboration_LiveCollaborationTrigger__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../components/live-collaboration/LiveCollaborationTrigger */ \"../../components/live-collaboration/LiveCollaborationTrigger.tsx\");\n/* harmony import */ var _element__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../../element */ \"../../element/index.ts\");\n/* harmony import */ var _data_restore__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../../data/restore */ \"../../data/restore.ts\");\n/* harmony import */ var _packages_utils__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../../packages/utils */ \"../utils.ts\");\n/* harmony import */ var _element_typeChecks__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../../element/typeChecks */ \"../../element/typeChecks.ts\");\n/* harmony import */ var _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../../element/mutateElement */ \"../../element/mutateElement.ts\");\n/* harmony import */ var _data_library__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../../data/library */ \"../../data/library.ts\");\n/* harmony import */ var _components_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../../components/Sidebar/Sidebar */ \"../../components/Sidebar/Sidebar.tsx\");\n/* harmony import */ var _components_Button__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../../components/Button */ \"../../components/Button.tsx\");\n/* harmony import */ var _components_DefaultSidebar__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../../components/DefaultSidebar */ \"../../components/DefaultSidebar.tsx\");\n/* harmony import */ var _data_url__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../../data/url */ \"../../data/url.ts\");\n/* harmony import */ var _data_transform__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../../data/transform */ \"../../data/transform.ts\");\n/* harmony import */ var _element_bounds__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ../../element/bounds */ \"../../element/bounds.ts\");\n/* harmony import */ var _withinBounds__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ../withinBounds */ \"../withinBounds.ts\");\nvar __rest = undefined && undefined.__rest || function (s, e) {\n var t = {};\n\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];\n\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];\n }\n return t;\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst ExcalidrawBase = props => {\n var _a, _b, _c;\n\n const {\n onChange,\n initialData,\n excalidrawAPI,\n isCollaborating = false,\n onPointerUpdate,\n renderTopRightUI,\n langCode = _i18n__WEBPACK_IMPORTED_MODULE_7__.defaultLang.code,\n viewModeEnabled,\n zenModeEnabled,\n gridModeEnabled,\n libraryReturnUrl,\n theme,\n name,\n renderCustomStats,\n onPaste,\n detectScroll = true,\n handleKeyboardGlobally = false,\n onLibraryChange,\n autoFocus = false,\n generateIdForFile,\n onLinkOpen,\n onPointerDown,\n onScrollChange,\n children,\n validateEmbeddable,\n renderEmbeddable\n } = props;\n const canvasActions = (_a = props.UIOptions) === null || _a === void 0 ? void 0 : _a.canvasActions; // FIXME normalize/set defaults in parent component so that the memo resolver\n // compares the same values\n\n const UIOptions = Object.assign(Object.assign({}, props.UIOptions), {\n canvasActions: Object.assign(Object.assign({}, _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_UI_OPTIONS.canvasActions), canvasActions)\n });\n\n if (canvasActions === null || canvasActions === void 0 ? void 0 : canvasActions.export) {\n UIOptions.canvasActions.export.saveFileToDisk = (_c = (_b = canvasActions.export) === null || _b === void 0 ? void 0 : _b.saveFileToDisk) !== null && _c !== void 0 ? _c : _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_UI_OPTIONS.canvasActions[\"export\"].saveFileToDisk;\n }\n\n if (UIOptions.canvasActions.toggleTheme === null && typeof theme === \"undefined\") {\n UIOptions.canvasActions.toggleTheme = true;\n }\n\n (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {\n // Block pinch-zooming on iOS outside of the content area\n const handleTouchMove = event => {\n // @ts-ignore\n if (typeof event.scale === \"number\" && event.scale !== 1) {\n event.preventDefault();\n }\n };\n\n document.addEventListener(\"touchmove\", handleTouchMove, {\n passive: false\n });\n return () => {\n document.removeEventListener(\"touchmove\", handleTouchMove);\n };\n }, []);\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(jotai__WEBPACK_IMPORTED_MODULE_14__.Provider, Object.assign({\n unstable_createStore: () => _jotai__WEBPACK_IMPORTED_MODULE_9__.jotaiStore,\n scope: _jotai__WEBPACK_IMPORTED_MODULE_9__.jotaiScope\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_InitializeApp__WEBPACK_IMPORTED_MODULE_2__.InitializeApp, Object.assign({\n langCode: langCode,\n theme: theme\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_App__WEBPACK_IMPORTED_MODULE_3__[\"default\"], Object.assign({\n onChange: onChange,\n initialData: initialData,\n excalidrawAPI: excalidrawAPI,\n isCollaborating: isCollaborating,\n onPointerUpdate: onPointerUpdate,\n renderTopRightUI: renderTopRightUI,\n langCode: langCode,\n viewModeEnabled: viewModeEnabled,\n zenModeEnabled: zenModeEnabled,\n gridModeEnabled: gridModeEnabled,\n libraryReturnUrl: libraryReturnUrl,\n theme: theme,\n name: name,\n renderCustomStats: renderCustomStats,\n UIOptions: UIOptions,\n onPaste: onPaste,\n detectScroll: detectScroll,\n handleKeyboardGlobally: handleKeyboardGlobally,\n onLibraryChange: onLibraryChange,\n autoFocus: autoFocus,\n generateIdForFile: generateIdForFile,\n onLinkOpen: onLinkOpen,\n onPointerDown: onPointerDown,\n onScrollChange: onScrollChange,\n validateEmbeddable: validateEmbeddable,\n renderEmbeddable: renderEmbeddable\n }, {\n children: children\n }))\n }))\n }));\n};\n\nconst areEqual = (prevProps, nextProps) => {\n // short-circuit early\n if (prevProps.children !== nextProps.children) {\n return false;\n }\n\n const {\n initialData: prevInitialData,\n UIOptions: prevUIOptions = {}\n } = prevProps,\n prev = __rest(prevProps, [\"initialData\", \"UIOptions\"]);\n\n const {\n initialData: nextInitialData,\n UIOptions: nextUIOptions = {}\n } = nextProps,\n next = __rest(nextProps, [\"initialData\", \"UIOptions\"]); // comparing UIOptions\n\n\n const prevUIOptionsKeys = Object.keys(prevUIOptions);\n const nextUIOptionsKeys = Object.keys(nextUIOptions);\n\n if (prevUIOptionsKeys.length !== nextUIOptionsKeys.length) {\n return false;\n }\n\n const isUIOptionsSame = prevUIOptionsKeys.every(key => {\n if (key === \"canvasActions\") {\n const canvasOptionKeys = Object.keys(prevUIOptions.canvasActions);\n return canvasOptionKeys.every(key => {\n var _a, _b, _c, _d;\n\n if (key === \"export\" && ((_a = prevUIOptions === null || prevUIOptions === void 0 ? void 0 : prevUIOptions.canvasActions) === null || _a === void 0 ? void 0 : _a.export) && ((_b = nextUIOptions === null || nextUIOptions === void 0 ? void 0 : nextUIOptions.canvasActions) === null || _b === void 0 ? void 0 : _b.export)) {\n return prevUIOptions.canvasActions.export.saveFileToDisk === nextUIOptions.canvasActions.export.saveFileToDisk;\n }\n\n return ((_c = prevUIOptions === null || prevUIOptions === void 0 ? void 0 : prevUIOptions.canvasActions) === null || _c === void 0 ? void 0 : _c[key]) === ((_d = nextUIOptions === null || nextUIOptions === void 0 ? void 0 : nextUIOptions.canvasActions) === null || _d === void 0 ? void 0 : _d[key]);\n });\n }\n\n return prevUIOptions[key] === nextUIOptions[key];\n });\n return isUIOptionsSame && (0,_utils__WEBPACK_IMPORTED_MODULE_4__.isShallowEqual)(prev, next);\n};\n\nconst Excalidraw = react__WEBPACK_IMPORTED_MODULE_1___default().memo(ExcalidrawBase, areEqual);\nExcalidraw.displayName = \"Excalidraw\";\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9pbmRleC50c3guanMiLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGFBQWEsU0FBSSxJQUFJLFNBQUk7QUFDekI7O0FBRUE7O0FBRUEsNEhBQTRILGNBQWM7QUFDMUk7QUFDQTtBQUNBO0FBQ0E7O0FBRWdEO0FBQ1A7QUFDc0I7QUFDeEI7QUFDTTtBQUNqQjtBQUNHO0FBQ1U7QUFDWTtBQUNwQjtBQUNvQjtBQUNLO0FBQ0M7QUFDZTtBQUMwQjs7QUFFcEc7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsbURBQWdCO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLHNHQUFzRztBQUN0Rzs7QUFFQSxrREFBa0Q7QUFDbEQsaURBQWlELEVBQUUsd0VBQWdDO0FBQ25GLEdBQUc7O0FBRUg7QUFDQSwrS0FBK0ssaUdBQXNEO0FBQ3JPOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFLGdEQUFTO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsU0FBUyxzREFBSSxDQUFDLDRDQUFRO0FBQ3RCLGdDQUFnQyw4Q0FBVTtBQUMxQyxXQUFXLDhDQUFVO0FBQ3JCLEdBQUc7QUFDSCxjQUFjLHNEQUFJLENBQUMsb0VBQWE7QUFDaEM7QUFDQTtBQUNBLEtBQUs7QUFDTCxnQkFBZ0Isc0RBQUksQ0FBQyx1REFBRztBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0EsT0FBTztBQUNQLEtBQUs7QUFDTCxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLGdFQUFnRTs7O0FBR2hFO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0EsR0FBRztBQUNILDRCQUE0QixzREFBYztBQUMxQzs7QUFFTyxtQkFBbUIsaURBQVU7QUFDcEM7QUFDZ0c7QUFDbkM7QUFDdUM7QUFDK0k7QUFDeEw7QUFDTTtBQUN3QjtBQUNSO0FBQ007QUFDNUI7QUFDVjtBQUMvQjtBQUNFO0FBQzZCO0FBQ3hCO0FBQ1c7QUFDNkI7QUFDbEI7QUFDb0I7QUFDWiIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL2luZGV4LnRzeD82YzVkIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfX3Jlc3QgPSB0aGlzICYmIHRoaXMuX19yZXN0IHx8IGZ1bmN0aW9uIChzLCBlKSB7XG4gIHZhciB0ID0ge307XG5cbiAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApICYmIGUuaW5kZXhPZihwKSA8IDApIHRbcF0gPSBzW3BdO1xuXG4gIGlmIChzICE9IG51bGwgJiYgdHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMgPT09IFwiZnVuY3Rpb25cIikgZm9yICh2YXIgaSA9IDAsIHAgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHMpOyBpIDwgcC5sZW5ndGg7IGkrKykge1xuICAgIGlmIChlLmluZGV4T2YocFtpXSkgPCAwICYmIE9iamVjdC5wcm90b3R5cGUucHJvcGVydHlJc0VudW1lcmFibGUuY2FsbChzLCBwW2ldKSkgdFtwW2ldXSA9IHNbcFtpXV07XG4gIH1cbiAgcmV0dXJuIHQ7XG59O1xuXG5pbXBvcnQgeyBqc3ggYXMgX2pzeCB9IGZyb20gXCJyZWFjdC9qc3gtcnVudGltZVwiO1xuaW1wb3J0IFJlYWN0LCB7IHVzZUVmZmVjdCB9IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHsgSW5pdGlhbGl6ZUFwcCB9IGZyb20gXCIuLi8uLi9jb21wb25lbnRzL0luaXRpYWxpemVBcHBcIjtcbmltcG9ydCBBcHAgZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvQXBwXCI7XG5pbXBvcnQgeyBpc1NoYWxsb3dFcXVhbCB9IGZyb20gXCIuLi8uLi91dGlsc1wiO1xuaW1wb3J0IFwiLi4vLi4vY3NzL2FwcC5zY3NzXCI7XG5pbXBvcnQgXCIuLi8uLi9jc3Mvc3R5bGVzLnNjc3NcIjtcbmltcG9ydCB7IGRlZmF1bHRMYW5nIH0gZnJvbSBcIi4uLy4uL2kxOG5cIjtcbmltcG9ydCB7IERFRkFVTFRfVUlfT1BUSU9OUyB9IGZyb20gXCIuLi8uLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IFByb3ZpZGVyIH0gZnJvbSBcImpvdGFpXCI7XG5pbXBvcnQgeyBqb3RhaVNjb3BlLCBqb3RhaVN0b3JlIH0gZnJvbSBcIi4uLy4uL2pvdGFpXCI7XG5pbXBvcnQgRm9vdGVyIGZyb20gXCIuLi8uLi9jb21wb25lbnRzL2Zvb3Rlci9Gb290ZXJDZW50ZXJcIjtcbmltcG9ydCBNYWluTWVudSBmcm9tIFwiLi4vLi4vY29tcG9uZW50cy9tYWluLW1lbnUvTWFpbk1lbnVcIjtcbmltcG9ydCBXZWxjb21lU2NyZWVuIGZyb20gXCIuLi8uLi9jb21wb25lbnRzL3dlbGNvbWUtc2NyZWVuL1dlbGNvbWVTY3JlZW5cIjtcbmltcG9ydCBMaXZlQ29sbGFib3JhdGlvblRyaWdnZXIgZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvbGl2ZS1jb2xsYWJvcmF0aW9uL0xpdmVDb2xsYWJvcmF0aW9uVHJpZ2dlclwiO1xuXG5jb25zdCBFeGNhbGlkcmF3QmFzZSA9IHByb3BzID0+IHtcbiAgdmFyIF9hLCBfYiwgX2M7XG5cbiAgY29uc3Qge1xuICAgIG9uQ2hhbmdlLFxuICAgIGluaXRpYWxEYXRhLFxuICAgIGV4Y2FsaWRyYXdBUEksXG4gICAgaXNDb2xsYWJvcmF0aW5nID0gZmFsc2UsXG4gICAgb25Qb2ludGVyVXBkYXRlLFxuICAgIHJlbmRlclRvcFJpZ2h0VUksXG4gICAgbGFuZ0NvZGUgPSBkZWZhdWx0TGFuZy5jb2RlLFxuICAgIHZpZXdNb2RlRW5hYmxlZCxcbiAgICB6ZW5Nb2RlRW5hYmxlZCxcbiAgICBncmlkTW9kZUVuYWJsZWQsXG4gICAgbGlicmFyeVJldHVyblVybCxcbiAgICB0aGVtZSxcbiAgICBuYW1lLFxuICAgIHJlbmRlckN1c3RvbVN0YXRzLFxuICAgIG9uUGFzdGUsXG4gICAgZGV0ZWN0U2Nyb2xsID0gdHJ1ZSxcbiAgICBoYW5kbGVLZXlib2FyZEdsb2JhbGx5ID0gZmFsc2UsXG4gICAgb25MaWJyYXJ5Q2hhbmdlLFxuICAgIGF1dG9Gb2N1cyA9IGZhbHNlLFxuICAgIGdlbmVyYXRlSWRGb3JGaWxlLFxuICAgIG9uTGlua09wZW4sXG4gICAgb25Qb2ludGVyRG93bixcbiAgICBvblNjcm9sbENoYW5nZSxcbiAgICBjaGlsZHJlbixcbiAgICB2YWxpZGF0ZUVtYmVkZGFibGUsXG4gICAgcmVuZGVyRW1iZWRkYWJsZVxuICB9ID0gcHJvcHM7XG4gIGNvbnN0IGNhbnZhc0FjdGlvbnMgPSAoX2EgPSBwcm9wcy5VSU9wdGlvbnMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jYW52YXNBY3Rpb25zOyAvLyBGSVhNRSBub3JtYWxpemUvc2V0IGRlZmF1bHRzIGluIHBhcmVudCBjb21wb25lbnQgc28gdGhhdCB0aGUgbWVtbyByZXNvbHZlclxuICAvLyBjb21wYXJlcyB0aGUgc2FtZSB2YWx1ZXNcblxuICBjb25zdCBVSU9wdGlvbnMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByb3BzLlVJT3B0aW9ucyksIHtcbiAgICBjYW52YXNBY3Rpb25zOiBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIERFRkFVTFRfVUlfT1BUSU9OUy5jYW52YXNBY3Rpb25zKSwgY2FudmFzQWN0aW9ucylcbiAgfSk7XG5cbiAgaWYgKGNhbnZhc0FjdGlvbnMgPT09IG51bGwgfHwgY2FudmFzQWN0aW9ucyA9PT0gdm9pZCAwID8gdm9pZCAwIDogY2FudmFzQWN0aW9ucy5leHBvcnQpIHtcbiAgICBVSU9wdGlvbnMuY2FudmFzQWN0aW9ucy5leHBvcnQuc2F2ZUZpbGVUb0Rpc2sgPSAoX2MgPSAoX2IgPSBjYW52YXNBY3Rpb25zLmV4cG9ydCkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLnNhdmVGaWxlVG9EaXNrKSAhPT0gbnVsbCAmJiBfYyAhPT0gdm9pZCAwID8gX2MgOiBERUZBVUxUX1VJX09QVElPTlMuY2FudmFzQWN0aW9ucy5leHBvcnQuc2F2ZUZpbGVUb0Rpc2s7XG4gIH1cblxuICBpZiAoVUlPcHRpb25zLmNhbnZhc0FjdGlvbnMudG9nZ2xlVGhlbWUgPT09IG51bGwgJiYgdHlwZW9mIHRoZW1lID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgVUlPcHRpb25zLmNhbnZhc0FjdGlvbnMudG9nZ2xlVGhlbWUgPSB0cnVlO1xuICB9XG5cbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICAvLyBCbG9jayBwaW5jaC16b29taW5nIG9uIGlPUyBvdXRzaWRlIG9mIHRoZSBjb250ZW50IGFyZWFcbiAgICBjb25zdCBoYW5kbGVUb3VjaE1vdmUgPSBldmVudCA9PiB7XG4gICAgICAvLyBAdHMtaWdub3JlXG4gICAgICBpZiAodHlwZW9mIGV2ZW50LnNjYWxlID09PSBcIm51bWJlclwiICYmIGV2ZW50LnNjYWxlICE9PSAxKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJ0b3VjaG1vdmVcIiwgaGFuZGxlVG91Y2hNb3ZlLCB7XG4gICAgICBwYXNzaXZlOiBmYWxzZVxuICAgIH0pO1xuICAgIHJldHVybiAoKSA9PiB7XG4gICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFwidG91Y2htb3ZlXCIsIGhhbmRsZVRvdWNoTW92ZSk7XG4gICAgfTtcbiAgfSwgW10pO1xuICByZXR1cm4gX2pzeChQcm92aWRlciwgT2JqZWN0LmFzc2lnbih7XG4gICAgdW5zdGFibGVfY3JlYXRlU3RvcmU6ICgpID0+IGpvdGFpU3RvcmUsXG4gICAgc2NvcGU6IGpvdGFpU2NvcGVcbiAgfSwge1xuICAgIGNoaWxkcmVuOiBfanN4KEluaXRpYWxpemVBcHAsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgbGFuZ0NvZGU6IGxhbmdDb2RlLFxuICAgICAgdGhlbWU6IHRoZW1lXG4gICAgfSwge1xuICAgICAgY2hpbGRyZW46IF9qc3goQXBwLCBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgb25DaGFuZ2U6IG9uQ2hhbmdlLFxuICAgICAgICBpbml0aWFsRGF0YTogaW5pdGlhbERhdGEsXG4gICAgICAgIGV4Y2FsaWRyYXdBUEk6IGV4Y2FsaWRyYXdBUEksXG4gICAgICAgIGlzQ29sbGFib3JhdGluZzogaXNDb2xsYWJvcmF0aW5nLFxuICAgICAgICBvblBvaW50ZXJVcGRhdGU6IG9uUG9pbnRlclVwZGF0ZSxcbiAgICAgICAgcmVuZGVyVG9wUmlnaHRVSTogcmVuZGVyVG9wUmlnaHRVSSxcbiAgICAgICAgbGFuZ0NvZGU6IGxhbmdDb2RlLFxuICAgICAgICB2aWV3TW9kZUVuYWJsZWQ6IHZpZXdNb2RlRW5hYmxlZCxcbiAgICAgICAgemVuTW9kZUVuYWJsZWQ6IHplbk1vZGVFbmFibGVkLFxuICAgICAgICBncmlkTW9kZUVuYWJsZWQ6IGdyaWRNb2RlRW5hYmxlZCxcbiAgICAgICAgbGlicmFyeVJldHVyblVybDogbGlicmFyeVJldHVyblVybCxcbiAgICAgICAgdGhlbWU6IHRoZW1lLFxuICAgICAgICBuYW1lOiBuYW1lLFxuICAgICAgICByZW5kZXJDdXN0b21TdGF0czogcmVuZGVyQ3VzdG9tU3RhdHMsXG4gICAgICAgIFVJT3B0aW9uczogVUlPcHRpb25zLFxuICAgICAgICBvblBhc3RlOiBvblBhc3RlLFxuICAgICAgICBkZXRlY3RTY3JvbGw6IGRldGVjdFNjcm9sbCxcbiAgICAgICAgaGFuZGxlS2V5Ym9hcmRHbG9iYWxseTogaGFuZGxlS2V5Ym9hcmRHbG9iYWxseSxcbiAgICAgICAgb25MaWJyYXJ5Q2hhbmdlOiBvbkxpYnJhcnlDaGFuZ2UsXG4gICAgICAgIGF1dG9Gb2N1czogYXV0b0ZvY3VzLFxuICAgICAgICBnZW5lcmF0ZUlkRm9yRmlsZTogZ2VuZXJhdGVJZEZvckZpbGUsXG4gICAgICAgIG9uTGlua09wZW46IG9uTGlua09wZW4sXG4gICAgICAgIG9uUG9pbnRlckRvd246IG9uUG9pbnRlckRvd24sXG4gICAgICAgIG9uU2Nyb2xsQ2hhbmdlOiBvblNjcm9sbENoYW5nZSxcbiAgICAgICAgdmFsaWRhdGVFbWJlZGRhYmxlOiB2YWxpZGF0ZUVtYmVkZGFibGUsXG4gICAgICAgIHJlbmRlckVtYmVkZGFibGU6IHJlbmRlckVtYmVkZGFibGVcbiAgICAgIH0sIHtcbiAgICAgICAgY2hpbGRyZW46IGNoaWxkcmVuXG4gICAgICB9KSlcbiAgICB9KSlcbiAgfSkpO1xufTtcblxuY29uc3QgYXJlRXF1YWwgPSAocHJldlByb3BzLCBuZXh0UHJvcHMpID0+IHtcbiAgLy8gc2hvcnQtY2lyY3VpdCBlYXJseVxuICBpZiAocHJldlByb3BzLmNoaWxkcmVuICE9PSBuZXh0UHJvcHMuY2hpbGRyZW4pIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCB7XG4gICAgaW5pdGlhbERhdGE6IHByZXZJbml0aWFsRGF0YSxcbiAgICBVSU9wdGlvbnM6IHByZXZVSU9wdGlvbnMgPSB7fVxuICB9ID0gcHJldlByb3BzLFxuICAgICAgICBwcmV2ID0gX19yZXN0KHByZXZQcm9wcywgW1wiaW5pdGlhbERhdGFcIiwgXCJVSU9wdGlvbnNcIl0pO1xuXG4gIGNvbnN0IHtcbiAgICBpbml0aWFsRGF0YTogbmV4dEluaXRpYWxEYXRhLFxuICAgIFVJT3B0aW9uczogbmV4dFVJT3B0aW9ucyA9IHt9XG4gIH0gPSBuZXh0UHJvcHMsXG4gICAgICAgIG5leHQgPSBfX3Jlc3QobmV4dFByb3BzLCBbXCJpbml0aWFsRGF0YVwiLCBcIlVJT3B0aW9uc1wiXSk7IC8vIGNvbXBhcmluZyBVSU9wdGlvbnNcblxuXG4gIGNvbnN0IHByZXZVSU9wdGlvbnNLZXlzID0gT2JqZWN0LmtleXMocHJldlVJT3B0aW9ucyk7XG4gIGNvbnN0IG5leHRVSU9wdGlvbnNLZXlzID0gT2JqZWN0LmtleXMobmV4dFVJT3B0aW9ucyk7XG5cbiAgaWYgKHByZXZVSU9wdGlvbnNLZXlzLmxlbmd0aCAhPT0gbmV4dFVJT3B0aW9uc0tleXMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgY29uc3QgaXNVSU9wdGlvbnNTYW1lID0gcHJldlVJT3B0aW9uc0tleXMuZXZlcnkoa2V5ID0+IHtcbiAgICBpZiAoa2V5ID09PSBcImNhbnZhc0FjdGlvbnNcIikge1xuICAgICAgY29uc3QgY2FudmFzT3B0aW9uS2V5cyA9IE9iamVjdC5rZXlzKHByZXZVSU9wdGlvbnMuY2FudmFzQWN0aW9ucyk7XG4gICAgICByZXR1cm4gY2FudmFzT3B0aW9uS2V5cy5ldmVyeShrZXkgPT4ge1xuICAgICAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG5cbiAgICAgICAgaWYgKGtleSA9PT0gXCJleHBvcnRcIiAmJiAoKF9hID0gcHJldlVJT3B0aW9ucyA9PT0gbnVsbCB8fCBwcmV2VUlPcHRpb25zID09PSB2b2lkIDAgPyB2b2lkIDAgOiBwcmV2VUlPcHRpb25zLmNhbnZhc0FjdGlvbnMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5leHBvcnQpICYmICgoX2IgPSBuZXh0VUlPcHRpb25zID09PSBudWxsIHx8IG5leHRVSU9wdGlvbnMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG5leHRVSU9wdGlvbnMuY2FudmFzQWN0aW9ucykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmV4cG9ydCkpIHtcbiAgICAgICAgICByZXR1cm4gcHJldlVJT3B0aW9ucy5jYW52YXNBY3Rpb25zLmV4cG9ydC5zYXZlRmlsZVRvRGlzayA9PT0gbmV4dFVJT3B0aW9ucy5jYW52YXNBY3Rpb25zLmV4cG9ydC5zYXZlRmlsZVRvRGlzaztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoKF9jID0gcHJldlVJT3B0aW9ucyA9PT0gbnVsbCB8fCBwcmV2VUlPcHRpb25zID09PSB2b2lkIDAgPyB2b2lkIDAgOiBwcmV2VUlPcHRpb25zLmNhbnZhc0FjdGlvbnMpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfY1trZXldKSA9PT0gKChfZCA9IG5leHRVSU9wdGlvbnMgPT09IG51bGwgfHwgbmV4dFVJT3B0aW9ucyA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dFVJT3B0aW9ucy5jYW52YXNBY3Rpb25zKSA9PT0gbnVsbCB8fCBfZCA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Rba2V5XSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcHJldlVJT3B0aW9uc1trZXldID09PSBuZXh0VUlPcHRpb25zW2tleV07XG4gIH0pO1xuICByZXR1cm4gaXNVSU9wdGlvbnNTYW1lICYmIGlzU2hhbGxvd0VxdWFsKHByZXYsIG5leHQpO1xufTtcblxuZXhwb3J0IGNvbnN0IEV4Y2FsaWRyYXcgPSBSZWFjdC5tZW1vKEV4Y2FsaWRyYXdCYXNlLCBhcmVFcXVhbCk7XG5FeGNhbGlkcmF3LmRpc3BsYXlOYW1lID0gXCJFeGNhbGlkcmF3XCI7XG5leHBvcnQgeyBnZXRTY2VuZVZlcnNpb24sIGlzSW52aXNpYmx5U21hbGxFbGVtZW50LCBnZXROb25EZWxldGVkRWxlbWVudHMgfSBmcm9tIFwiLi4vLi4vZWxlbWVudFwiO1xuZXhwb3J0IHsgZGVmYXVsdExhbmcsIHVzZUkxOG4sIGxhbmd1YWdlcyB9IGZyb20gXCIuLi8uLi9pMThuXCI7XG5leHBvcnQgeyByZXN0b3JlLCByZXN0b3JlQXBwU3RhdGUsIHJlc3RvcmVFbGVtZW50cywgcmVzdG9yZUxpYnJhcnlJdGVtcyB9IGZyb20gXCIuLi8uLi9kYXRhL3Jlc3RvcmVcIjtcbmV4cG9ydCB7IGV4cG9ydFRvQ2FudmFzLCBleHBvcnRUb0Jsb2IsIGV4cG9ydFRvU3ZnLCBzZXJpYWxpemVBc0pTT04sIHNlcmlhbGl6ZUxpYnJhcnlBc0pTT04sIGxvYWRMaWJyYXJ5RnJvbUJsb2IsIGxvYWRGcm9tQmxvYiwgbG9hZFNjZW5lT3JMaWJyYXJ5RnJvbUJsb2IsIGdldEZyZWVEcmF3U3ZnUGF0aCwgZXhwb3J0VG9DbGlwYm9hcmQsIG1lcmdlTGlicmFyeUl0ZW1zIH0gZnJvbSBcIi4uLy4uL3BhY2thZ2VzL3V0aWxzXCI7XG5leHBvcnQgeyBpc0xpbmVhckVsZW1lbnQgfSBmcm9tIFwiLi4vLi4vZWxlbWVudC90eXBlQ2hlY2tzXCI7XG5leHBvcnQgeyBGT05UX0ZBTUlMWSwgVEhFTUUsIE1JTUVfVFlQRVMgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5leHBvcnQgeyBtdXRhdGVFbGVtZW50LCBuZXdFbGVtZW50V2l0aCwgYnVtcFZlcnNpb24gfSBmcm9tIFwiLi4vLi4vZWxlbWVudC9tdXRhdGVFbGVtZW50XCI7XG5leHBvcnQgeyBwYXJzZUxpYnJhcnlUb2tlbnNGcm9tVXJsLCB1c2VIYW5kbGVMaWJyYXJ5IH0gZnJvbSBcIi4uLy4uL2RhdGEvbGlicmFyeVwiO1xuZXhwb3J0IHsgc2NlbmVDb29yZHNUb1ZpZXdwb3J0Q29vcmRzLCB2aWV3cG9ydENvb3Jkc1RvU2NlbmVDb29yZHMgfSBmcm9tIFwiLi4vLi4vdXRpbHNcIjtcbmV4cG9ydCB7IFNpZGViYXIgfSBmcm9tIFwiLi4vLi4vY29tcG9uZW50cy9TaWRlYmFyL1NpZGViYXJcIjtcbmV4cG9ydCB7IEJ1dHRvbiB9IGZyb20gXCIuLi8uLi9jb21wb25lbnRzL0J1dHRvblwiO1xuZXhwb3J0IHsgRm9vdGVyIH07XG5leHBvcnQgeyBNYWluTWVudSB9O1xuZXhwb3J0IHsgdXNlRGV2aWNlIH0gZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvQXBwXCI7XG5leHBvcnQgeyBXZWxjb21lU2NyZWVuIH07XG5leHBvcnQgeyBMaXZlQ29sbGFib3JhdGlvblRyaWdnZXIgfTtcbmV4cG9ydCB7IERlZmF1bHRTaWRlYmFyIH0gZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvRGVmYXVsdFNpZGViYXJcIjtcbmV4cG9ydCB7IG5vcm1hbGl6ZUxpbmsgfSBmcm9tIFwiLi4vLi4vZGF0YS91cmxcIjtcbmV4cG9ydCB7IGNvbnZlcnRUb0V4Y2FsaWRyYXdFbGVtZW50cyB9IGZyb20gXCIuLi8uLi9kYXRhL3RyYW5zZm9ybVwiO1xuZXhwb3J0IHsgZ2V0Q29tbW9uQm91bmRzIH0gZnJvbSBcIi4uLy4uL2VsZW1lbnQvYm91bmRzXCI7XG5leHBvcnQgeyBlbGVtZW50c092ZXJsYXBwaW5nQkJveCwgaXNFbGVtZW50SW5zaWRlQkJveCwgZWxlbWVudFBhcnRpYWxseU92ZXJsYXBzV2l0aE9yQ29udGFpbnNCQm94IH0gZnJvbSBcIi4uL3dpdGhpbkJvdW5kc1wiOyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./index.tsx\n");
4358
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Button\": () => (/* reexport safe */ _components_Button__WEBPACK_IMPORTED_MODULE_22__.Button),\n/* harmony export */ \"DefaultSidebar\": () => (/* reexport safe */ _components_DefaultSidebar__WEBPACK_IMPORTED_MODULE_23__.DefaultSidebar),\n/* harmony export */ \"Excalidraw\": () => (/* binding */ Excalidraw),\n/* harmony export */ \"FONT_FAMILY\": () => (/* reexport safe */ _constants__WEBPACK_IMPORTED_MODULE_8__.FONT_FAMILY),\n/* harmony export */ \"Footer\": () => (/* reexport safe */ _components_footer_FooterCenter__WEBPACK_IMPORTED_MODULE_10__[\"default\"]),\n/* harmony export */ \"LiveCollaborationTrigger\": () => (/* reexport safe */ _components_live_collaboration_LiveCollaborationTrigger__WEBPACK_IMPORTED_MODULE_13__[\"default\"]),\n/* harmony export */ \"MIME_TYPES\": () => (/* reexport safe */ _constants__WEBPACK_IMPORTED_MODULE_8__.MIME_TYPES),\n/* harmony export */ \"MainMenu\": () => (/* reexport safe */ _components_main_menu_MainMenu__WEBPACK_IMPORTED_MODULE_11__[\"default\"]),\n/* harmony export */ \"Sidebar\": () => (/* reexport safe */ _components_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_21__.Sidebar),\n/* harmony export */ \"THEME\": () => (/* reexport safe */ _constants__WEBPACK_IMPORTED_MODULE_8__.THEME),\n/* harmony export */ \"WelcomeScreen\": () => (/* reexport safe */ _components_welcome_screen_WelcomeScreen__WEBPACK_IMPORTED_MODULE_12__[\"default\"]),\n/* harmony export */ \"bumpVersion\": () => (/* reexport safe */ _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.bumpVersion),\n/* harmony export */ \"convertToExcalidrawElements\": () => (/* reexport safe */ _data_transform__WEBPACK_IMPORTED_MODULE_25__.convertToExcalidrawElements),\n/* harmony export */ \"defaultLang\": () => (/* reexport safe */ _i18n__WEBPACK_IMPORTED_MODULE_7__.defaultLang),\n/* harmony export */ \"elementPartiallyOverlapsWithOrContainsBBox\": () => (/* reexport safe */ _withinBounds__WEBPACK_IMPORTED_MODULE_27__.elementPartiallyOverlapsWithOrContainsBBox),\n/* harmony export */ \"elementsOverlappingBBox\": () => (/* reexport safe */ _withinBounds__WEBPACK_IMPORTED_MODULE_27__.elementsOverlappingBBox),\n/* harmony export */ \"exportToBlob\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.exportToBlob),\n/* harmony export */ \"exportToCanvas\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.exportToCanvas),\n/* harmony export */ \"exportToClipboard\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.exportToClipboard),\n/* harmony export */ \"exportToSvg\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.exportToSvg),\n/* harmony export */ \"getCommonBounds\": () => (/* reexport safe */ _element_bounds__WEBPACK_IMPORTED_MODULE_26__.getCommonBounds),\n/* harmony export */ \"getFreeDrawSvgPath\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.getFreeDrawSvgPath),\n/* harmony export */ \"getNonDeletedElements\": () => (/* reexport safe */ _element__WEBPACK_IMPORTED_MODULE_15__.getNonDeletedElements),\n/* harmony export */ \"getSceneVersion\": () => (/* reexport safe */ _element__WEBPACK_IMPORTED_MODULE_15__.getSceneVersion),\n/* harmony export */ \"isElementInsideBBox\": () => (/* reexport safe */ _withinBounds__WEBPACK_IMPORTED_MODULE_27__.isElementInsideBBox),\n/* harmony export */ \"isInvisiblySmallElement\": () => (/* reexport safe */ _element__WEBPACK_IMPORTED_MODULE_15__.isInvisiblySmallElement),\n/* harmony export */ \"isLinearElement\": () => (/* reexport safe */ _element_typeChecks__WEBPACK_IMPORTED_MODULE_18__.isLinearElement),\n/* harmony export */ \"languages\": () => (/* reexport safe */ _i18n__WEBPACK_IMPORTED_MODULE_7__.languages),\n/* harmony export */ \"loadFromBlob\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.loadFromBlob),\n/* harmony export */ \"loadLibraryFromBlob\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.loadLibraryFromBlob),\n/* harmony export */ \"loadSceneOrLibraryFromBlob\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.loadSceneOrLibraryFromBlob),\n/* harmony export */ \"mergeLibraryItems\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.mergeLibraryItems),\n/* harmony export */ \"mutateElement\": () => (/* reexport safe */ _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.mutateElement),\n/* harmony export */ \"newElementWith\": () => (/* reexport safe */ _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__.newElementWith),\n/* harmony export */ \"normalizeLink\": () => (/* reexport safe */ _data_url__WEBPACK_IMPORTED_MODULE_24__.normalizeLink),\n/* harmony export */ \"parseLibraryTokensFromUrl\": () => (/* reexport safe */ _data_library__WEBPACK_IMPORTED_MODULE_20__.parseLibraryTokensFromUrl),\n/* harmony export */ \"restore\": () => (/* reexport safe */ _data_restore__WEBPACK_IMPORTED_MODULE_16__.restore),\n/* harmony export */ \"restoreAppState\": () => (/* reexport safe */ _data_restore__WEBPACK_IMPORTED_MODULE_16__.restoreAppState),\n/* harmony export */ \"restoreElements\": () => (/* reexport safe */ _data_restore__WEBPACK_IMPORTED_MODULE_16__.restoreElements),\n/* harmony export */ \"restoreLibraryItems\": () => (/* reexport safe */ _data_restore__WEBPACK_IMPORTED_MODULE_16__.restoreLibraryItems),\n/* harmony export */ \"sceneCoordsToViewportCoords\": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_4__.sceneCoordsToViewportCoords),\n/* harmony export */ \"serializeAsJSON\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.serializeAsJSON),\n/* harmony export */ \"serializeLibraryAsJSON\": () => (/* reexport safe */ _packages_utils__WEBPACK_IMPORTED_MODULE_17__.serializeLibraryAsJSON),\n/* harmony export */ \"useDevice\": () => (/* reexport safe */ _components_App__WEBPACK_IMPORTED_MODULE_3__.useDevice),\n/* harmony export */ \"useHandleLibrary\": () => (/* reexport safe */ _data_library__WEBPACK_IMPORTED_MODULE_20__.useHandleLibrary),\n/* harmony export */ \"useI18n\": () => (/* reexport safe */ _i18n__WEBPACK_IMPORTED_MODULE_7__.useI18n),\n/* harmony export */ \"viewportCoordsToSceneCoords\": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_4__.viewportCoordsToSceneCoords)\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 _components_InitializeApp__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../components/InitializeApp */ \"../../components/InitializeApp.tsx\");\n/* harmony import */ var _components_App__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../components/App */ \"../../components/App.tsx\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../utils */ \"../../utils.ts\");\n/* harmony import */ var _css_app_scss__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../css/app.scss */ \"../../css/app.scss\");\n/* harmony import */ var _css_styles_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../css/styles.scss */ \"../../css/styles.scss\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../i18n */ \"../../i18n.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../constants */ \"../../constants.ts\");\n/* harmony import */ var jotai__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! jotai */ \"../../../node_modules/jotai/esm/index.mjs\");\n/* harmony import */ var _jotai__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../jotai */ \"../../jotai.ts\");\n/* harmony import */ var _components_footer_FooterCenter__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../components/footer/FooterCenter */ \"../../components/footer/FooterCenter.tsx\");\n/* harmony import */ var _components_main_menu_MainMenu__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../components/main-menu/MainMenu */ \"../../components/main-menu/MainMenu.tsx\");\n/* harmony import */ var _components_welcome_screen_WelcomeScreen__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../components/welcome-screen/WelcomeScreen */ \"../../components/welcome-screen/WelcomeScreen.tsx\");\n/* harmony import */ var _components_live_collaboration_LiveCollaborationTrigger__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../components/live-collaboration/LiveCollaborationTrigger */ \"../../components/live-collaboration/LiveCollaborationTrigger.tsx\");\n/* harmony import */ var _element__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../../element */ \"../../element/index.ts\");\n/* harmony import */ var _data_restore__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../../data/restore */ \"../../data/restore.ts\");\n/* harmony import */ var _packages_utils__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../../packages/utils */ \"../utils.ts\");\n/* harmony import */ var _element_typeChecks__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../../element/typeChecks */ \"../../element/typeChecks.ts\");\n/* harmony import */ var _element_mutateElement__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../../element/mutateElement */ \"../../element/mutateElement.ts\");\n/* harmony import */ var _data_library__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../../data/library */ \"../../data/library.ts\");\n/* harmony import */ var _components_Sidebar_Sidebar__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../../components/Sidebar/Sidebar */ \"../../components/Sidebar/Sidebar.tsx\");\n/* harmony import */ var _components_Button__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../../components/Button */ \"../../components/Button.tsx\");\n/* harmony import */ var _components_DefaultSidebar__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../../components/DefaultSidebar */ \"../../components/DefaultSidebar.tsx\");\n/* harmony import */ var _data_url__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../../data/url */ \"../../data/url.ts\");\n/* harmony import */ var _data_transform__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../../data/transform */ \"../../data/transform.ts\");\n/* harmony import */ var _element_bounds__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ../../element/bounds */ \"../../element/bounds.ts\");\n/* harmony import */ var _withinBounds__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ../withinBounds */ \"../withinBounds.ts\");\nvar __rest = undefined && undefined.__rest || function (s, e) {\n var t = {};\n\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];\n\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];\n }\n return t;\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst ExcalidrawBase = props => {\n var _a, _b, _c;\n\n const {\n onChange,\n initialData,\n excalidrawRef,\n isCollaborating = false,\n onPointerUpdate,\n renderTopRightUI,\n langCode = _i18n__WEBPACK_IMPORTED_MODULE_7__.defaultLang.code,\n viewModeEnabled,\n zenModeEnabled,\n gridModeEnabled,\n libraryReturnUrl,\n theme,\n name,\n renderCustomStats,\n onPaste,\n detectScroll = true,\n handleKeyboardGlobally = false,\n onLibraryChange,\n autoFocus = false,\n generateIdForFile,\n onLinkOpen,\n onPointerDown,\n onScrollChange,\n children,\n validateEmbeddable,\n renderEmbeddable\n } = props;\n const canvasActions = (_a = props.UIOptions) === null || _a === void 0 ? void 0 : _a.canvasActions; // FIXME normalize/set defaults in parent component so that the memo resolver\n // compares the same values\n\n const UIOptions = Object.assign(Object.assign({}, props.UIOptions), {\n canvasActions: Object.assign(Object.assign({}, _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_UI_OPTIONS.canvasActions), canvasActions)\n });\n\n if (canvasActions === null || canvasActions === void 0 ? void 0 : canvasActions.export) {\n UIOptions.canvasActions.export.saveFileToDisk = (_c = (_b = canvasActions.export) === null || _b === void 0 ? void 0 : _b.saveFileToDisk) !== null && _c !== void 0 ? _c : _constants__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_UI_OPTIONS.canvasActions[\"export\"].saveFileToDisk;\n }\n\n if (UIOptions.canvasActions.toggleTheme === null && typeof theme === \"undefined\") {\n UIOptions.canvasActions.toggleTheme = true;\n }\n\n (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {\n // Block pinch-zooming on iOS outside of the content area\n const handleTouchMove = event => {\n // @ts-ignore\n if (typeof event.scale === \"number\" && event.scale !== 1) {\n event.preventDefault();\n }\n };\n\n document.addEventListener(\"touchmove\", handleTouchMove, {\n passive: false\n });\n return () => {\n document.removeEventListener(\"touchmove\", handleTouchMove);\n };\n }, []);\n return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(jotai__WEBPACK_IMPORTED_MODULE_14__.Provider, Object.assign({\n unstable_createStore: () => _jotai__WEBPACK_IMPORTED_MODULE_9__.jotaiStore,\n scope: _jotai__WEBPACK_IMPORTED_MODULE_9__.jotaiScope\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_InitializeApp__WEBPACK_IMPORTED_MODULE_2__.InitializeApp, Object.assign({\n langCode: langCode,\n theme: theme\n }, {\n children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_App__WEBPACK_IMPORTED_MODULE_3__[\"default\"], Object.assign({\n onChange: onChange,\n initialData: initialData,\n excalidrawRef: excalidrawRef,\n isCollaborating: isCollaborating,\n onPointerUpdate: onPointerUpdate,\n renderTopRightUI: renderTopRightUI,\n langCode: langCode,\n viewModeEnabled: viewModeEnabled,\n zenModeEnabled: zenModeEnabled,\n gridModeEnabled: gridModeEnabled,\n libraryReturnUrl: libraryReturnUrl,\n theme: theme,\n name: name,\n renderCustomStats: renderCustomStats,\n UIOptions: UIOptions,\n onPaste: onPaste,\n detectScroll: detectScroll,\n handleKeyboardGlobally: handleKeyboardGlobally,\n onLibraryChange: onLibraryChange,\n autoFocus: autoFocus,\n generateIdForFile: generateIdForFile,\n onLinkOpen: onLinkOpen,\n onPointerDown: onPointerDown,\n onScrollChange: onScrollChange,\n validateEmbeddable: validateEmbeddable,\n renderEmbeddable: renderEmbeddable\n }, {\n children: children\n }))\n }))\n }));\n};\n\nconst areEqual = (prevProps, nextProps) => {\n // short-circuit early\n if (prevProps.children !== nextProps.children) {\n return false;\n }\n\n const {\n initialData: prevInitialData,\n UIOptions: prevUIOptions = {}\n } = prevProps,\n prev = __rest(prevProps, [\"initialData\", \"UIOptions\"]);\n\n const {\n initialData: nextInitialData,\n UIOptions: nextUIOptions = {}\n } = nextProps,\n next = __rest(nextProps, [\"initialData\", \"UIOptions\"]); // comparing UIOptions\n\n\n const prevUIOptionsKeys = Object.keys(prevUIOptions);\n const nextUIOptionsKeys = Object.keys(nextUIOptions);\n\n if (prevUIOptionsKeys.length !== nextUIOptionsKeys.length) {\n return false;\n }\n\n const isUIOptionsSame = prevUIOptionsKeys.every(key => {\n if (key === \"canvasActions\") {\n const canvasOptionKeys = Object.keys(prevUIOptions.canvasActions);\n return canvasOptionKeys.every(key => {\n var _a, _b, _c, _d;\n\n if (key === \"export\" && ((_a = prevUIOptions === null || prevUIOptions === void 0 ? void 0 : prevUIOptions.canvasActions) === null || _a === void 0 ? void 0 : _a.export) && ((_b = nextUIOptions === null || nextUIOptions === void 0 ? void 0 : nextUIOptions.canvasActions) === null || _b === void 0 ? void 0 : _b.export)) {\n return prevUIOptions.canvasActions.export.saveFileToDisk === nextUIOptions.canvasActions.export.saveFileToDisk;\n }\n\n return ((_c = prevUIOptions === null || prevUIOptions === void 0 ? void 0 : prevUIOptions.canvasActions) === null || _c === void 0 ? void 0 : _c[key]) === ((_d = nextUIOptions === null || nextUIOptions === void 0 ? void 0 : nextUIOptions.canvasActions) === null || _d === void 0 ? void 0 : _d[key]);\n });\n }\n\n return prevUIOptions[key] === nextUIOptions[key];\n });\n return isUIOptionsSame && (0,_utils__WEBPACK_IMPORTED_MODULE_4__.isShallowEqual)(prev, next);\n};\n\nconst forwardedRefComp = (0,react__WEBPACK_IMPORTED_MODULE_1__.forwardRef)((props, ref) => (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ExcalidrawBase, Object.assign({}, props, {\n excalidrawRef: ref\n})));\nconst Excalidraw = react__WEBPACK_IMPORTED_MODULE_1___default().memo(forwardedRefComp, areEqual);\nExcalidraw.displayName = \"Excalidraw\";\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9pbmRleC50c3guanMiLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGFBQWEsU0FBSSxJQUFJLFNBQUk7QUFDekI7O0FBRUE7O0FBRUEsNEhBQTRILGNBQWM7QUFDMUk7QUFDQTtBQUNBO0FBQ0E7O0FBRWdEO0FBQ0s7QUFDVTtBQUN4QjtBQUNNO0FBQ2pCO0FBQ0c7QUFDVTtBQUNZO0FBQ3BCO0FBQ29CO0FBQ0s7QUFDQztBQUNlO0FBQzBCOztBQUVwRztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxtREFBZ0I7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osc0dBQXNHO0FBQ3RHOztBQUVBLGtEQUFrRDtBQUNsRCxpREFBaUQsRUFBRSx3RUFBZ0M7QUFDbkYsR0FBRzs7QUFFSDtBQUNBLCtLQUErSyxpR0FBc0Q7QUFDck87O0FBRUE7QUFDQTtBQUNBOztBQUVBLEVBQUUsZ0RBQVM7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxTQUFTLHNEQUFJLENBQUMsNENBQVE7QUFDdEIsZ0NBQWdDLDhDQUFVO0FBQzFDLFdBQVcsOENBQVU7QUFDckIsR0FBRztBQUNILGNBQWMsc0RBQUksQ0FBQyxvRUFBYTtBQUNoQztBQUNBO0FBQ0EsS0FBSztBQUNMLGdCQUFnQixzREFBSSxDQUFDLHVEQUFHO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxPQUFPO0FBQ1AsS0FBSztBQUNMLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osZ0VBQWdFOzs7QUFHaEU7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQSxHQUFHO0FBQ0gsNEJBQTRCLHNEQUFjO0FBQzFDOztBQUVBLHlCQUF5QixpREFBVSxpQkFBaUIsc0RBQUksaUNBQWlDO0FBQ3pGO0FBQ0EsQ0FBQztBQUNNLG1CQUFtQixpREFBVTtBQUNwQztBQUNnRztBQUNuQztBQUN1QztBQUMrSTtBQUN4TDtBQUNNO0FBQ3dCO0FBQ1I7QUFDTTtBQUM1QjtBQUNWO0FBQy9CO0FBQ0U7QUFDNkI7QUFDeEI7QUFDVztBQUM2QjtBQUNsQjtBQUNvQjtBQUNaIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vaW5kZXgudHN4PzZjNWQiXSwic291cmNlc0NvbnRlbnQiOlsidmFyIF9fcmVzdCA9IHRoaXMgJiYgdGhpcy5fX3Jlc3QgfHwgZnVuY3Rpb24gKHMsIGUpIHtcbiAgdmFyIHQgPSB7fTtcblxuICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkgJiYgZS5pbmRleE9mKHApIDwgMCkgdFtwXSA9IHNbcF07XG5cbiAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKSBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKGUuaW5kZXhPZihwW2ldKSA8IDAgJiYgT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKHMsIHBbaV0pKSB0W3BbaV1dID0gc1twW2ldXTtcbiAgfVxuICByZXR1cm4gdDtcbn07XG5cbmltcG9ydCB7IGpzeCBhcyBfanN4IH0gZnJvbSBcInJlYWN0L2pzeC1ydW50aW1lXCI7XG5pbXBvcnQgUmVhY3QsIHsgdXNlRWZmZWN0LCBmb3J3YXJkUmVmIH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBJbml0aWFsaXplQXBwIH0gZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvSW5pdGlhbGl6ZUFwcFwiO1xuaW1wb3J0IEFwcCBmcm9tIFwiLi4vLi4vY29tcG9uZW50cy9BcHBcIjtcbmltcG9ydCB7IGlzU2hhbGxvd0VxdWFsIH0gZnJvbSBcIi4uLy4uL3V0aWxzXCI7XG5pbXBvcnQgXCIuLi8uLi9jc3MvYXBwLnNjc3NcIjtcbmltcG9ydCBcIi4uLy4uL2Nzcy9zdHlsZXMuc2Nzc1wiO1xuaW1wb3J0IHsgZGVmYXVsdExhbmcgfSBmcm9tIFwiLi4vLi4vaTE4blwiO1xuaW1wb3J0IHsgREVGQVVMVF9VSV9PUFRJT05TIH0gZnJvbSBcIi4uLy4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgUHJvdmlkZXIgfSBmcm9tIFwiam90YWlcIjtcbmltcG9ydCB7IGpvdGFpU2NvcGUsIGpvdGFpU3RvcmUgfSBmcm9tIFwiLi4vLi4vam90YWlcIjtcbmltcG9ydCBGb290ZXIgZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvZm9vdGVyL0Zvb3RlckNlbnRlclwiO1xuaW1wb3J0IE1haW5NZW51IGZyb20gXCIuLi8uLi9jb21wb25lbnRzL21haW4tbWVudS9NYWluTWVudVwiO1xuaW1wb3J0IFdlbGNvbWVTY3JlZW4gZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvd2VsY29tZS1zY3JlZW4vV2VsY29tZVNjcmVlblwiO1xuaW1wb3J0IExpdmVDb2xsYWJvcmF0aW9uVHJpZ2dlciBmcm9tIFwiLi4vLi4vY29tcG9uZW50cy9saXZlLWNvbGxhYm9yYXRpb24vTGl2ZUNvbGxhYm9yYXRpb25UcmlnZ2VyXCI7XG5cbmNvbnN0IEV4Y2FsaWRyYXdCYXNlID0gcHJvcHMgPT4ge1xuICB2YXIgX2EsIF9iLCBfYztcblxuICBjb25zdCB7XG4gICAgb25DaGFuZ2UsXG4gICAgaW5pdGlhbERhdGEsXG4gICAgZXhjYWxpZHJhd1JlZixcbiAgICBpc0NvbGxhYm9yYXRpbmcgPSBmYWxzZSxcbiAgICBvblBvaW50ZXJVcGRhdGUsXG4gICAgcmVuZGVyVG9wUmlnaHRVSSxcbiAgICBsYW5nQ29kZSA9IGRlZmF1bHRMYW5nLmNvZGUsXG4gICAgdmlld01vZGVFbmFibGVkLFxuICAgIHplbk1vZGVFbmFibGVkLFxuICAgIGdyaWRNb2RlRW5hYmxlZCxcbiAgICBsaWJyYXJ5UmV0dXJuVXJsLFxuICAgIHRoZW1lLFxuICAgIG5hbWUsXG4gICAgcmVuZGVyQ3VzdG9tU3RhdHMsXG4gICAgb25QYXN0ZSxcbiAgICBkZXRlY3RTY3JvbGwgPSB0cnVlLFxuICAgIGhhbmRsZUtleWJvYXJkR2xvYmFsbHkgPSBmYWxzZSxcbiAgICBvbkxpYnJhcnlDaGFuZ2UsXG4gICAgYXV0b0ZvY3VzID0gZmFsc2UsXG4gICAgZ2VuZXJhdGVJZEZvckZpbGUsXG4gICAgb25MaW5rT3BlbixcbiAgICBvblBvaW50ZXJEb3duLFxuICAgIG9uU2Nyb2xsQ2hhbmdlLFxuICAgIGNoaWxkcmVuLFxuICAgIHZhbGlkYXRlRW1iZWRkYWJsZSxcbiAgICByZW5kZXJFbWJlZGRhYmxlXG4gIH0gPSBwcm9wcztcbiAgY29uc3QgY2FudmFzQWN0aW9ucyA9IChfYSA9IHByb3BzLlVJT3B0aW9ucykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmNhbnZhc0FjdGlvbnM7IC8vIEZJWE1FIG5vcm1hbGl6ZS9zZXQgZGVmYXVsdHMgaW4gcGFyZW50IGNvbXBvbmVudCBzbyB0aGF0IHRoZSBtZW1vIHJlc29sdmVyXG4gIC8vIGNvbXBhcmVzIHRoZSBzYW1lIHZhbHVlc1xuXG4gIGNvbnN0IFVJT3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgcHJvcHMuVUlPcHRpb25zKSwge1xuICAgIGNhbnZhc0FjdGlvbnM6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgREVGQVVMVF9VSV9PUFRJT05TLmNhbnZhc0FjdGlvbnMpLCBjYW52YXNBY3Rpb25zKVxuICB9KTtcblxuICBpZiAoY2FudmFzQWN0aW9ucyA9PT0gbnVsbCB8fCBjYW52YXNBY3Rpb25zID09PSB2b2lkIDAgPyB2b2lkIDAgOiBjYW52YXNBY3Rpb25zLmV4cG9ydCkge1xuICAgIFVJT3B0aW9ucy5jYW52YXNBY3Rpb25zLmV4cG9ydC5zYXZlRmlsZVRvRGlzayA9IChfYyA9IChfYiA9IGNhbnZhc0FjdGlvbnMuZXhwb3J0KSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Iuc2F2ZUZpbGVUb0Rpc2spICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IERFRkFVTFRfVUlfT1BUSU9OUy5jYW52YXNBY3Rpb25zLmV4cG9ydC5zYXZlRmlsZVRvRGlzaztcbiAgfVxuXG4gIGlmIChVSU9wdGlvbnMuY2FudmFzQWN0aW9ucy50b2dnbGVUaGVtZSA9PT0gbnVsbCAmJiB0eXBlb2YgdGhlbWUgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICBVSU9wdGlvbnMuY2FudmFzQWN0aW9ucy50b2dnbGVUaGVtZSA9IHRydWU7XG4gIH1cblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIC8vIEJsb2NrIHBpbmNoLXpvb21pbmcgb24gaU9TIG91dHNpZGUgb2YgdGhlIGNvbnRlbnQgYXJlYVxuICAgIGNvbnN0IGhhbmRsZVRvdWNoTW92ZSA9IGV2ZW50ID0+IHtcbiAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgIGlmICh0eXBlb2YgZXZlbnQuc2NhbGUgPT09IFwibnVtYmVyXCIgJiYgZXZlbnQuc2NhbGUgIT09IDEpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcInRvdWNobW92ZVwiLCBoYW5kbGVUb3VjaE1vdmUsIHtcbiAgICAgIHBhc3NpdmU6IGZhbHNlXG4gICAgfSk7XG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJ0b3VjaG1vdmVcIiwgaGFuZGxlVG91Y2hNb3ZlKTtcbiAgICB9O1xuICB9LCBbXSk7XG4gIHJldHVybiBfanN4KFByb3ZpZGVyLCBPYmplY3QuYXNzaWduKHtcbiAgICB1bnN0YWJsZV9jcmVhdGVTdG9yZTogKCkgPT4gam90YWlTdG9yZSxcbiAgICBzY29wZTogam90YWlTY29wZVxuICB9LCB7XG4gICAgY2hpbGRyZW46IF9qc3goSW5pdGlhbGl6ZUFwcCwgT2JqZWN0LmFzc2lnbih7XG4gICAgICBsYW5nQ29kZTogbGFuZ0NvZGUsXG4gICAgICB0aGVtZTogdGhlbWVcbiAgICB9LCB7XG4gICAgICBjaGlsZHJlbjogX2pzeChBcHAsIE9iamVjdC5hc3NpZ24oe1xuICAgICAgICBvbkNoYW5nZTogb25DaGFuZ2UsXG4gICAgICAgIGluaXRpYWxEYXRhOiBpbml0aWFsRGF0YSxcbiAgICAgICAgZXhjYWxpZHJhd1JlZjogZXhjYWxpZHJhd1JlZixcbiAgICAgICAgaXNDb2xsYWJvcmF0aW5nOiBpc0NvbGxhYm9yYXRpbmcsXG4gICAgICAgIG9uUG9pbnRlclVwZGF0ZTogb25Qb2ludGVyVXBkYXRlLFxuICAgICAgICByZW5kZXJUb3BSaWdodFVJOiByZW5kZXJUb3BSaWdodFVJLFxuICAgICAgICBsYW5nQ29kZTogbGFuZ0NvZGUsXG4gICAgICAgIHZpZXdNb2RlRW5hYmxlZDogdmlld01vZGVFbmFibGVkLFxuICAgICAgICB6ZW5Nb2RlRW5hYmxlZDogemVuTW9kZUVuYWJsZWQsXG4gICAgICAgIGdyaWRNb2RlRW5hYmxlZDogZ3JpZE1vZGVFbmFibGVkLFxuICAgICAgICBsaWJyYXJ5UmV0dXJuVXJsOiBsaWJyYXJ5UmV0dXJuVXJsLFxuICAgICAgICB0aGVtZTogdGhlbWUsXG4gICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgIHJlbmRlckN1c3RvbVN0YXRzOiByZW5kZXJDdXN0b21TdGF0cyxcbiAgICAgICAgVUlPcHRpb25zOiBVSU9wdGlvbnMsXG4gICAgICAgIG9uUGFzdGU6IG9uUGFzdGUsXG4gICAgICAgIGRldGVjdFNjcm9sbDogZGV0ZWN0U2Nyb2xsLFxuICAgICAgICBoYW5kbGVLZXlib2FyZEdsb2JhbGx5OiBoYW5kbGVLZXlib2FyZEdsb2JhbGx5LFxuICAgICAgICBvbkxpYnJhcnlDaGFuZ2U6IG9uTGlicmFyeUNoYW5nZSxcbiAgICAgICAgYXV0b0ZvY3VzOiBhdXRvRm9jdXMsXG4gICAgICAgIGdlbmVyYXRlSWRGb3JGaWxlOiBnZW5lcmF0ZUlkRm9yRmlsZSxcbiAgICAgICAgb25MaW5rT3Blbjogb25MaW5rT3BlbixcbiAgICAgICAgb25Qb2ludGVyRG93bjogb25Qb2ludGVyRG93bixcbiAgICAgICAgb25TY3JvbGxDaGFuZ2U6IG9uU2Nyb2xsQ2hhbmdlLFxuICAgICAgICB2YWxpZGF0ZUVtYmVkZGFibGU6IHZhbGlkYXRlRW1iZWRkYWJsZSxcbiAgICAgICAgcmVuZGVyRW1iZWRkYWJsZTogcmVuZGVyRW1iZWRkYWJsZVxuICAgICAgfSwge1xuICAgICAgICBjaGlsZHJlbjogY2hpbGRyZW5cbiAgICAgIH0pKVxuICAgIH0pKVxuICB9KSk7XG59O1xuXG5jb25zdCBhcmVFcXVhbCA9IChwcmV2UHJvcHMsIG5leHRQcm9wcykgPT4ge1xuICAvLyBzaG9ydC1jaXJjdWl0IGVhcmx5XG4gIGlmIChwcmV2UHJvcHMuY2hpbGRyZW4gIT09IG5leHRQcm9wcy5jaGlsZHJlbikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGNvbnN0IHtcbiAgICBpbml0aWFsRGF0YTogcHJldkluaXRpYWxEYXRhLFxuICAgIFVJT3B0aW9uczogcHJldlVJT3B0aW9ucyA9IHt9XG4gIH0gPSBwcmV2UHJvcHMsXG4gICAgICAgIHByZXYgPSBfX3Jlc3QocHJldlByb3BzLCBbXCJpbml0aWFsRGF0YVwiLCBcIlVJT3B0aW9uc1wiXSk7XG5cbiAgY29uc3Qge1xuICAgIGluaXRpYWxEYXRhOiBuZXh0SW5pdGlhbERhdGEsXG4gICAgVUlPcHRpb25zOiBuZXh0VUlPcHRpb25zID0ge31cbiAgfSA9IG5leHRQcm9wcyxcbiAgICAgICAgbmV4dCA9IF9fcmVzdChuZXh0UHJvcHMsIFtcImluaXRpYWxEYXRhXCIsIFwiVUlPcHRpb25zXCJdKTsgLy8gY29tcGFyaW5nIFVJT3B0aW9uc1xuXG5cbiAgY29uc3QgcHJldlVJT3B0aW9uc0tleXMgPSBPYmplY3Qua2V5cyhwcmV2VUlPcHRpb25zKTtcbiAgY29uc3QgbmV4dFVJT3B0aW9uc0tleXMgPSBPYmplY3Qua2V5cyhuZXh0VUlPcHRpb25zKTtcblxuICBpZiAocHJldlVJT3B0aW9uc0tleXMubGVuZ3RoICE9PSBuZXh0VUlPcHRpb25zS2V5cy5sZW5ndGgpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCBpc1VJT3B0aW9uc1NhbWUgPSBwcmV2VUlPcHRpb25zS2V5cy5ldmVyeShrZXkgPT4ge1xuICAgIGlmIChrZXkgPT09IFwiY2FudmFzQWN0aW9uc1wiKSB7XG4gICAgICBjb25zdCBjYW52YXNPcHRpb25LZXlzID0gT2JqZWN0LmtleXMocHJldlVJT3B0aW9ucy5jYW52YXNBY3Rpb25zKTtcbiAgICAgIHJldHVybiBjYW52YXNPcHRpb25LZXlzLmV2ZXJ5KGtleSA9PiB7XG4gICAgICAgIHZhciBfYSwgX2IsIF9jLCBfZDtcblxuICAgICAgICBpZiAoa2V5ID09PSBcImV4cG9ydFwiICYmICgoX2EgPSBwcmV2VUlPcHRpb25zID09PSBudWxsIHx8IHByZXZVSU9wdGlvbnMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHByZXZVSU9wdGlvbnMuY2FudmFzQWN0aW9ucykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmV4cG9ydCkgJiYgKChfYiA9IG5leHRVSU9wdGlvbnMgPT09IG51bGwgfHwgbmV4dFVJT3B0aW9ucyA9PT0gdm9pZCAwID8gdm9pZCAwIDogbmV4dFVJT3B0aW9ucy5jYW52YXNBY3Rpb25zKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuZXhwb3J0KSkge1xuICAgICAgICAgIHJldHVybiBwcmV2VUlPcHRpb25zLmNhbnZhc0FjdGlvbnMuZXhwb3J0LnNhdmVGaWxlVG9EaXNrID09PSBuZXh0VUlPcHRpb25zLmNhbnZhc0FjdGlvbnMuZXhwb3J0LnNhdmVGaWxlVG9EaXNrO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuICgoX2MgPSBwcmV2VUlPcHRpb25zID09PSBudWxsIHx8IHByZXZVSU9wdGlvbnMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHByZXZVSU9wdGlvbnMuY2FudmFzQWN0aW9ucykgPT09IG51bGwgfHwgX2MgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9jW2tleV0pID09PSAoKF9kID0gbmV4dFVJT3B0aW9ucyA9PT0gbnVsbCB8fCBuZXh0VUlPcHRpb25zID09PSB2b2lkIDAgPyB2b2lkIDAgOiBuZXh0VUlPcHRpb25zLmNhbnZhc0FjdGlvbnMpID09PSBudWxsIHx8IF9kID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfZFtrZXldKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBwcmV2VUlPcHRpb25zW2tleV0gPT09IG5leHRVSU9wdGlvbnNba2V5XTtcbiAgfSk7XG4gIHJldHVybiBpc1VJT3B0aW9uc1NhbWUgJiYgaXNTaGFsbG93RXF1YWwocHJldiwgbmV4dCk7XG59O1xuXG5jb25zdCBmb3J3YXJkZWRSZWZDb21wID0gZm9yd2FyZFJlZigocHJvcHMsIHJlZikgPT4gX2pzeChFeGNhbGlkcmF3QmFzZSwgT2JqZWN0LmFzc2lnbih7fSwgcHJvcHMsIHtcbiAgZXhjYWxpZHJhd1JlZjogcmVmXG59KSkpO1xuZXhwb3J0IGNvbnN0IEV4Y2FsaWRyYXcgPSBSZWFjdC5tZW1vKGZvcndhcmRlZFJlZkNvbXAsIGFyZUVxdWFsKTtcbkV4Y2FsaWRyYXcuZGlzcGxheU5hbWUgPSBcIkV4Y2FsaWRyYXdcIjtcbmV4cG9ydCB7IGdldFNjZW5lVmVyc2lvbiwgaXNJbnZpc2libHlTbWFsbEVsZW1lbnQsIGdldE5vbkRlbGV0ZWRFbGVtZW50cyB9IGZyb20gXCIuLi8uLi9lbGVtZW50XCI7XG5leHBvcnQgeyBkZWZhdWx0TGFuZywgdXNlSTE4biwgbGFuZ3VhZ2VzIH0gZnJvbSBcIi4uLy4uL2kxOG5cIjtcbmV4cG9ydCB7IHJlc3RvcmUsIHJlc3RvcmVBcHBTdGF0ZSwgcmVzdG9yZUVsZW1lbnRzLCByZXN0b3JlTGlicmFyeUl0ZW1zIH0gZnJvbSBcIi4uLy4uL2RhdGEvcmVzdG9yZVwiO1xuZXhwb3J0IHsgZXhwb3J0VG9DYW52YXMsIGV4cG9ydFRvQmxvYiwgZXhwb3J0VG9TdmcsIHNlcmlhbGl6ZUFzSlNPTiwgc2VyaWFsaXplTGlicmFyeUFzSlNPTiwgbG9hZExpYnJhcnlGcm9tQmxvYiwgbG9hZEZyb21CbG9iLCBsb2FkU2NlbmVPckxpYnJhcnlGcm9tQmxvYiwgZ2V0RnJlZURyYXdTdmdQYXRoLCBleHBvcnRUb0NsaXBib2FyZCwgbWVyZ2VMaWJyYXJ5SXRlbXMgfSBmcm9tIFwiLi4vLi4vcGFja2FnZXMvdXRpbHNcIjtcbmV4cG9ydCB7IGlzTGluZWFyRWxlbWVudCB9IGZyb20gXCIuLi8uLi9lbGVtZW50L3R5cGVDaGVja3NcIjtcbmV4cG9ydCB7IEZPTlRfRkFNSUxZLCBUSEVNRSwgTUlNRV9UWVBFUyB9IGZyb20gXCIuLi8uLi9jb25zdGFudHNcIjtcbmV4cG9ydCB7IG11dGF0ZUVsZW1lbnQsIG5ld0VsZW1lbnRXaXRoLCBidW1wVmVyc2lvbiB9IGZyb20gXCIuLi8uLi9lbGVtZW50L211dGF0ZUVsZW1lbnRcIjtcbmV4cG9ydCB7IHBhcnNlTGlicmFyeVRva2Vuc0Zyb21VcmwsIHVzZUhhbmRsZUxpYnJhcnkgfSBmcm9tIFwiLi4vLi4vZGF0YS9saWJyYXJ5XCI7XG5leHBvcnQgeyBzY2VuZUNvb3Jkc1RvVmlld3BvcnRDb29yZHMsIHZpZXdwb3J0Q29vcmRzVG9TY2VuZUNvb3JkcyB9IGZyb20gXCIuLi8uLi91dGlsc1wiO1xuZXhwb3J0IHsgU2lkZWJhciB9IGZyb20gXCIuLi8uLi9jb21wb25lbnRzL1NpZGViYXIvU2lkZWJhclwiO1xuZXhwb3J0IHsgQnV0dG9uIH0gZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvQnV0dG9uXCI7XG5leHBvcnQgeyBGb290ZXIgfTtcbmV4cG9ydCB7IE1haW5NZW51IH07XG5leHBvcnQgeyB1c2VEZXZpY2UgfSBmcm9tIFwiLi4vLi4vY29tcG9uZW50cy9BcHBcIjtcbmV4cG9ydCB7IFdlbGNvbWVTY3JlZW4gfTtcbmV4cG9ydCB7IExpdmVDb2xsYWJvcmF0aW9uVHJpZ2dlciB9O1xuZXhwb3J0IHsgRGVmYXVsdFNpZGViYXIgfSBmcm9tIFwiLi4vLi4vY29tcG9uZW50cy9EZWZhdWx0U2lkZWJhclwiO1xuZXhwb3J0IHsgbm9ybWFsaXplTGluayB9IGZyb20gXCIuLi8uLi9kYXRhL3VybFwiO1xuZXhwb3J0IHsgY29udmVydFRvRXhjYWxpZHJhd0VsZW1lbnRzIH0gZnJvbSBcIi4uLy4uL2RhdGEvdHJhbnNmb3JtXCI7XG5leHBvcnQgeyBnZXRDb21tb25Cb3VuZHMgfSBmcm9tIFwiLi4vLi4vZWxlbWVudC9ib3VuZHNcIjtcbmV4cG9ydCB7IGVsZW1lbnRzT3ZlcmxhcHBpbmdCQm94LCBpc0VsZW1lbnRJbnNpZGVCQm94LCBlbGVtZW50UGFydGlhbGx5T3ZlcmxhcHNXaXRoT3JDb250YWluc0JCb3ggfSBmcm9tIFwiLi4vd2l0aGluQm91bmRzXCI7Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./index.tsx\n");
4359
4359
 
4360
4360
  /***/ }),
4361
4361
 
@@ -4366,7 +4366,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
4366
4366
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4367
4367
 
4368
4368
  "use strict";
4369
- 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-7251-baadf54\"}/dist/`;\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9wdWJsaWNQYXRoLmpzLmpzIiwibWFwcGluZ3MiOiI7O0FBQXNDOztBQUV0QyxJQUFJLGFBQW9CLEtBQUssZ0RBQVE7QUFDckM7O0FBRUE7QUFDQSxFQUFFLHFCQUF1Qix3REFBd0Qsd0JBQXlCLENBQUMsR0FBRyxxQkFBNEIsQ0FBQztBQUMzSSIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3B1YmxpY1BhdGguanM/NjdmOSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBFTlYgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5cbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gRU5WLlRFU1QpIHtcbiAgLyogZXNsaW50LWRpc2FibGUgKi9cblxuICAvKiBnbG9iYWwgX193ZWJwYWNrX3B1YmxpY19wYXRoX186d3JpdGFibGUgKi9cbiAgX193ZWJwYWNrX3B1YmxpY19wYXRoX18gPSB3aW5kb3cuRVhDQUxJRFJBV19BU1NFVF9QQVRIIHx8IGBodHRwczovL3VucGtnLmNvbS8ke3Byb2Nlc3MuZW52LlZJVEVfUEtHX05BTUV9QCR7cHJvY2Vzcy5lbnYuVklURV9QS0dfVkVSU0lPTn0vZGlzdC9gO1xufSJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./publicPath.js\n");
4369
+ 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-7255-5e200e3\"}/dist/`;\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9wdWJsaWNQYXRoLmpzLmpzIiwibWFwcGluZ3MiOiI7O0FBQXNDOztBQUV0QyxJQUFJLGFBQW9CLEtBQUssZ0RBQVE7QUFDckM7O0FBRUE7QUFDQSxFQUFFLHFCQUF1Qix3REFBd0Qsd0JBQXlCLENBQUMsR0FBRyxxQkFBNEIsQ0FBQztBQUMzSSIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3B1YmxpY1BhdGguanM/NjdmOSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBFTlYgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5cbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gRU5WLlRFU1QpIHtcbiAgLyogZXNsaW50LWRpc2FibGUgKi9cblxuICAvKiBnbG9iYWwgX193ZWJwYWNrX3B1YmxpY19wYXRoX186d3JpdGFibGUgKi9cbiAgX193ZWJwYWNrX3B1YmxpY19wYXRoX18gPSB3aW5kb3cuRVhDQUxJRFJBV19BU1NFVF9QQVRIIHx8IGBodHRwczovL3VucGtnLmNvbS8ke3Byb2Nlc3MuZW52LlZJVEVfUEtHX05BTUV9QCR7cHJvY2Vzcy5lbnYuVklURV9QS0dfVkVSU0lPTn0vZGlzdC9gO1xufSJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./publicPath.js\n");
4370
4370
 
4371
4371
  /***/ }),
4372
4372
 
@@ -4542,7 +4542,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
4542
4542
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4543
4543
 
4544
4544
  "use strict";
4545
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\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-7251-baadf54\",\"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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Q0EsS0FBSyxJQUFJLEdBQUc7QUFDWjs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMOztBQUVBLG1DQUFtQyxnRUFBZTtBQUNsRCxnQkFBZ0IsZ0RBQVE7QUFDeEIsaUJBQWlCLGdEQUFRO0FBQ3pCO0FBQ0E7O0FBRU87QUFDUDtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vc2NlbmUvZXhwb3J0LnRzP2MzNzMiXSwic291cmNlc0NvbnRlbnQiOlsidmFyIF9fYXdhaXRlciA9IHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xuICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7XG4gICAgICByZXNvbHZlKHZhbHVlKTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZWplY3QoZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7XG4gICAgICByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTtcbiAgICB9XG5cbiAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XG4gIH0pO1xufTtcblxuaW1wb3J0IHJvdWdoIGZyb20gXCJyb3VnaGpzL2Jpbi9yb3VnaFwiO1xuaW1wb3J0IHsgZ2V0Q29tbW9uQm91bmRzLCBnZXRFbGVtZW50QWJzb2x1dGVDb29yZHMgfSBmcm9tIFwiLi4vZWxlbWVudC9ib3VuZHNcIjtcbmltcG9ydCB7IHJlbmRlclNjZW5lVG9TdmcsIHJlbmRlclN0YXRpY1NjZW5lIH0gZnJvbSBcIi4uL3JlbmRlcmVyL3JlbmRlclNjZW5lXCI7XG5pbXBvcnQgeyBkaXN0YW5jZSwgaXNPbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IERFRkFVTFRfRVhQT1JUX1BBRERJTkcsIFNWR19OUywgVEhFTUVfRklMVEVSIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgZ2V0RGVmYXVsdEFwcFN0YXRlIH0gZnJvbSBcIi4uL2FwcFN0YXRlXCI7XG5pbXBvcnQgeyBzZXJpYWxpemVBc0pTT04gfSBmcm9tIFwiLi4vZGF0YS9qc29uXCI7XG5pbXBvcnQgeyBnZXRJbml0aWFsaXplZEltYWdlRWxlbWVudHMsIHVwZGF0ZUltYWdlQ2FjaGUgfSBmcm9tIFwiLi4vZWxlbWVudC9pbWFnZVwiO1xuaW1wb3J0IFNjZW5lIGZyb20gXCIuL1NjZW5lXCI7XG5jb25zdCBTVkdfRVhQT1JUX1RBRyA9IGA8IS0tIHN2Zy1zb3VyY2U6ZXhjYWxpZHJhdyAtLT5gO1xuZXhwb3J0IGNvbnN0IGV4cG9ydFRvQ2FudmFzID0gKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMsIHtcbiAgZXhwb3J0QmFja2dyb3VuZCxcbiAgZXhwb3J0UGFkZGluZyA9IERFRkFVTFRfRVhQT1JUX1BBRERJTkcsXG4gIHZpZXdCYWNrZ3JvdW5kQ29sb3Jcbn0sIGNyZWF0ZUNhbnZhcyA9ICh3aWR0aCwgaGVpZ2h0KSA9PiB7XG4gIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gIGNhbnZhcy53aWR0aCA9IHdpZHRoICogYXBwU3RhdGUuZXhwb3J0U2NhbGU7XG4gIGNhbnZhcy5oZWlnaHQgPSBoZWlnaHQgKiBhcHBTdGF0ZS5leHBvcnRTY2FsZTtcbiAgcmV0dXJuIHtcbiAgICBjYW52YXMsXG4gICAgc2NhbGU6IGFwcFN0YXRlLmV4cG9ydFNjYWxlXG4gIH07XG59KSA9PiBfX2F3YWl0ZXIodm9pZCAwLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgY29uc3QgW21pblgsIG1pblksIHdpZHRoLCBoZWlnaHRdID0gZ2V0Q2FudmFzU2l6ZShlbGVtZW50cywgZXhwb3J0UGFkZGluZyk7XG4gIGNvbnN0IHtcbiAgICBjYW52YXMsXG4gICAgc2NhbGUgPSAxXG4gIH0gPSBjcmVhdGVDYW52YXMod2lkdGgsIGhlaWdodCk7XG4gIGNvbnN0IGRlZmF1bHRBcHBTdGF0ZSA9IGdldERlZmF1bHRBcHBTdGF0ZSgpO1xuICBjb25zdCB7XG4gICAgaW1hZ2VDYWNoZVxuICB9ID0geWllbGQgdXBkYXRlSW1hZ2VDYWNoZSh7XG4gICAgaW1hZ2VDYWNoZTogbmV3IE1hcCgpLFxuICAgIGZpbGVJZHM6IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cyhlbGVtZW50cykubWFwKGVsZW1lbnQgPT4gZWxlbWVudC5maWxlSWQpLFxuICAgIGZpbGVzXG4gIH0pO1xuICBjb25zdCBvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPSBpc09ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZShlbGVtZW50cyk7XG4gIHJlbmRlclN0YXRpY1NjZW5lKHtcbiAgICBjYW52YXMsXG4gICAgcmM6IHJvdWdoLmNhbnZhcyhjYW52YXMpLFxuICAgIGVsZW1lbnRzLFxuICAgIHZpc2libGVFbGVtZW50czogZWxlbWVudHMsXG4gICAgc2NhbGUsXG4gICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYXBwU3RhdGUpLCB7XG4gICAgICB2aWV3QmFja2dyb3VuZENvbG9yOiBleHBvcnRCYWNrZ3JvdW5kID8gdmlld0JhY2tncm91bmRDb2xvciA6IG51bGwsXG4gICAgICBzY3JvbGxYOiAtbWluWCArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyksXG4gICAgICBzY3JvbGxZOiAtbWluWSArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyksXG4gICAgICB6b29tOiBkZWZhdWx0QXBwU3RhdGUuem9vbSxcbiAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2UsXG4gICAgICB0aGVtZTogYXBwU3RhdGUuZXhwb3J0V2l0aERhcmtNb2RlID8gXCJkYXJrXCIgOiBcImxpZ2h0XCJcbiAgICB9KSxcbiAgICByZW5kZXJDb25maWc6IHtcbiAgICAgIGltYWdlQ2FjaGUsXG4gICAgICByZW5kZXJHcmlkOiBmYWxzZSxcbiAgICAgIGlzRXhwb3J0aW5nOiB0cnVlXG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIGNhbnZhcztcbn0pO1xuZXhwb3J0IGNvbnN0IGV4cG9ydFRvU3ZnID0gKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMsIG9wdHMpID0+IF9fYXdhaXRlcih2b2lkIDAsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICB2YXIgX2EsIF9iLCBfYztcblxuICBjb25zdCB7XG4gICAgZXhwb3J0UGFkZGluZyA9IERFRkFVTFRfRVhQT1JUX1BBRERJTkcsXG4gICAgdmlld0JhY2tncm91bmRDb2xvcixcbiAgICBleHBvcnRTY2FsZSA9IDEsXG4gICAgZXhwb3J0RW1iZWRTY2VuZVxuICB9ID0gYXBwU3RhdGU7XG4gIGxldCBtZXRhZGF0YSA9IFwiXCI7XG5cbiAgaWYgKGV4cG9ydEVtYmVkU2NlbmUpIHtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSB5aWVsZCAoeWllbGQgaW1wb3J0KFxuICAgICAgLyogd2VicGFja0NodW5rTmFtZTogXCJpbWFnZVwiICovXG4gICAgICBcIi4uLy4uL3NyYy9kYXRhL2ltYWdlXCIpKS5lbmNvZGVTdmdNZXRhZGF0YSh7XG4gICAgICAgIHRleHQ6IChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuc2VyaWFsaXplQXNKU09OKSA/IChfYSA9IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5zZXJpYWxpemVBc0pTT04pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jYWxsKG9wdHMpIDogc2VyaWFsaXplQXNKU09OKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMgfHwge30sIFwibG9jYWxcIilcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBbbWluWCwgbWluWSwgd2lkdGgsIGhlaWdodF0gPSBnZXRDYW52YXNTaXplKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nKTsgLy8gaW5pdGlhbGl6ZSBTVkcgcm9vdFxuXG4gIGNvbnN0IHN2Z1Jvb3QgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoU1ZHX05TLCBcInN2Z1wiKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJ2ZXJzaW9uXCIsIFwiMS4xXCIpO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcInhtbG5zXCIsIFNWR19OUyk7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwidmlld0JveFwiLCBgMCAwICR7d2lkdGh9ICR7aGVpZ2h0fWApO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcIndpZHRoXCIsIGAke3dpZHRoICogZXhwb3J0U2NhbGV9YCk7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwiaGVpZ2h0XCIsIGAke2hlaWdodCAqIGV4cG9ydFNjYWxlfWApO1xuXG4gIGlmIChhcHBTdGF0ZS5leHBvcnRXaXRoRGFya01vZGUpIHtcbiAgICBzdmdSb290LnNldEF0dHJpYnV0ZShcImZpbHRlclwiLCBUSEVNRV9GSUxURVIpO1xuICB9XG5cbiAgbGV0IGFzc2V0UGF0aCA9IFwiaHR0cHM6Ly9leGNhbGlkcmF3LmNvbS9cIjsgLy8gQXNzZXQgcGF0aCBuZWVkcyB0byBiZSBkZXRlcm1pbmVkIG9ubHkgd2hlbiB1c2luZyBwYWNrYWdlXG5cbiAgaWYgKHByb2Nlc3MuZW52LlZJVEVfSVNfRVhDQUxJRFJBV19OUE1fUEFDS0FHRSkge1xuICAgIGFzc2V0UGF0aCA9IHdpbmRvdy5FWENBTElEUkFXX0FTU0VUX1BBVEggfHwgYGh0dHBzOi8vdW5wa2cuY29tLyR7cHJvY2Vzcy5lbnYuVklURV9QS0dfTkFNRX1AJHtwcm9jZXNzLmVudi5QS0dfVkVSU0lPTn1gO1xuXG4gICAgaWYgKGFzc2V0UGF0aCA9PT0gbnVsbCB8fCBhc3NldFBhdGggPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFzc2V0UGF0aC5zdGFydHNXaXRoKFwiL1wiKSkge1xuICAgICAgYXNzZXRQYXRoID0gYXNzZXRQYXRoLnJlcGxhY2UoXCIvXCIsIGAke3dpbmRvdy5sb2NhdGlvbi5vcmlnaW59L2ApO1xuICAgIH1cblxuICAgIGFzc2V0UGF0aCA9IGAke2Fzc2V0UGF0aH0vZGlzdC9leGNhbGlkcmF3LWFzc2V0cy9gO1xuICB9IC8vIGRvIG5vdCBhcHBseSBjbGlwcGluZyB3aGVuIHdlJ3JlIGV4cG9ydGluZyB0aGUgd2hvbGUgc2NlbmVcblxuXG4gIGNvbnN0IGlzRXhwb3J0aW5nV2hvbGVDYW52YXMgPSAoKF9jID0gKF9iID0gU2NlbmUuZ2V0U2NlbmUoZWxlbWVudHNbMF0pKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5sZW5ndGgpID09PSBlbGVtZW50cy5sZW5ndGg7XG4gIGNvbnN0IG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA9IGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKGVsZW1lbnRzKTtcbiAgY29uc3Qgb2Zmc2V0WCA9IC1taW5YICsgKG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IDAgOiBleHBvcnRQYWRkaW5nKTtcbiAgY29uc3Qgb2Zmc2V0WSA9IC1taW5ZICsgKG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IDAgOiBleHBvcnRQYWRkaW5nKTtcbiAgY29uc3QgZXhwb3J0aW5nRnJhbWUgPSBpc0V4cG9ydGluZ1dob2xlQ2FudmFzIHx8ICFvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyB1bmRlZmluZWQgOiBlbGVtZW50cy5maW5kKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuICBsZXQgZXhwb3J0aW5nRnJhbWVDbGlwUGF0aCA9IFwiXCI7XG5cbiAgaWYgKGV4cG9ydGluZ0ZyYW1lKSB7XG4gICAgY29uc3QgW3gxLCB5MSwgeDIsIHkyXSA9IGdldEVsZW1lbnRBYnNvbHV0ZUNvb3JkcyhleHBvcnRpbmdGcmFtZSk7XG4gICAgY29uc3QgY3ggPSAoeDIgLSB4MSkgLyAyIC0gKGV4cG9ydGluZ0ZyYW1lLnggLSB4MSk7XG4gICAgY29uc3QgY3kgPSAoeTIgLSB5MSkgLyAyIC0gKGV4cG9ydGluZ0ZyYW1lLnkgLSB5MSk7XG4gICAgZXhwb3J0aW5nRnJhbWVDbGlwUGF0aCA9IGA8Y2xpcFBhdGggaWQ9JHtleHBvcnRpbmdGcmFtZS5pZH0+XG4gICAgICAgICAgICA8cmVjdCB0cmFuc2Zvcm09XCJ0cmFuc2xhdGUoJHtleHBvcnRpbmdGcmFtZS54ICsgb2Zmc2V0WH0gJHtleHBvcnRpbmdGcmFtZS55ICsgb2Zmc2V0WX0pIHJvdGF0ZSgke2V4cG9ydGluZ0ZyYW1lLmFuZ2xlfSAke2N4fSAke2N5fSlcIlxuICAgICAgICAgIHdpZHRoPVwiJHtleHBvcnRpbmdGcmFtZS53aWR0aH1cIlxuICAgICAgICAgIGhlaWdodD1cIiR7ZXhwb3J0aW5nRnJhbWUuaGVpZ2h0fVwiXG4gICAgICAgICAgPlxuICAgICAgICAgIDwvcmVjdD5cbiAgICAgICAgPC9jbGlwUGF0aD5gO1xuICB9XG5cbiAgc3ZnUm9vdC5pbm5lckhUTUwgPSBgXG4gICR7U1ZHX0VYUE9SVF9UQUd9XG4gICR7bWV0YWRhdGF9XG4gIDxkZWZzPlxuICAgIDxzdHlsZSBjbGFzcz1cInN0eWxlLWZvbnRzXCI+XG4gICAgICBAZm9udC1mYWNlIHtcbiAgICAgICAgZm9udC1mYW1pbHk6IFwiVmlyZ2lsXCI7XG4gICAgICAgIHNyYzogdXJsKFwiJHthc3NldFBhdGh9VmlyZ2lsLndvZmYyXCIpO1xuICAgICAgfVxuICAgICAgQGZvbnQtZmFjZSB7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBcIkNhc2NhZGlhXCI7XG4gICAgICAgIHNyYzogdXJsKFwiJHthc3NldFBhdGh9Q2FzY2FkaWEud29mZjJcIik7XG4gICAgICB9XG4gICAgPC9zdHlsZT5cbiAgICAke2V4cG9ydGluZ0ZyYW1lQ2xpcFBhdGh9XG4gIDwvZGVmcz5cbiAgYDsgLy8gcmVuZGVyIGJhY2tncm91bmQgcmVjdFxuXG4gIGlmIChhcHBTdGF0ZS5leHBvcnRCYWNrZ3JvdW5kICYmIHZpZXdCYWNrZ3JvdW5kQ29sb3IpIHtcbiAgICBjb25zdCByZWN0ID0gc3ZnUm9vdC5vd25lckRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsIFwicmVjdFwiKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcInhcIiwgXCIwXCIpO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwieVwiLCBcIjBcIik7XG4gICAgcmVjdC5zZXRBdHRyaWJ1dGUoXCJ3aWR0aFwiLCBgJHt3aWR0aH1gKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcImhlaWdodFwiLCBgJHtoZWlnaHR9YCk7XG4gICAgcmVjdC5zZXRBdHRyaWJ1dGUoXCJmaWxsXCIsIHZpZXdCYWNrZ3JvdW5kQ29sb3IpO1xuICAgIHN2Z1Jvb3QuYXBwZW5kQ2hpbGQocmVjdCk7XG4gIH1cblxuICBjb25zdCByc3ZnID0gcm91Z2guc3ZnKHN2Z1Jvb3QpO1xuICByZW5kZXJTY2VuZVRvU3ZnKGVsZW1lbnRzLCByc3ZnLCBzdmdSb290LCBmaWxlcyB8fCB7fSwge1xuICAgIG9mZnNldFgsXG4gICAgb2Zmc2V0WSxcbiAgICBleHBvcnRXaXRoRGFya01vZGU6IGFwcFN0YXRlLmV4cG9ydFdpdGhEYXJrTW9kZSxcbiAgICBleHBvcnRpbmdGcmFtZUlkOiAoZXhwb3J0aW5nRnJhbWUgPT09IG51bGwgfHwgZXhwb3J0aW5nRnJhbWUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4cG9ydGluZ0ZyYW1lLmlkKSB8fCBudWxsLFxuICAgIHJlbmRlckVtYmVkZGFibGVzOiBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucmVuZGVyRW1iZWRkYWJsZXNcbiAgfSk7XG4gIHJldHVybiBzdmdSb290O1xufSk7IC8vIGNhbGN1bGF0ZSBzbWFsbGVzdCBhcmVhIHRvIGZpdCB0aGUgY29udGVudHMgaW5cblxuY29uc3QgZ2V0Q2FudmFzU2l6ZSA9IChlbGVtZW50cywgZXhwb3J0UGFkZGluZykgPT4ge1xuICAvLyB3ZSBzaG91bGQgZGVjaWRlIGlmIHdlIGFyZSBleHBvcnRpbmcgdGhlIHdob2xlIGNhbnZhc1xuICAvLyBpZiBzbywgd2UgYXJlIG5vdCBjbGlwcGluZyBlbGVtZW50cyBpbiB0aGUgZnJhbWVcbiAgLy8gYW5kIHRoZXJlZm9yZSwgd2Ugc2hvdWxkIG5vdCBkbyBhbnl0aGluZyBzcGVjaWFsXG4gIHZhciBfYSwgX2I7XG5cbiAgY29uc3QgaXNFeHBvcnRpbmdXaG9sZUNhbnZhcyA9ICgoX2IgPSAoX2EgPSBTY2VuZS5nZXRTY2VuZShlbGVtZW50c1swXSkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5nZXROb25EZWxldGVkRWxlbWVudHMoKSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmxlbmd0aCkgPT09IGVsZW1lbnRzLmxlbmd0aDtcbiAgY29uc3Qgb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID0gaXNPbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUoZWxlbWVudHMpO1xuXG4gIGlmICghaXNFeHBvcnRpbmdXaG9sZUNhbnZhcyB8fCBvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUpIHtcbiAgICBjb25zdCBmcmFtZXMgPSBlbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG4gICAgY29uc3QgZXhwb3J0ZWRGcmFtZUlkcyA9IGZyYW1lcy5yZWR1Y2UoKGFjYywgZnJhbWUpID0+IHtcbiAgICAgIGFjY1tmcmFtZS5pZF0gPSB0cnVlO1xuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCB7fSk7IC8vIGVsZW1lbnRzIGluIGEgZnJhbWUgZG8gbm90IGFmZmVjdCB0aGUgY2FudmFzIHNpemUgaWYgd2UncmUgbm90IGV4cG9ydGluZ1xuICAgIC8vIHRoZSB3aG9sZSBjYW52YXNcblxuICAgIGVsZW1lbnRzID0gZWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICByZXR1cm4gIWV4cG9ydGVkRnJhbWVJZHNbKF9hID0gZWxlbWVudC5mcmFtZUlkKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBcIlwiXTtcbiAgICB9KTtcbiAgfVxuXG4gIGNvbnN0IFttaW5YLCBtaW5ZLCBtYXhYLCBtYXhZXSA9IGdldENvbW1vbkJvdW5kcyhlbGVtZW50cyk7XG4gIGNvbnN0IHdpZHRoID0gZGlzdGFuY2UobWluWCwgbWF4WCkgKyAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gMCA6IGV4cG9ydFBhZGRpbmcgKiAyKTtcbiAgY29uc3QgaGVpZ2h0ID0gZGlzdGFuY2UobWluWSwgbWF4WSkgKyAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gMCA6IGV4cG9ydFBhZGRpbmcgKiAyKTtcbiAgcmV0dXJuIFttaW5YLCBtaW5ZLCB3aWR0aCwgaGVpZ2h0XTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRFeHBvcnRTaXplID0gKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nLCBzY2FsZSkgPT4ge1xuICBjb25zdCBbLCwgd2lkdGgsIGhlaWdodF0gPSBnZXRDYW52YXNTaXplKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nKS5tYXAoZGltZW5zaW9uID0+IE1hdGgudHJ1bmMoZGltZW5zaW9uICogc2NhbGUpKTtcbiAgcmV0dXJuIFt3aWR0aCwgaGVpZ2h0XTtcbn07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../scene/export.ts\n");
4545
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\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-7255-5e200e3\",\"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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Q0EsS0FBSyxJQUFJLEdBQUc7QUFDWjs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMOztBQUVBLG1DQUFtQyxnRUFBZTtBQUNsRCxnQkFBZ0IsZ0RBQVE7QUFDeEIsaUJBQWlCLGdEQUFRO0FBQ3pCO0FBQ0E7O0FBRU87QUFDUDtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi4vLi4vc2NlbmUvZXhwb3J0LnRzP2MzNzMiXSwic291cmNlc0NvbnRlbnQiOlsidmFyIF9fYXdhaXRlciA9IHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xuICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7XG4gICAgICByZXNvbHZlKHZhbHVlKTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZWplY3QoZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7XG4gICAgICByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTtcbiAgICB9XG5cbiAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XG4gIH0pO1xufTtcblxuaW1wb3J0IHJvdWdoIGZyb20gXCJyb3VnaGpzL2Jpbi9yb3VnaFwiO1xuaW1wb3J0IHsgZ2V0Q29tbW9uQm91bmRzLCBnZXRFbGVtZW50QWJzb2x1dGVDb29yZHMgfSBmcm9tIFwiLi4vZWxlbWVudC9ib3VuZHNcIjtcbmltcG9ydCB7IHJlbmRlclNjZW5lVG9TdmcsIHJlbmRlclN0YXRpY1NjZW5lIH0gZnJvbSBcIi4uL3JlbmRlcmVyL3JlbmRlclNjZW5lXCI7XG5pbXBvcnQgeyBkaXN0YW5jZSwgaXNPbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IERFRkFVTFRfRVhQT1JUX1BBRERJTkcsIFNWR19OUywgVEhFTUVfRklMVEVSIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgZ2V0RGVmYXVsdEFwcFN0YXRlIH0gZnJvbSBcIi4uL2FwcFN0YXRlXCI7XG5pbXBvcnQgeyBzZXJpYWxpemVBc0pTT04gfSBmcm9tIFwiLi4vZGF0YS9qc29uXCI7XG5pbXBvcnQgeyBnZXRJbml0aWFsaXplZEltYWdlRWxlbWVudHMsIHVwZGF0ZUltYWdlQ2FjaGUgfSBmcm9tIFwiLi4vZWxlbWVudC9pbWFnZVwiO1xuaW1wb3J0IFNjZW5lIGZyb20gXCIuL1NjZW5lXCI7XG5jb25zdCBTVkdfRVhQT1JUX1RBRyA9IGA8IS0tIHN2Zy1zb3VyY2U6ZXhjYWxpZHJhdyAtLT5gO1xuZXhwb3J0IGNvbnN0IGV4cG9ydFRvQ2FudmFzID0gKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMsIHtcbiAgZXhwb3J0QmFja2dyb3VuZCxcbiAgZXhwb3J0UGFkZGluZyA9IERFRkFVTFRfRVhQT1JUX1BBRERJTkcsXG4gIHZpZXdCYWNrZ3JvdW5kQ29sb3Jcbn0sIGNyZWF0ZUNhbnZhcyA9ICh3aWR0aCwgaGVpZ2h0KSA9PiB7XG4gIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gIGNhbnZhcy53aWR0aCA9IHdpZHRoICogYXBwU3RhdGUuZXhwb3J0U2NhbGU7XG4gIGNhbnZhcy5oZWlnaHQgPSBoZWlnaHQgKiBhcHBTdGF0ZS5leHBvcnRTY2FsZTtcbiAgcmV0dXJuIHtcbiAgICBjYW52YXMsXG4gICAgc2NhbGU6IGFwcFN0YXRlLmV4cG9ydFNjYWxlXG4gIH07XG59KSA9PiBfX2F3YWl0ZXIodm9pZCAwLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcbiAgY29uc3QgW21pblgsIG1pblksIHdpZHRoLCBoZWlnaHRdID0gZ2V0Q2FudmFzU2l6ZShlbGVtZW50cywgZXhwb3J0UGFkZGluZyk7XG4gIGNvbnN0IHtcbiAgICBjYW52YXMsXG4gICAgc2NhbGUgPSAxXG4gIH0gPSBjcmVhdGVDYW52YXMod2lkdGgsIGhlaWdodCk7XG4gIGNvbnN0IGRlZmF1bHRBcHBTdGF0ZSA9IGdldERlZmF1bHRBcHBTdGF0ZSgpO1xuICBjb25zdCB7XG4gICAgaW1hZ2VDYWNoZVxuICB9ID0geWllbGQgdXBkYXRlSW1hZ2VDYWNoZSh7XG4gICAgaW1hZ2VDYWNoZTogbmV3IE1hcCgpLFxuICAgIGZpbGVJZHM6IGdldEluaXRpYWxpemVkSW1hZ2VFbGVtZW50cyhlbGVtZW50cykubWFwKGVsZW1lbnQgPT4gZWxlbWVudC5maWxlSWQpLFxuICAgIGZpbGVzXG4gIH0pO1xuICBjb25zdCBvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPSBpc09ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZShlbGVtZW50cyk7XG4gIHJlbmRlclN0YXRpY1NjZW5lKHtcbiAgICBjYW52YXMsXG4gICAgcmM6IHJvdWdoLmNhbnZhcyhjYW52YXMpLFxuICAgIGVsZW1lbnRzLFxuICAgIHZpc2libGVFbGVtZW50czogZWxlbWVudHMsXG4gICAgc2NhbGUsXG4gICAgYXBwU3RhdGU6IE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSwgYXBwU3RhdGUpLCB7XG4gICAgICB2aWV3QmFja2dyb3VuZENvbG9yOiBleHBvcnRCYWNrZ3JvdW5kID8gdmlld0JhY2tncm91bmRDb2xvciA6IG51bGwsXG4gICAgICBzY3JvbGxYOiAtbWluWCArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyksXG4gICAgICBzY3JvbGxZOiAtbWluWSArIChvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyAwIDogZXhwb3J0UGFkZGluZyksXG4gICAgICB6b29tOiBkZWZhdWx0QXBwU3RhdGUuem9vbSxcbiAgICAgIHNob3VsZENhY2hlSWdub3JlWm9vbTogZmFsc2UsXG4gICAgICB0aGVtZTogYXBwU3RhdGUuZXhwb3J0V2l0aERhcmtNb2RlID8gXCJkYXJrXCIgOiBcImxpZ2h0XCJcbiAgICB9KSxcbiAgICByZW5kZXJDb25maWc6IHtcbiAgICAgIGltYWdlQ2FjaGUsXG4gICAgICByZW5kZXJHcmlkOiBmYWxzZSxcbiAgICAgIGlzRXhwb3J0aW5nOiB0cnVlXG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIGNhbnZhcztcbn0pO1xuZXhwb3J0IGNvbnN0IGV4cG9ydFRvU3ZnID0gKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMsIG9wdHMpID0+IF9fYXdhaXRlcih2b2lkIDAsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xuICB2YXIgX2EsIF9iLCBfYztcblxuICBjb25zdCB7XG4gICAgZXhwb3J0UGFkZGluZyA9IERFRkFVTFRfRVhQT1JUX1BBRERJTkcsXG4gICAgdmlld0JhY2tncm91bmRDb2xvcixcbiAgICBleHBvcnRTY2FsZSA9IDEsXG4gICAgZXhwb3J0RW1iZWRTY2VuZVxuICB9ID0gYXBwU3RhdGU7XG4gIGxldCBtZXRhZGF0YSA9IFwiXCI7XG5cbiAgaWYgKGV4cG9ydEVtYmVkU2NlbmUpIHtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSB5aWVsZCAoeWllbGQgaW1wb3J0KFxuICAgICAgLyogd2VicGFja0NodW5rTmFtZTogXCJpbWFnZVwiICovXG4gICAgICBcIi4uLy4uL3NyYy9kYXRhL2ltYWdlXCIpKS5lbmNvZGVTdmdNZXRhZGF0YSh7XG4gICAgICAgIHRleHQ6IChvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMuc2VyaWFsaXplQXNKU09OKSA/IChfYSA9IG9wdHMgPT09IG51bGwgfHwgb3B0cyA9PT0gdm9pZCAwID8gdm9pZCAwIDogb3B0cy5zZXJpYWxpemVBc0pTT04pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5jYWxsKG9wdHMpIDogc2VyaWFsaXplQXNKU09OKGVsZW1lbnRzLCBhcHBTdGF0ZSwgZmlsZXMgfHwge30sIFwibG9jYWxcIilcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBbbWluWCwgbWluWSwgd2lkdGgsIGhlaWdodF0gPSBnZXRDYW52YXNTaXplKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nKTsgLy8gaW5pdGlhbGl6ZSBTVkcgcm9vdFxuXG4gIGNvbnN0IHN2Z1Jvb3QgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoU1ZHX05TLCBcInN2Z1wiKTtcbiAgc3ZnUm9vdC5zZXRBdHRyaWJ1dGUoXCJ2ZXJzaW9uXCIsIFwiMS4xXCIpO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcInhtbG5zXCIsIFNWR19OUyk7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwidmlld0JveFwiLCBgMCAwICR7d2lkdGh9ICR7aGVpZ2h0fWApO1xuICBzdmdSb290LnNldEF0dHJpYnV0ZShcIndpZHRoXCIsIGAke3dpZHRoICogZXhwb3J0U2NhbGV9YCk7XG4gIHN2Z1Jvb3Quc2V0QXR0cmlidXRlKFwiaGVpZ2h0XCIsIGAke2hlaWdodCAqIGV4cG9ydFNjYWxlfWApO1xuXG4gIGlmIChhcHBTdGF0ZS5leHBvcnRXaXRoRGFya01vZGUpIHtcbiAgICBzdmdSb290LnNldEF0dHJpYnV0ZShcImZpbHRlclwiLCBUSEVNRV9GSUxURVIpO1xuICB9XG5cbiAgbGV0IGFzc2V0UGF0aCA9IFwiaHR0cHM6Ly9leGNhbGlkcmF3LmNvbS9cIjsgLy8gQXNzZXQgcGF0aCBuZWVkcyB0byBiZSBkZXRlcm1pbmVkIG9ubHkgd2hlbiB1c2luZyBwYWNrYWdlXG5cbiAgaWYgKHByb2Nlc3MuZW52LlZJVEVfSVNfRVhDQUxJRFJBV19OUE1fUEFDS0FHRSkge1xuICAgIGFzc2V0UGF0aCA9IHdpbmRvdy5FWENBTElEUkFXX0FTU0VUX1BBVEggfHwgYGh0dHBzOi8vdW5wa2cuY29tLyR7cHJvY2Vzcy5lbnYuVklURV9QS0dfTkFNRX1AJHtwcm9jZXNzLmVudi5QS0dfVkVSU0lPTn1gO1xuXG4gICAgaWYgKGFzc2V0UGF0aCA9PT0gbnVsbCB8fCBhc3NldFBhdGggPT09IHZvaWQgMCA/IHZvaWQgMCA6IGFzc2V0UGF0aC5zdGFydHNXaXRoKFwiL1wiKSkge1xuICAgICAgYXNzZXRQYXRoID0gYXNzZXRQYXRoLnJlcGxhY2UoXCIvXCIsIGAke3dpbmRvdy5sb2NhdGlvbi5vcmlnaW59L2ApO1xuICAgIH1cblxuICAgIGFzc2V0UGF0aCA9IGAke2Fzc2V0UGF0aH0vZGlzdC9leGNhbGlkcmF3LWFzc2V0cy9gO1xuICB9IC8vIGRvIG5vdCBhcHBseSBjbGlwcGluZyB3aGVuIHdlJ3JlIGV4cG9ydGluZyB0aGUgd2hvbGUgc2NlbmVcblxuXG4gIGNvbnN0IGlzRXhwb3J0aW5nV2hvbGVDYW52YXMgPSAoKF9jID0gKF9iID0gU2NlbmUuZ2V0U2NlbmUoZWxlbWVudHNbMF0pKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuZ2V0Tm9uRGVsZXRlZEVsZW1lbnRzKCkpID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5sZW5ndGgpID09PSBlbGVtZW50cy5sZW5ndGg7XG4gIGNvbnN0IG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA9IGlzT25seUV4cG9ydGluZ1NpbmdsZUZyYW1lKGVsZW1lbnRzKTtcbiAgY29uc3Qgb2Zmc2V0WCA9IC1taW5YICsgKG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IDAgOiBleHBvcnRQYWRkaW5nKTtcbiAgY29uc3Qgb2Zmc2V0WSA9IC1taW5ZICsgKG9ubHlFeHBvcnRpbmdTaW5nbGVGcmFtZSA/IDAgOiBleHBvcnRQYWRkaW5nKTtcbiAgY29uc3QgZXhwb3J0aW5nRnJhbWUgPSBpc0V4cG9ydGluZ1dob2xlQ2FudmFzIHx8ICFvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUgPyB1bmRlZmluZWQgOiBlbGVtZW50cy5maW5kKGVsZW1lbnQgPT4gZWxlbWVudC50eXBlID09PSBcImZyYW1lXCIpO1xuICBsZXQgZXhwb3J0aW5nRnJhbWVDbGlwUGF0aCA9IFwiXCI7XG5cbiAgaWYgKGV4cG9ydGluZ0ZyYW1lKSB7XG4gICAgY29uc3QgW3gxLCB5MSwgeDIsIHkyXSA9IGdldEVsZW1lbnRBYnNvbHV0ZUNvb3JkcyhleHBvcnRpbmdGcmFtZSk7XG4gICAgY29uc3QgY3ggPSAoeDIgLSB4MSkgLyAyIC0gKGV4cG9ydGluZ0ZyYW1lLnggLSB4MSk7XG4gICAgY29uc3QgY3kgPSAoeTIgLSB5MSkgLyAyIC0gKGV4cG9ydGluZ0ZyYW1lLnkgLSB5MSk7XG4gICAgZXhwb3J0aW5nRnJhbWVDbGlwUGF0aCA9IGA8Y2xpcFBhdGggaWQ9JHtleHBvcnRpbmdGcmFtZS5pZH0+XG4gICAgICAgICAgICA8cmVjdCB0cmFuc2Zvcm09XCJ0cmFuc2xhdGUoJHtleHBvcnRpbmdGcmFtZS54ICsgb2Zmc2V0WH0gJHtleHBvcnRpbmdGcmFtZS55ICsgb2Zmc2V0WX0pIHJvdGF0ZSgke2V4cG9ydGluZ0ZyYW1lLmFuZ2xlfSAke2N4fSAke2N5fSlcIlxuICAgICAgICAgIHdpZHRoPVwiJHtleHBvcnRpbmdGcmFtZS53aWR0aH1cIlxuICAgICAgICAgIGhlaWdodD1cIiR7ZXhwb3J0aW5nRnJhbWUuaGVpZ2h0fVwiXG4gICAgICAgICAgPlxuICAgICAgICAgIDwvcmVjdD5cbiAgICAgICAgPC9jbGlwUGF0aD5gO1xuICB9XG5cbiAgc3ZnUm9vdC5pbm5lckhUTUwgPSBgXG4gICR7U1ZHX0VYUE9SVF9UQUd9XG4gICR7bWV0YWRhdGF9XG4gIDxkZWZzPlxuICAgIDxzdHlsZSBjbGFzcz1cInN0eWxlLWZvbnRzXCI+XG4gICAgICBAZm9udC1mYWNlIHtcbiAgICAgICAgZm9udC1mYW1pbHk6IFwiVmlyZ2lsXCI7XG4gICAgICAgIHNyYzogdXJsKFwiJHthc3NldFBhdGh9VmlyZ2lsLndvZmYyXCIpO1xuICAgICAgfVxuICAgICAgQGZvbnQtZmFjZSB7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBcIkNhc2NhZGlhXCI7XG4gICAgICAgIHNyYzogdXJsKFwiJHthc3NldFBhdGh9Q2FzY2FkaWEud29mZjJcIik7XG4gICAgICB9XG4gICAgPC9zdHlsZT5cbiAgICAke2V4cG9ydGluZ0ZyYW1lQ2xpcFBhdGh9XG4gIDwvZGVmcz5cbiAgYDsgLy8gcmVuZGVyIGJhY2tncm91bmQgcmVjdFxuXG4gIGlmIChhcHBTdGF0ZS5leHBvcnRCYWNrZ3JvdW5kICYmIHZpZXdCYWNrZ3JvdW5kQ29sb3IpIHtcbiAgICBjb25zdCByZWN0ID0gc3ZnUm9vdC5vd25lckRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsIFwicmVjdFwiKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcInhcIiwgXCIwXCIpO1xuICAgIHJlY3Quc2V0QXR0cmlidXRlKFwieVwiLCBcIjBcIik7XG4gICAgcmVjdC5zZXRBdHRyaWJ1dGUoXCJ3aWR0aFwiLCBgJHt3aWR0aH1gKTtcbiAgICByZWN0LnNldEF0dHJpYnV0ZShcImhlaWdodFwiLCBgJHtoZWlnaHR9YCk7XG4gICAgcmVjdC5zZXRBdHRyaWJ1dGUoXCJmaWxsXCIsIHZpZXdCYWNrZ3JvdW5kQ29sb3IpO1xuICAgIHN2Z1Jvb3QuYXBwZW5kQ2hpbGQocmVjdCk7XG4gIH1cblxuICBjb25zdCByc3ZnID0gcm91Z2guc3ZnKHN2Z1Jvb3QpO1xuICByZW5kZXJTY2VuZVRvU3ZnKGVsZW1lbnRzLCByc3ZnLCBzdmdSb290LCBmaWxlcyB8fCB7fSwge1xuICAgIG9mZnNldFgsXG4gICAgb2Zmc2V0WSxcbiAgICBleHBvcnRXaXRoRGFya01vZGU6IGFwcFN0YXRlLmV4cG9ydFdpdGhEYXJrTW9kZSxcbiAgICBleHBvcnRpbmdGcmFtZUlkOiAoZXhwb3J0aW5nRnJhbWUgPT09IG51bGwgfHwgZXhwb3J0aW5nRnJhbWUgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGV4cG9ydGluZ0ZyYW1lLmlkKSB8fCBudWxsLFxuICAgIHJlbmRlckVtYmVkZGFibGVzOiBvcHRzID09PSBudWxsIHx8IG9wdHMgPT09IHZvaWQgMCA/IHZvaWQgMCA6IG9wdHMucmVuZGVyRW1iZWRkYWJsZXNcbiAgfSk7XG4gIHJldHVybiBzdmdSb290O1xufSk7IC8vIGNhbGN1bGF0ZSBzbWFsbGVzdCBhcmVhIHRvIGZpdCB0aGUgY29udGVudHMgaW5cblxuY29uc3QgZ2V0Q2FudmFzU2l6ZSA9IChlbGVtZW50cywgZXhwb3J0UGFkZGluZykgPT4ge1xuICAvLyB3ZSBzaG91bGQgZGVjaWRlIGlmIHdlIGFyZSBleHBvcnRpbmcgdGhlIHdob2xlIGNhbnZhc1xuICAvLyBpZiBzbywgd2UgYXJlIG5vdCBjbGlwcGluZyBlbGVtZW50cyBpbiB0aGUgZnJhbWVcbiAgLy8gYW5kIHRoZXJlZm9yZSwgd2Ugc2hvdWxkIG5vdCBkbyBhbnl0aGluZyBzcGVjaWFsXG4gIHZhciBfYSwgX2I7XG5cbiAgY29uc3QgaXNFeHBvcnRpbmdXaG9sZUNhbnZhcyA9ICgoX2IgPSAoX2EgPSBTY2VuZS5nZXRTY2VuZShlbGVtZW50c1swXSkpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5nZXROb25EZWxldGVkRWxlbWVudHMoKSkgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmxlbmd0aCkgPT09IGVsZW1lbnRzLmxlbmd0aDtcbiAgY29uc3Qgb25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID0gaXNPbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUoZWxlbWVudHMpO1xuXG4gIGlmICghaXNFeHBvcnRpbmdXaG9sZUNhbnZhcyB8fCBvbmx5RXhwb3J0aW5nU2luZ2xlRnJhbWUpIHtcbiAgICBjb25zdCBmcmFtZXMgPSBlbGVtZW50cy5maWx0ZXIoZWxlbWVudCA9PiBlbGVtZW50LnR5cGUgPT09IFwiZnJhbWVcIik7XG4gICAgY29uc3QgZXhwb3J0ZWRGcmFtZUlkcyA9IGZyYW1lcy5yZWR1Y2UoKGFjYywgZnJhbWUpID0+IHtcbiAgICAgIGFjY1tmcmFtZS5pZF0gPSB0cnVlO1xuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCB7fSk7IC8vIGVsZW1lbnRzIGluIGEgZnJhbWUgZG8gbm90IGFmZmVjdCB0aGUgY2FudmFzIHNpemUgaWYgd2UncmUgbm90IGV4cG9ydGluZ1xuICAgIC8vIHRoZSB3aG9sZSBjYW52YXNcblxuICAgIGVsZW1lbnRzID0gZWxlbWVudHMuZmlsdGVyKGVsZW1lbnQgPT4ge1xuICAgICAgdmFyIF9hO1xuXG4gICAgICByZXR1cm4gIWV4cG9ydGVkRnJhbWVJZHNbKF9hID0gZWxlbWVudC5mcmFtZUlkKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBcIlwiXTtcbiAgICB9KTtcbiAgfVxuXG4gIGNvbnN0IFttaW5YLCBtaW5ZLCBtYXhYLCBtYXhZXSA9IGdldENvbW1vbkJvdW5kcyhlbGVtZW50cyk7XG4gIGNvbnN0IHdpZHRoID0gZGlzdGFuY2UobWluWCwgbWF4WCkgKyAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gMCA6IGV4cG9ydFBhZGRpbmcgKiAyKTtcbiAgY29uc3QgaGVpZ2h0ID0gZGlzdGFuY2UobWluWSwgbWF4WSkgKyAob25seUV4cG9ydGluZ1NpbmdsZUZyYW1lID8gMCA6IGV4cG9ydFBhZGRpbmcgKiAyKTtcbiAgcmV0dXJuIFttaW5YLCBtaW5ZLCB3aWR0aCwgaGVpZ2h0XTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRFeHBvcnRTaXplID0gKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nLCBzY2FsZSkgPT4ge1xuICBjb25zdCBbLCwgd2lkdGgsIGhlaWdodF0gPSBnZXRDYW52YXNTaXplKGVsZW1lbnRzLCBleHBvcnRQYWRkaW5nKS5tYXAoZGltZW5zaW9uID0+IE1hdGgudHJ1bmMoZGltZW5zaW9uICogc2NhbGUpKTtcbiAgcmV0dXJuIFt3aWR0aCwgaGVpZ2h0XTtcbn07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../../scene/export.ts\n");
4546
4546
 
4547
4547
  /***/ }),
4548
4548
 
@@ -5704,7 +5704,7 @@ module.exports = JSON.parse('{"ar-SA":99,"az-AZ":18,"bg-BG":75,"bn-BD":55,"ca-ES
5704
5704
  /******/ // This function allow to reference async chunks
5705
5705
  /******/ __webpack_require__.u = (chunkId) => {
5706
5706
  /******/ // return url for filenames based on template
5707
- /******/ return "excalidraw-assets-dev/" + chunkId + "-" + {"locales/ar-SA-json":"f35c4f87e6e2dcf7c20a","locales/az-AZ-json":"5d70eb8bf3f20abc3bac","locales/bg-BG-json":"88cced5fd8a6d8298501","locales/bn-BD-json":"a06588c61947851c8579","locales/ca-ES-json":"9b25933a25836cc0be23","locales/cs-CZ-json":"1d6c97ea271d017058c9","locales/da-DK-json":"34a60c9843cecd71376f","locales/de-DE-json":"d13450595b795867412b","locales/el-GR-json":"c854b199f3ac07d40294","locales/es-ES-json":"6a667bfbf4ff3d0181a7","locales/eu-ES-json":"3ec11367a80491b09056","locales/fa-IR-json":"e459964936177074abe7","locales/fi-FI-json":"f7839bb6f5ad0a3c7e0d","locales/fr-FR-json":"20e8535e2675a6736c81","locales/gl-ES-json":"861f534b46c0db1fa8db","locales/he-IL-json":"504d78736487793ffccd","locales/hi-IN-json":"82d988431011c330242a","locales/hu-HU-json":"d4150250980011726fd9","locales/id-ID-json":"82e300d4fe1e87adba9b","locales/it-IT-json":"6ecc9aec005faab90f41","locales/ja-JP-json":"3c6a065f0f1303b297fa","locales/kaa-json":"983a9ccc652aa01980f3","locales/kab-KAB-json":"cac3cf66f1db5c1a6e19","locales/kk-KZ-json":"e9dd81c22419efd44478","locales/km-KH-json":"be77acee611d96d88dda","locales/ko-KR-json":"ad8e9d31d52b26f3fbc2","locales/ku-TR-json":"ed67af91ae1920f114a8","locales/lt-LT-json":"2c3d35d6fb5dbf95a27e","locales/lv-LV-json":"fa8973c231afb2ddafe9","locales/mr-IN-json":"2949146743072eb11b40","locales/my-MM-json":"4c04ffe415641f69ed75","locales/nb-NO-json":"b8d7a5b70562dacdad45","locales/nl-NL-json":"a65f82a25fe038c45d35","locales/nn-NO-json":"858fbccbc5be386977db","locales/oc-FR-json":"a68ea08272c8da3c0e3f","locales/pa-IN-json":"90a2b3775bd7d8983def","locales/pl-PL-json":"9bb55330d5aaf336646e","locales/pt-BR-json":"3635e753c1b6e5b681fa","locales/pt-PT-json":"0d3694a92e0134549086","locales/ro-RO-json":"e83fda16c860c6d0b383","locales/ru-RU-json":"ddc13261ce5d864d36a9","locales/si-LK-json":"16eb66dbfc6c55fc85b1","locales/sk-SK-json":"782ead8707f2ad0e8e4e","locales/sl-SI-json":"82e55cf7cdbdc7d7f959","locales/sv-SE-json":"2f362899d3ac4089534f","locales/ta-IN-json":"07623a485202da63a84b","locales/th-TH-json":"4e4b97f5f6e905191383","locales/tr-TR-json":"003be1cf6ebf0b787dec","locales/uk-UA-json":"ca6ea1156db2649d3e27","locales/vi-VN-json":"9a5e5fab41a1a120a916","locales/zh-CN-json":"670c28a6ae1e3ddecaa4","locales/zh-HK-json":"93b9b676d4f4b5702797","locales/zh-TW-json":"805d10b0eed9ca51b318","vendor":"05ba14a033ad4c84ef2a"}[chunkId] + ".js";
5707
+ /******/ return "excalidraw-assets-dev/" + chunkId + "-" + {"locales/ar-SA-json":"f35c4f87e6e2dcf7c20a","locales/az-AZ-json":"5d70eb8bf3f20abc3bac","locales/bg-BG-json":"88cced5fd8a6d8298501","locales/bn-BD-json":"a06588c61947851c8579","locales/ca-ES-json":"9b25933a25836cc0be23","locales/cs-CZ-json":"1d6c97ea271d017058c9","locales/da-DK-json":"34a60c9843cecd71376f","locales/de-DE-json":"d13450595b795867412b","locales/el-GR-json":"c854b199f3ac07d40294","locales/es-ES-json":"6a667bfbf4ff3d0181a7","locales/eu-ES-json":"3ec11367a80491b09056","locales/fa-IR-json":"e459964936177074abe7","locales/fi-FI-json":"f7839bb6f5ad0a3c7e0d","locales/fr-FR-json":"20e8535e2675a6736c81","locales/gl-ES-json":"861f534b46c0db1fa8db","locales/he-IL-json":"504d78736487793ffccd","locales/hi-IN-json":"82d988431011c330242a","locales/hu-HU-json":"d4150250980011726fd9","locales/id-ID-json":"82e300d4fe1e87adba9b","locales/it-IT-json":"6ecc9aec005faab90f41","locales/ja-JP-json":"3c6a065f0f1303b297fa","locales/kaa-json":"983a9ccc652aa01980f3","locales/kab-KAB-json":"cac3cf66f1db5c1a6e19","locales/kk-KZ-json":"e9dd81c22419efd44478","locales/km-KH-json":"be77acee611d96d88dda","locales/ko-KR-json":"ad8e9d31d52b26f3fbc2","locales/ku-TR-json":"ed67af91ae1920f114a8","locales/lt-LT-json":"2c3d35d6fb5dbf95a27e","locales/lv-LV-json":"fa8973c231afb2ddafe9","locales/mr-IN-json":"2949146743072eb11b40","locales/my-MM-json":"4c04ffe415641f69ed75","locales/nb-NO-json":"b8d7a5b70562dacdad45","locales/nl-NL-json":"a65f82a25fe038c45d35","locales/nn-NO-json":"858fbccbc5be386977db","locales/oc-FR-json":"a68ea08272c8da3c0e3f","locales/pa-IN-json":"90a2b3775bd7d8983def","locales/pl-PL-json":"9bb55330d5aaf336646e","locales/pt-BR-json":"3635e753c1b6e5b681fa","locales/pt-PT-json":"0d3694a92e0134549086","locales/ro-RO-json":"e83fda16c860c6d0b383","locales/ru-RU-json":"ddc13261ce5d864d36a9","locales/si-LK-json":"16eb66dbfc6c55fc85b1","locales/sk-SK-json":"782ead8707f2ad0e8e4e","locales/sl-SI-json":"82e55cf7cdbdc7d7f959","locales/sv-SE-json":"2f362899d3ac4089534f","locales/ta-IN-json":"07623a485202da63a84b","locales/th-TH-json":"4e4b97f5f6e905191383","locales/tr-TR-json":"003be1cf6ebf0b787dec","locales/uk-UA-json":"ca6ea1156db2649d3e27","locales/vi-VN-json":"9a5e5fab41a1a120a916","locales/zh-CN-json":"670c28a6ae1e3ddecaa4","locales/zh-HK-json":"93b9b676d4f4b5702797","locales/zh-TW-json":"805d10b0eed9ca51b318","vendor":"c57ffc1c961d2a51b881"}[chunkId] + ".js";
5708
5708
  /******/ };
5709
5709
  /******/ })();
5710
5710
  /******/