dcp-client 4.3.2-webgpu.0 → 4.3.2-webgpu.1

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.
@@ -3967,7 +3967,7 @@ eval("// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission
3967
3967
  \**********************/
3968
3968
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
3969
3969
 
3970
- eval("/**\n * @file build.js\n * Provide build information for DCP rtlink code, the same way as the dcp/build\n * module is injected for dcp-client code. That is what src/common/dcp-build.js\n * was supposed to do. We collide symbols here with a dcp-client built-in, so\n * that the code works the same everywhere but a gives different results depending\n * on how it was linked.\n *\n * This file is expressly processed by the copy-stamp rule in the core install\n * map, so that the symbols in here get substituted with their 'real' values as\n * the product is installed. A side effect of this is that dev versions running\n * out of the source tree will have symbol names instead of symbol values here.\n *\n * @author Wes Garland, wes@distributive.network\n * @date Nov 2022\n */\n\nexports.version = '1f4eab51b277cbfe9ca6f36a756f726820c55208';\nexports.branch = 'develop';\n\n/* When/how configure.sh ran */\nexports.config = __webpack_require__(/*! ../etc/local-config.json */ \"./etc/local-config.json\");\ndelete exports.config.install;\n\n/* When/how install.sh ran (not for dcp-client) */\nexports.install = {\n timestamp: new Date(Number('__TIMESTAMP__') * 1000),\n build: '__DCP_BUILD',\n};\n\n\n\n\n//# sourceURL=webpack://dcp/./src/build.js?");
3970
+ eval("/**\n * @file build.js\n * Provide build information for DCP rtlink code, the same way as the dcp/build\n * module is injected for dcp-client code. That is what src/common/dcp-build.js\n * was supposed to do. We collide symbols here with a dcp-client built-in, so\n * that the code works the same everywhere but a gives different results depending\n * on how it was linked.\n *\n * This file is expressly processed by the copy-stamp rule in the core install\n * map, so that the symbols in here get substituted with their 'real' values as\n * the product is installed. A side effect of this is that dev versions running\n * out of the source tree will have symbol names instead of symbol values here.\n *\n * @author Wes Garland, wes@distributive.network\n * @date Nov 2022\n */\n\nexports.version = '8a95bd250c03421b473f543c2e9c7a85516d622c';\nexports.branch = 'prod-20230922';\n\n/* When/how configure.sh ran */\nexports.config = __webpack_require__(/*! ../etc/local-config.json */ \"./etc/local-config.json\");\ndelete exports.config.install;\n\n/* When/how install.sh ran (not for dcp-client) */\nexports.install = {\n timestamp: new Date(Number('__TIMESTAMP__') * 1000),\n build: '__DCP_BUILD',\n};\n\n\n\n\n//# sourceURL=webpack://dcp/./src/build.js?");
3971
3971
 
3972
3972
  /***/ }),
3973
3973
 
@@ -4019,7 +4019,7 @@ eval("/**\n * @file dcp-assert.js\n * Simple assertion modul
4019
4019
  \*********************************/
4020
4020
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4021
4021
 
4022
- eval("/* provided dependency */ var process = __webpack_require__(/*! ./node_modules/process/browser.js */ \"./node_modules/process/browser.js\");\n/**\n * @file dcp-build.js Return an object describing the current DCP build.\n * @author Ryan Rossiter <ryan@kingsds.network>\n * @author Wes Garland, wes@distributive.network\n * @date July 2020\n * @date Apr 2023\n */\n\nif ((__webpack_require__(/*! dcp/common/dcp-env */ \"./src/common/dcp-env.js\").platform) === 'nodejs')\n{\n const { requireNative } = __webpack_require__(/*! dcp/dcp-client/webpack-native-bridge */ \"./src/dcp-client/webpack-native-bridge.js\");\n const fs = requireNative('fs');\n const path = requireNative('path');\n\n try\n {\n const rtlink = requireNative('dcp-rtlink');\n const localConfig = false\n || process.env.DCP_LOCAL_CONFIG_JSON /* dcp-client bundler's temp dir */\n || path.join(rtlink.runningLocation, 'etc', 'local-config.json'); /* installed or src dir config */\n Object.assign(exports, JSON.parse(fs.readFileSync(localConfig), 'utf-8'));\n }\n catch(error)\n {\n if (error.code !== 'MODULE_NOT_FOUND')\n throw error;\n /* If we arrive here, we couldn't resolve dcp-rtlink => we're on dcp-client */\n Object.assign(exports, {\"version\":\"1f4eab51b277cbfe9ca6f36a756f726820c55208\",\"branch\":\"develop\",\"dcpClient\":{\"version\":\"4.3.0\",\"resolved\":\"git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-client.git#026d4e0b62a4ad4f7ec70096c72ee5e2650d056f\",\"overridden\":false},\"built\":\"Wed Oct 11 2023 10:25:53 GMT-0400 (Eastern Daylight Saving Time)\",\"config\":{\"generated\":\"Wed 11 Oct 2023 10:25:52 AM EDT by erose on lorge\",\"build\":\"debug\"},\"webpack\":\"5.88.2\",\"node\":\"v18.17.1\"}.config);\n }\n}\nelse\n{\n /* For all non-node platforms, just assume that we're also on dcp-client */\n Object.assign(exports, {\"version\":\"1f4eab51b277cbfe9ca6f36a756f726820c55208\",\"branch\":\"develop\",\"dcpClient\":{\"version\":\"4.3.0\",\"resolved\":\"git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-client.git#026d4e0b62a4ad4f7ec70096c72ee5e2650d056f\",\"overridden\":false},\"built\":\"Wed Oct 11 2023 10:25:53 GMT-0400 (Eastern Daylight Saving Time)\",\"config\":{\"generated\":\"Wed 11 Oct 2023 10:25:52 AM EDT by erose on lorge\",\"build\":\"debug\"},\"webpack\":\"5.88.2\",\"node\":\"v18.17.1\"}.config);\n}\n\nif (typeof exports.build === 'undefined') {\n throw new Error('Could not determine build type!');\n}\n\n\n//# sourceURL=webpack://dcp/./src/common/dcp-build.js?");
4022
+ eval("/* provided dependency */ var process = __webpack_require__(/*! ./node_modules/process/browser.js */ \"./node_modules/process/browser.js\");\n/**\n * @file dcp-build.js Return an object describing the current DCP build.\n * @author Ryan Rossiter <ryan@kingsds.network>\n * @author Wes Garland, wes@distributive.network\n * @date July 2020\n * @date Apr 2023\n */\n\nif ((__webpack_require__(/*! dcp/common/dcp-env */ \"./src/common/dcp-env.js\").platform) === 'nodejs')\n{\n const { requireNative } = __webpack_require__(/*! dcp/dcp-client/webpack-native-bridge */ \"./src/dcp-client/webpack-native-bridge.js\");\n const fs = requireNative('fs');\n const path = requireNative('path');\n\n try\n {\n const rtlink = requireNative('dcp-rtlink');\n const localConfig = false\n || process.env.DCP_LOCAL_CONFIG_JSON /* dcp-client bundler's temp dir */\n || path.join(rtlink.runningLocation, 'etc', 'local-config.json'); /* installed or src dir config */\n Object.assign(exports, JSON.parse(fs.readFileSync(localConfig), 'utf-8'));\n }\n catch(error)\n {\n if (error.code !== 'MODULE_NOT_FOUND')\n throw error;\n /* If we arrive here, we couldn't resolve dcp-rtlink => we're on dcp-client */\n Object.assign(exports, {\"version\":\"8a95bd250c03421b473f543c2e9c7a85516d622c\",\"branch\":\"prod-20230922\",\"dcpClient\":{\"version\":\"4.3.0\",\"resolved\":\"git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-client.git#2ba1f35c876d61c52ffec4f5c67f2c5c8449ec5c\",\"overridden\":false},\"built\":\"Tue Sep 26 2023 09:10:57 GMT-0400 (Eastern Daylight Saving Time)\",\"config\":{\"generated\":\"Tue 26 Sep 2023 09:10:56 AM EDT by erose on lorge\",\"build\":\"debug\"},\"webpack\":\"5.88.2\",\"node\":\"v18.17.1\"}.config);\n }\n}\nelse\n{\n /* For all non-node platforms, just assume that we're also on dcp-client */\n Object.assign(exports, {\"version\":\"8a95bd250c03421b473f543c2e9c7a85516d622c\",\"branch\":\"prod-20230922\",\"dcpClient\":{\"version\":\"4.3.0\",\"resolved\":\"git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-client.git#2ba1f35c876d61c52ffec4f5c67f2c5c8449ec5c\",\"overridden\":false},\"built\":\"Tue Sep 26 2023 09:10:57 GMT-0400 (Eastern Daylight Saving Time)\",\"config\":{\"generated\":\"Tue 26 Sep 2023 09:10:56 AM EDT by erose on lorge\",\"build\":\"debug\"},\"webpack\":\"5.88.2\",\"node\":\"v18.17.1\"}.config);\n}\n\nif (typeof exports.build === 'undefined') {\n throw new Error('Could not determine build type!');\n}\n\n\n//# sourceURL=webpack://dcp/./src/common/dcp-build.js?");
4023
4023
 
4024
4024
  /***/ }),
4025
4025
 
@@ -4293,7 +4293,7 @@ eval("/**\n * @file password.js\n * Modal providing a way to
4293
4293
  \**********************************************/
4294
4294
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4295
4295
 
4296
- eval("/**\n * @file client-modal/utils.js\n * @author KC Erb\n * @date Mar 2020\n * \n * All shared functions among the modals.\n */\nconst { fetchRelative } = __webpack_require__(/*! ./fetch-relative */ \"./src/dcp-client/client-modal/fetch-relative.js\");\nconst { DCPError } = __webpack_require__(/*! dcp/common/dcp-error */ \"./src/common/dcp-error.js\");\nconst DCP_ENV = __webpack_require__(/*! dcp/common/dcp-env */ \"./src/common/dcp-env.js\");\nexports.OnCloseErrorCode = 'DCP_CM:CANCELX';\n\nif (DCP_ENV.isBrowserPlatform) {\n // Provide as export for the convenience of `utils.MicroModal` instead of a separate require.\n exports.MicroModal = __webpack_require__(/*! micromodal */ \"./node_modules/micromodal/dist/micromodal.es.js\")[\"default\"];\n}\n\n/**\n * Return a unique string, formatted as a GET parameter, that changes often enough to\n * always force the browser to fetch the latest version of our resource.\n *\n * @note Currently always returns the Date-based poison due to webpack. \n */\nfunction cachePoison() {\n if (true)\n return '?ucp=1f4eab51b277cbfe9ca6f36a756f726820c55208'; /* installer token */\n return '?ucp=' + Date.now();\n}\n \n/* Detect load type - on webpack, load dynamic content relative to webpack bundle;\n * otherwise load relative to the current scheduler's configured portal.\n */\nexports.myScript = (typeof document !== 'undefined') && document.currentScript;\nexports.corsProxyHref = undefined;\nif (exports.myScript && exports.myScript === (__webpack_require__(/*! ./fetch-relative */ \"./src/dcp-client/client-modal/fetch-relative.js\").myScript)) {\n let url = new ((__webpack_require__(/*! dcp/common/dcp-url */ \"./src/common/dcp-url.js\").DcpURL))(exports.myScript.src);\n exports.corsProxyHref = url.resolve('../cors-proxy.html');\n}\n\n/**\n * Look for modal id and required ids on page based on config, if not found, provide from dcp-client.\n * The first id in the required array must be the id of the modal's form element.\n * @param {Object} modalConfig Modal configuration object\n * @param {string} modalConfig.id Id of parent modal element\n * @param {string[]} modalConfig.required Array of required ids in parent modal element\n * @param {string[]} [modalConfig.optional] Array of optional ids in parent modal element\n * @param {string} modalConfig.path Relative path to modal html in dcp-client\n * @returns {DOMElement[]} Array of modal elements on page [config.id, ...config.required]\n */\nexports.initModal = async function (modalConfig, onClose) {\n exports.corsProxyHref = exports.corsProxyHref || dcpConfig.portal.location.resolve('dcp-client/cors-proxy.html');\n\n // Call ensure modal on any eager-loaded modals.\n if (modalConfig.eagerLoad) {\n Promise.all(\n modalConfig.eagerLoad.map(config => ensureModal(config))\n )\n };\n\n const [elements, optionalElements] = await ensureModal(modalConfig);\n\n // Wire up form to prevent default, resolve on submission, reject+reset when closed (or call onClose when closed)\n const [modal, form] = elements;\n form.reset(); // ensure that form is fresh\n let formResolve, formReject;\n let formPromise = new Promise( function(res, rej) {\n formResolve = res;\n formReject = rej;\n });\n form.onsubmit = function (submitEvent) {\n submitEvent.preventDefault();\n modal.setAttribute(\"data-state\", \"submitted\");\n formResolve(submitEvent);\n }\n\n exports.MicroModal.show(modalConfig.id, { \n disableFocus: true, \n onClose: onClose || getDefaultOnClose(formReject)\n });\n return [elements, formPromise, optionalElements];\n};\n\n// Ensure all required modal elements are on page according to modalConfig\nasync function ensureModal(modalConfig) {\n let allRequiredIds = [modalConfig.id, ...modalConfig.required];\n let missing = allRequiredIds.filter( id => !document.getElementById(id) );\n if (missing.length > 0) {\n if (missing.length !== allRequiredIds.length)\n console.warn(`Some of the ids needed to replace the default DCP-modal were found, but not all. So the default DCP-Modal will be used. Missing ids are: [${missing}].`);\n let contents = await fetchRelative(exports.corsProxyHref, modalConfig.path + cachePoison());\n const container = document.createElement('div');\n container.innerHTML = contents;\n document.body.appendChild(container);\n }\n\n const elements = allRequiredIds.map(id => document.getElementById(id));\n const optionalElements = (modalConfig.optional || []).map(id => document.getElementById(id));\n return [elements, optionalElements];\n};\n\n// This onClose is called by MicroModal and thus has the modal passed to it.\nfunction getDefaultOnClose (formReject) {\n return (modal) => {\n modal.offsetLeft; // forces style recalc\n const origState = modal.dataset.state;\n // reset form including data-state\n modal.setAttribute(\"data-state\", \"new\");\n // reject if closed without submitting form.\n if (origState !== \"submitted\") {\n const err = new DCPError(\"Modal was closed but modal's form was not submitted.\", exports.OnCloseErrorCode);\n formReject(err);\n }\n }\n}\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/client-modal/utils.js?");
4296
+ eval("/**\n * @file client-modal/utils.js\n * @author KC Erb\n * @date Mar 2020\n * \n * All shared functions among the modals.\n */\nconst { fetchRelative } = __webpack_require__(/*! ./fetch-relative */ \"./src/dcp-client/client-modal/fetch-relative.js\");\nconst { DCPError } = __webpack_require__(/*! dcp/common/dcp-error */ \"./src/common/dcp-error.js\");\nconst DCP_ENV = __webpack_require__(/*! dcp/common/dcp-env */ \"./src/common/dcp-env.js\");\nexports.OnCloseErrorCode = 'DCP_CM:CANCELX';\n\nif (DCP_ENV.isBrowserPlatform) {\n // Provide as export for the convenience of `utils.MicroModal` instead of a separate require.\n exports.MicroModal = __webpack_require__(/*! micromodal */ \"./node_modules/micromodal/dist/micromodal.es.js\")[\"default\"];\n}\n\n/**\n * Return a unique string, formatted as a GET parameter, that changes often enough to\n * always force the browser to fetch the latest version of our resource.\n *\n * @note Currently always returns the Date-based poison due to webpack. \n */\nfunction cachePoison() {\n if (true)\n return '?ucp=8a95bd250c03421b473f543c2e9c7a85516d622c'; /* installer token */\n return '?ucp=' + Date.now();\n}\n \n/* Detect load type - on webpack, load dynamic content relative to webpack bundle;\n * otherwise load relative to the current scheduler's configured portal.\n */\nexports.myScript = (typeof document !== 'undefined') && document.currentScript;\nexports.corsProxyHref = undefined;\nif (exports.myScript && exports.myScript === (__webpack_require__(/*! ./fetch-relative */ \"./src/dcp-client/client-modal/fetch-relative.js\").myScript)) {\n let url = new ((__webpack_require__(/*! dcp/common/dcp-url */ \"./src/common/dcp-url.js\").DcpURL))(exports.myScript.src);\n exports.corsProxyHref = url.resolve('../cors-proxy.html');\n}\n\n/**\n * Look for modal id and required ids on page based on config, if not found, provide from dcp-client.\n * The first id in the required array must be the id of the modal's form element.\n * @param {Object} modalConfig Modal configuration object\n * @param {string} modalConfig.id Id of parent modal element\n * @param {string[]} modalConfig.required Array of required ids in parent modal element\n * @param {string[]} [modalConfig.optional] Array of optional ids in parent modal element\n * @param {string} modalConfig.path Relative path to modal html in dcp-client\n * @returns {DOMElement[]} Array of modal elements on page [config.id, ...config.required]\n */\nexports.initModal = async function (modalConfig, onClose) {\n exports.corsProxyHref = exports.corsProxyHref || dcpConfig.portal.location.resolve('dcp-client/cors-proxy.html');\n\n // Call ensure modal on any eager-loaded modals.\n if (modalConfig.eagerLoad) {\n Promise.all(\n modalConfig.eagerLoad.map(config => ensureModal(config))\n )\n };\n\n const [elements, optionalElements] = await ensureModal(modalConfig);\n\n // Wire up form to prevent default, resolve on submission, reject+reset when closed (or call onClose when closed)\n const [modal, form] = elements;\n form.reset(); // ensure that form is fresh\n let formResolve, formReject;\n let formPromise = new Promise( function(res, rej) {\n formResolve = res;\n formReject = rej;\n });\n form.onsubmit = function (submitEvent) {\n submitEvent.preventDefault();\n modal.setAttribute(\"data-state\", \"submitted\");\n formResolve(submitEvent);\n }\n\n exports.MicroModal.show(modalConfig.id, { \n disableFocus: true, \n onClose: onClose || getDefaultOnClose(formReject)\n });\n return [elements, formPromise, optionalElements];\n};\n\n// Ensure all required modal elements are on page according to modalConfig\nasync function ensureModal(modalConfig) {\n let allRequiredIds = [modalConfig.id, ...modalConfig.required];\n let missing = allRequiredIds.filter( id => !document.getElementById(id) );\n if (missing.length > 0) {\n if (missing.length !== allRequiredIds.length)\n console.warn(`Some of the ids needed to replace the default DCP-modal were found, but not all. So the default DCP-Modal will be used. Missing ids are: [${missing}].`);\n let contents = await fetchRelative(exports.corsProxyHref, modalConfig.path + cachePoison());\n const container = document.createElement('div');\n container.innerHTML = contents;\n document.body.appendChild(container);\n }\n\n const elements = allRequiredIds.map(id => document.getElementById(id));\n const optionalElements = (modalConfig.optional || []).map(id => document.getElementById(id));\n return [elements, optionalElements];\n};\n\n// This onClose is called by MicroModal and thus has the modal passed to it.\nfunction getDefaultOnClose (formReject) {\n return (modal) => {\n modal.offsetLeft; // forces style recalc\n const origState = modal.dataset.state;\n // reset form including data-state\n modal.setAttribute(\"data-state\", \"new\");\n // reject if closed without submitting form.\n if (origState !== \"submitted\") {\n const err = new DCPError(\"Modal was closed but modal's form was not submitted.\", exports.OnCloseErrorCode);\n formReject(err);\n }\n }\n}\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/client-modal/utils.js?");
4297
4297
 
4298
4298
  /***/ }),
4299
4299
 
@@ -4325,7 +4325,7 @@ eval("/**\n * @file Module that implements Compute API\n * @module dcp/comput
4325
4325
  /***/ ((module, exports, __webpack_require__) => {
4326
4326
 
4327
4327
  "use strict";
4328
- eval("/* module decorator */ module = __webpack_require__.nmd(module);\n/* provided dependency */ var process = __webpack_require__(/*! ./node_modules/process/browser.js */ \"./node_modules/process/browser.js\");\n/**\n * @file dcp-client-bundle-src.js\n * Top-level file which gets webpacked into the bundle consumed by dcp-client 2.5\n * @author Wes Garland, wes@kingsds.network\n * @date July 2019\n */\n\n{\n let thisScript = typeof document !== 'undefined' ? (typeof document.currentScript !== 'undefined' && document.currentScript) || document.getElementById('_dcp_client_bundle') : {}\n let realModuleDeclare\n\n if ( false || typeof module.declare === 'undefined') {\n realModuleDeclare = ( true) ? module.declare : 0\n if (false) {}\n module.declare = function moduleUnWrapper (deps, factory) {\n factory(null, module.exports, module)\n return module.exports\n }\n }\n\n let _debugging = () => false\n if (process.env.DCP_CONFIG_USE_DEPRECATED_FUTURE)\n dcpConfig.future = (__webpack_require__(/*! ../common/config-future.js */ \"./src/common/config-future.js\").futureFactory)(_debugging, dcpConfig);\n\n /* These modules are official API and must be part of DCP Client */\n let officialApi = {\n 'protocol': __webpack_require__(/*! ../protocol-v4 */ \"./src/protocol-v4/index.js\"),\n 'compute': (__webpack_require__(/*! ./compute */ \"./src/dcp-client/compute.js\").compute),\n 'worker': __webpack_require__(/*! ./worker */ \"./src/dcp-client/worker/index.js\"),\n 'wallet': __webpack_require__(/*! ./wallet */ \"./src/dcp-client/wallet/index.js\"),\n };\n\n /* Some of these modules are API-track. Some of them need to be published to be\n * available for top-level resolution by DCP internals. Those (mostly) should have\n * been written using relative module paths.....\n */\n let modules = Object.assign({\n 'dcp-build': {\"version\":\"1f4eab51b277cbfe9ca6f36a756f726820c55208\",\"branch\":\"develop\",\"dcpClient\":{\"version\":\"4.3.0\",\"resolved\":\"git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-client.git#026d4e0b62a4ad4f7ec70096c72ee5e2650d056f\",\"overridden\":false},\"built\":\"Wed Oct 11 2023 10:25:53 GMT-0400 (Eastern Daylight Saving Time)\",\"config\":{\"generated\":\"Wed 11 Oct 2023 10:25:52 AM EDT by erose on lorge\",\"build\":\"debug\"},\"webpack\":\"5.88.2\",\"node\":\"v18.17.1\"},\n 'dcp-xhr': __webpack_require__(/*! ../common/dcp-xhr */ \"./src/common/dcp-xhr.js\"),\n 'dcp-env': __webpack_require__(/*! ../common/dcp-env */ \"./src/common/dcp-env.js\"),\n 'dcp-url': __webpack_require__(/*! ../common/dcp-url */ \"./src/common/dcp-url.js\"),\n 'cli': __webpack_require__(/*! ../common/cli */ \"./src/common/cli.js\"),\n 'dcp-timers': __webpack_require__(/*! ../common/dcp-timers */ \"./src/common/dcp-timers.js\"),\n 'dcp-dot-dir': __webpack_require__(/*! ../common/dcp-dot-dir */ \"./src/common/dcp-dot-dir.js\"),\n 'dcp-assert': __webpack_require__(/*! ../common/dcp-assert */ \"./src/common/dcp-assert.js\"),\n 'dcp-events': __webpack_require__(/*! ../common/dcp-events */ \"./src/common/dcp-events/index.js\"),\n 'utils': __webpack_require__(/*! ../utils */ \"./src/utils/index.js\"),\n 'debugging': __webpack_require__(/*! ../debugging */ \"./src/debugging.js\"),\n 'publish': __webpack_require__(/*! ../common/dcp-publish */ \"./src/common/dcp-publish.js\"),\n 'compute-groups': {\n ...__webpack_require__(/*! ./compute-groups */ \"./src/dcp-client/compute-groups/index.js\"),\n publicGroupOpaqueId: (__webpack_require__(/*! ../common/scheduler-constants */ \"./src/common/scheduler-constants.js\").computeGroups[\"public\"].opaqueId),\n },\n 'bank-util': __webpack_require__(/*! ./bank-util */ \"./src/dcp-client/bank-util.js\"),\n 'protocol-v4': __webpack_require__(/*! ../protocol-v4 */ \"./src/protocol-v4/index.js\"), /* deprecated */\n 'client-modal': __webpack_require__(/*! ./client-modal */ \"./src/dcp-client/client-modal/index.js\"),\n 'eth': __webpack_require__(/*! ./wallet/eth */ \"./src/dcp-client/wallet/eth.js\"),\n 'serialize': __webpack_require__(/*! ../utils/serialize */ \"./src/utils/serialize.js\"),\n 'kvin': __webpack_require__(/*! kvin */ \"./node_modules/kvin/kvin.js\"),\n 'job': __webpack_require__(/*! ./job */ \"./src/dcp-client/job/index.js\"),\n 'range-object': __webpack_require__(/*! ./range-object */ \"./src/dcp-client/range-object.js\"),\n 'stats-ranges': __webpack_require__(/*! ./stats-ranges */ \"./src/dcp-client/stats-ranges.js\"),\n 'job-values': __webpack_require__(/*! ./job-values */ \"./src/dcp-client/job-values.js\"),\n 'signal-handler': __webpack_require__(/*! ../node-libs/signal-handler */ \"./src/node-libs/signal-handler.js\"),\n 'standard-objects': {}\n }, officialApi);\n\n /* Export the JS Standard Classes (etc) from the global object of the bundle evaluation context,\n * in case we have code somewhere that needs to use these for instanceof checks.\n */\n ;[ Object, Function, Boolean, Symbol,\n Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError,\n Number, Math, Date,\n String, RegExp,\n Array, Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array,\n Map, Set, WeakMap, WeakSet,\n ArrayBuffer, DataView, JSON,\n Promise, \n Reflect, Proxy, Intl, WebAssembly, __webpack_require__\n ].forEach(function (obj) {\n if (obj.name && (typeof obj === 'function' || typeof obj === 'object'))\n modules['standard-objects'][obj.name] = obj\n })\n\n /* Export the constructors used by object literals and boxing objects. Usually these are the same as\n * the standard objects, but not always -- evaluation environments like node vm contexts can have\n * different standard objects supplied via the sandboxing object than the engine uses internally.\n */\n modules['engine-constructors'] = {\n Object: ({}).constructor,\n Array: ([]).constructor,\n Number: (0).constructor,\n String: ('').constructor,\n Boolean: (false).constructor,\n Function: (()=>1).constructor,\n };\n\n if (typeof BigInt !== 'undefined')\n {\n modules['standard-objects']['BigInt'] === BigInt;\n modules['engine-constructors'].BigInt = (0n).constructor;\n }\n if (typeof BigInt64Array !== 'undefined')\n modules['standard-objects']['BigInt64Array'] === BigInt64Array;\n if (typeof BigInt64Array !== 'undefined')\n modules['standard-objects']['BigUint64Array'] === BigUint64Array;\n\n module.declare([], function(require, exports, module) {\n Object.assign(exports, modules)\n exports['dcp-config'] = dcpConfig\n exports['dcp-default-config'] = {\"_serializeVerId\":\"v8\",\"what\":{\"ctr\":0,\"ps\":{\"dcp\":{\"ctr\":0,\"ps\":{\"connectionOptions\":{\"ctr\":0,\"ps\":{\"default\":{\"ctr\":0,\"ps\":{\"connectTimeout\":60,\"disconnectTimeout\":900,\"lingerTimeout\":18000,\"identityUnlockTimeout\":300,\"batchWaitTime\":0.03,\"ttl\":{\"raw\":{\"min\":15,\"max\":600,\"default\":120}},\"transports\":{\"arr\":[\"socketio\"]},\"socketio\":{\"raw\":{}}}}}},\"validitySlopValue\":10,\"validityStampCachePurgeInterval\":60,\"maxConnectionTimeout\":300000}},\"worker\":{\"raw\":{}},\"evaluator\":{\"ctr\":0,\"ps\":{\"listen\":{\"ctr\":\"dcpUrl$$DcpURL\",\"ps\":{},\"arg\":\"http://localhost:9000/\"},\"location\":{\"ctr\":\"dcpUrl$$DcpURL\",\"ps\":{},\"arg\":\"http://localhost:9000/\"},\"friendLocation\":{\"seen\":6}}},\"supervisor\":{\"raw\":{\"dcp\":{\"connectionOptions\":{\"default\":{\"identityUnlockTimeout\":900}}},\"tuning\":{\"watchdogInterval\":7,\"minSandboxStartDelay\":0.1,\"maxSandboxStartDelay\":0.7,\"minSandboxSlack\":0.2,\"maxSandboxSlack\":0.5,\"maxSandboxSliceRetries\":1,\"cachedJobsThreshold\":0,\"prefetchInterval\":30,\"pruneFrequency\":30000,\"mustPruneMultiplier\":1.3,\"defaultDelayIncrement\":50,\"maxExtraSandboxes\":8,\"maxResultSubmissionRetries\":3,\"reservedSliceLifetime\":300000},\"repoMan\":{\"frequency\":60000,\"thresholdMultiplier\":2},\"sandbox\":{\"generalTimeout\":6000,\"sliceTimeout\":86400000,\"progressTimeout\":300000,\"progressReportInterval\":1200000,\"maxSandboxUse\":1000},\"pCores\":0}},\"standaloneWorker\":{\"undefined\":true},\"scheduler\":{\"ctr\":0,\"ps\":{\"location\":{\"ctr\":\"dcpUrl$$DcpURL\",\"ps\":{},\"arg\":\"https://scheduler.distributed.computer/\"},\"worker\":{\"ctr\":0,\"ps\":{\"types\":{\"arr\":[\"v4\"]},\"operations\":{\"raw\":\"1.0.0\"}}},\"compatibility\":{\"raw\":{\"minimum\":{\"dcp\":\"^5.0.0\",\"dcp-client\":\"^4.0.0\",\"dcp-worker\":\"^2.1.0\",\"operations\":{\"work\":\"^4.1.0\",\"compute\":\"^1.0.0\",\"bank\":\"^4.0.0\"}},\"exclusions\":{}}}}}}}};\n })\n if (realModuleDeclare)\n module.declare = realModuleDeclare\n\n bundleExports = thisScript.exports = exports; /* must be last expression evaluated! */\n}\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/index.js?");
4328
+ eval("/* module decorator */ module = __webpack_require__.nmd(module);\n/* provided dependency */ var process = __webpack_require__(/*! ./node_modules/process/browser.js */ \"./node_modules/process/browser.js\");\n/**\n * @file dcp-client-bundle-src.js\n * Top-level file which gets webpacked into the bundle consumed by dcp-client 2.5\n * @author Wes Garland, wes@kingsds.network\n * @date July 2019\n */\n\n{\n let thisScript = typeof document !== 'undefined' ? (typeof document.currentScript !== 'undefined' && document.currentScript) || document.getElementById('_dcp_client_bundle') : {}\n let realModuleDeclare\n\n if ( false || typeof module.declare === 'undefined') {\n realModuleDeclare = ( true) ? module.declare : 0\n if (false) {}\n module.declare = function moduleUnWrapper (deps, factory) {\n factory(null, module.exports, module)\n return module.exports\n }\n }\n\n let _debugging = () => false\n if (process.env.DCP_CONFIG_USE_DEPRECATED_FUTURE)\n dcpConfig.future = (__webpack_require__(/*! ../common/config-future.js */ \"./src/common/config-future.js\").futureFactory)(_debugging, dcpConfig);\n\n /* These modules are official API and must be part of DCP Client */\n let officialApi = {\n 'protocol': __webpack_require__(/*! ../protocol-v4 */ \"./src/protocol-v4/index.js\"),\n 'compute': (__webpack_require__(/*! ./compute */ \"./src/dcp-client/compute.js\").compute),\n 'worker': __webpack_require__(/*! ./worker */ \"./src/dcp-client/worker/index.js\"),\n 'wallet': __webpack_require__(/*! ./wallet */ \"./src/dcp-client/wallet/index.js\"),\n };\n\n /* Some of these modules are API-track. Some of them need to be published to be\n * available for top-level resolution by DCP internals. Those (mostly) should have\n * been written using relative module paths.....\n */\n let modules = Object.assign({\n 'dcp-build': {\"version\":\"8a95bd250c03421b473f543c2e9c7a85516d622c\",\"branch\":\"prod-20230922\",\"dcpClient\":{\"version\":\"4.3.0\",\"resolved\":\"git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-client.git#2ba1f35c876d61c52ffec4f5c67f2c5c8449ec5c\",\"overridden\":false},\"built\":\"Tue Sep 26 2023 09:10:57 GMT-0400 (Eastern Daylight Saving Time)\",\"config\":{\"generated\":\"Tue 26 Sep 2023 09:10:56 AM EDT by erose on lorge\",\"build\":\"debug\"},\"webpack\":\"5.88.2\",\"node\":\"v18.17.1\"},\n 'dcp-xhr': __webpack_require__(/*! ../common/dcp-xhr */ \"./src/common/dcp-xhr.js\"),\n 'dcp-env': __webpack_require__(/*! ../common/dcp-env */ \"./src/common/dcp-env.js\"),\n 'dcp-url': __webpack_require__(/*! ../common/dcp-url */ \"./src/common/dcp-url.js\"),\n 'cli': __webpack_require__(/*! ../common/cli */ \"./src/common/cli.js\"),\n 'dcp-timers': __webpack_require__(/*! ../common/dcp-timers */ \"./src/common/dcp-timers.js\"),\n 'dcp-dot-dir': __webpack_require__(/*! ../common/dcp-dot-dir */ \"./src/common/dcp-dot-dir.js\"),\n 'dcp-assert': __webpack_require__(/*! ../common/dcp-assert */ \"./src/common/dcp-assert.js\"),\n 'dcp-events': __webpack_require__(/*! ../common/dcp-events */ \"./src/common/dcp-events/index.js\"),\n 'utils': __webpack_require__(/*! ../utils */ \"./src/utils/index.js\"),\n 'debugging': __webpack_require__(/*! ../debugging */ \"./src/debugging.js\"),\n 'publish': __webpack_require__(/*! ../common/dcp-publish */ \"./src/common/dcp-publish.js\"),\n 'compute-groups': {\n ...__webpack_require__(/*! ./compute-groups */ \"./src/dcp-client/compute-groups/index.js\"),\n publicGroupOpaqueId: (__webpack_require__(/*! ../common/scheduler-constants */ \"./src/common/scheduler-constants.js\").computeGroups[\"public\"].opaqueId),\n },\n 'bank-util': __webpack_require__(/*! ./bank-util */ \"./src/dcp-client/bank-util.js\"),\n 'protocol-v4': __webpack_require__(/*! ../protocol-v4 */ \"./src/protocol-v4/index.js\"), /* deprecated */\n 'client-modal': __webpack_require__(/*! ./client-modal */ \"./src/dcp-client/client-modal/index.js\"),\n 'eth': __webpack_require__(/*! ./wallet/eth */ \"./src/dcp-client/wallet/eth.js\"),\n 'serialize': __webpack_require__(/*! ../utils/serialize */ \"./src/utils/serialize.js\"),\n 'kvin': __webpack_require__(/*! kvin */ \"./node_modules/kvin/kvin.js\"),\n 'job': __webpack_require__(/*! ./job */ \"./src/dcp-client/job/index.js\"),\n 'range-object': __webpack_require__(/*! ./range-object */ \"./src/dcp-client/range-object.js\"),\n 'stats-ranges': __webpack_require__(/*! ./stats-ranges */ \"./src/dcp-client/stats-ranges.js\"),\n 'job-values': __webpack_require__(/*! ./job-values */ \"./src/dcp-client/job-values.js\"),\n 'signal-handler': __webpack_require__(/*! ../node-libs/signal-handler */ \"./src/node-libs/signal-handler.js\"),\n 'standard-objects': {}\n }, officialApi);\n\n /* Export the JS Standard Classes (etc) from the global object of the bundle evaluation context,\n * in case we have code somewhere that needs to use these for instanceof checks.\n */\n ;[ Object, Function, Boolean, Symbol,\n Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError,\n Number, Math, Date,\n String, RegExp,\n Array, Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array,\n Map, Set, WeakMap, WeakSet,\n ArrayBuffer, DataView, JSON,\n Promise, \n Reflect, Proxy, Intl, WebAssembly, __webpack_require__\n ].forEach(function (obj) {\n if (obj.name && (typeof obj === 'function' || typeof obj === 'object'))\n modules['standard-objects'][obj.name] = obj\n })\n\n /* Export the constructors used by object literals and boxing objects. Usually these are the same as\n * the standard objects, but not always -- evaluation environments like node vm contexts can have\n * different standard objects supplied via the sandboxing object than the engine uses internally.\n */\n modules['engine-constructors'] = {\n Object: ({}).constructor,\n Array: ([]).constructor,\n Number: (0).constructor,\n String: ('').constructor,\n Boolean: (false).constructor,\n Function: (()=>1).constructor,\n };\n\n if (typeof BigInt !== 'undefined')\n {\n modules['standard-objects']['BigInt'] === BigInt;\n modules['engine-constructors'].BigInt = (0n).constructor;\n }\n if (typeof BigInt64Array !== 'undefined')\n modules['standard-objects']['BigInt64Array'] === BigInt64Array;\n if (typeof BigInt64Array !== 'undefined')\n modules['standard-objects']['BigUint64Array'] === BigUint64Array;\n\n module.declare([], function(require, exports, module) {\n Object.assign(exports, modules)\n exports['dcp-config'] = dcpConfig\n exports['dcp-default-config'] = {\"_serializeVerId\":\"v8\",\"what\":{\"ctr\":0,\"ps\":{\"dcp\":{\"ctr\":0,\"ps\":{\"connectionOptions\":{\"ctr\":0,\"ps\":{\"default\":{\"ctr\":0,\"ps\":{\"connectTimeout\":60,\"disconnectTimeout\":900,\"lingerTimeout\":18000,\"identityUnlockTimeout\":300,\"batchWaitTime\":0.03,\"ttl\":{\"raw\":{\"min\":15,\"max\":600,\"default\":120}},\"transports\":{\"arr\":[\"socketio\"]},\"socketio\":{\"raw\":{}}}}}},\"validitySlopValue\":10,\"validityStampCachePurgeInterval\":60,\"maxConnectionTimeout\":300000}},\"worker\":{\"raw\":{}},\"evaluator\":{\"ctr\":0,\"ps\":{\"listen\":{\"ctr\":\"dcpUrl$$DcpURL\",\"ps\":{},\"arg\":\"http://localhost:9000/\"},\"location\":{\"ctr\":\"dcpUrl$$DcpURL\",\"ps\":{},\"arg\":\"http://localhost:9000/\"},\"friendLocation\":{\"seen\":6}}},\"supervisor\":{\"raw\":{\"dcp\":{\"connectionOptions\":{\"default\":{\"identityUnlockTimeout\":900}}},\"tuning\":{\"watchdogInterval\":7,\"minSandboxStartDelay\":0.1,\"maxSandboxStartDelay\":0.7,\"minSandboxSlack\":0.2,\"maxSandboxSlack\":0.5,\"maxSandboxSliceRetries\":1,\"cachedJobsThreshold\":0,\"prefetchInterval\":30,\"pruneFrequency\":30000,\"mustPruneMultiplier\":1.3,\"defaultDelayIncrement\":50,\"maxExtraSandboxes\":8,\"maxResultSubmissionRetries\":3,\"reservedSliceLifetime\":300000},\"repoMan\":{\"frequency\":60000,\"thresholdMultiplier\":2},\"sandbox\":{\"generalTimeout\":6000,\"sliceTimeout\":86400000,\"progressTimeout\":300000,\"progressReportInterval\":1200000,\"maxSandboxUse\":1000},\"pCores\":0}},\"standaloneWorker\":{\"undefined\":true},\"scheduler\":{\"ctr\":0,\"ps\":{\"location\":{\"ctr\":\"dcpUrl$$DcpURL\",\"ps\":{},\"arg\":\"https://scheduler.distributed.computer/\"},\"worker\":{\"ctr\":0,\"ps\":{\"types\":{\"arr\":[\"v4\"]},\"operations\":{\"raw\":\"1.0.0\"}}},\"compatibility\":{\"raw\":{\"minimum\":{\"dcp\":\"^5.0.0\",\"dcp-client\":\"^4.0.0\",\"dcp-worker\":\"^2.1.0\",\"operations\":{\"work\":\"^4.1.0\",\"compute\":\"^1.0.0\",\"bank\":\"^4.0.0\"}},\"exclusions\":{}}}}}}}};\n })\n if (realModuleDeclare)\n module.declare = realModuleDeclare\n\n bundleExports = thisScript.exports = exports; /* must be last expression evaluated! */\n}\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/index.js?");
4329
4329
 
4330
4330
  /***/ }),
4331
4331
 
@@ -4397,7 +4397,7 @@ eval("/**\n * @file job/upload-slices.js\n * @author Ryan Saweczko,
4397
4397
  \****************************************/
4398
4398
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4399
4399
 
4400
- eval("/**\n * @file range-object.js\n * @author Eddie Roosenmaallen, eddie@kingsds.network\n * Matthew Palma, mpalma@kingsds.network\n * Robert Mirandola, robert@kingsds.network\n * @date October 2018\n * July 2022\n * This module exports classes and methods for working with RangeObjects\n *\n * RangeObject:\n * new RangeObject(start, end[, step[, group]])\n * new RangeObject({ start, end[, step[, group]] })\n * new RangeObject('[object RangeObject {start},{end},{step},{group}]')\n *\n * In the first two forms, step and group are optional, defaulting to 1. In the string form, all paramteres are required\n *\n *\n * Methods:\n * toString() Returns a string descriptor, suitable to pass to a new constructor\n * toObject() Returns a vanilla ES object with the four parameters as properties\n * toArray() Resolve all values from the RangeObject, grouping if group > 1, as an array\n * nthValue(n) Look up a single value/group\n * slice([start[, end]]) Resolve a selection of values from start to end (exclusive).\n * Same semantics as Array.prototype.slice, including negative indexes\n * materialize(now) Resolve all values and store as an array (eg. for random distributions)\n *\n * Properties:\n * length Return the total number of values (or groups, if group > 1) generasted by the RangeObject\n * dist Name of the distributor function\n * values If present, the Distribution has been materialized\n * materializeOnScheduler If present and truthy, the distribution will be materialized on the scheduler before\n * instantiating tasks\n *\n * Examples:\n * bob = new RangeObject(1, 10)\n * bob.toArray() // [1,2,3,4,5,6,7,8,9,10]\n * bob.slice(-2) // [9,10]\n * fred = new RangeObject({ start:1, end: 1000, step: 3})\n * fred.toArray() // [1,4,7 (...) 994, 997, 1000]\n * fred.toObject() // { start: 1, end: 1000, step: 3, group: 1}\n * bill = new RO.RangeObject(0, 999, 3, 3)\n * rangeobject.js?1541083657962:42 Uncaught RangeError: Range must be divisible evenly into groups\n * at new RangeObject (rangeobject.js?1541083657962:42)\n * at <anonymous>:1:8\n * bill = new RO.RangeObject(0, 998, 3, 3)\n * bill.toArray() // [[0, 3, 6] (...), [990, 993, 996]]\n *\n * MultiRangeObject:\n * new MultiRangeObject(rol1, rol2, ... roln)\n * new MultiRangeObject([rol1, rol2, ... roln])\n * Each argument is either a RangeObject, an Array-like object (, or a Distribution object? NYI ~ER). The\n * values generated by the MRO will be a multi-dimentional array, where each element of the array is a vector\n * across all input ranges.\n */\n\n\n/**\n * @typedef {object} RangeLike\n * @property {number} start\n * @property {number} end\n * @property {number} nthValue\n */\n\n// Some utility functions to make validating the parameters easier\nconst assert = (premise, msg) => {\n if (!premise) throw new Error(msg);\n}\n\nconst assertNumeric = (val, msg) => {\n assert(typeof val === 'number', msg);\n assert(!Number.isNaN(val), msg);\n assert(Number.isFinite(val), msg);\n}\n\nconst RANGEOBJ_REGEX = /^\\[object RangeObject (-?\\d+(?:\\.\\d+)?),(-?\\d+(?:\\.\\d+)?),(-?\\d+(?:\\.\\d+)?),(\\d+|undefined)\\]$/;\n\n/** \n * Defines a consistent interface for each of the range object types\n * to inherit from, provides some array methods.\n * @access public\n */\nclass SuperRangeObject {\n constructor() {\n return new Proxy(this, {\n get: (target, name) => {\n if ((typeof name === 'string' || typeof name === 'number') && Number.isInteger(parseFloat(name))) {\n return target.nthValue(parseFloat(name));\n } else {\n return target[name];\n }\n }\n });\n }\n\n [Symbol.iterator]() {\n let index = 0;\n\n return {\n next: () => ({ value: this.nthValue(index++), done: index > this.length })\n };\n }\n\n get length() {\n return 0;\n }\n\n nthValue(n) {\n throw new Error(\"nthValue not overridden\");\n }\n\n toArray() {\n return this.slice()\n }\n\n /**\n * Generate array from range starting at value `start` and ending at value `end` via `nthValue`.\n * @param {number} [start=0] index to start slice\n * @param {number} [end] index to end slice, return rest of array if not provided.\n * @access public\n */\n slice(start, end) {\n if (typeof start === 'undefined') { start = 0 } else if (start < 0) { start += this.length }\n\n if (typeof end === 'undefined') { end = this.length } else if (end < 0) { end += (this.length) }\n\n if (end > this.length) { end = this.length }\n\n const arr = []\n for (let i = start; i < end; i++) { arr.push(this.nthValue(i)) }\n\n return arr\n }\n\n /**\n * Converts range to an Array and then calls `filter(...args)` on it.\n * @param {...any} args Same args as you would pass to Array#filter\n * @access public\n */\n filter(...args) {\n return this.toArray().filter(...args);\n }\n}\n\n/**\n * Range objects are vanilla ES objects used to describe value range sets for use by `compute.for()`.\n * The range must be increasing, i.e. `start` must be less than `end`.\n * Calculations made to derive the set of numbers in a range are carried out with `BigNumber`, \n * eg. arbitrary-precision, support. The numbers `Infinity` and `-Infinity` are not supported, and \n * the API does not differentiate between `+0` and `-0`.\n */\n/**\n * An object which represents a range of values.\n * @param {number|object} startOrObject Beginning of range, or object literal with `start` and `end` properties.\n * @param {number} end End of range\n * @param {number} [step=1] Step size in range\n * @param {number|undefined} [group] Groups in range\n * @access public\n * @extends SuperRangeObject\n * @example <caption>With implicit step size = 1.</caption>\n * let rangeObject = new RangeObject(0.5,3);\n * rangeObject.toArray();\n * // [ 0.5, 1.5, 2.5 ]\n * \n * @example <caption>With explicit step size.</caption>\n * let rangeObject = new RangeObject(1,9,3);\n * rangeObject.toArray();\n * // [ 1, 4, 7 ]\n * \n * @example <caption>With grouping.</caption>\n * let rangeObject = new RangeObject(1,9,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7 ] ]\n */\nclass RangeObject extends SuperRangeObject {\n \n constructor (start, end, step, group) {\n super();\n if (typeof start === 'string' && start.match(RANGEOBJ_REGEX)) {\n const parts = start.match(RANGEOBJ_REGEX)\n start = {\n start: parseFloat(parts[1]),\n end: parseFloat(parts[2]),\n step: parseFloat(parts[3]),\n group: (parts[4] === 'undefined'? undefined : parseFloat(parts[4]))\n }\n }\n\n if (typeof start === 'object') {\n this.start = start.start;\n this.end = start.end;\n this.step = start.step;\n this.group = start.group;\n } else {\n this.start = start;\n this.end = end;\n this.step = step;\n this.group = group;\n }\n\n assertNumeric(this.start, `Invalid start parameter \"${this.start}\", must be numeric and finite.`);\n assertNumeric(this.end, `Invalid end parameter \"${this.end}\", must be numeric and finite.`);\n\n // Ensure step moves in the correct direction for start-end (ie, negative if end < start)\n if (typeof this.step === 'undefined') {\n this.step = Math.sign(this.end - this.start);\n } else {\n assertNumeric(this.step, `Invalid step parameter \"${this.step}\", must be numeric and finite.`);\n if ((this.step === 0 && this.start !== this.end) || Math.sign(this.step) !== Math.sign(this.end - this.start)) {\n throw new Error('RangeObject step must approach end from start.');\n }\n }\n\n if (typeof this.group !== 'undefined') {\n // group must remain undefined if not provided because no grouping should occur if not provided.\n // As per spec, even if group is 1 it should group into arrays of 1 element\n assertNumeric(this.group, `Invalid group parameter \"${this.group}\", must be numeric and finite.`);\n assert(Number.isInteger(this.group), `Invalid group parameter \"${this.group}\", must be an integer.`);\n assert(this.group > 0, `Invalid group parameter \"${this.group}\", must be greater than zero.`);\n }\n }\n\n /**\n * @returns {boolean}\n */\n static isRangelike (r) {\n if (r instanceof RangeObject) { return true }\n if (typeof r === 'object' &&\n typeof r.start === 'number' &&\n typeof r.end === 'number' &&\n typeof r.nthValue === 'function') { return true }\n\n return false\n }\n\n /**\n * @returns {boolean}\n */\n static isRangeObject(r) {\n if (r instanceof RangeObject) { return true }\n\n return false\n }\n\n /**\n * Test whether a value can be passed to the RangeObject constructor\n * @param r Value to test\n * @param strict Optional. Truthy to disallow objects which already look Rangelike\n */\n static isProtoRangelike (r, strict = true) {\n if (typeof r === 'object' &&\n typeof r.start === 'number' &&\n typeof r.end === 'number') { return true }\n\n if (typeof r === 'string' &&\n r.match(RANGEOBJ_REGEX)) { return true }\n\n if (!strict && RangeObject.isRangelike(r)) { return true }\n\n return false\n }\n\n /**\n * Create string representation of range: [object RangeObject start,end,step,group]\n * @access public\n */\n toString () {\n return `[object RangeObject ${this.start},${this.end},${this.step},${this.group}]`\n }\n\n /**\n * Create object literal for range with properties: start, end, step, and group.\n * @access public\n */\n toObject () {\n return {\n start: this.start,\n end: this.end,\n step: this.step,\n group: this.group\n }\n }\n\n /**\n * Return nth value in range\n * @param {number} n\n * @access public\n * @example\n * let rangeObject = new RangeObject(1,10,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7, 10 ] ]\n * rangeObject.nthValue(1);\n * // [ 7, 10 ]\n */\n nthValue(n) {\n /**\n * `>=` since the value at index 7 in an array that's of length 7 is outside\n * its range\n */\n if (n < 0 || n >= this.length) {\n return undefined;\n }\n\n if (typeof this.group !== 'undefined') {\n const start = (this.group * this.step * n) + this.start\n const arr = []\n\n for (let i = 0; i < this.group && i + this.group * n < this.stepCount; i++) {\n arr.push(start + (i * this.step))\n }\n\n return arr;\n }\n\n return this.start + (n * this.step);\n }\n\n /**\n * Return max value in range\n * @access public\n * @returns {number}\n * @example\n * let rangeObject = new RangeObject(1,10,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7, 10 ] ]\n * rangeObject.max;\n * // 10\n */\n get max () {\n if (typeof this.group === 'undefined' && this.step === 1) { return this.end }\n\n let tail\n if (typeof this.group === 'undefined') {\n [ tail ] = this.slice(-1)\n } else {\n [ tail ] = this.slice(-1)[0].slice(-1)\n }\n return tail\n }\n\n /**\n * Boolean indicating whether all groups are filled.\n * Only defined for RangeObjects that group results.\n * @access public\n * @returns {boolean}\n * @example <caption>With remainder</caption>\n * let rangeObject = new RangeObject(1,9,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7 ] ]\n * rangeObject.hasRemainder;\n * // true\n * @example <caption>Without remainder</caption>\n * let rangeObject = new RangeObject(1,10,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7, 10 ] ]\n * rangeObject.hasRemainder;\n * // true\n */\n get hasRemainder () {\n if (typeof this.group === 'undefined') { return false }\n const groups = this.stepCount / this.group;\n\n return (groups !== Math.floor(groups));\n }\n\n /**\n * Number of elements in range, or number of groups if grouped.\n * @access public\n * @returns {number}\n * @example <caption>Without grouping</caption>\n * let rangeObject = new RangeObject(1,10,3);\n * rangeObject.toArray();\n * // [ 1, 4, 7, 10 ]\n * rangeObject.length;\n * // 4\n * @example <caption>With grouping</caption>\n * let rangeObject = new RangeObject(1,9,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7 ] ]\n * rangeObject.length;\n * // 2\n */\n get length () {\n return Math.ceil(this.stepCount / (this.group || 1));\n }\n\n /**\n * Number of steps in range (sort of like number of elements, except grouping is no longer relevant).\n * @access public\n * @returns {number}\n * @example <caption>Without grouping</caption>\n * let rangeObject = new RangeObject(1,10,3);\n * rangeObject.toArray();\n * // [ 1, 4, 7, 10 ]\n * rangeObject.stepCount;\n * // 4\n * @example <caption>With grouping</caption>\n * let rangeObject = new RangeObject(1,9,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7 ] ]\n * rangeObject.length;\n * // 3\n */\n get stepCount () {\n if (this.step === 0) return 1;\n return Math.floor(Math.abs((this.end - this.start) / this.step)) + 1;\n }\n}\n\n/**\n * A sparse range object contains many {@link RangeObject}s. The range objects are stored as arrays and then are\n * concatenated into one array in the order that they were supplied to the constructor.\n * @param {RangeObject|RangeObject[]|object} arg - First range object, or array of range objects, or object with `sparse` key containing an array of range objects.\n * @param {RangeObject} rangeObject - If first argument is a RangeObject, subsquent arguments are range objects too.\n * @access public\n * @extends SuperRangeObject\n * @example\n * r0 = new RangeObject(1,2)\n * r1 = new RangeObject(1,3)\n * sro = new SparseRangeObject(r0, r1)\n * // [ 1, 2, 1, 2, 3]\n */\nclass SparseRangeObject extends SuperRangeObject {\n constructor() {\n super();\n let sparse = [];\n\n if (arguments.length === 1 && arguments[0].ranges) \n sparse = [...arguments[0].ranges];\n else \n sparse = [...arguments];\n \n if (sparse instanceof SparseRangeObject)\n throw new Error('Argument is of type sparse range object');\n \n // If sparse key is passed, make sure the arguments are only the range objects (compute.for() implementation) \n if (sparse[0].sparse)\n sparse = sparse[0].sparse;\n \n sparse.map( r =>\n {\n if (!RangeObject.isProtoRangelike(r))\n throw new Error('Argument is not of type RangeObject');\n })\n \n if (sparse[0].group)\n {\n for (let i = 0; i < sparse.length; i++)\n {\n if (sparse[i].group !== sparse[0].group)\n throw new Error('Range Object has different dimension than other range objects');\n }\n } \n \n this.sparse = true;\n this.ranges = sparse.map(r => \n { \n return new RangeObject(r);\n })\n \n }\n \n /**\n * Test whether a value can be passed to the SparseRangeObject constructor\n * @param r Value to test\n * @param strict Optional. Truthy to disallow objects which already look Rangelike\n */\n static isProtoSparseRangelike (r, strict = true) \n {\n if (typeof r === 'object' && r.sparse) { return true; }\n return false;\n }\n \n /**\n * Return nth value in range\n * @param {number} n\n * @access public\n * @example\n * let sparseRangeObject = new SparseRangeObject(1,3,1);\n * rangeObject.toArray();\n * // [ 1, 2, 3]\n * rangeObject.nthValue(1);\n * // 2\n */\n nthValue(n) \n {\n if (n < 0 || n >= this.length) { return undefined }\n \n let count = 0;\n let rangeCount = 0;\n while (count !== n)\n {\n if (count <= n)\n {\n for (let i = 0; i < this.ranges[rangeCount].length; i++)\n {\n if (count === n)\n return this.ranges[rangeCount][i];\n else\n count++;\n }\n }\n rangeCount++;\n }\n return this.ranges[rangeCount][0];\n }\n \n /**\n * Create object literal with `sparse` property and `range` property containing array of range objects.\n */\n toObject () {\n \n const obj = {\n sparse: true,\n ranges: this.ranges\n }\n return obj;\n }\n \n get length()\n {\n let len = 0;\n this.ranges.forEach((r) => len += r.length);\n\n return len;\n }\n \n}\n\n/**\n * Range objects are vanilla ES objects used to describe value range sets for use by `compute.for()`. \n * Calculations made to derive the set of numbers in a range are carried out with `BigNumber`, \n * eg. arbitrary-precision, support. The numbers `Infinity` and `-Infinity` are not supported, and \n * the API does not differentiate between `+0` and `-0`.\n */\nclass MultiRangeObject extends SuperRangeObject {\n /**\n * A multi-range object contains many {@link RangeObject}s. They are iterated over \n * with the fastest moving index going over the right-most range object in array order. Each element\n * of a multi range is a tuple of values from constituent ranges.\n * @param {RangeObject|RangeObject[]|object} arg - First range object, or array of range objects, or object with `ranges` key containing an array of range objects.\n * @param {RangeObject} rangeObject - If first argument is a RangeObject, subsquent arguments are range objects too.\n * @access public\n * @extends SuperRangeObject\n * @example\n * r0 = new RangeObject(1,2)\n * r1 = new RangeObject(1,3)\n * mro = new MultiRangeObject(r0, r1)\n * mro.toArray()\n * // [ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 2, 1 ], [ 2, 2 ], [ 2, 3 ] ]\n */\n constructor () {\n super();\n var ranges = []\n\n if (arguments.length === 1 && typeof arguments[0] === 'string') {\n const inputs = JSON.parse(arguments[0])\n if (Array.isArray(inputs)) {\n ranges = inputs\n } else if (inputs.ranges) {\n ranges = inputs.ranges\n } else {\n ranges = [inputs]\n }\n } else if (arguments.length === 1 && Array.isArray(arguments[0])) {\n ranges = [...arguments[0]]\n } else if (arguments.length === 1 && !!arguments[0].ranges) {\n ranges = [...arguments[0].ranges]\n } else {\n ranges = [...arguments]\n }\n\n this.ranges = ranges.map(r => {\n if (RangeObject.isRangelike(r)) { return r }\n if (RangeObject.isRangeObject(r)) { return r }\n if (DistributionRange.isDistribution(r)) { return r }\n if (RangeObject.isProtoRangelike(r)) { return new RangeObject(r) }\n if (DistributionRange.isProtoDistribution(r)) { return new DistributionRange(r) }\n\n return Array.isArray(r) ? r : [r]\n })\n }\n\n /**\n * Test whether a value can be passed to the MultiRangeObject constructor\n * @param r Value to test\n * @param strict Optional. Truthy to disallow objects which already look Rangelike\n */\n static isProtoMultiRangelike (r, strict = true) {\n if ((typeof r === 'object') &&\n Array.isArray(r.ranges) &&\n !r.sparse)\n {\n return true;\n }\n\n return false\n }\n\n /**\n * Create string representation of this MultiRangeObject\n * @access public\n * @example\n * \"[object MultiRangeObject ' + this.ranges.length + ']\"\n */\n toString () {\n return '[object MultiRangeObject ' + this.ranges.length + ']'\n }\n\n /**\n * Create object literal with `ranges` property containing array of range objects.\n */\n toObject () {\n return { ranges: this.ranges }\n }\n\n /**\n * Returns a tuple of values from the ranges given by this multi range object.\n * @param {number} n index of multi-range tuple to return\n * @access public\n * @example\n * r0 = new RangeObject(1,2)\n * r1 = new RangeObject(1,3)\n * mro = new MultiRangeObject(r0, r1)\n * mro.toArray()\n * // [ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 2, 1 ], [ 2, 2 ], [ 2, 3 ] ]\n * mro.nthValue(2)\n * // [ 1, 3 ]\n */\n nthValue (n) {\n if (n < 0 || n >= this.length) { return undefined }\n\n const indexes = []\n\n for (let r = (this.ranges.length - 1); r >= 0; r--) {\n const idx = n % this.ranges[r].length\n\n indexes.unshift(idx)\n\n n -= idx\n n /= this.ranges[r].length\n }\n\n const values = []\n\n for (let i = 0; i < indexes.length; i++) {\n values[i] = Array.isArray(this.ranges[i]) ? this.ranges[i][indexes[i]] : this.ranges[i].nthValue(indexes[i])\n }\n\n return values\n }\n\n /**\n * Boolean indicating whether any of the ranges in this multi-range object has a remainder. See {@link RangeObject#hasRemainder}.\n * @access public\n * @returns {boolean}\n */\n get hasRemainder () {\n for (let r of this.ranges) {\n if (r.hasRemainder) { return true }\n }\n\n return false\n }\n\n get length () {\n let len = 1\n\n this.ranges.forEach((r) => len *= r.length)\n\n return len\n }\n}\n\n// DistributionRange object wraps a distributing function into a RangeObject-like API\n// which can be dropped directly into a MultiRangeObject to generate input slices\nclass DistributionRange extends SuperRangeObject {\n constructor (n, dist, ...params) {\n super();\n\n this.distributor = (__webpack_require__(/*! ./stats-ranges */ \"./src/dcp-client/stats-ranges.js\").distributor);\n\n // If argv[0] is a string formatted as DistributionRange.toString(), then unpack it\n if (typeof n === 'string' && n.match(/^\\[object DistributionRange (\\w+?)\\((\\d+?)(?:,(.+?))?\\)\\]$/)) {\n const parts = n.match(/^\\[object DistributionRange (\\w+?)\\((\\d+?)(?:,(.+?))?\\)\\]$/)\n dist = parts[1]\n n = parseInt(parts[2])\n params = (parts[3] || '').split(',').map(e => parseFloat(e))\n }\n\n // If argv[0] is a string describing a DistributionRange, then unpack it\n if (typeof n === 'string' && n.match(/^(\\w+?)\\((\\d+?)(?:,(.+?))?\\)$/)) {\n const parts = n.match(/^(\\w+?)\\((\\d+?)(?:,(.+?))?\\)$/)\n dist = parts[1]\n n = parseInt(parts[2])\n params = (parts[3] || '').split(',').map(e => parseFloat(e))\n }\n\n // If argv[0] is a object of the right shape, then unpack it\n if (typeof n === 'object' &&\n typeof n.length === 'number' &&\n typeof n.dist === 'string' &&\n Array.isArray(n.params)) {\n // console.log('Unpacking proto-object', n)\n dist = n.dist\n params = n.params\n n = n.length\n if (Array.isArray(n.values)) { this.values = n.values }\n if (typeof n.materializeOnScheduler === 'boolean') { this.materializeOnScheduler = n.materializeOnScheduler }\n }\n\n Object.defineProperty(this, 'length', {\n value: n,\n enumerable: true\n })\n Object.defineProperty(this, 'dist', {\n value: dist,\n enumerable: true\n })\n Object.defineProperty(this, 'params', {\n value: params || [],\n enumerable: true\n })\n\n if (typeof this.distributor[dist] !== 'function') {\n // console.log({n,dist,params})\n throw new TypeError('dist param must point to an exported distributing function')\n }\n }\n\n /**\n * @returns {boolean}\n */\n static isDistribution (d) {\n return d instanceof DistributionRange\n }\n\n static isDistributionLike (d) {\n if (DistributionRange.isDistribution(d)) { return true }\n if (typeof d === 'object' &&\n typeof d.nthValue === 'function' &&\n typeof d.slice === 'function') { return true }\n\n return false\n }\n\n static isProtoDistribution (d) {\n if (typeof d === 'string' && d.match(/^\\[object DistributionRange (\\w+?)\\((\\d+?)(?:,(.+?))?\\)\\]$/)) { return true }\n if (typeof d === 'string' && d.match(/^(\\w+?)\\((\\d+?)(?:,(.+?))?\\)$/)) { return true }\n if (typeof d === 'object' &&\n typeof d.length === 'number' &&\n typeof d.dist === 'string' &&\n Array.isArray(d.params)) { return true }\n\n return false\n }\n\n toString () {\n return `[object DistributionRange ${this.dist}(${[this.length, ...this.params].join()})]`\n }\n\n toObject () {\n this.materialize();\n return {\n length: this.length,\n dist: this.dist,\n params: this.params,\n materializeOnScheduler: this.materializeOnScheduler || undefined,\n values: this.values || undefined\n }\n }\n\n nthValue (n) {\n if (n < 0 || n >= this.length) { return undefined }\n\n if (this.values) { return this.values[n] }\n\n const fn = this.distributor[this.dist]\n\n if (typeof fn === 'function') { return fn.apply(fn, [n, this.length, ...this.params]) }\n\n return undefined\n }\n\n /** Resolve the distribution to a static array\n * @param now If false, then set a flag to materialize on the scheduler. Default: materialize now\n */\n materialize (now = true) {\n if (now === false) { return this.materializeOnScheduler = true }\n\n this.values = this.toArray()\n }\n}\n\n/** Rehydrate an input range from a vanilla ES5 object to an appropriate rangelike object\n * @param obj Serialized job.data object (or JSON string)\n * @return as appropriate, a RangeObject, DistributionRange, MultiRangeObject, or array\n */\nfunction rehydrateRange (obj) {\n const { RemoteDataPattern } = __webpack_require__(/*! dcp/dcp-client/remote-data-pattern */ \"./src/dcp-client/remote-data-pattern.js\");\n const { RemoteDataSet } = __webpack_require__(/*! dcp/dcp-client/remote-data-set */ \"./src/dcp-client/remote-data-set.js\");\n\n if (typeof obj === 'string') {\n obj = JSON.parse(obj)\n }\n\n if (typeof obj === 'number') {\n return obj\n }\n\n if (obj instanceof RangeObject ||\n obj instanceof SparseRangeObject ||\n obj instanceof MultiRangeObject ||\n obj instanceof RemoteDataSet ||\n obj instanceof RemoteDataPattern ||\n obj instanceof DistributionRange) {\n return obj;\n }\n\n // If obj looks like a RemoteDataSet, make one of those\n if (RemoteDataSet.isProtoRemoteDataSetLike(obj)) {\n return new RemoteDataSet(obj)\n }\n \n // If obj looks like a RemoteDataPattern, make one of those\n if (RemoteDataPattern.isProtoRemoteDataPatternLike(obj)) {\n return new RemoteDataPattern(obj.pattern, obj.sliceCount)\n }\n\n // If obj is an iterable, coerce it to an array\n if (Symbol.iterator in Object(obj)) {\n return Array.from(obj)\n }\n \n // If obj looks like a SparseRangeObject, make one of those\n if (SparseRangeObject.isProtoSparseRangelike(obj))\n return new SparseRangeObject(obj);\n\n // If obj looks like a MultiRangeObject, make one of those\n if (MultiRangeObject.isProtoMultiRangelike(obj)) {\n return new MultiRangeObject(obj)\n }\n\n // If obj looks rangelike, make a RangeObject\n if (RangeObject.isProtoRangelike(obj)) {\n return new RangeObject(obj)\n }\n\n // If obj looks like a proto-distribution, make a DistributionRange\n if (DistributionRange.isProtoDistribution(obj)) {\n return new DistributionRange(obj)\n }\n\n throw new TypeError(`obj cannot be cast to any supported Rangelike object: ${JSON.stringify(obj)}`)\n}\n\nexports.SuperRangeObject = SuperRangeObject;\nexports.RangeObject = RangeObject;\nexports.MultiRangeObject = MultiRangeObject;\nexports.DistributionRange = DistributionRange;\nexports.SparseRangeObject = SparseRangeObject;\nexports.rehydrateRange = rehydrateRange;\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/range-object.js?");
4400
+ eval("/**\n * @file range-object.js\n * @author Eddie Roosenmaallen, eddie@kingsds.network\n * Matthew Palma, mpalma@kingsds.network\n * Robert Mirandola, robert@kingsds.network\n * @date October 2018\n * July 2022\n * This module exports classes and methods for working with RangeObjects\n *\n * RangeObject:\n * new RangeObject(start, end[, step[, group]])\n * new RangeObject({ start, end[, step[, group]] })\n * new RangeObject('[object RangeObject {start},{end},{step},{group}]')\n *\n * In the first two forms, step and group are optional, defaulting to 1. In the string form, all paramteres are required\n *\n *\n * Methods:\n * toString() Returns a string descriptor, suitable to pass to a new constructor\n * toObject() Returns a vanilla ES object with the four parameters as properties\n * toArray() Resolve all values from the RangeObject, grouping if group > 1, as an array\n * nthValue(n) Look up a single value/group\n * slice([start[, end]]) Resolve a selection of values from start to end (exclusive).\n * Same semantics as Array.prototype.slice, including negative indexes\n * materialize(now) Resolve all values and store as an array (eg. for random distributions)\n *\n * Properties:\n * length Return the total number of values (or groups, if group > 1) generasted by the RangeObject\n * dist Name of the distributor function\n * values If present, the Distribution has been materialized\n * materializeOnScheduler If present and truthy, the distribution will be materialized on the scheduler before\n * instantiating tasks\n *\n * Examples:\n * bob = new RangeObject(1, 10)\n * bob.toArray() // [1,2,3,4,5,6,7,8,9,10]\n * bob.slice(-2) // [9,10]\n * fred = new RangeObject({ start:1, end: 1000, step: 3})\n * fred.toArray() // [1,4,7 (...) 994, 997, 1000]\n * fred.toObject() // { start: 1, end: 1000, step: 3, group: 1}\n * bill = new RO.RangeObject(0, 999, 3, 3)\n * rangeobject.js?1541083657962:42 Uncaught RangeError: Range must be divisible evenly into groups\n * at new RangeObject (rangeobject.js?1541083657962:42)\n * at <anonymous>:1:8\n * bill = new RO.RangeObject(0, 998, 3, 3)\n * bill.toArray() // [[0, 3, 6] (...), [990, 993, 996]]\n *\n * MultiRangeObject:\n * new MultiRangeObject(rol1, rol2, ... roln)\n * new MultiRangeObject([rol1, rol2, ... roln])\n * Each argument is either a RangeObject, an Array-like object (, or a Distribution object? NYI ~ER). The\n * values generated by the MRO will be a multi-dimentional array, where each element of the array is a vector\n * across all input ranges.\n */\n\n\n/**\n * @typedef {object} RangeLike\n * @property {number} start\n * @property {number} end\n * @property {number} nthValue\n */\n\n// Some utility functions to make validating the parameters easier\nconst assert = (premise, msg) => {\n if (!premise) throw new Error(msg);\n}\n\nconst assertNumeric = (val, msg) => {\n assert(typeof val === 'number', msg);\n assert(!Number.isNaN(val), msg);\n assert(Number.isFinite(val), msg);\n}\n\nconst RANGEOBJ_REGEX = /^\\[object RangeObject (-?\\d+(?:\\.\\d+)?),(-?\\d+(?:\\.\\d+)?),(-?\\d+(?:\\.\\d+)?),(\\d+|undefined)\\]$/;\n\n/** \n * Defines a consistent interface for each of the range object types\n * to inherit from, provides some array methods.\n * @access public\n */\nclass SuperRangeObject {\n constructor() {\n return new Proxy(this, {\n get: (target, name) => {\n if ((typeof name === 'string' || typeof name === 'number') && Number.isInteger(parseFloat(name))) {\n return target.nthValue(parseFloat(name));\n } else {\n return target[name];\n }\n }\n });\n }\n\n [Symbol.iterator]() {\n let index = 0;\n\n return {\n next: () => ({ value: this.nthValue(index++), done: index > this.length })\n };\n }\n\n get length() {\n return 0;\n }\n\n nthValue(n) {\n throw new Error(\"nthValue not overridden\");\n }\n\n toArray() {\n return this.slice()\n }\n\n /**\n * Generate array from range starting at value `start` and ending at value `end` via `nthValue`.\n * @param {number} [start=0] index to start slice\n * @param {number} [end] index to end slice, return rest of array if not provided.\n * @access public\n */\n slice(start, end) {\n if (typeof start === 'undefined') { start = 0 } else if (start < 0) { start += this.length }\n\n if (typeof end === 'undefined') { end = this.length } else if (end < 0) { end += (this.length) }\n\n if (end > this.length) { end = this.length }\n\n const arr = []\n for (let i = start; i < end; i++) { arr.push(this.nthValue(i)) }\n\n return arr\n }\n\n /**\n * Converts range to an Array and then calls `filter(...args)` on it.\n * @param {...any} args Same args as you would pass to Array#filter\n * @access public\n */\n filter(...args) {\n return this.toArray().filter(...args);\n }\n}\n\n/**\n * Range objects are vanilla ES objects used to describe value range sets for use by `compute.for()`.\n * The range must be increasing, i.e. `start` must be less than `end`.\n * Calculations made to derive the set of numbers in a range are carried out with `BigNumber`, \n * eg. arbitrary-precision, support. The numbers `Infinity` and `-Infinity` are not supported, and \n * the API does not differentiate between `+0` and `-0`.\n */\n/**\n * An object which represents a range of values.\n * @param {number|object} startOrObject Beginning of range, or object literal with `start` and `end` properties.\n * @param {number} end End of range\n * @param {number} [step=1] Step size in range\n * @param {number|undefined} [group] Groups in range\n * @access public\n * @extends SuperRangeObject\n * @example <caption>With implicit step size = 1.</caption>\n * let rangeObject = new RangeObject(0.5,3);\n * rangeObject.toArray();\n * // [ 0.5, 1.5, 2.5 ]\n * \n * @example <caption>With explicit step size.</caption>\n * let rangeObject = new RangeObject(1,9,3);\n * rangeObject.toArray();\n * // [ 1, 4, 7 ]\n * \n * @example <caption>With grouping.</caption>\n * let rangeObject = new RangeObject(1,9,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7 ] ]\n */\nclass RangeObject extends SuperRangeObject {\n \n constructor (start, end, step, group) {\n super();\n if (typeof start === 'string' && start.match(RANGEOBJ_REGEX)) {\n const parts = start.match(RANGEOBJ_REGEX)\n start = {\n start: parseFloat(parts[1]),\n end: parseFloat(parts[2]),\n step: parseFloat(parts[3]),\n group: (parts[4] === 'undefined'? undefined : parseFloat(parts[4]))\n }\n }\n\n if (typeof start === 'object') {\n this.start = start.start;\n this.end = start.end;\n this.step = start.step;\n this.group = start.group;\n } else {\n this.start = start;\n this.end = end;\n this.step = step;\n this.group = group;\n }\n\n assertNumeric(this.start, `Invalid start parameter \"${this.start}\", must be numeric and finite.`);\n assertNumeric(this.end, `Invalid end parameter \"${this.end}\", must be numeric and finite.`);\n\n // Ensure step moves in the correct direction for start-end (ie, negative if end < start)\n if (typeof this.step === 'undefined') {\n this.step = Math.sign(this.end - this.start);\n } else {\n assertNumeric(this.step, `Invalid step parameter \"${this.step}\", must be numeric and finite.`);\n if ((this.step === 0 && this.start !== this.end) || Math.sign(this.step) !== Math.sign(this.end - this.start)) {\n throw new Error('RangeObject step must approach end from start.');\n }\n }\n\n if (typeof this.group !== 'undefined') {\n // group must remain undefined if not provided because no grouping should occur if not provided.\n // As per spec, even if group is 1 it should group into arrays of 1 element\n assertNumeric(this.group, `Invalid group parameter \"${this.group}\", must be numeric and finite.`);\n assert(Number.isInteger(this.group), `Invalid group parameter \"${this.group}\", must be an integer.`);\n assert(this.group > 0, `Invalid group parameter \"${this.group}\", must be greater than zero.`);\n }\n }\n\n /**\n * @returns {boolean}\n */\n static isRangelike (r) {\n if (r instanceof RangeObject) { return true }\n if (typeof r === 'object' &&\n typeof r.start === 'number' &&\n typeof r.end === 'number' &&\n typeof r.nthValue === 'function') { return true }\n\n return false\n }\n\n /**\n * @returns {boolean}\n */\n static isRangeObject(r) {\n if (r instanceof RangeObject) { return true }\n\n return false\n }\n\n /**\n * Test whether a value can be passed to the RangeObject constructor\n * @param r Value to test\n * @param strict Optional. Truthy to disallow objects which already look Rangelike\n */\n static isProtoRangelike (r, strict = true) {\n if (typeof r === 'object' &&\n typeof r.start === 'number' &&\n typeof r.end === 'number') { return true }\n\n if (typeof r === 'string' &&\n r.match(RANGEOBJ_REGEX)) { return true }\n\n if (!strict && RangeObject.isRangelike(r)) { return true }\n\n return false\n }\n\n /**\n * Create string representation of range: [object RangeObject start,end,step,group]\n * @access public\n */\n toString () {\n return `[object RangeObject ${this.start},${this.end},${this.step},${this.group}]`\n }\n\n /**\n * Create object literal for range with properties: start, end, step, and group.\n * @access public\n */\n toObject () {\n return {\n start: this.start,\n end: this.end,\n step: this.step,\n group: this.group\n }\n }\n\n /**\n * Return nth value in range\n * @param {number} n\n * @access public\n * @example\n * let rangeObject = new RangeObject(1,10,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7, 10 ] ]\n * rangeObject.nthValue(1);\n * // [ 7, 10 ]\n */\n nthValue(n) {\n /**\n * `>=` since the value at index 7 in an array that's of length 7 is outside\n * its range\n */\n if (n < 0 || n >= this.length) {\n return undefined;\n }\n\n if (typeof this.group !== 'undefined') {\n const start = (this.group * this.step * n) + this.start\n const arr = []\n\n for (let i = 0; i < this.group && i + this.group * n < this.stepCount; i++) {\n arr.push(start + (i * this.step))\n }\n\n return arr;\n }\n\n return this.start + (n * this.step);\n }\n\n /**\n * Return max value in range\n * @access public\n * @returns {number}\n * @example\n * let rangeObject = new RangeObject(1,10,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7, 10 ] ]\n * rangeObject.max;\n * // 10\n */\n get max () {\n if (typeof this.group === 'undefined' && this.step === 1) { return this.end }\n\n let tail\n if (typeof this.group === 'undefined') {\n [ tail ] = this.slice(-1)\n } else {\n [ tail ] = this.slice(-1)[0].slice(-1)\n }\n return tail\n }\n\n /**\n * Boolean indicating whether all groups are filled.\n * Only defined for RangeObjects that group results.\n * @access public\n * @returns {boolean}\n * @example <caption>With remainder</caption>\n * let rangeObject = new RangeObject(1,9,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7 ] ]\n * rangeObject.hasRemainder;\n * // true\n * @example <caption>Without remainder</caption>\n * let rangeObject = new RangeObject(1,10,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7, 10 ] ]\n * rangeObject.hasRemainder;\n * // true\n */\n get hasRemainder () {\n if (typeof this.group === 'undefined') { return false }\n const groups = this.stepCount / this.group;\n\n return (groups !== Math.floor(groups));\n }\n\n /**\n * Number of elements in range, or number of groups if grouped.\n * @access public\n * @returns {number}\n * @example <caption>Without grouping</caption>\n * let rangeObject = new RangeObject(1,10,3);\n * rangeObject.toArray();\n * // [ 1, 4, 7, 10 ]\n * rangeObject.length;\n * // 4\n * @example <caption>With grouping</caption>\n * let rangeObject = new RangeObject(1,9,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7 ] ]\n * rangeObject.length;\n * // 2\n */\n get length () {\n return Math.ceil(this.stepCount / (this.group || 1));\n }\n\n /**\n * Number of steps in range (sort of like number of elements, except grouping is no longer relevant).\n * @access public\n * @returns {number}\n * @example <caption>Without grouping</caption>\n * let rangeObject = new RangeObject(1,10,3);\n * rangeObject.toArray();\n * // [ 1, 4, 7, 10 ]\n * rangeObject.stepCount;\n * // 4\n * @example <caption>With grouping</caption>\n * let rangeObject = new RangeObject(1,9,3,2);\n * rangeObject.toArray();\n * // [ [ 1, 4 ], [ 7 ] ]\n * rangeObject.length;\n * // 3\n */\n get stepCount () {\n if (this.step === 0) return 1;\n return Math.floor(Math.abs((this.end - this.start) / this.step)) + 1;\n }\n}\n\n/**\n * A sparse range object contains many {@link RangeObject}s. The range objects are stored as arrays and then are\n * concatenated into one array in the order that they were supplied to the constructor.\n * @param {RangeObject|RangeObject[]|object} arg - First range object, or array of range objects, or object with `sparse` key containing an array of range objects.\n * @param {RangeObject} rangeObject - If first argument is a RangeObject, subsquent arguments are range objects too.\n * @access public\n * @extends SuperRangeObject\n * @example\n * r0 = new RangeObject(1,2)\n * r1 = new RangeObject(1,3)\n * sro = new SparseRangeObject(r0, r1)\n * // [ 1, 2, 1, 2, 3]\n */\nclass SparseRangeObject extends SuperRangeObject {\n constructor() {\n super();\n let sparse = [];\n\n if (arguments.length === 1 && arguments[0].ranges) \n sparse = [...arguments[0].ranges];\n else \n sparse = [...arguments[0]];\n \n if (sparse instanceof SparseRangeObject)\n throw new Error('Argument is of type sparse range object');\n \n // If sparse key is passed, make sure the arguments are only the range objects (compute.for() implementation) \n if (sparse[0].sparse)\n sparse = sparse[0].sparse;\n \n sparse.map( r =>\n {\n if (!RangeObject.isProtoRangelike(r))\n throw new Error('Argument is not of type RangeObject');\n })\n \n if (sparse[0].group)\n {\n for (let i = 0; i < sparse.length; i++)\n {\n if (sparse[i].group !== sparse[0].group)\n throw new Error('Range Object has different dimension than other range objects');\n }\n } \n \n this.sparse = true;\n this.ranges = sparse.map(r => \n { \n return new RangeObject(r);\n })\n \n }\n \n /**\n * Test whether a value can be passed to the SparseRangeObject constructor\n * @param r Value to test\n * @param strict Optional. Truthy to disallow objects which already look Rangelike\n */\n static isProtoSparseRangelike (r, strict = true) \n {\n if (typeof r === 'object' && r.sparse) { return true; }\n return false;\n }\n \n /**\n * Return nth value in range\n * @param {number} n\n * @access public\n * @example\n * let sparseRangeObject = new SparseRangeObject(1,3,1);\n * rangeObject.toArray();\n * // [ 1, 2, 3]\n * rangeObject.nthValue(1);\n * // 2\n */\n nthValue(n) \n {\n if (n < 0 || n >= this.length) { return undefined }\n \n let count = 0;\n let rangeCount = 0;\n while (count !== n)\n {\n if (count <= n)\n {\n for (let i = 0; i < this.ranges[rangeCount].length; i++)\n {\n if (count === n)\n return this.ranges[rangeCount][i];\n else\n count++;\n }\n }\n rangeCount++;\n }\n return this.ranges[rangeCount][0];\n }\n \n /**\n * Create object literal with `sparse` property and `range` property containing array of range objects.\n */\n toObject () {\n \n const obj = {\n sparse: true,\n ranges: this.ranges\n }\n return obj;\n }\n \n get length()\n {\n let len = 0;\n this.ranges.forEach((r) => len += r.length);\n\n return len;\n }\n \n}\n\n/**\n * Range objects are vanilla ES objects used to describe value range sets for use by `compute.for()`. \n * Calculations made to derive the set of numbers in a range are carried out with `BigNumber`, \n * eg. arbitrary-precision, support. The numbers `Infinity` and `-Infinity` are not supported, and \n * the API does not differentiate between `+0` and `-0`.\n */\nclass MultiRangeObject extends SuperRangeObject {\n /**\n * A multi-range object contains many {@link RangeObject}s. They are iterated over \n * with the fastest moving index going over the right-most range object in array order. Each element\n * of a multi range is a tuple of values from constituent ranges.\n * @param {RangeObject|RangeObject[]|object} arg - First range object, or array of range objects, or object with `ranges` key containing an array of range objects.\n * @param {RangeObject} rangeObject - If first argument is a RangeObject, subsquent arguments are range objects too.\n * @access public\n * @extends SuperRangeObject\n * @example\n * r0 = new RangeObject(1,2)\n * r1 = new RangeObject(1,3)\n * mro = new MultiRangeObject(r0, r1)\n * mro.toArray()\n * // [ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 2, 1 ], [ 2, 2 ], [ 2, 3 ] ]\n */\n constructor () {\n super();\n var ranges = []\n\n if (arguments.length === 1 && typeof arguments[0] === 'string') {\n const inputs = JSON.parse(arguments[0])\n if (Array.isArray(inputs)) {\n ranges = inputs\n } else if (inputs.ranges) {\n ranges = inputs.ranges\n } else {\n ranges = [inputs]\n }\n } else if (arguments.length === 1 && Array.isArray(arguments[0])) {\n ranges = [...arguments[0]]\n } else if (arguments.length === 1 && !!arguments[0].ranges) {\n ranges = [...arguments[0].ranges]\n } else {\n ranges = [...arguments]\n }\n\n this.ranges = ranges.map(r => {\n if (RangeObject.isRangelike(r)) { return r }\n if (RangeObject.isRangeObject(r)) { return r }\n if (DistributionRange.isDistribution(r)) { return r }\n if (RangeObject.isProtoRangelike(r)) { return new RangeObject(r) }\n if (DistributionRange.isProtoDistribution(r)) { return new DistributionRange(r) }\n\n return Array.isArray(r) ? r : [r]\n })\n }\n\n /**\n * Test whether a value can be passed to the MultiRangeObject constructor\n * @param r Value to test\n * @param strict Optional. Truthy to disallow objects which already look Rangelike\n */\n static isProtoMultiRangelike (r, strict = true) {\n if ((typeof r === 'object') &&\n Array.isArray(r.ranges) &&\n !r.sparse)\n {\n return true;\n }\n\n return false\n }\n\n /**\n * Create string representation of this MultiRangeObject\n * @access public\n * @example\n * \"[object MultiRangeObject ' + this.ranges.length + ']\"\n */\n toString () {\n return '[object MultiRangeObject ' + this.ranges.length + ']'\n }\n\n /**\n * Create object literal with `ranges` property containing array of range objects.\n */\n toObject () {\n return { ranges: this.ranges }\n }\n\n /**\n * Returns a tuple of values from the ranges given by this multi range object.\n * @param {number} n index of multi-range tuple to return\n * @access public\n * @example\n * r0 = new RangeObject(1,2)\n * r1 = new RangeObject(1,3)\n * mro = new MultiRangeObject(r0, r1)\n * mro.toArray()\n * // [ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 2, 1 ], [ 2, 2 ], [ 2, 3 ] ]\n * mro.nthValue(2)\n * // [ 1, 3 ]\n */\n nthValue (n) {\n if (n < 0 || n >= this.length) { return undefined }\n\n const indexes = []\n\n for (let r = (this.ranges.length - 1); r >= 0; r--) {\n const idx = n % this.ranges[r].length\n\n indexes.unshift(idx)\n\n n -= idx\n n /= this.ranges[r].length\n }\n\n const values = []\n\n for (let i = 0; i < indexes.length; i++) {\n values[i] = Array.isArray(this.ranges[i]) ? this.ranges[i][indexes[i]] : this.ranges[i].nthValue(indexes[i])\n }\n\n return values\n }\n\n /**\n * Boolean indicating whether any of the ranges in this multi-range object has a remainder. See {@link RangeObject#hasRemainder}.\n * @access public\n * @returns {boolean}\n */\n get hasRemainder () {\n for (let r of this.ranges) {\n if (r.hasRemainder) { return true }\n }\n\n return false\n }\n\n get length () {\n let len = 1\n\n this.ranges.forEach((r) => len *= r.length)\n\n return len\n }\n}\n\n// DistributionRange object wraps a distributing function into a RangeObject-like API\n// which can be dropped directly into a MultiRangeObject to generate input slices\nclass DistributionRange extends SuperRangeObject {\n constructor (n, dist, ...params) {\n super();\n\n this.distributor = (__webpack_require__(/*! ./stats-ranges */ \"./src/dcp-client/stats-ranges.js\").distributor);\n\n // If argv[0] is a string formatted as DistributionRange.toString(), then unpack it\n if (typeof n === 'string' && n.match(/^\\[object DistributionRange (\\w+?)\\((\\d+?)(?:,(.+?))?\\)\\]$/)) {\n const parts = n.match(/^\\[object DistributionRange (\\w+?)\\((\\d+?)(?:,(.+?))?\\)\\]$/)\n dist = parts[1]\n n = parseInt(parts[2])\n params = (parts[3] || '').split(',').map(e => parseFloat(e))\n }\n\n // If argv[0] is a string describing a DistributionRange, then unpack it\n if (typeof n === 'string' && n.match(/^(\\w+?)\\((\\d+?)(?:,(.+?))?\\)$/)) {\n const parts = n.match(/^(\\w+?)\\((\\d+?)(?:,(.+?))?\\)$/)\n dist = parts[1]\n n = parseInt(parts[2])\n params = (parts[3] || '').split(',').map(e => parseFloat(e))\n }\n\n // If argv[0] is a object of the right shape, then unpack it\n if (typeof n === 'object' &&\n typeof n.length === 'number' &&\n typeof n.dist === 'string' &&\n Array.isArray(n.params)) {\n // console.log('Unpacking proto-object', n)\n dist = n.dist\n params = n.params\n n = n.length\n if (Array.isArray(n.values)) { this.values = n.values }\n if (typeof n.materializeOnScheduler === 'boolean') { this.materializeOnScheduler = n.materializeOnScheduler }\n }\n\n Object.defineProperty(this, 'length', {\n value: n,\n enumerable: true\n })\n Object.defineProperty(this, 'dist', {\n value: dist,\n enumerable: true\n })\n Object.defineProperty(this, 'params', {\n value: params || [],\n enumerable: true\n })\n\n if (typeof this.distributor[dist] !== 'function') {\n // console.log({n,dist,params})\n throw new TypeError('dist param must point to an exported distributing function')\n }\n }\n\n /**\n * @returns {boolean}\n */\n static isDistribution (d) {\n return d instanceof DistributionRange\n }\n\n static isDistributionLike (d) {\n if (DistributionRange.isDistribution(d)) { return true }\n if (typeof d === 'object' &&\n typeof d.nthValue === 'function' &&\n typeof d.slice === 'function') { return true }\n\n return false\n }\n\n static isProtoDistribution (d) {\n if (typeof d === 'string' && d.match(/^\\[object DistributionRange (\\w+?)\\((\\d+?)(?:,(.+?))?\\)\\]$/)) { return true }\n if (typeof d === 'string' && d.match(/^(\\w+?)\\((\\d+?)(?:,(.+?))?\\)$/)) { return true }\n if (typeof d === 'object' &&\n typeof d.length === 'number' &&\n typeof d.dist === 'string' &&\n Array.isArray(d.params)) { return true }\n\n return false\n }\n\n toString () {\n return `[object DistributionRange ${this.dist}(${[this.length, ...this.params].join()})]`\n }\n\n toObject () {\n this.materialize();\n return {\n length: this.length,\n dist: this.dist,\n params: this.params,\n materializeOnScheduler: this.materializeOnScheduler || undefined,\n values: this.values || undefined\n }\n }\n\n nthValue (n) {\n if (n < 0 || n >= this.length) { return undefined }\n\n if (this.values) { return this.values[n] }\n\n const fn = this.distributor[this.dist]\n\n if (typeof fn === 'function') { return fn.apply(fn, [n, this.length, ...this.params]) }\n\n return undefined\n }\n\n /** Resolve the distribution to a static array\n * @param now If false, then set a flag to materialize on the scheduler. Default: materialize now\n */\n materialize (now = true) {\n if (now === false) { return this.materializeOnScheduler = true }\n\n this.values = this.toArray()\n }\n}\n\n/** Rehydrate an input range from a vanilla ES5 object to an appropriate rangelike object\n * @param obj Serialized job.data object (or JSON string)\n * @return as appropriate, a RangeObject, DistributionRange, MultiRangeObject, or array\n */\nfunction rehydrateRange (obj) {\n const { RemoteDataPattern } = __webpack_require__(/*! dcp/dcp-client/remote-data-pattern */ \"./src/dcp-client/remote-data-pattern.js\");\n const { RemoteDataSet } = __webpack_require__(/*! dcp/dcp-client/remote-data-set */ \"./src/dcp-client/remote-data-set.js\");\n\n if (typeof obj === 'string') {\n obj = JSON.parse(obj)\n }\n\n if (typeof obj === 'number') {\n return obj\n }\n\n if (obj instanceof RangeObject ||\n obj instanceof SparseRangeObject ||\n obj instanceof MultiRangeObject ||\n obj instanceof RemoteDataSet ||\n obj instanceof RemoteDataPattern ||\n obj instanceof DistributionRange) {\n return obj;\n }\n\n // If obj looks like a RemoteDataSet, make one of those\n if (RemoteDataSet.isProtoRemoteDataSetLike(obj)) {\n return new RemoteDataSet(obj)\n }\n \n // If obj looks like a RemoteDataPattern, make one of those\n if (RemoteDataPattern.isProtoRemoteDataPatternLike(obj)) {\n return new RemoteDataPattern(obj.pattern, obj.sliceCount)\n }\n\n // If obj is an iterable, coerce it to an array\n if (Symbol.iterator in Object(obj)) {\n return Array.from(obj)\n }\n \n // If obj looks like a SparseRangeObject, make one of those\n if (SparseRangeObject.isProtoSparseRangelike(obj))\n return new SparseRangeObject(obj);\n\n // If obj looks like a MultiRangeObject, make one of those\n if (MultiRangeObject.isProtoMultiRangelike(obj)) {\n return new MultiRangeObject(obj)\n }\n\n // If obj looks rangelike, make a RangeObject\n if (RangeObject.isProtoRangelike(obj)) {\n return new RangeObject(obj)\n }\n\n // If obj looks like a proto-distribution, make a DistributionRange\n if (DistributionRange.isProtoDistribution(obj)) {\n return new DistributionRange(obj)\n }\n\n throw new TypeError(`obj cannot be cast to any supported Rangelike object: ${JSON.stringify(obj)}`)\n}\n\nexports.SuperRangeObject = SuperRangeObject;\nexports.RangeObject = RangeObject;\nexports.MultiRangeObject = MultiRangeObject;\nexports.DistributionRange = DistributionRange;\nexports.SparseRangeObject = SparseRangeObject;\nexports.rehydrateRange = rehydrateRange;\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/range-object.js?");
4401
4401
 
4402
4402
  /***/ }),
4403
4403
 
@@ -4447,7 +4447,7 @@ eval("/* provided dependency */ var process = __webpack_require__(/*! ./node_mod
4447
4447
  \*************************************************/
4448
4448
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
4449
4449
 
4450
- eval("/**\n * @file /src/schedmsg/schedmsg-web.js\n * @author Ryan Rossiter, ryan@kingsds.network\n * @date March 2020\n *\n * This is the SchedMsg implementation for commands that are browser-specific\n * or have browser-specific behaviour.\n */\n\nconst { SchedMsg } = __webpack_require__(/*! ./schedmsg */ \"./src/dcp-client/schedmsg/schedmsg.js\");\n\nclass SchedMsgWeb extends SchedMsg {\n constructor(worker) {\n super(worker);\n\n this.registerHandler('announce', this.onAnnouncement.bind(this));\n this.registerHandler('openPopup', this.onOpenPopup.bind(this));\n this.registerHandler('reload', this.onReload.bind(this));\n }\n\n onAnnouncement({ message }) {\n \n window.alert('DCP Worker Announcement: ' + message);\n\n }\n\n onOpenPopup({ href }) {\n window.open(href);\n }\n\n onReload() {\n const hash = window.location.hash;\n\n let newUrl = window.location.href.replace(/#.*/, '');\n newUrl += (newUrl.indexOf('?') === -1 ? '?' : '&');\n newUrl += 'dcp=1f4eab51b277cbfe9ca6f36a756f726820c55208,' + Date.now() + hash;\n\n window.location.replace(newUrl);\n }\n}\n\nObject.assign(module.exports, {\n SchedMsgWeb\n});\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/schedmsg/schedmsg-web.js?");
4450
+ eval("/**\n * @file /src/schedmsg/schedmsg-web.js\n * @author Ryan Rossiter, ryan@kingsds.network\n * @date March 2020\n *\n * This is the SchedMsg implementation for commands that are browser-specific\n * or have browser-specific behaviour.\n */\n\nconst { SchedMsg } = __webpack_require__(/*! ./schedmsg */ \"./src/dcp-client/schedmsg/schedmsg.js\");\n\nclass SchedMsgWeb extends SchedMsg {\n constructor(worker) {\n super(worker);\n\n this.registerHandler('announce', this.onAnnouncement.bind(this));\n this.registerHandler('openPopup', this.onOpenPopup.bind(this));\n this.registerHandler('reload', this.onReload.bind(this));\n }\n\n onAnnouncement({ message }) {\n \n window.alert('DCP Worker Announcement: ' + message);\n\n }\n\n onOpenPopup({ href }) {\n window.open(href);\n }\n\n onReload() {\n const hash = window.location.hash;\n\n let newUrl = window.location.href.replace(/#.*/, '');\n newUrl += (newUrl.indexOf('?') === -1 ? '?' : '&');\n newUrl += 'dcp=8a95bd250c03421b473f543c2e9c7a85516d622c,' + Date.now() + hash;\n\n window.location.replace(newUrl);\n }\n}\n\nObject.assign(module.exports, {\n SchedMsgWeb\n});\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/schedmsg/schedmsg-web.js?");
4451
4451
 
4452
4452
  /***/ }),
4453
4453
 
@@ -4573,7 +4573,7 @@ eval("\n/**\n * @file dcp/src/dcp-client/worker/SupShared.js\n *\n * Code shared
4573
4573
  \*****************************************************/
4574
4574
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4575
4575
 
4576
- eval("/**\n * @file evaluators/browser.js\n * Library which implements a browser-based DCP Evaluator. This evaluator\n * uses Web Workers to implement the base evaluator, and passes messages into\n * the worker via the postMessage/onMessage interface. The sandbox code is\n * loaded from the evaluator via the importScripts() mechanism. That mechanism\n * is disabled by the sandbox before the sandbox runs any untrusted code from\n * the Supervisor.\n *\n * @author Andrew Fryer, andrewf@kingsds.networka\n * Wes Garland, wes@kingsds.network\n * @date Aug 2020, Mar 2021\n */\n\nconst { DcpURL } = __webpack_require__(/*! dcp/common/dcp-url */ \"./src/common/dcp-url.js\");\n\nexports.sandboxSetupDefs = __webpack_require__(/*! dcp-client/generated/sandbox-definitions.json */ \"./node_modules/dcp-client/generated/sandbox-definitions.json\").browser;\n\n/**\n * Generate the list of URLs that must be fetched by the Web Worker instance in order for it \n * to become a Sandbox that the Supervisor can talk to.\n *\n * The sandbox code is defined by the current dcp-client package, which is a dependency of dcp;\n * when this file is built into the dcp-client package, the file list is entrained in the\n * webpack bundle and used here, unless overridden in exports.sandboxSetupDefs.\n *\n * The sandboxSetupDefs contains a list of strings. Each string is a dependency, and they\n * represent scripts which must be run in order.\n *\n * If the dependency string contains a '/' character, the dependency is treated as a module in an\n * NPM package; this means that we can require.resolve() it to find its location authoritatively.\n *\n * If the dependency string does not contain a '/' character, the dependency is assumed to be\n * located in the require.resolve('dcp-client/libexec/sandbox') directory.\n *\n * Note: we fake require.resolve here by using knowledge of DCP web servers' file layouts, since\n * there is no good way to do that from inside webpack in web browser. Any third-party\n * serving up a custom worker will need to either have the same uri path->filesystem \n * mapping, or they will need to monkey-patch this function.\n */\nexports.generateSandboxURLs = function browserEvaluator$$generateSandboxURLs() {\n const { currentScript } = document;\n var urls = [];\n var baseHref = currentScript ? new DcpURL(currentScript.src).origin : dcpConfig.scheduler.location.origin;\n var baseUrl = new DcpURL(baseHref);\n\n for (let def of exports.sandboxSetupDefs) {\n if (def.match(/\\//))\n urls.push(baseUrl.resolve(def)); \n else\n urls.push(baseUrl.resolve('dcp-client/libexec/sandbox/' + def + '.js'))\n }\n\n return urls;\n}\n\n/**\n * Instantiate a new Web Worker which will execute the sandbox startup code,\n * creating a DCP Evaluator.\n */\nexports.BrowserEvaluator = function BrowserEvaluator(_options) {\n var options = Object.assign({}, _options);\n var urls = exports.generateSandboxURLs();\n\n if (typeof Worker === 'undefined') {\n throw new Error(\"Can't instantiate a browser evaluator, `Worker` is not defined.\");\n }\n\n /* Create a script fragment which knows how to fetch the code to start the sandbox, and send it to the Web Worker\n * (evaluator). Which pieces of JavaScript to fetch from the server via importScripts() is determined from \n * generateSandboxURLs(), which in turn comes from the DCP Worker code which was embedded in this webpack bundle.\n */\n\n // Cache busting\n if (dcpConfig.build === 'debug')\n urls = urls.map(url => url + '?' + Date.now());\n\n const initSandboxCode = `importScripts(${urls.map(script => '\"' + script + '\"').join()})`;\n const blob = window.URL.createObjectURL(new Blob([initSandboxCode], { type: 'application/javascript' }));\n return new Worker(blob, options);\n};\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/worker/evaluators/browser.js?");
4576
+ eval("/**\n * @file evaluators/browser.js\n * Library which implements a browser-based DCP Evaluator. This evaluator\n * uses Web Workers to implement the base evaluator, and passes messages into\n * the worker via the postMessage/onMessage interface. The sandbox code is\n * loaded from the evaluator via the importScripts() mechanism. That mechanism\n * is disabled by the sandbox before the sandbox runs any untrusted code from\n * the Supervisor.\n *\n * @author Andrew Fryer, andrewf@kingsds.networka\n * Wes Garland, wes@kingsds.network\n * @date Aug 2020, Mar 2021\n */\n\nconst { DcpURL } = __webpack_require__(/*! dcp/common/dcp-url */ \"./src/common/dcp-url.js\");\n\nexports.sandboxSetupDefs = __webpack_require__(/*! dcp-client/generated/sandbox-definitions.json */ \"./node_modules/dcp-client/generated/sandbox-definitions.json\").browser;\n\n/**\n * Generate the list of URLs that must be fetched by the Web Worker instance in order for it \n * to become a Sandbox that the Supervisor can talk to.\n *\n * The sandbox code is defined by the current dcp-client package, which is a dependency of dcp;\n * when this file is built into the dcp-client package, the file list is entrained in the\n * webpack bundle and used here, unless overridden in exports.sandboxSetupDefs.\n *\n * The sandboxSetupDefs contains a list of strings. Each string is a dependency, and they\n * represent scripts which must be run in order.\n *\n * If the dependency string contains a '/' character, the dependency is treated as a module in an\n * NPM package; this means that we can require.resolve() it to find its location authoritatively.\n *\n * If the dependency string does not contain a '/' character, the dependency is assumed to be\n * located in the require.resolve('dcp-client/libexec/sandbox') directory.\n *\n * Note: we fake require.resolve here by using knowledge of DCP web servers' file layouts, since\n * there is no good way to do that from inside webpack in web browser. Any third-party\n * serving up a custom worker will need to either have the same uri path->filesystem \n * mapping, or they will need to monkey-patch this function.\n */\nexports.generateSandboxURLs = function browserEvaluator$$generateSandboxURLs() {\n const { currentScript } = document;\n var urls = [];\n var baseHref = currentScript ? new DcpURL(currentScript.src).origin : dcpConfig.portal.location.origin;\n var baseUrl = new DcpURL(baseHref);\n\n for (let def of exports.sandboxSetupDefs) {\n if (def.match(/\\//))\n urls.push(baseUrl.resolve(def)); \n else\n urls.push(baseUrl.resolve('dcp-client/libexec/sandbox/' + def + '.js'))\n }\n\n return urls;\n}\n\n/**\n * Instantiate a new Web Worker which will execute the sandbox startup code,\n * creating a DCP Evaluator.\n */\nexports.BrowserEvaluator = function BrowserEvaluator(_options) {\n var options = Object.assign({}, _options);\n var urls = exports.generateSandboxURLs();\n\n if (typeof Worker === 'undefined') {\n throw new Error(\"Can't instantiate a browser evaluator, `Worker` is not defined.\");\n }\n\n /* Create a script fragment which knows how to fetch the code to start the sandbox, and send it to the Web Worker\n * (evaluator). Which pieces of JavaScript to fetch from the server via importScripts() is determined from \n * generateSandboxURLs(), which in turn comes from the DCP Worker code which was embedded in this webpack bundle.\n */\n\n // Cache busting\n if (dcpConfig.build === 'debug')\n urls = urls.map(url => url + '?' + Date.now());\n\n const initSandboxCode = `importScripts(${urls.map(script => '\"' + script + '\"').join()})`;\n const blob = window.URL.createObjectURL(new Blob([initSandboxCode], { type: 'application/javascript' }));\n return new Worker(blob, options);\n};\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/worker/evaluators/browser.js?");
4577
4577
 
4578
4578
  /***/ }),
4579
4579
 
@@ -4798,7 +4798,7 @@ eval("/**\n * @file dcp/src/dcp-client/worker/supervisor2/rolling-statistics.js\
4798
4798
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4799
4799
 
4800
4800
  "use strict";
4801
- eval("/**\n * @file dcp/src/dcp-client/worker/supervisor2/sandbox2.js\n *\n * A sandbox that when constructed and assigned can do work for\n * a distributed slice. A sandbox runs for a single slice at a time.\n *\n * Usage (simplified...):\n * const sandbox = new Sandbox(this, { ...this.options.sandboxOptions });\n * await sandbox.start();\n * sandbox.slice = slice;\n * await sandbox.assign(jobManager);\n * return sandbox.work()\n * .then((result) => {\n * slice.collectResult(result, true);\n * sandbox.checkSandboxReUse();\n * this.supervisor.recordResult(slice)\n * })\n * .catch((error) => {\n * slice.collectResult(error, false);\n * const reason = this.supervisor.handleSandboxWorkError(sandbox, slice, error);\n * this.supervisor.returnSlice(slice, reason);\n * this.returnSandbox(sandbox);\n * });\n *\n * Debug flags:\n * Sandbox.debugWork = true // - turns off 30 second timeout to let user debug sandbox innards more easily\n * Sandbox.debugState = true // - logs all state transitions for this sandbox\n * Sandbox.debugEvents = true // - logs all events received from the sandbox\n *\n * Initial states:\n * UNREADY\n *\n * Terminal states:\n * TERMINATED\n *\n * Valid transitions:\n * ( sandbox.start )\n * UNREADY -> READYING -> READY_FOR_ASSIGN\n * READYING -> TERMINATED\n * ( sandbox.assign )\n * READY_FOR_ASSIGN -> ASSIGNING -> ASSIGNED\n * ASSIGNING -> TERMINATED\n * ( sandbox.markAsWorking )\n * ASSIGEND -> WORKING\n * ( sandbox.work )\n * WORKING -> ASSIGNED\n * -> TERMINATED\n * ( sandbox.terminate )\n * any -> TERMINATED\n *\n * @author Matthew Palma, mpalma@kingsds.network\n * Ryan Rossiter, ryan@kingsds.network\n * Wes Garland, wes@distributive.network\n * Paul, paul@distributive.network\n * @date May 2019\n * May 2019\n * Decemeber 2020\n * June, Dec 2022, Jan-May 2023\n * @module sandbox\n * @copyright Copyright (c) 2018-2023, Distributive Corp. All Rights Reserved\n */\n// @ts-check\n\n\nconst debugging = (__webpack_require__(/*! dcp/debugging */ \"./src/debugging.js\").scope)('worker');\nconst dcp_timers = __webpack_require__(/*! dcp/common/dcp-timers */ \"./src/common/dcp-timers.js\");\nconst { assert, assertEq3 } = __webpack_require__(/*! dcp/common/dcp-assert */ \"./src/common/dcp-assert.js\");\nconst { Synchronizer } = __webpack_require__(/*! dcp/common/concurrency */ \"./src/common/concurrency.js\");\nconst nanoid = (__webpack_require__(/*! nanoid */ \"./node_modules/nanoid/index.browser.js\").nanoid);\nconst EventEmitter = __webpack_require__(/*! events */ \"./node_modules/events/events.js\");\nconst kvin = __webpack_require__(/*! kvin */ \"./node_modules/kvin/kvin.js\");\nconst common = __webpack_require__(/*! ./common */ \"./src/dcp-client/worker/supervisor2/common.js\");\nconst { selectiveDebug, truncateAddress, timeDilation, selectiveDebug2 } = common;\nconst { stringify } = __webpack_require__(/*! dcp/utils */ \"./src/utils/index.js\");\n\n/**\n * Wraps console.debug to emulate debug module prefixing messages on npm.\n * @param {...any} args\n */\nconst debug = (...args) => {\n if (debugging())\n console.debug('Sandbox:', ...args);\n};\n\n// Sandbox states\nconst UNREADY = 'UNREADY' // No Sandbox (web worker, saworker, etc) has been constructed yet\nconst READYING = 'READYING' // Sandbox is being constructed and environment (bravojs, env) is being set up\nconst READY_FOR_ASSIGN = 'READY_FOR_ASSIGN' // Sandbox is ready to be assigned\nconst ASSIGNED = 'ASSIGNED' // Sandbox is assigned but not working\nconst ASSIGNING = 'ASSIGNING' // Sandbox is in the process of being ASSIGNED\nconst WORKING = 'WORKING' // Sandbox is working\nconst TERMINATED = 'TERMINATED' // Sandbox is terminated.\nconst EVAL_RESULT_PREFIX = 'evalResult::';\n\nclass SandboxError extends Error\n{\n /**\n * @param {string} errorCode\n * @param {string|Error} msg\n */\n constructor(errorCode, msg)\n {\n super((msg.constructor?.name === 'String') ? msg : msg['message']);\n /** @type {string} */\n this.errorCode = errorCode;\n if (msg.constructor?.name !== 'String')\n for (const prop of [ 'name', 'code', 'stack', 'lineNumber', 'columnNumber' ])\n if (msg[prop]) this[prop] = msg[prop];\n }\n}\nclass NoProgressError extends SandboxError { constructor(msg) { super('ENOPROGRESS', msg); } }\nclass SliceTooSlowError extends SandboxError { constructor(msg) { super('ESLICETOOSLOW', msg); } }\nclass UncaughtExceptionError extends SandboxError { constructor(msg) { super('EUNCAUGHT', msg); } }\n\n/** @typedef {import('./slice2').Slice} Slice */\n/** @typedef {import('./config').Config} Config */\n/** @typedef {import('./index').Supervisor} Supervisor */\n/** @typedef {import('./job-manager').JobManager} JobManager */\n/** @typedef {import('./module-cache').ModuleCache} ModuleCache */\n/** @typedef {import('dcp/utils/jsdoc-types').SandboxOptions} SandboxOptions */\n\n/**\n * Public event emitter.\n * https://gitlab.com/Distributed-Compute-Protocol/dcp-docs-wes/-/blob/wip/worker/worker-events.md\n */\nclass SandboxHandle extends EventEmitter\n{\n /** @type {{ id: number, public: { name: string, description: string, link: string }, jobManager: JobManager, slice: Slice }} */\n #info;\n\n /**\n * @constructor\n * @param {Sandbox} sandbox\n */\n constructor (sandbox)\n {\n super({ captureRejections: false });\n this.#info = sandbox.info;\n }\n /** @type {number} */\n get id () { return this.#info.id; }\n /** @type {{ name: string, description: string, link: string }} */\n get public () { return this.#info.public ?? { name: '<unassigned>', description: '', link: '' }; }\n /** @type {string} */\n get jobAddress () { return this.#info.jobManager?.address; }\n /** @type {number} */\n get sliceNumber () { return this.#info.slice?.sliceNumber ?? -1; }\n}\nexports.SandboxHandle = SandboxHandle;\n\n//\n// Index to functionality -- search for '_Idx' to toggle through the index.\n//\n// 1) class Sandbox\n// 2) checkSandboxReUse, postMessageToEvaluator, changeState,\n// and punctuatedTimer is expiremental for replacing hard-coded timeouts.\n// 3) start, describe, assign, applyRequirements, assignEvaluator\n// 4) eval, resetState, work, resetProgressTimeout, resetSliceTimeout\n// 5) handleRing0Message, handleRing1Message, handleRing2Message, handleRing3Message\n// 6) onmessage, onerror, terminate\n// 7) updateTime, resetSliceReport, sandboxEmit, error, warning\n//\n\n// _Idx\n//\n// class Sandbox\n//\n\nclass Sandbox extends EventEmitter\n{\n /**\n * A Sandbox (i.e. a worker sandbox) which executes distributed slices.\n *\n * @constructor\n * @param {Supervisor} supervisor\n * @param {SandboxOptions} options\n */\n constructor (supervisor, options)\n {\n super({ captureRejections: false });\n /** @type {Supervisor} */\n this.supervisor = supervisor;\n /** @type {ModuleCache} */\n this.moduleCache = supervisor.moduleCache;\n /** @type {SandboxOptions} */\n this.options = {\n ignoreNoProgress: false,\n ...options,\n SandboxConstructor: options.SandboxConstructor || (__webpack_require__(/*! ../evaluators */ \"./src/dcp-client/worker/evaluators/index.js\").BrowserEvaluator),\n }\n /** @type {Synchronizer} */\n this.state = new Synchronizer(UNREADY, [ UNREADY, READYING, READY_FOR_ASSIGN, ASSIGNING, ASSIGNED, WORKING, TERMINATED ]);\n\n /** @type {{ id: number, public: { name: string, description: string, link: string }, jobManager: JobManager, slice: Slice }} */\n this.info = {\n id: Sandbox.getNewId(),\n public: null,\n jobManager: null,\n slice: null,\n };\n\n /**\n * Event emitter containing info that describes the sandbox.\n * @type {SandboxHandle}\n */\n this.sandboxHandle = new SandboxHandle(this);\n\n /** Properties of type object. */\n this.evaluatorHandle = null;\n this.capabilities = null;\n this.progressTimeout = null;\n this.sliceTimeout = null;\n this.rejectionData = null;\n\n /** @type {number?} */\n this.progress = 100;\n /** @type {{ last: { deltaMs: number, value: any, throttledReports: number }, lastDeterministic: { deltaMs: number, progress: number, value: any, throttledReports: number } }} */\n this.progressReports = null; // cf. job-noProgress.js\n /** @type {object} */\n this.progressTimeout = null;\n /** @type {object} */\n this.sliceTimeout = null;\n\n /** @type {{ total: number, CPU: number, webGL: number, webGPU: number }} */\n this.sliceTimeReport = null;\n /** @type {number} */\n this.moduleInDataSize = 0; // Sandbox level input size; set during assign, never reset.\n /** @type {number} */\n this.sliceOutDataSize = 0; // Slice level output size; reset for every slice executed.\n\n /** @type {number?} */\n this.sliceStartTime = null;\n /** @type {number} */\n this.useCounter = 1; // Anticipating the initial use.\n /** @type {Config} */\n this.hive = this.supervisor.options;\n\n ///** @type {((data: any) => Promise<void>)[]} */\n this.ringMessageHandlers = [\n this.handleRing0Message,\n this.handleRing1Message,\n this.handleRing2Message,\n this.handleRing3Message,\n ];\n\n this.resetSliceReport();\n }\n\n /** @type {number} */\n get id () { return this.info.id; }\n /** @type {{ name: string, description: string, link: string }} */\n get public () { return this.info.public; }\n /** @type {{ name: string, description: string, link: string }} */\n set public (data) { this.info.public = data; }\n /** @type {JobManager} */\n get jobManager () { return this.info.jobManager; }\n /** @type {string} */\n get jobAddress () { return this.jobManager?.address; }\n /** @type {Slice} */\n get slice () { return this.info.slice; }\n /** @type {Slice} */\n set slice (slice) { this.info.slice = slice; }\n /** @type {number} */\n get sliceNumber () { return this.slice ? this.slice.sliceNumber : -1; }\n /** @type {number} */\n get generalTimeout () { return 2 * this.hive.generalTimeout; }\n /** @type {number} */\n get punctuatedTimeout () { return this.hive.generalTimeout; }\n\n /**\n * Debug string that characterizes sandbox.\n * @type {string}\n */\n get identifier()\n {\n if (!this.jobAddress)\n return `${this.id}.${this.state}`;\n const address = truncateAddress(this.jobAddress);\n if (this.slice)\n return `${this.id}.${address}.${this.state}~${this.slice.sliceNumber}`;\n return `${this.id}.${address}.${this.state}`;\n }\n\n /** @returns {number} */\n static getNewId() { return Sandbox.idCounter++; }\n\n /** @type {boolean} */\n get isReadyForAssign () { return this.state.is(READY_FOR_ASSIGN); }\n /** @type {boolean} */\n get isAssigned () { return this.state.is(ASSIGNED); }\n /** @type {boolean} */\n get isWorking () { return this.state.is(WORKING); }\n /** @type {boolean} */\n get isTerminated () { return this.state.is(TERMINATED); }\n\n // _Idx\n //\n // checkSandboxReUse, postMessageToEvaluator, changeState,\n // punctuatedTimer is expiremental for replacing hard-coded timeouts.\n //\n\n /**\n * Mark WORKING sandbox as ASSIGNED in preparation for possible reuse.\n * Allow use of sandbox on a given job up to a limit of dcpConfig.supervisor.sandbox.maxSandboxUse .\n */\n checkSandboxReUse ()\n {\n selectiveDebug2() && console.debug(`Sandbox2.checkSandboxReUse: useCounter ${this.useCounter}, ${this.identifier}`);\n if (this.useCounter++ < this.hive.maxSandboxUse)\n {\n this.state.set(WORKING, ASSIGNED);\n this.sandboxEmit('ready');\n }\n else\n {\n this.terminate(false);\n common.removeElement(this.supervisor.sandboxInventory, this);\n }\n }\n\n /** Transitions: ASSIGNED --> WORKING. */\n markAsWorking ()\n {\n if (!this.isAssigned)\n throw new Error(`Sandbox ${this.identifier} is not ready to work`);\n this.state.set(ASSIGNED, WORKING);\n }\n \n /**\n * Safely post message to evaluator.\n * @param {object} message\n */\n postMessageToEvaluator (message)\n {\n if (this.isTerminated) // When evaluator goes down, all sandboxes are terminated.\n throw new Error(`postMessageToEvaluator: Sandbox ${this.identifier} has been terminated.`);\n return this.evaluatorHandle.postMessage(message);\n }\n \n /**\n * Safely change state.\n * @param {string} currentState\n * @param {string} nextState\n */\n changeState (currentState, nextState)\n {\n if (this.isTerminated) // When evaluator goes down, all sandboxes are terminated.\n throw new Error(`changeState: Sandbox ${this.identifier} has been terminated.`);\n this.state.set(currentState, nextState);\n }\n\n /** Upon fatal error return slice to scheduler. */\n returnSlice ()\n {\n selectiveDebug() && console.debug('Sandbox.returnSlice', this.identifier);\n return this.supervisor.returnSlice(this.slice, 'Sandbox.returnSlice');\n }\n\n /**\n * @callback cbFn\n * @returns {void}\n */\n\n /**\n * UNUSED.\n * Future work.\n * Replaces the timers in:\n * describe,\n * applyRequirements,\n * resetState,\n * The idea is to have a long timeout with a warning every\n * 6 seconds saying why it is waiting.\n * @param {cbFn} body\n * @param {string} waitMessage\n * @param {string} timerExpiredMessage\n * @returns {Promise<{ closeIntervalTimer: cbFn }>}\n */\n punctuatedTimer(body, waitMessage, timerExpiredMessage)\n {\n const that = this;\n return new Promise((resolve, reject) => {\n let intervalCounter = 0;\n let intervalHandle = null;\n function closeIntervalTimer()\n {\n if (intervalHandle !== null)\n dcp_timers.clearTimeout(intervalHandle);\n intervalHandle = null;\n }\n intervalHandle = dcp_timers.setInterval(() => {\n if (++intervalCounter > 12)\n {\n closeIntervalTimer();\n that.error(timerExpiredMessage);\n }\n that.warning(waitMessage);\n body();\n }, this.punctuatedTimeout)\n // Allow workers and localExec to exit.\n intervalHandle.unref();\n resolve({ closeIntervalTimer });\n });\n }\n\n // _Idx\n //\n // start, describe, assign, applyRequirements, assignEvaluator\n //\n\n /**\n * Readies the sandbox. This will result in the sandbox being ready and not assigned.\n * It will need to be assigned with a job before it is able to do work.\n * Sandbox.start will terminate the sandbox upon failure.\n * @todo maybe preload specific modules or let the cache pass in what modules to load?\n *\n * @returns {Promise<void>}\n * @throws on failure to ready\n */\n async start ()\n {\n debug('Sandbox.start begin');\n await this.supervisor.delayManager.nextDelay('sandboxStart');\n this.changeState(UNREADY, READYING);\n\n try\n {\n // RING 0\n this.evaluatorHandle = new this.options.SandboxConstructor({\n name: `DCP Sandbox #${this.id}`,\n });\n // Annoying! onerror terminates sandbox which can happen independent of whether the slice\n // is ok or not. Since we don't know, we have to return the slice when onerror is called\n // during sandbox.work .\n /** @todo XXXpfr Beware of onerror firing often. */\n this.evaluatorHandle.onerror = this.onerror.bind(this);\n\n const messageHandler = this.onmessage.bind(this);\n this.evaluatorHandle.onmessage = function onmessage(event)\n {\n const data = (event.data.serialized)\n ? kvin.parse(event.data.message)\n : kvin.unmarshal(event.data);\n messageHandler({ data });\n }\n\n const evaluatorPostMessage = this.evaluatorHandle.postMessage.bind(this.evaluatorHandle);\n this.evaluatorHandle.postMessage = function postMessage(message)\n {\n evaluatorPostMessage(kvin.marshal(message));\n }\n\n const that = this;\n this.evaluatorHandle.addEventListener('end', function sandbox$start$addEventListener() {\n selectiveDebug() && console.debug(\"END:Sandbox evaluatorHandle end-handler\", that.identifier, new Date());\n that.supervisor.evaluator.shuttingDown = true;\n that.terminate(true);\n });\n\n // Don't let an open sockets prevent clean worker exit.\n if (this.evaluatorHandle.unref)\n this.evaluatorHandle.unref();\n\n // Now in RING 1\n\n // Now in RING 2\n await this.describe();\n this.changeState(READYING, READY_FOR_ASSIGN);\n\n // Emit the 'sandbox' event on the worker event emitter.\n this.supervisor.safeEmit(this.supervisor.worker, 'sandbox', this.sandboxHandle);\n }\n catch (error)\n {\n if (this.isTerminated)\n debug(`Failed to start sandbox because it is already terminated: ${this.identifier}.\\n\\tMay be due to screensaver worker being down or evaluator was stopped.`);\n else\n {\n debug(`Failed to start sandbox ${this.identifier}.`, error.message); // FIX s.b. error\n this.terminate(false);\n }\n throw error;\n }\n }\n\n /**\n * Sends a post message to describe its capabilities.\n * Side effect: Sets the capabilities property of the current sandbox.\n *\n * @returns {Promise<any>} Resolves with the sandbox's capabilities.\n * Rejects with an error saying a response was not received.\n * @memberof Sandbox\n */\n describe ()\n {\n debugging('sandbox') && debug('Beginning to describe evaluator', this.identifier);\n const that = this;\n\n return new Promise(function sandbox$describePromise(resolve, reject) {\n let describeTimeout;\n\n if (that.isTerminated) // When evaluator goes down, all sandboxes are terminated.\n reject(new Error(`Sandbox ${that.identifier} has been terminated.`));\n\n if (that.evaluatorHandle === null)\n reject(new Error(`Evaluator has not been initialized: ${that.identifier}`));\n\n function sandbox$describe$success(data)\n {\n if (describeTimeout !== false)\n {\n dcp_timers.clearTimeout(describeTimeout);\n describeTimeout = false;\n\n const { capabilities } = data;\n if (typeof capabilities === 'undefined')\n reject(new Error(`Did not receive capabilities from describe response: ${that.identifier}`));\n that.capabilities = capabilities;\n\n debugging('sandbox') && debug('Evaluator has been described');\n resolve(capabilities);\n }\n }\n // Emitted by handleRing2Message.\n that.once('describe', sandbox$describe$success);\n\n describeTimeout = dcp_timers.setTimeout(function sandbox$describe$fail() {\n if (describeTimeout !== false)\n {\n describeTimeout = false;\n that.removeListener('describe', sandbox$describe$success);\n reject(new Error( `Describe message timed-out. No describe response was received from the describe command: ${that.identifier}`));\n }\n }, that.generalTimeout);\n // Allow workers and localExec to exit.\n describeTimeout.unref();\n\n const message = {\n request: 'describe',\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n /**\n * This will assign the sandbox with a job, loading its sandbox code into the sandbox.\n * Sandbox.assign will not terminate the sandbox upon failure.\n * The sandbox will be terminated in JobManager.assignSandbox .\n * @param {JobManager} jobManager - The job manager that will be the owner of this sandbox.\n * @returns {Promise<Sandbox>}\n * @throws on initialization failure\n */\n async assign (jobManager)\n {\n if (!this.slice) // Design assumption.\n throw new Error(`Must have valid sandbox.slice before sandbox.assign is called: ${this.identifier}`);\n\n await this.supervisor.delayManager.nextDelay('sandboxAssign');\n debug('Sandbox.assign', this.identifier, Date.now() - this.supervisor.lastTime);\n\n try\n {\n this.changeState(READY_FOR_ASSIGN, ASSIGNING);\n this.info.jobManager = jobManager;\n this.job = this.jobManager.jobMessage;\n\n /* At this point, the worker has decided that this sandbox will be associated with a specific job. \n Therefore, we emit the SandboxHandle<job> event*/\n this.sandboxEmit('job', jobManager.jobHandle);\n\n assertEq3(this.job.address, this.jobAddress);\n assert(typeof this.job === 'object');\n assert(typeof this.job.requirements === 'object');\n assert(Array.isArray(this.job.dependencies));\n assert(Array.isArray(this.job.requirePath));\n\n // Extract public data from job, with defaults\n this.public = Object.assign({\n name: `Anonymous Job ${truncateAddress(this.jobAddress)}`,\n description: 'Discreetly helping make the world smarter.',\n link: 'https://distributed.computer/about',\n }, this.job.public);\n\n // Future: We may want other filename tags for appliances // RR Nov 2019\n\n // Important: The order of applying requirements before loading the sandbox code\n // is important for modules and sandbox code to set globals over the whitelist.\n await this.applyRequirements(this.job.requirements);\n //const _t0 = Date.now();\n await this.assignEvaluator();\n //console.log('Finished Sandbox.assignEvaluator', Date.now() - _t0);\n this.changeState(ASSIGNING, ASSIGNED);\n this.sandboxEmit('ready');\n }\n catch (error)\n {\n if (this.isTerminated)\n debug(`Failed to assign sandbox ${this.identifier} to evaluator because it is already terminated.\\n\\tMay be due to screensaver worker being down or evaluator was stopped.`);\n else\n {\n debug(`Failed to assign sandbox ${this.identifier} to evaluator.`);\n this.terminate(false);\n }\n throw error;\n }\n\n return this;\n }\n\n /**\n * Passes the job's requirements object into the sandbox so that the global access lists can be updated accordingly.\n * E.g. disallow access to OffscreenCanvas without environment.offscreenCanvas=true present.\n * Must be called after @start.\n *\n * @returns {Promise<void>} - resolves on success, rejects otherwise\n */\n applyRequirements (requirements)\n {\n assert(typeof requirements === 'object');\n const that = this;\n\n return new Promise(function sandbox$applyRequirementsPromise(resolve, reject) {\n let requirementTimeout;\n\n function sandbox$applyRequirements$success()\n {\n if (requirementTimeout !== false)\n {\n dcp_timers.clearTimeout(requirementTimeout);\n requirementTimeout = false;\n resolve();\n }\n }\n // Emitted by handleRing1Message.\n that.once('applyRequirementsDone', sandbox$applyRequirements$success);\n\n requirementTimeout = dcp_timers.setTimeout(function sandbox$finishApplySandboxRequirements$fail() {\n if (requirementTimeout !== false)\n {\n requirementTimeout = false;\n that.removeListener('applyRequirementsDone', sandbox$applyRequirements$success);\n reject(new Error(`applyRequirements never received 'applyRequirementsDone' response from sandbox: ${that.identifier}`));\n }\n }, that.generalTimeout);\n // Allow workers and localExec to exit.\n requirementTimeout.unref();\n\n const message = {\n requirements,\n request: 'applyRequirements',\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n /**\n * Assign job to the evaluator.\n * @returns {Promise<any>} - resolves on success, rejects otherwise\n */\n assignEvaluator ()\n {\n debugging('sandbox') && console.debug('Begin assigning job to evaluator', this.identifier);\n const that = this;\n\n return new Promise(function sandbox$$assignEvaluatorPromise(resolve, reject) {\n function sandbox$assignEvaluator$success(event)\n {\n that.removeListener('reject', sandbox$assignEvaluator$fail);\n debugging('sandbox') && debug('Job assigned to evaluator');\n resolve(event);\n }\n\n function sandbox$assignEvaluator$fail(error)\n {\n that.removeListener('assigned', sandbox$assignEvaluator$success);\n that.error(`assignEvaluator failed(${that.identifier}): evaluator may be out of memory or the screensaver may be down.`, error);\n selectiveDebug() && console.debug('assignEvaluator failed', that.identifier, error);\n if (that.slice) // Normally the slice hasn't been set yet.\n that.returnSlice();\n reject(error);\n }\n\n // Emitted by handleRing2Message.\n that.once('assigned', sandbox$assignEvaluator$success);\n that.once('reject', sandbox$assignEvaluator$fail);\n\n // Had to add useStrict -- not sure if anything else was missed.\n const jobMessage = {\n address: that.job.address,\n arguments: that.job.arguments,\n dependencies: that.job.dependencies,\n modulePath: that.job.modulePath,\n public: that.job.public,\n requireModules: that.job.requireModules,\n requirePath: that.job.requirePath,\n workFunction: that.job.workFunction,\n useStrict: that.job.useStrict,\n };\n\n const message = {\n request: 'assign',\n job: jobMessage,\n sandboxConfig: that.hive.sandboxConfig,\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n // _Idx\n //\n // eval, resetState, work, resetProgressTimeout, resetSliceTimeout\n //\n\n /**\n * Evaluates a string inside the sandbox.\n * @todo XXXpfr -- I don't understand how this gets called?\n * There's an old comment saying: \"no longer working though?\"\n *\n * @param {string} code - the code to evaluate in the sandbox\n * @param {string} filename - the name of the 'file' to help with debugging,\n * @returns {Promise<any>} - resolves with eval result on success, rejects otherwise\n */\n eval (code, filename)\n {\n const that = this;\n const msgId = nanoid();\n\n return new Promise(function sandbox$$eval$Promise(resolve, reject) {\n const eventId = EVAL_RESULT_PREFIX + msgId;\n\n function sandbox$eval$success(event)\n {\n that.removeListener('reject', sandbox$eval$fail);\n resolve(event);\n };\n\n function sandbox$eval$fail(error)\n {\n that.removeListener(eventId, sandbox$eval$success);\n reject(error);\n };\n\n that.once(eventId, sandbox$eval$success);\n that.once('reject', sandbox$eval$fail);\n\n const message = {\n request: 'eval',\n data: code,\n filename,\n msgId,\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n /**\n * Resets the state of the bootstrap, without resetting the sandbox function if assigned.\n * Mostly used to reset the progress status before reusing a sandbox on another slice.\n * Must be called after @start.\n *\n * @returns {Promise<void>} - resolves with result on success, rejects otherwise\n */\n resetState ()\n {\n const that = this;\n assert(this.isWorking); // Design assumption.\n\n return new Promise(function sandbox$resetStatePromise(resolve, reject) {\n let resetStateTimeout;\n\n function sandbox$resetState$success ()\n {\n if (resetStateTimeout !== false)\n {\n dcp_timers.clearTimeout(resetStateTimeout);\n resetStateTimeout = false;\n resolve();\n }\n }\n that.once('resetStateDone', sandbox$resetState$success);\n\n resetStateTimeout = dcp_timers.setTimeout(function sandbox$resetState$fail() {\n if (resetStateTimeout !== false)\n {\n resetStateTimeout = false;\n that.removeListener('resetStateDone', sandbox$resetState$success);\n reject(new Error(`resetState never received resetStateDone event from sandbox: ${that.identifier}`));\n }\n }, that.generalTimeout);\n // Allow workers and localExec to exit.\n resetStateTimeout.unref();\n\n const message = {\n request: 'resetState',\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n /**\n * Executes a slice received from the supervisor.\n * Must be called after this.start, this.assign and this.markAsWorking .\n * Sandbox.work will not terminate the sandbox upon failure.\n * The sandbox will be terminated in Supervisor.handleSandboxWorkError .\n * @returns {Promise<any>} - resolves with result on success, rejects otherwise\n */\n async work ()\n {\n const that = this;\n\n if (!this.slice) // Design assumption\n throw new Error(`Must have valid sandbox.slice before sandbox.assign is called: ${this.identifier}`);\n\n await this.supervisor.delayManager.nextDelay('sandboxWork');\n debug('Sandbox.work begin', this.identifier, Date.now() - this.supervisor.lastTime);\n\n if (this.isTerminated) // When evaluator goes down, all sandboxes are terminated.\n throw new Error(`Sandbox ${this.identifier} has been terminated.`);\n if (!this.isWorking)\n throw new Error(`Sandbox ${this.identifier} in Sandbox.work must be marked as working.`)\n\n // cf. DCP-1719,1720\n this.resetSliceReport();\n\n // Check that sandbox and slice have the same job.\n if (this.jobAddress !== this.slice.jobAddress)\n throw new Error(`Sandbox.work: sandbox ${this.identifier} and slice ${this.slice.identifier} are from different jobsz`);\n\n /** @todo Should sliceHnd just be replaced with { sandbox: this } since this.public is part of this? */\n let sliceHnd = { job: this.public, sandbox: this };\n await this.resetState();\n if (!this.slice)\n {\n this.error(`Slice for job ${this.jobAddress} vanished during work initialization - aborting`);\n return;\n }\n\n const { datum: inputDatum, error: dataError } = this.slice;\n if (dataError)\n {\n that.postWorkEmit('error', {\n message: dataError.message,\n stack: dataError.stack,\n name: this.public.name\n });\n }\n\n this.resetProgressTimeout();\n this.resetSliceTimeout();\n\n return new Promise(function sandbox$$workPromise(resolve, reject) {\n function sandbox$$work$success (event)\n {\n that.removeListener('reject', sandbox$$work$fail);\n resolve(event);\n }\n\n function sandbox$$work$fail (error)\n {\n that.removeListener('resolve', sandbox$$work$success);\n reject(error);\n }\n\n that.once('resolve', sandbox$$work$success);\n that.once('reject', sandbox$$work$fail);\n\n that.sliceStartTime = Date.now();\n that.slice.startTime = that.sliceStartTime;\n that.progress = null;\n that.progressReports = {\n last: undefined,\n lastDeterministic: undefined,\n };\n\n that.resetProgressTimeout();\n that.resetSliceTimeout();\n that.emit('start', sliceHnd);\n\n if (dataError)\n {\n that.removeListener('resolve', sandbox$$work$success);\n that.removeListener('reject', sandbox$$work$fail);\n dcp_timers.setTimeout(() => reject(dataError), 0)\n }\n else\n {\n // Do the work.\n const message = { request: 'main', data: inputDatum, };\n that.postMessageToEvaluator(message);\n }\n })\n .then(async function sandbox$$work$then(event) {\n // Tell supervisor sandbox slot is available.\n that.slice.markAsWorkDone();\n\n selectiveDebug2() && console.debug('Sandbox.sliceFinish', that.identifier, event?.timeReport);\n that.sandboxEmit('sliceEnd', that.slice?.sliceNumber)\n that.emit('complete', that.jobAddress);\n\n // Reset slice property.\n that.slice = null;\n\n // JobManager.runSliceOnSandbox will transition WORKDONE -> ASSIGNED\n return event;\n })\n .catch(async function sandbox$$work$catch(error) {\n selectiveDebug() && console.debug('Sandbox.work catch', that.identifier, error);\n // Tell supervisor sandbox slot is available.\n if (that.slice)\n that.slice.markAsWorkDone();\n // Current sandbox will not be reused.\n // Do not overwrite that.slice because it is needed in subsequent error reporting.\n\n if (error instanceof NoProgressError)\n {\n const payload = {\n name: that.public.name,\n message: error.message,\n timestamp: Date.now() - that.sliceStartTime,\n };\n that.postWorkEmit('error', payload);\n that.postWorkEmit('noProgress', { ...payload, progressReports: that.progressReports });\n }\n if (error.name === 'EWORKREJECT')\n that.handleRejectedWork(that.sliceTimeReport);\n\n // Otherwise sandbox will be terminated in Supervisor.handleSandboxWorkError\n debugging('sandbox') && debug(`Sandbox ${that.identifier} failed to execute slice`, error);\n\n throw error;\n });\n }\n\n resetProgressTimeout()\n {\n const that = this;\n\n if (this.progressTimeout)\n dcp_timers.clearTimeout(this.progressTimeout);\n\n this.progressTimeout = dcp_timers.setTimeout(function sandbox$ProgressTimeout() {\n if (that.options.ignoreNoProgress)\n return that.warning('ENOPROGRESS silenced by localExec: In a remote worker, this slice would be stopped for not calling progress frequently enough.');\n\n that.emit('reject', new NoProgressError(`No progress event was received in the last ${that.hive.progressTimeout / 1000} seconds.`));\n }, this.hive.progressTimeout * timeDilation);\n // Allow workers and localExec to exit.\n this.progressTimeout.unref();\n }\n\n resetSliceTimeout()\n {\n const that = this;\n\n if (this.sliceTimeout)\n dcp_timers.clearTimeout(this.sliceTimeout);\n\n this.sliceTimeout = dcp_timers.setTimeout(function sandbox$SliceTimeout() {\n if (Sandbox.debugWork)\n return that.warning('Sandbox.debugWork: Ignoring slice timeout');\n\n that.emit('reject', new SliceTooSlowError(`Slice took longer than ${that.hive.sliceTimeout / 1000} seconds.`));\n }, this.hive.sliceTimeout * timeDilation);\n // Allow workers and localExec to exit.\n this.sliceTimeout.unref();\n }\n\n /**\n * Send payload to the workEmit endpoint in the event router.\n * @param {string} eventName\n * @param {*} payload\n * @returns {Promise<*>}\n */\n postWorkEmit (eventName, payload)\n {\n // Need to check if the sandbox hasn't been assigned a slice yet.\n if (!this.slice)\n this.error('Sandbox not assigned a slice before sending workEmit message to scheduler', payload, `'workEmit' event originates from '${eventName}' event`);\n else\n {\n const slice = this.slice;\n // Authorization should always be valid.\n if (!slice.authorizationMessage)\n this.warning(`workEmit: missing authorization message for slice ${slice.identifier}`);\n else\n {\n const workEmitPayload = {\n eventName,\n payload,\n job: slice.jobAddress,\n slice: slice.sliceNumber,\n worker: this.supervisor.workerId,\n authorizationMessage : slice.authorizationMessage,\n };\n return this.supervisor.dcp4.safeWorkEmit(workEmitPayload, `Failed to send workEmit (${eventName}) payload for slice ${slice.identifier}`)\n .then((success) => {\n if (!success)\n this.warning(`Message sent to workEmit is unauthorized; not accepted '${eventName}'`);\n });\n }\n }\n }\n\n /**\n * Save rejected slice timeReport data in this.slice.rejectedTimeReport, then when needed in\n * Supervisor.recordResult, merge this.slice.rejectedTimeReport into this.slice.timeReport.\n * @param {{ total: number, CPU: number, webGL: number, webGPU: number }} timeReport\n */\n handleRejectedWork (timeReport)\n {\n selectiveDebug() && console.debug('handleRejectedWork', this.identifier);\n // If the slice already has rejectedTimeReport, add this timeReport to it.\n // If not, assign this timeReport to slices rejectedTimeReport property\n if (this.slice)\n {\n if (!this.slice.rejectedTimeReport)\n this.slice.rejectedTimeReport = timeReport;\n else\n {\n ['total', 'CPU', 'webGL', 'webGPU'].forEach((key) => {\n if (timeReport[key])\n this.slice.rejectedTimeReport[key] += timeReport[key];\n });\n }\n }\n }\n\n /**\n * Attach CGIO to result returned by a slice workFn.\n * @param {*} completeData - results\n */\n attachCGIOToResult (completeData)\n {\n if (!completeData)\n throw new Error('Slice result is not ready'); // Should never fire.\n if (completeData['timeReport'])\n throw new Error('Slice result already has timeReport'); // Should never fire.\n if (completeData['dataReport'])\n throw new Error('Slice result already has dataReport'); // Should never fire.\n if (this.listenerCount('resolve') > 0)\n {\n completeData['timeReport'] = this.sliceTimeReport;\n completeData['dataReport'] = {\n InDataSize: this.moduleInDataSize + this.jobManager.inputDataSize + this.slice.inputDataSize,\n OutDataSize: this.sliceOutDataSize,\n };\n this.emit('resolve', completeData);\n selectiveDebug() && console.debug('attachCGIOToResult', this.moduleInDataSize, this.jobManager.inputDataSize, this.slice.inputDataSize, completeData['dataReport'].InDataSize);\n }\n else\n {\n // If there is no internal listener for 'resolve', the slice was rejected\n // and we need to update this.slice.rejectedTimeReport appropriately.\n this.handleRejectedWork(this.sliceTimeReport);\n }\n // Clear time and data reports so we can catch mistaken writes.\n this.sliceTimeReport = null;\n this.sliceOutDataSize = 0;\n }\n\n // _Idx\n //\n // handleRing0Message, handleRing1Message, handleRing2Message, handleRing3Message\n //\n\n async handleRing0Message(data) // eslint-disable-line require-await\n {\n debugging('ring0') && debug('Ring0', this.identifier, data.request);\n\n switch (data.request)\n {\n case 'scriptLoaded':\n if(data.result !== \"success\")\n this.onerror(data);\n break;\n case 'error':\n debug('Sandbox error in ring0', data.error);\n this.rejectWithCleanup('during initialization', data.error);\n break;\n default:\n this.error('Received unhandled request from sandbox: ' + data.request, null, `data: ${ JSON.stringify(data)}`);\n break;\n }\n }\n\n async handleRing1Message(data) // eslint-disable-line require-await\n {\n debugging('ring1') && debug('Ring1', this.identifier, data.request);\n\n switch (data.request)\n {\n case 'applyRequirementsDone':\n // emit internally\n this.emit(data.request, data)\n break;\n default:\n this.error('Received unhandled request from sandbox ring 1: ' + data.request, null, `data: ${ JSON.stringify(data)}`);\n break; \n }\n }\n\n async handleRing2Message(data)\n {\n debugging('ring2') && debug('Ring2', this.identifier, data.request);\n\n switch (data.request)\n {\n case 'dependency': {\n try\n {\n const moduleData = await this.moduleCache.fetchModule(data.data, this.jobAddress);\n // Success! Restore this['packageManager'] delay to retryMinSleepMs (currently 32ms.)\n // Is there a better way to reset than explicit calls?\n this.supervisor.delayManager.resetEBO('packageManager');\n // Send module data to be evaluator.\n const message = {\n request: 'moduleGroup',\n data: moduleData,\n id: data.id,\n };\n // Module data is dynamic since it may only be required in a conditional branch.\n // Moreover, on a long job, the published module itself may be updated on the scheduler.\n const moduleLength = kvin.stringify(moduleData).length; /** @TODO - fix per DCP-3750 */\n this.moduleInDataSize += moduleLength;\n selectiveDebug() && console.debug('Sandbox.Ring2.fetchModule size', this.moduleInDataSize, moduleLength);\n this.postMessageToEvaluator(message);\n }\n catch (error)\n {\n /*\n * In the event of an error here, we want to let the client know there was a problem in\n * loading their module. In principle we shouldn't need a valid sandbox.slice at sandbox.assign.\n * However, in the implementation of Sup2 there is precisely 1 callsite of sandbox.assign and\n * we do have an associated slice at this point. So we make the assumption that sandbox.slice\n * is valid here.\n */\n if (!this.slice) // Design assumption\n throw new Error(`Must have valid slice in sandbox before sandbox.assign is called: ${this.identifier}`);\n\n const payload = {\n name: error.name,\n message: error.message,\n timestamp: error.timestamp ? error.timestamp : new Date(),\n };\n\n this.postWorkEmit('error', payload);\n this.emit('reject', error);\n\n debugging() && console.debug(`Sandbox.Ring2: fetchModule failed ${this.identifier}`, payload, error, Date.now() - this.supervisor.lastTime);\n\n // Close packageManager to start the connection reconnect logic.\n // Should we do a retry loop with fetchModule too?\n this.supervisor.dcp4.resetConnection('packageManager');\n }\n break;\n }\n case 'error':\n /*\n * Ring 2 error messages will only fire for problems inside of the worker that are separate from\n * the work function. In most cases there are other handlers for situations where 'error' may be emitted\n * such as timeouts if the expected message isn't recieved.\n */\n debug('Sandbox error in ring2', data.error);\n this.rejectWithCleanup('during assignment and dependency resolution', data.error);\n break;\n case 'describe':\n case 'evalResult':\n case 'resetStateDone':\n case 'assigned':\n this.emit(data.request, data); // emit internally\n break;\n case 'reject':\n this.emit('reject', data.error); // emit internally\n break;\n default:\n this.error(`Received unhandled request from sandbox ring 2. Data: ${JSON.stringify(data, null, 2)}`);\n break;\n }\n }\n\n async handleRing3Message(data) // eslint-disable-line require-await\n {\n debugging('ring3') && debug('Ring3', this.identifier, data.request);\n\n switch (data.request)\n {\n case 'complete':\n dcp_timers.clearTimeout(this.progressTimeout);\n dcp_timers.clearTimeout(this.sliceTimeout);\n this.progressTimeout = this.sliceTimeout = null;\n\n if (this.progress === null)\n {\n if (this.options.ignoreNoProgress)\n this.warning(\"ENOPROGRESS silenced by localExec: Progress was not called during this slice's execution, in a remote sandbox this would cause the slice to fail.\");\n else\n {\n // If a progress update was never received (progress === null) then reject\n this.emit('reject', new NoProgressError('Sandbox never emitted a progress event.'));\n this.handleRejectedWork(this.sliceTimeReport);\n break;\n }\n }\n \n this.progress = 100;\n this.sliceOutDataSize += kvin.stringify(data.result).length; /** @TODO - fix per DCP-3750 */\n this.attachCGIOToResult(data);\n break;\n case 'progress':\n {\n const { progress, indeterminate, throttledReports, value } = data;\n this.progress = progress;\n // cf. job-noProgress.js\n const progressReport = {\n deltaMs: Date.now() - this.sliceStartTime,\n progress,\n value,\n throttledReports,\n }\n this.progressReports.last = progressReport;\n if (!indeterminate)\n this.progressReports.lastDeterministic = progressReport;\n\n this.resetProgressTimeout();\n this.sandboxEmit('progress', indeterminate || progress < 0 || progress > 100 ? undefined : progress);\n break;\n }\n case 'noProgress':\n this.emit('reject', new NoProgressError(data.message));\n break;\n case 'console':\n data.payload.message = kvin.marshal(data.payload.message);\n this.sliceOutDataSize += JSON.stringify(data.payload.message).length; /** @TODO - fix per DCP-3750 */\n this.postWorkEmit('console', data.payload);\n break;\n case 'emitEvent': /* ad-hoc event from the sandbox (work.emit) */\n this.postWorkEmit('custom', data.payload);\n break;\n case 'measurement':\n this.updateTime(data);\n break;\n case 'sandboxError': /* the sandbox itself has an error condition */\n debug(`Ring3 received a 'sandboxError' event for sandbox ${this.identifier}`, data.error);\n this.emit('sandboxError', data.error);\n this.rejectWithCleanup('internal sandbox error while executing work function', data.error);\n break;\n case 'workError': /* the work function threw/rejected */\n debug(`Ring3 received a 'workError' event for sandbox ${this.identifier}`, data.error);\n this.postWorkEmit('error', data.error);\n const wrappedError = new UncaughtExceptionError(data.error);\n this.rejectWithCleanup('error while executing work function', wrappedError);\n break;\n default:\n this.error('Received unhandled request from sandbox ring 3: ' + data.request, null, `data: ${ JSON.stringify(data)}`);\n break; \n }\n }\n\n /**\n * Try to send the error back to the reject handler in Sandbox.work.\n * But if the reject handler is not available (s.b. rare) then cleanup, emit error and throw.\n * @param {string} message\n * @param {Error|string} error\n */\n rejectWithCleanup (message, error)\n {\n if (this.listenerCount('reject') > 0)\n this.emit('reject', error);\n else\n {\n this.terminate(false);\n this.error(`Sandbox ${this.identifier} ${message}`, error);\n throw error;\n }\n }\n\n // _Idx\n //\n // onmessage, onerror, terminate\n //\n\n /**\n * Handles progress and completion events from sandbox.\n * Unless explicitly returned out of this function will re-emit the event\n * where the name of the event is event.data.request.\n *\n * @param {object} event - event received from the evaaluator sandbox\n * @returns {Promise<void>}\n */\n onmessage (event)\n {\n debugging('event') && debug('onmessage-event', event.data.ringSource);\n if (Sandbox.debugEvents)\n console.debug('sandbox - eventDebug:', { id: this.id, state: this.state.valueOf(), event: JSON.stringify(event) });\n\n const { data } = event;\n const ringLevel = data.ringSource\n\n // Give the data to a handler depending on ring level\n if (ringLevel === -1)\n {\n /** @todo XXXpfr Beware of this happening often. */\n this.error(`Message sent directly from raw postMessage for event ${event}. Terminating worker...`);\n this.terminate(true);\n }\n else\n {\n const handler = this.ringMessageHandlers[ringLevel];\n if (handler)\n return handler.call(this, data.value);\n this.warning(`No handler defined for message from ring ${ringLevel} for event ${event}.`);\n }\n }\n\n /**\n * Error handler for the internal sandbox.\n * Emits error event that gets handled up in the Worker class.\n */\n onerror (event)\n {\n /** @todo XXXpfr Beware of onerror firing often. */\n this.error(`Sandbox.onerror emitted an error: ${event}`);\n this.terminate(true, true);\n }\n\n /**\n * Clears the timeout and terminates the sandbox and sometimes emits a reject event.\n *\n * @param {boolean} [reject=true] - if true emit reject event\n * @param {boolean} [immediate=false] - passed to terminate, used by standaloneWorker to immediately close the connection\n */\n terminate (reject = true, immediate = false)\n {\n if (this.slice)\n this.returnSlice();\n if (this.isTerminated)\n return;\n\n selectiveDebug() && console.debug(`Terminate sandbox ${this.identifier}`);\n\n this.state = new Synchronizer(TERMINATED, [ UNREADY, READYING, READY_FOR_ASSIGN, ASSIGNING, ASSIGNED, WORKING, TERMINATED ]);\n\n dcp_timers.clearTimeout(this.progressTimeout);\n dcp_timers.clearTimeout(this.sliceTimeout);\n this.progressTimeout = this.sliceTimeout = null;\n\n if (this.evaluatorHandle && typeof this.evaluatorHandle.terminate === 'function')\n {\n try\n {\n this.evaluatorHandle.terminate(immediate);\n }\n catch (e)\n {\n this.error(`Error terminating sandbox ${this.id}:`, e);\n }\n finally\n {\n this.evaluatorHandle = null;\n }\n }\n\n if (reject)\n this.emit('reject', new Error(`Sandbox ${this.identifier} was terminated.`));\n\n this.sandboxEmit('end');\n }\n\n // _Idx\n //\n // updateTime, resetSliceReport, sandboxEmit, error, warning\n //\n\n /**\n * ringNPostMessage can send a `measurement` request and update these\n * totals.\n */\n updateTime (measurementEvent)\n {\n ['total', 'CPU', 'webGL', 'webGPU'].forEach((key) => {\n if (measurementEvent[key])\n this.sliceTimeReport[key] += measurementEvent[key];\n });\n }\n\n /**\n * Start over sandbox work timers.\n */\n resetSliceReport ()\n {\n this.sliceTimeReport = {\n total: 0,\n CPU: 0,\n webGL: 0,\n webGPU: 0,\n };\n this.sliceOutDataSize = 0;\n }\n\n /**\n * Safe event emitter on sandboxHandle.\n * @param {string} event\n * @param {...any} args\n */\n sandboxEmit(event, ...args)\n {\n this.supervisor.safeEmit(this.sandboxHandle, event, ...args);\n }\n\n /**\n * Error feedback to user.\n * @param {string} message\n * @param {Array<Error>|Error|string} [coreError]\n * @param {string} [additionalInfo]\n * @param {boolean} [supressStack=false]\n */\n error (message, coreError, additionalInfo, supressStack = false)\n {\n this.supervisor.error(message, coreError, additionalInfo, supressStack);\n }\n\n /**\n * Warning feedback to user.\n * @param {string[]} messages\n */\n warning (...messages)\n {\n this.supervisor.warning(...messages);\n }\n}\n\nSandbox.idCounter = 1;\nSandbox.debugWork = false;\nSandbox.debugState = false;\nSandbox.debugEvents = false;\n\nexports.Sandbox = Sandbox;\nexports.SandboxError = SandboxError;\nexports.NoProgressError = NoProgressError;\nexports.SliceTooSlowError = SliceTooSlowError;\nexports.UncaughtExceptionError = UncaughtExceptionError;\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/worker/supervisor2/sandbox2.js?");
4801
+ eval("/**\n * @file dcp/src/dcp-client/worker/supervisor2/sandbox2.js\n *\n * A sandbox that when constructed and assigned can do work for\n * a distributed slice. A sandbox runs for a single slice at a time.\n *\n * Usage (simplified...):\n * const sandbox = new Sandbox(this, { ...this.options.sandboxOptions });\n * await sandbox.start();\n * sandbox.slice = slice;\n * await sandbox.assign(jobManager);\n * return sandbox.work()\n * .then((result) => {\n * slice.collectResult(result, true);\n * sandbox.checkSandboxReUse();\n * this.supervisor.recordResult(slice)\n * })\n * .catch((error) => {\n * slice.collectResult(error, false);\n * const reason = this.supervisor.handleSandboxWorkError(sandbox, slice, error);\n * this.supervisor.returnSlice(slice, reason);\n * this.returnSandbox(sandbox);\n * });\n *\n * Debug flags:\n * Sandbox.debugWork = true // - turns off 30 second timeout to let user debug sandbox innards more easily\n * Sandbox.debugState = true // - logs all state transitions for this sandbox\n * Sandbox.debugEvents = true // - logs all events received from the sandbox\n *\n * Initial states:\n * UNREADY\n *\n * Terminal states:\n * TERMINATED\n *\n * Valid transitions:\n * ( sandbox.start )\n * UNREADY -> READYING -> READY_FOR_ASSIGN\n * READYING -> TERMINATED\n * ( sandbox.assign )\n * READY_FOR_ASSIGN -> ASSIGNING -> ASSIGNED\n * ASSIGNING -> TERMINATED\n * ( sandbox.markAsWorking )\n * ASSIGEND -> WORKING\n * ( sandbox.work )\n * WORKING -> ASSIGNED\n * -> TERMINATED\n * ( sandbox.terminate )\n * any -> TERMINATED\n *\n * @author Matthew Palma, mpalma@kingsds.network\n * Ryan Rossiter, ryan@kingsds.network\n * Wes Garland, wes@distributive.network\n * Paul, paul@distributive.network\n * @date May 2019\n * May 2019\n * Decemeber 2020\n * June, Dec 2022, Jan-May 2023\n * @module sandbox\n * @copyright Copyright (c) 2018-2023, Distributive Corp. All Rights Reserved\n */\n// @ts-check\n\n\nconst debugging = (__webpack_require__(/*! dcp/debugging */ \"./src/debugging.js\").scope)('worker');\nconst dcp_timers = __webpack_require__(/*! dcp/common/dcp-timers */ \"./src/common/dcp-timers.js\");\nconst { assert, assertEq3 } = __webpack_require__(/*! dcp/common/dcp-assert */ \"./src/common/dcp-assert.js\");\nconst { Synchronizer } = __webpack_require__(/*! dcp/common/concurrency */ \"./src/common/concurrency.js\");\nconst nanoid = (__webpack_require__(/*! nanoid */ \"./node_modules/nanoid/index.browser.js\").nanoid);\nconst EventEmitter = __webpack_require__(/*! events */ \"./node_modules/events/events.js\");\nconst kvin = __webpack_require__(/*! kvin */ \"./node_modules/kvin/kvin.js\");\nconst { Config } = __webpack_require__(/*! ./config */ \"./src/dcp-client/worker/supervisor2/config.js\");\nconst common = __webpack_require__(/*! ./common */ \"./src/dcp-client/worker/supervisor2/common.js\");\nconst { selectiveDebug, truncateAddress, timeDilation, selectiveDebug2 } = common;\nconst { stringify } = __webpack_require__(/*! dcp/utils */ \"./src/utils/index.js\");\n\n/**\n * Wraps console.debug to emulate debug module prefixing messages on npm.\n * @param {...any} args\n */\nconst debug = (...args) => {\n if (debugging())\n console.debug('Sandbox:', ...args);\n};\n\n// Sandbox states\nconst UNREADY = 'UNREADY' // No Sandbox (web worker, saworker, etc) has been constructed yet\nconst READYING = 'READYING' // Sandbox is being constructed and environment (bravojs, env) is being set up\nconst READY_FOR_ASSIGN = 'READY_FOR_ASSIGN' // Sandbox is ready to be assigned\nconst ASSIGNED = 'ASSIGNED' // Sandbox is assigned but not working\nconst ASSIGNING = 'ASSIGNING' // Sandbox is in the process of being ASSIGNED\nconst WORKING = 'WORKING' // Sandbox is working\nconst TERMINATED = 'TERMINATED' // Sandbox is terminated.\nconst EVAL_RESULT_PREFIX = 'evalResult::';\n\nclass SandboxError extends Error\n{\n /**\n * @param {string} errorCode\n * @param {string|Error} msg\n */\n constructor(errorCode, msg)\n {\n super((msg.constructor?.name === 'String') ? msg : msg['message']);\n /** @type {string} */\n this.errorCode = errorCode;\n if (msg.constructor?.name !== 'String')\n for (const prop of [ 'name', 'code', 'stack', 'lineNumber', 'columnNumber' ])\n if (msg[prop]) this[prop] = msg[prop];\n }\n}\nclass NoProgressError extends SandboxError { constructor(msg) { super('ENOPROGRESS', msg); } }\nclass SliceTooSlowError extends SandboxError { constructor(msg) { super('ESLICETOOSLOW', msg); } }\nclass UncaughtExceptionError extends SandboxError { constructor(msg) { super('EUNCAUGHT', msg); } }\n\n/** @typedef {import('./slice2').Slice} Slice */\n/** @typedef {import('./index').Supervisor} Supervisor */\n/** @typedef {import('./job-manager').JobManager} JobManager */\n/** @typedef {import('./module-cache').ModuleCache} ModuleCache */\n/** @typedef {import('dcp/utils/jsdoc-types').SandboxOptions} SandboxOptions */\n\n/**\n * Public event emitter.\n * https://gitlab.com/Distributed-Compute-Protocol/dcp-docs-wes/-/blob/wip/worker/worker-events.md\n */\nclass SandboxHandle extends EventEmitter\n{\n /** @type {{ id: number, public: { name: string, description: string, link: string }, jobManager: JobManager, slice: Slice }} */\n #info;\n\n /**\n * @constructor\n * @param {Sandbox} sandbox\n */\n constructor (sandbox)\n {\n super({ captureRejections: false });\n this.#info = sandbox.info;\n }\n /** @type {number} */\n get id () { return this.#info.id; }\n /** @type {{ name: string, description: string, link: string }} */\n get public () { return this.#info.public ?? { name: '<unassigned>', description: '', link: '' }; }\n /** @type {string} */\n get jobAddress () { return this.#info.jobManager?.address; }\n /** @type {number} */\n get sliceNumber () { return this.#info.slice?.sliceNumber ?? -1; }\n}\nexports.SandboxHandle = SandboxHandle;\n\n//\n// Index to functionality -- search for '_Idx' to toggle through the index.\n//\n// 1) class Sandbox\n// 2) checkSandboxReUse, postMessageToEvaluator, changeState,\n// and punctuatedTimer is expiremental for replacing hard-coded timeouts.\n// 3) start, describe, assign, applyRequirements, assignEvaluator\n// 4) eval, resetState, work, resetProgressTimeout, resetSliceTimeout\n// 5) handleRing0Message, handleRing1Message, handleRing2Message, handleRing3Message\n// 6) onmessage, onerror, terminate\n// 7) updateTime, resetSliceReport, sandboxEmit, error, warning\n//\n\n// _Idx\n//\n// class Sandbox\n//\n\nclass Sandbox extends EventEmitter\n{\n /**\n * A Sandbox (i.e. a worker sandbox) which executes distributed slices.\n *\n * @constructor\n * @param {Supervisor} supervisor\n * @param {SandboxOptions} options\n */\n constructor (supervisor, options)\n {\n super({ captureRejections: false });\n /** @type {Supervisor} */\n this.supervisor = supervisor;\n /** @type {ModuleCache} */\n this.moduleCache = supervisor.moduleCache;\n /** @type {SandboxOptions} */\n this.options = {\n ignoreNoProgress: false,\n ...options,\n SandboxConstructor: options.SandboxConstructor || (__webpack_require__(/*! ../evaluators */ \"./src/dcp-client/worker/evaluators/index.js\").BrowserEvaluator),\n }\n /** @type {Synchronizer} */\n this.state = new Synchronizer(UNREADY, [ UNREADY, READYING, READY_FOR_ASSIGN, ASSIGNING, ASSIGNED, WORKING, TERMINATED ]);\n\n /** @type {{ id: number, public: { name: string, description: string, link: string }, jobManager: JobManager, slice: Slice }} */\n this.info = {\n id: Sandbox.getNewId(),\n public: null,\n jobManager: null,\n slice: null,\n };\n\n /**\n * Event emitter containing info that describes the sandbox.\n * @type {SandboxHandle}\n */\n this.sandboxHandle = new SandboxHandle(this);\n\n /** Properties of type object. */\n this.evaluatorHandle = null;\n this.capabilities = null;\n this.progressTimeout = null;\n this.sliceTimeout = null;\n this.rejectionData = null;\n\n /** @type {number?} */\n this.progress = 100;\n /** @type {{ last: { deltaMs: number, value: any, throttledReports: number }, lastDeterministic: { deltaMs: number, progress: number, value: any, throttledReports: number } }} */\n this.progressReports = null; // cf. job-noProgress.js\n /** @type {object} */\n this.progressTimeout = null;\n /** @type {object} */\n this.sliceTimeout = null;\n\n /** @type {{ total: number, CPU: number, webGL: number, webGPU: number }} */\n this.sliceTimeReport = null;\n /** @type {number} */\n this.moduleInDataSize = 0; // Sandbox level input size; set during assign, never reset.\n /** @type {number} */\n this.sliceOutDataSize = 0; // Slice level output size; reset for every slice executed.\n\n /** @type {number?} */\n this.sliceStartTime = null;\n /** @type {number} */\n this.useCounter = 1; // Anticipating the initial use.\n /** @type {Config} */\n this.hive = new Config();\n\n ///** @type {((data: any) => Promise<void>)[]} */\n this.ringMessageHandlers = [\n this.handleRing0Message,\n this.handleRing1Message,\n this.handleRing2Message,\n this.handleRing3Message,\n ];\n\n this.resetSliceReport();\n }\n\n /** @type {number} */\n get id () { return this.info.id; }\n /** @type {{ name: string, description: string, link: string }} */\n get public () { return this.info.public; }\n /** @type {{ name: string, description: string, link: string }} */\n set public (data) { this.info.public = data; }\n /** @type {JobManager} */\n get jobManager () { return this.info.jobManager; }\n /** @type {string} */\n get jobAddress () { return this.jobManager?.address; }\n /** @type {Slice} */\n get slice () { return this.info.slice; }\n /** @type {Slice} */\n set slice (slice) { this.info.slice = slice; }\n /** @type {number} */\n get sliceNumber () { return this.slice ? this.slice.sliceNumber : -1; }\n /** @type {number} */\n get generalTimeout () { return 2 * this.hive.generalTimeout; }\n /** @type {number} */\n get punctuatedTimeout () { return this.hive.generalTimeout; }\n\n /**\n * Debug string that characterizes sandbox.\n * @type {string}\n */\n get identifier()\n {\n if (!this.jobAddress)\n return `${this.id}.${this.state}`;\n const address = truncateAddress(this.jobAddress);\n if (this.slice)\n return `${this.id}.${address}.${this.state}~${this.slice.sliceNumber}`;\n return `${this.id}.${address}.${this.state}`;\n }\n\n /** @returns {number} */\n static getNewId() { return Sandbox.idCounter++; }\n\n /** @type {boolean} */\n get isReadyForAssign () { return this.state.is(READY_FOR_ASSIGN); }\n /** @type {boolean} */\n get isAssigned () { return this.state.is(ASSIGNED); }\n /** @type {boolean} */\n get isWorking () { return this.state.is(WORKING); }\n /** @type {boolean} */\n get isTerminated () { return this.state.is(TERMINATED); }\n\n // _Idx\n //\n // checkSandboxReUse, postMessageToEvaluator, changeState,\n // punctuatedTimer is expiremental for replacing hard-coded timeouts.\n //\n\n /**\n * Mark WORKING sandbox as ASSIGNED in preparation for possible reuse.\n * Allow use of sandbox on a given job up to a limit of dcpConfig.supervisor.sandbox.maxSandboxUse .\n */\n checkSandboxReUse ()\n {\n selectiveDebug2() && console.debug(`Sandbox2.checkSandboxReUse: useCounter ${this.useCounter}, ${this.identifier}`);\n if (this.useCounter++ < this.hive.maxSandboxUse)\n {\n this.state.set(WORKING, ASSIGNED);\n this.sandboxEmit('ready');\n }\n else\n {\n this.terminate(false);\n common.removeElement(this.supervisor.sandboxInventory, this);\n }\n }\n\n /** Transitions: ASSIGNED --> WORKING. */\n markAsWorking ()\n {\n if (!this.isAssigned)\n throw new Error(`Sandbox ${this.identifier} is not ready to work`);\n this.state.set(ASSIGNED, WORKING);\n }\n \n /**\n * Safely post message to evaluator.\n * @param {object} message\n */\n postMessageToEvaluator (message)\n {\n if (this.isTerminated) // When evaluator goes down, all sandboxes are terminated.\n throw new Error(`postMessageToEvaluator: Sandbox ${this.identifier} has been terminated.`);\n return this.evaluatorHandle.postMessage(message);\n }\n \n /**\n * Safely change state.\n * @param {string} currentState\n * @param {string} nextState\n */\n changeState (currentState, nextState)\n {\n if (this.isTerminated) // When evaluator goes down, all sandboxes are terminated.\n throw new Error(`changeState: Sandbox ${this.identifier} has been terminated.`);\n this.state.set(currentState, nextState);\n }\n\n /** Upon fatal error return slice to scheduler. */\n returnSlice ()\n {\n selectiveDebug() && console.debug('Sandbox.returnSlice', this.identifier);\n return this.supervisor.returnSlice(this.slice, 'Sandbox.returnSlice');\n }\n\n /**\n * @callback cbFn\n * @returns {void}\n */\n\n /**\n * UNUSED.\n * Future work.\n * Replaces the timers in:\n * describe,\n * applyRequirements,\n * resetState,\n * The idea is to have a long timeout with a warning every\n * 6 seconds saying why it is waiting.\n * @param {cbFn} body\n * @param {string} waitMessage\n * @param {string} timerExpiredMessage\n * @returns {Promise<{ closeIntervalTimer: cbFn }>}\n */\n punctuatedTimer(body, waitMessage, timerExpiredMessage)\n {\n const that = this;\n return new Promise((resolve, reject) => {\n let intervalCounter = 0;\n let intervalHandle = null;\n function closeIntervalTimer()\n {\n if (intervalHandle !== null)\n dcp_timers.clearTimeout(intervalHandle);\n intervalHandle = null;\n }\n intervalHandle = dcp_timers.setInterval(() => {\n if (++intervalCounter > 12)\n {\n closeIntervalTimer();\n that.error(timerExpiredMessage);\n }\n that.warning(waitMessage);\n body();\n }, this.punctuatedTimeout)\n // Allow workers and localExec to exit.\n intervalHandle.unref();\n resolve({ closeIntervalTimer });\n });\n }\n\n // _Idx\n //\n // start, describe, assign, applyRequirements, assignEvaluator\n //\n\n /**\n * Readies the sandbox. This will result in the sandbox being ready and not assigned.\n * It will need to be assigned with a job before it is able to do work.\n * Sandbox.start will terminate the sandbox upon failure.\n * @todo maybe preload specific modules or let the cache pass in what modules to load?\n *\n * @returns {Promise<void>}\n * @throws on failure to ready\n */\n async start ()\n {\n debug('Sandbox.start begin');\n await this.supervisor.delayManager.nextDelay('sandboxStart');\n this.changeState(UNREADY, READYING);\n\n try\n {\n // RING 0\n this.evaluatorHandle = new this.options.SandboxConstructor({\n name: `DCP Sandbox #${this.id}`,\n });\n // Annoying! onerror terminates sandbox which can happen independent of whether the slice\n // is ok or not. Since we don't know, we have to return the slice when onerror is called\n // during sandbox.work .\n /** @todo XXXpfr Beware of onerror firing often. */\n this.evaluatorHandle.onerror = this.onerror.bind(this);\n\n const messageHandler = this.onmessage.bind(this);\n this.evaluatorHandle.onmessage = function onmessage(event)\n {\n const data = (event.data.serialized)\n ? kvin.parse(event.data.message)\n : kvin.unmarshal(event.data);\n messageHandler({ data });\n }\n\n const evaluatorPostMessage = this.evaluatorHandle.postMessage.bind(this.evaluatorHandle);\n this.evaluatorHandle.postMessage = function postMessage(message)\n {\n evaluatorPostMessage(kvin.marshal(message));\n }\n\n const that = this;\n this.evaluatorHandle.addEventListener('end', function sandbox$start$addEventListener() {\n selectiveDebug() && console.debug(\"END:Sandbox evaluatorHandle end-handler\", that.identifier, new Date());\n that.supervisor.evaluator.shuttingDown = true;\n that.terminate(true);\n });\n\n // Don't let an open sockets prevent clean worker exit.\n if (this.evaluatorHandle.unref)\n this.evaluatorHandle.unref();\n\n // Now in RING 1\n\n // Now in RING 2\n await this.describe();\n this.changeState(READYING, READY_FOR_ASSIGN);\n\n // Emit the 'sandbox' event on the worker event emitter.\n this.supervisor.safeEmit(this.supervisor.worker, 'sandbox', this.sandboxHandle);\n }\n catch (error)\n {\n if (this.isTerminated)\n debug(`Failed to start sandbox because it is already terminated: ${this.identifier}.\\n\\tMay be due to screensaver worker being down or evaluator was stopped.`);\n else\n {\n debug(`Failed to start sandbox ${this.identifier}.`, error.message); // FIX s.b. error\n this.terminate(false);\n }\n throw error;\n }\n }\n\n /**\n * Sends a post message to describe its capabilities.\n * Side effect: Sets the capabilities property of the current sandbox.\n *\n * @returns {Promise<any>} Resolves with the sandbox's capabilities.\n * Rejects with an error saying a response was not received.\n * @memberof Sandbox\n */\n describe ()\n {\n debugging('sandbox') && debug('Beginning to describe evaluator', this.identifier);\n const that = this;\n\n return new Promise(function sandbox$describePromise(resolve, reject) {\n let describeTimeout;\n\n if (that.isTerminated) // When evaluator goes down, all sandboxes are terminated.\n reject(new Error(`Sandbox ${that.identifier} has been terminated.`));\n\n if (that.evaluatorHandle === null)\n reject(new Error(`Evaluator has not been initialized: ${that.identifier}`));\n\n function sandbox$describe$success(data)\n {\n if (describeTimeout !== false)\n {\n dcp_timers.clearTimeout(describeTimeout);\n describeTimeout = false;\n\n const { capabilities } = data;\n if (typeof capabilities === 'undefined')\n reject(new Error(`Did not receive capabilities from describe response: ${that.identifier}`));\n that.capabilities = capabilities;\n\n debugging('sandbox') && debug('Evaluator has been described');\n resolve(capabilities);\n }\n }\n // Emitted by handleRing2Message.\n that.once('describe', sandbox$describe$success);\n\n describeTimeout = dcp_timers.setTimeout(function sandbox$describe$fail() {\n if (describeTimeout !== false)\n {\n describeTimeout = false;\n that.removeListener('describe', sandbox$describe$success);\n reject(new Error( `Describe message timed-out. No describe response was received from the describe command: ${that.identifier}`));\n }\n }, that.generalTimeout);\n // Allow workers and localExec to exit.\n describeTimeout.unref();\n\n const message = {\n request: 'describe',\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n /**\n * This will assign the sandbox with a job, loading its sandbox code into the sandbox.\n * Sandbox.assign will not terminate the sandbox upon failure.\n * The sandbox will be terminated in JobManager.assignSandbox .\n * @param {JobManager} jobManager - The job manager that will be the owner of this sandbox.\n * @returns {Promise<Sandbox>}\n * @throws on initialization failure\n */\n async assign (jobManager)\n {\n if (!this.slice) // Design assumption.\n throw new Error(`Must have valid sandbox.slice before sandbox.assign is called: ${this.identifier}`);\n\n await this.supervisor.delayManager.nextDelay('sandboxAssign');\n debug('Sandbox.assign', this.identifier, Date.now() - this.supervisor.lastTime);\n\n try\n {\n this.changeState(READY_FOR_ASSIGN, ASSIGNING);\n this.info.jobManager = jobManager;\n this.job = this.jobManager.jobMessage;\n\n /* At this point, the worker has decided that this sandbox will be associated with a specific job. \n Therefore, we emit the SandboxHandle<job> event*/\n this.sandboxEmit('job', jobManager.jobHandle);\n\n assertEq3(this.job.address, this.jobAddress);\n assert(typeof this.job === 'object');\n assert(typeof this.job.requirements === 'object');\n assert(Array.isArray(this.job.dependencies));\n assert(Array.isArray(this.job.requirePath));\n\n // Extract public data from job, with defaults\n this.public = Object.assign({\n name: `Anonymous Job ${truncateAddress(this.jobAddress)}`,\n description: 'Discreetly helping make the world smarter.',\n link: 'https://distributed.computer/about',\n }, this.job.public);\n\n // Future: We may want other filename tags for appliances // RR Nov 2019\n\n // Important: The order of applying requirements before loading the sandbox code\n // is important for modules and sandbox code to set globals over the whitelist.\n await this.applyRequirements(this.job.requirements);\n //const _t0 = Date.now();\n await this.assignEvaluator();\n //console.log('Finished Sandbox.assignEvaluator', Date.now() - _t0);\n this.changeState(ASSIGNING, ASSIGNED);\n this.sandboxEmit('ready');\n }\n catch (error)\n {\n if (this.isTerminated)\n debug(`Failed to assign sandbox ${this.identifier} to evaluator because it is already terminated.\\n\\tMay be due to screensaver worker being down or evaluator was stopped.`);\n else\n {\n debug(`Failed to assign sandbox ${this.identifier} to evaluator.`);\n this.terminate(false);\n }\n throw error;\n }\n\n return this;\n }\n\n /**\n * Passes the job's requirements object into the sandbox so that the global access lists can be updated accordingly.\n * E.g. disallow access to OffscreenCanvas without environment.offscreenCanvas=true present.\n * Must be called after @start.\n *\n * @returns {Promise<void>} - resolves on success, rejects otherwise\n */\n applyRequirements (requirements)\n {\n assert(typeof requirements === 'object');\n const that = this;\n\n return new Promise(function sandbox$applyRequirementsPromise(resolve, reject) {\n let requirementTimeout;\n\n function sandbox$applyRequirements$success()\n {\n if (requirementTimeout !== false)\n {\n dcp_timers.clearTimeout(requirementTimeout);\n requirementTimeout = false;\n resolve();\n }\n }\n // Emitted by handleRing1Message.\n that.once('applyRequirementsDone', sandbox$applyRequirements$success);\n\n requirementTimeout = dcp_timers.setTimeout(function sandbox$finishApplySandboxRequirements$fail() {\n if (requirementTimeout !== false)\n {\n requirementTimeout = false;\n that.removeListener('applyRequirementsDone', sandbox$applyRequirements$success);\n reject(new Error(`applyRequirements never received 'applyRequirementsDone' response from sandbox: ${that.identifier}`));\n }\n }, that.generalTimeout);\n // Allow workers and localExec to exit.\n requirementTimeout.unref();\n\n const message = {\n requirements,\n request: 'applyRequirements',\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n /**\n * Assign job to the evaluator.\n * @returns {Promise<any>} - resolves on success, rejects otherwise\n */\n assignEvaluator ()\n {\n debugging('sandbox') && console.debug('Begin assigning job to evaluator', this.identifier);\n const that = this;\n\n return new Promise(function sandbox$$assignEvaluatorPromise(resolve, reject) {\n function sandbox$assignEvaluator$success(event)\n {\n that.removeListener('reject', sandbox$assignEvaluator$fail);\n debugging('sandbox') && debug('Job assigned to evaluator');\n resolve(event);\n }\n\n function sandbox$assignEvaluator$fail(error)\n {\n that.removeListener('assigned', sandbox$assignEvaluator$success);\n that.error(`assignEvaluator failed(${that.identifier}): evaluator may be out of memory or the screensaver may be down.`, error);\n selectiveDebug() && console.debug('assignEvaluator failed', that.identifier, error);\n if (that.slice) // Normally the slice hasn't been set yet.\n that.returnSlice();\n reject(error);\n }\n\n // Emitted by handleRing2Message.\n that.once('assigned', sandbox$assignEvaluator$success);\n that.once('reject', sandbox$assignEvaluator$fail);\n\n // Had to add useStrict -- not sure if anything else was missed.\n const jobMessage = {\n address: that.job.address,\n arguments: that.job.arguments,\n dependencies: that.job.dependencies,\n modulePath: that.job.modulePath,\n public: that.job.public,\n requireModules: that.job.requireModules,\n requirePath: that.job.requirePath,\n workFunction: that.job.workFunction,\n useStrict: that.job.useStrict,\n };\n\n const message = {\n request: 'assign',\n job: jobMessage,\n sandboxConfig: that.hive.sandboxConfig,\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n // _Idx\n //\n // eval, resetState, work, resetProgressTimeout, resetSliceTimeout\n //\n\n /**\n * Evaluates a string inside the sandbox.\n * @todo XXXpfr -- I don't understand how this gets called?\n * There's an old comment saying: \"no longer working though?\"\n *\n * @param {string} code - the code to evaluate in the sandbox\n * @param {string} filename - the name of the 'file' to help with debugging,\n * @returns {Promise<any>} - resolves with eval result on success, rejects otherwise\n */\n eval (code, filename)\n {\n const that = this;\n const msgId = nanoid();\n\n return new Promise(function sandbox$$eval$Promise(resolve, reject) {\n const eventId = EVAL_RESULT_PREFIX + msgId;\n\n function sandbox$eval$success(event)\n {\n that.removeListener('reject', sandbox$eval$fail);\n resolve(event);\n };\n\n function sandbox$eval$fail(error)\n {\n that.removeListener(eventId, sandbox$eval$success);\n reject(error);\n };\n\n that.once(eventId, sandbox$eval$success);\n that.once('reject', sandbox$eval$fail);\n\n const message = {\n request: 'eval',\n data: code,\n filename,\n msgId,\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n /**\n * Resets the state of the bootstrap, without resetting the sandbox function if assigned.\n * Mostly used to reset the progress status before reusing a sandbox on another slice.\n * Must be called after @start.\n *\n * @returns {Promise<void>} - resolves with result on success, rejects otherwise\n */\n resetState ()\n {\n const that = this;\n assert(this.isWorking); // Design assumption.\n\n return new Promise(function sandbox$resetStatePromise(resolve, reject) {\n let resetStateTimeout;\n\n function sandbox$resetState$success ()\n {\n if (resetStateTimeout !== false)\n {\n dcp_timers.clearTimeout(resetStateTimeout);\n resetStateTimeout = false;\n resolve();\n }\n }\n that.once('resetStateDone', sandbox$resetState$success);\n\n resetStateTimeout = dcp_timers.setTimeout(function sandbox$resetState$fail() {\n if (resetStateTimeout !== false)\n {\n resetStateTimeout = false;\n that.removeListener('resetStateDone', sandbox$resetState$success);\n reject(new Error(`resetState never received resetStateDone event from sandbox: ${that.identifier}`));\n }\n }, that.generalTimeout);\n // Allow workers and localExec to exit.\n resetStateTimeout.unref();\n\n const message = {\n request: 'resetState',\n };\n that.postMessageToEvaluator(message);\n });\n }\n\n /**\n * Executes a slice received from the supervisor.\n * Must be called after this.start, this.assign and this.markAsWorking .\n * Sandbox.work will not terminate the sandbox upon failure.\n * The sandbox will be terminated in Supervisor.handleSandboxWorkError .\n * @returns {Promise<any>} - resolves with result on success, rejects otherwise\n */\n async work ()\n {\n const that = this;\n\n if (!this.slice) // Design assumption\n throw new Error(`Must have valid sandbox.slice before sandbox.assign is called: ${this.identifier}`);\n\n await this.supervisor.delayManager.nextDelay('sandboxWork');\n debug('Sandbox.work begin', this.identifier, Date.now() - this.supervisor.lastTime);\n\n if (this.isTerminated) // When evaluator goes down, all sandboxes are terminated.\n throw new Error(`Sandbox ${this.identifier} has been terminated.`);\n if (!this.isWorking)\n throw new Error(`Sandbox ${this.identifier} in Sandbox.work must be marked as working.`)\n\n // cf. DCP-1719,1720\n this.resetSliceReport();\n\n // Check that sandbox and slice have the same job.\n if (this.jobAddress !== this.slice.jobAddress)\n throw new Error(`Sandbox.work: sandbox ${this.identifier} and slice ${this.slice.identifier} are from different jobsz`);\n\n /** @todo Should sliceHnd just be replaced with { sandbox: this } since this.public is part of this? */\n let sliceHnd = { job: this.public, sandbox: this };\n await this.resetState();\n if (!this.slice)\n {\n this.error(`Slice for job ${this.jobAddress} vanished during work initialization - aborting`);\n return;\n }\n\n const { datum: inputDatum, error: dataError } = this.slice;\n if (dataError)\n {\n that.postWorkEmit('error', {\n message: dataError.message,\n stack: dataError.stack,\n name: this.public.name\n });\n }\n\n this.resetProgressTimeout();\n this.resetSliceTimeout();\n\n return new Promise(function sandbox$$workPromise(resolve, reject) {\n function sandbox$$work$success (event)\n {\n that.removeListener('reject', sandbox$$work$fail);\n resolve(event);\n }\n\n function sandbox$$work$fail (error)\n {\n that.removeListener('resolve', sandbox$$work$success);\n reject(error);\n }\n\n that.once('resolve', sandbox$$work$success);\n that.once('reject', sandbox$$work$fail);\n\n that.sliceStartTime = Date.now();\n that.slice.startTime = that.sliceStartTime;\n that.progress = null;\n that.progressReports = {\n last: undefined,\n lastDeterministic: undefined,\n };\n\n that.resetProgressTimeout();\n that.resetSliceTimeout();\n that.emit('start', sliceHnd);\n\n if (dataError)\n {\n that.removeListener('resolve', sandbox$$work$success);\n that.removeListener('reject', sandbox$$work$fail);\n dcp_timers.setTimeout(() => reject(dataError), 0)\n }\n else\n {\n // Do the work.\n const message = { request: 'main', data: inputDatum, };\n that.postMessageToEvaluator(message);\n }\n })\n .then(async function sandbox$$work$then(event) {\n // Tell supervisor sandbox slot is available.\n that.slice.markAsWorkDone();\n\n selectiveDebug2() && console.debug('Sandbox.sliceFinish', that.identifier, event?.timeReport);\n that.sandboxEmit('sliceEnd', that.slice?.sliceNumber)\n that.emit('complete', that.jobAddress);\n\n // Reset slice property.\n that.slice = null;\n\n // JobManager.runSliceOnSandbox will transition WORKDONE -> ASSIGNED\n return event;\n })\n .catch(async function sandbox$$work$catch(error) {\n selectiveDebug() && console.debug('Sandbox.work catch', that.identifier, error);\n // Tell supervisor sandbox slot is available.\n if (that.slice)\n that.slice.markAsWorkDone();\n // Current sandbox will not be reused.\n // Do not overwrite that.slice because it is needed in subsequent error reporting.\n\n if (error instanceof NoProgressError)\n {\n const payload = {\n name: that.public.name,\n message: error.message,\n timestamp: Date.now() - that.sliceStartTime,\n };\n that.postWorkEmit('error', payload);\n that.postWorkEmit('noProgress', { ...payload, progressReports: that.progressReports });\n }\n if (error.name === 'EWORKREJECT')\n that.handleRejectedWork(that.sliceTimeReport);\n\n // Otherwise sandbox will be terminated in Supervisor.handleSandboxWorkError\n debugging('sandbox') && debug(`Sandbox ${that.identifier} failed to execute slice`, error);\n\n throw error;\n });\n }\n\n resetProgressTimeout()\n {\n const that = this;\n\n if (this.progressTimeout)\n dcp_timers.clearTimeout(this.progressTimeout);\n\n this.progressTimeout = dcp_timers.setTimeout(function sandbox$ProgressTimeout() {\n if (that.options.ignoreNoProgress)\n return that.warning('ENOPROGRESS silenced by localExec: In a remote worker, this slice would be stopped for not calling progress frequently enough.');\n\n that.emit('reject', new NoProgressError(`No progress event was received in the last ${that.hive.progressTimeout / 1000} seconds.`));\n }, this.hive.progressTimeout * timeDilation);\n // Allow workers and localExec to exit.\n this.progressTimeout.unref();\n }\n\n resetSliceTimeout()\n {\n const that = this;\n\n if (this.sliceTimeout)\n dcp_timers.clearTimeout(this.sliceTimeout);\n\n this.sliceTimeout = dcp_timers.setTimeout(function sandbox$SliceTimeout() {\n if (Sandbox.debugWork)\n return that.warning('Sandbox.debugWork: Ignoring slice timeout');\n\n that.emit('reject', new SliceTooSlowError(`Slice took longer than ${that.hive.sliceTimeout / 1000} seconds.`));\n }, this.hive.sliceTimeout * timeDilation);\n // Allow workers and localExec to exit.\n this.sliceTimeout.unref();\n }\n\n /**\n * Send payload to the workEmit endpoint in the event router.\n * @param {string} eventName\n * @param {*} payload\n * @returns {Promise<*>}\n */\n postWorkEmit (eventName, payload)\n {\n // Need to check if the sandbox hasn't been assigned a slice yet.\n if (!this.slice)\n this.error('Sandbox not assigned a slice before sending workEmit message to scheduler', payload, `'workEmit' event originates from '${eventName}' event`);\n else\n {\n const slice = this.slice;\n // Authorization should always be valid.\n if (!slice.authorizationMessage)\n this.warning(`workEmit: missing authorization message for slice ${slice.identifier}`);\n else\n {\n const workEmitPayload = {\n eventName,\n payload,\n job: slice.jobAddress,\n slice: slice.sliceNumber,\n worker: this.supervisor.workerId,\n authorizationMessage : slice.authorizationMessage,\n };\n return this.supervisor.dcp4.safeWorkEmit(workEmitPayload, `Failed to send workEmit (${eventName}) payload for slice ${slice.identifier}`)\n .then((success) => {\n if (!success)\n this.warning(`Message sent to workEmit is unauthorized; not accepted '${eventName}'`);\n });\n }\n }\n }\n\n /**\n * Save rejected slice timeReport data in this.slice.rejectedTimeReport, then when needed in\n * Supervisor.recordResult, merge this.slice.rejectedTimeReport into this.slice.timeReport.\n * @param {{ total: number, CPU: number, webGL: number, webGPU: number }} timeReport\n */\n handleRejectedWork (timeReport)\n {\n selectiveDebug() && console.debug('handleRejectedWork', this.identifier);\n // If the slice already has rejectedTimeReport, add this timeReport to it.\n // If not, assign this timeReport to slices rejectedTimeReport property\n if (this.slice)\n {\n if (!this.slice.rejectedTimeReport)\n this.slice.rejectedTimeReport = timeReport;\n else\n {\n ['total', 'CPU', 'webGL', 'webGPU'].forEach((key) => {\n if (timeReport[key])\n this.slice.rejectedTimeReport[key] += timeReport[key];\n });\n }\n }\n }\n\n /**\n * Attach CGIO to result returned by a slice workFn.\n * @param {*} completeData - results\n */\n attachCGIOToResult (completeData)\n {\n if (!completeData)\n throw new Error('Slice result is not ready'); // Should never fire.\n if (completeData['timeReport'])\n throw new Error('Slice result already has timeReport'); // Should never fire.\n if (completeData['dataReport'])\n throw new Error('Slice result already has dataReport'); // Should never fire.\n if (this.listenerCount('resolve') > 0)\n {\n completeData['timeReport'] = this.sliceTimeReport;\n completeData['dataReport'] = {\n InDataSize: this.moduleInDataSize + this.jobManager.inputDataSize + this.slice.inputDataSize,\n OutDataSize: this.sliceOutDataSize,\n };\n this.emit('resolve', completeData);\n selectiveDebug() && console.debug('attachCGIOToResult', this.moduleInDataSize, this.jobManager.inputDataSize, this.slice.inputDataSize, completeData['dataReport'].InDataSize);\n }\n else\n {\n // If there is no internal listener for 'resolve', the slice was rejected\n // and we need to update this.slice.rejectedTimeReport appropriately.\n this.handleRejectedWork(this.sliceTimeReport);\n }\n // Clear time and data reports so we can catch mistaken writes.\n this.sliceTimeReport = null;\n this.sliceOutDataSize = 0;\n }\n\n // _Idx\n //\n // handleRing0Message, handleRing1Message, handleRing2Message, handleRing3Message\n //\n\n async handleRing0Message(data) // eslint-disable-line require-await\n {\n debugging('ring0') && debug('Ring0', this.identifier, data.request);\n\n switch (data.request)\n {\n // The 'sandboxLoaded' event is used by dcp-native; do not remove.\n case 'sandboxLoaded': // SAVE\n break;\n case 'scriptLoaded':\n if(data.result !== \"success\")\n this.onerror(data);\n break;\n case 'error':\n debug('Sandbox error in ring0', data.error);\n this.rejectWithCleanup('during initialization', data.error);\n break;\n default:\n this.error('Received unhandled request from sandbox: ' + data.request, null, `data: ${ JSON.stringify(data)}`);\n break;\n }\n }\n\n async handleRing1Message(data) // eslint-disable-line require-await\n {\n debugging('ring1') && debug('Ring1', this.identifier, data.request);\n\n switch (data.request)\n {\n case 'applyRequirementsDone':\n // emit internally\n this.emit(data.request, data)\n break;\n default:\n this.error('Received unhandled request from sandbox ring 1: ' + data.request, null, `data: ${ JSON.stringify(data)}`);\n break; \n }\n }\n\n async handleRing2Message(data)\n {\n debugging('ring2') && debug('Ring2', this.identifier, data.request);\n\n switch (data.request)\n {\n case 'dependency': {\n try\n {\n const moduleData = await this.moduleCache.fetchModule(data.data, this.jobAddress);\n // Success! Restore this['packageManager'] delay to retryMinSleepMs (currently 32ms.)\n // Is there a better way to reset than explicit calls?\n this.supervisor.delayManager.resetEBO('packageManager');\n // Send module data to be evaluator.\n const message = {\n request: 'moduleGroup',\n data: moduleData,\n id: data.id,\n };\n // Module data is dynamic since it may only be required in a conditional branch.\n // Moreover, on a long job, the published module itself may be updated on the scheduler.\n const moduleLength = kvin.stringify(moduleData).length; /** @TODO - fix per DCP-3750 */\n this.moduleInDataSize += moduleLength;\n selectiveDebug() && console.debug('Sandbox.Ring2.fetchModule size', this.moduleInDataSize, moduleLength);\n this.postMessageToEvaluator(message);\n }\n catch (error)\n {\n /*\n * In the event of an error here, we want to let the client know there was a problem in\n * loading their module. In principle we shouldn't need a valid sandbox.slice at sandbox.assign.\n * However, in the implementation of Sup2 there is precisely 1 callsite of sandbox.assign and\n * we do have an associated slice at this point. So we make the assumption that sandbox.slice\n * is valid here.\n */\n if (!this.slice) // Design assumption\n throw new Error(`Must have valid slice in sandbox before sandbox.assign is called: ${this.identifier}`);\n\n const payload = {\n name: error.name,\n message: error.message,\n timestamp: error.timestamp ? error.timestamp : new Date(),\n };\n\n this.postWorkEmit('error', payload);\n this.emit('reject', error);\n\n debugging() && console.debug(`Sandbox.Ring2: fetchModule failed ${this.identifier}`, payload, error, Date.now() - this.supervisor.lastTime);\n\n // Close packageManager to start the connection reconnect logic.\n // Should we do a retry loop with fetchModule too?\n this.supervisor.dcp4.resetConnection('packageManager');\n }\n break;\n }\n case 'error':\n /*\n * Ring 2 error messages will only fire for problems inside of the worker that are separate from\n * the work function. In most cases there are other handlers for situations where 'error' may be emitted\n * such as timeouts if the expected message isn't recieved.\n */\n debug('Sandbox error in ring2', data.error);\n this.rejectWithCleanup('during assignment and dependency resolution', data.error);\n break;\n case 'describe':\n case 'evalResult':\n case 'resetStateDone':\n case 'assigned':\n this.emit(data.request, data); // emit internally\n break;\n case 'reject':\n this.emit('reject', data.error); // emit internally\n break;\n default:\n this.error(`Received unhandled request from sandbox ring 2. Data: ${JSON.stringify(data, null, 2)}`);\n break;\n }\n }\n\n async handleRing3Message(data) // eslint-disable-line require-await\n {\n debugging('ring3') && debug('Ring3', this.identifier, data.request);\n\n switch (data.request)\n {\n case 'complete':\n dcp_timers.clearTimeout(this.progressTimeout);\n dcp_timers.clearTimeout(this.sliceTimeout);\n this.progressTimeout = this.sliceTimeout = null;\n\n if (this.progress === null)\n {\n if (this.options.ignoreNoProgress)\n this.warning(\"ENOPROGRESS silenced by localExec: Progress was not called during this slice's execution, in a remote sandbox this would cause the slice to fail.\");\n else\n {\n // If a progress update was never received (progress === null) then reject\n this.emit('reject', new NoProgressError('Sandbox never emitted a progress event.'));\n this.handleRejectedWork(this.sliceTimeReport);\n break;\n }\n }\n \n this.progress = 100;\n this.sliceOutDataSize += kvin.stringify(data.result).length; /** @TODO - fix per DCP-3750 */\n this.attachCGIOToResult(data);\n break;\n case 'progress':\n {\n const { progress, indeterminate, throttledReports, value } = data;\n this.progress = progress;\n // cf. job-noProgress.js\n const progressReport = {\n deltaMs: Date.now() - this.sliceStartTime,\n progress,\n value,\n throttledReports,\n }\n this.progressReports.last = progressReport;\n if (!indeterminate)\n this.progressReports.lastDeterministic = progressReport;\n\n this.resetProgressTimeout();\n this.sandboxEmit('progress', indeterminate || progress < 0 || progress > 100 ? undefined : progress);\n break;\n }\n case 'noProgress':\n this.emit('reject', new NoProgressError(data.message));\n break;\n case 'console':\n data.payload.message = kvin.marshal(data.payload.message);\n this.sliceOutDataSize += JSON.stringify(data.payload.message).length; /** @TODO - fix per DCP-3750 */\n this.postWorkEmit('console', data.payload);\n break;\n case 'emitEvent': /* ad-hoc event from the sandbox (work.emit) */\n this.postWorkEmit('custom', data.payload);\n break;\n case 'measurement':\n this.updateTime(data);\n break;\n case 'sandboxError': /* the sandbox itself has an error condition */\n debug(`Ring3 received a 'sandboxError' event for sandbox ${this.identifier}`, data.error);\n this.emit('sandboxError', data.error);\n this.rejectWithCleanup('internal sandbox error while executing work function', data.error);\n break;\n case 'workError': /* the work function threw/rejected */\n debug(`Ring3 received a 'workError' event for sandbox ${this.identifier}`, data.error);\n this.postWorkEmit('error', data.error);\n const wrappedError = new UncaughtExceptionError(data.error);\n this.rejectWithCleanup('error while executing work function', wrappedError);\n break;\n default:\n this.error('Received unhandled request from sandbox ring 3: ' + data.request, null, `data: ${ JSON.stringify(data)}`);\n break; \n }\n }\n\n /**\n * Try to send the error back to the reject handler in Sandbox.work.\n * But if the reject handler is not available (s.b. rare) then cleanup, emit error and throw.\n * @param {string} message\n * @param {Error|string} error\n */\n rejectWithCleanup (message, error)\n {\n if (this.listenerCount('reject') > 0)\n this.emit('reject', error);\n else\n {\n this.terminate(false);\n this.error(`Sandbox ${this.identifier} ${message}`, error);\n throw error;\n }\n }\n\n // _Idx\n //\n // onmessage, onerror, terminate\n //\n\n /**\n * Handles progress and completion events from sandbox.\n * Unless explicitly returned out of this function will re-emit the event\n * where the name of the event is event.data.request.\n *\n * @param {object} event - event received from the evaaluator sandbox\n * @returns {Promise<void>}\n */\n onmessage (event)\n {\n debugging('event') && debug('onmessage-event', event.data.ringSource);\n if (Sandbox.debugEvents)\n console.debug('sandbox - eventDebug:', { id: this.id, state: this.state.valueOf(), event: JSON.stringify(event) });\n\n const { data } = event;\n const ringLevel = data.ringSource\n\n // Give the data to a handler depending on ring level\n if (ringLevel === -1)\n {\n /** @todo XXXpfr Beware of this happening often. */\n this.error(`Message sent directly from raw postMessage for event ${event}. Terminating worker...`);\n this.terminate(true);\n }\n else\n {\n const handler = this.ringMessageHandlers[ringLevel];\n if (handler)\n return handler.call(this, data.value);\n this.warning(`No handler defined for message from ring ${ringLevel} for event ${event}.`);\n }\n }\n\n /**\n * Error handler for the internal sandbox.\n * Emits error event that gets handled up in the Worker class.\n */\n onerror (event)\n {\n /** @todo XXXpfr Beware of onerror firing often. */\n this.error(`Sandbox.onerror emitted an error: ${event}`);\n this.terminate(true, true);\n }\n\n /**\n * Clears the timeout and terminates the sandbox and sometimes emits a reject event.\n *\n * @param {boolean} [reject=true] - if true emit reject event\n * @param {boolean} [immediate=false] - passed to terminate, used by standaloneWorker to immediately close the connection\n */\n terminate (reject = true, immediate = false)\n {\n if (this.slice)\n this.returnSlice();\n if (this.isTerminated)\n return;\n\n selectiveDebug() && console.debug(`Terminate sandbox ${this.identifier}`);\n\n this.state = new Synchronizer(TERMINATED, [ UNREADY, READYING, READY_FOR_ASSIGN, ASSIGNING, ASSIGNED, WORKING, TERMINATED ]);\n\n dcp_timers.clearTimeout(this.progressTimeout);\n dcp_timers.clearTimeout(this.sliceTimeout);\n this.progressTimeout = this.sliceTimeout = null;\n\n if (this.evaluatorHandle && typeof this.evaluatorHandle.terminate === 'function')\n {\n try\n {\n this.evaluatorHandle.terminate(immediate);\n }\n catch (e)\n {\n this.error(`Error terminating sandbox ${this.id}:`, e);\n }\n finally\n {\n this.evaluatorHandle = null;\n }\n }\n\n if (reject)\n this.emit('reject', new Error(`Sandbox ${this.identifier} was terminated.`));\n\n this.sandboxEmit('end');\n }\n\n // _Idx\n //\n // updateTime, resetSliceReport, sandboxEmit, error, warning\n //\n\n /**\n * ringNPostMessage can send a `measurement` request and update these\n * totals.\n */\n updateTime (measurementEvent)\n {\n ['total', 'CPU', 'webGL', 'webGPU'].forEach((key) => {\n if (measurementEvent[key])\n this.sliceTimeReport[key] += measurementEvent[key];\n });\n }\n\n /**\n * Start over sandbox work timers.\n */\n resetSliceReport ()\n {\n this.sliceTimeReport = {\n total: 0,\n CPU: 0,\n webGL: 0,\n webGPU: 0,\n };\n this.sliceOutDataSize = 0;\n }\n\n /**\n * Safe event emitter on sandboxHandle.\n * @param {string} event\n * @param {...any} args\n */\n sandboxEmit(event, ...args)\n {\n this.supervisor.safeEmit(this.sandboxHandle, event, ...args);\n }\n\n /**\n * Error feedback to user.\n * @param {string} message\n * @param {Array<Error>|Error|string} [coreError]\n * @param {string} [additionalInfo]\n * @param {boolean} [supressStack=false]\n */\n error (message, coreError, additionalInfo, supressStack = false)\n {\n this.supervisor.error(message, coreError, additionalInfo, supressStack);\n }\n\n /**\n * Warning feedback to user.\n * @param {string[]} messages\n */\n warning (...messages)\n {\n this.supervisor.warning(...messages);\n }\n}\n\nSandbox.idCounter = 1;\nSandbox.debugWork = false;\nSandbox.debugState = false;\nSandbox.debugEvents = false;\n\nexports.Sandbox = Sandbox;\nexports.SandboxError = SandboxError;\nexports.NoProgressError = NoProgressError;\nexports.SliceTooSlowError = SliceTooSlowError;\nexports.UncaughtExceptionError = UncaughtExceptionError;\n\n\n//# sourceURL=webpack://dcp/./src/dcp-client/worker/supervisor2/sandbox2.js?");
4802
4802
 
4803
4803
  /***/ }),
4804
4804
 
@@ -5208,7 +5208,7 @@ eval("/* provided dependency */ var process = __webpack_require__(/*! ./node_mod
5208
5208
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
5209
5209
 
5210
5210
  "use strict";
5211
- eval("/**\n * @file src/utils/inventory.js\n * Inventory method and related helpers, originally written for Supervisor2.\n *\n * @author Wes Garland, wes@kingsds.network\n * @date Mar 2021\n */\n\n\nconst { EventEmitter } = __webpack_require__(/*! events */ \"./node_modules/events/events.js\");\nconst inspect = Symbol.for('nodejs.util.inspect.custom');\n\n/** \n * Inventory constructor. This is very much like an Array, but methods `splice`, `fill`, `copyWithin`,\n * and direct access to elements is prohibited.\n *\n * Methods added to Inventory which are not on Array:\n * - add: add an element to the Inventory\n * - delete: remove an element from the Inventory\n * - replace: replace one item in the inventory with another\n * - duplicate: return a new exports.Inventory, seeded with this Inventory's items\n *\n * Events 'add' and 'delete' are emitted whenever elements are added or deleted from\n * the inventory. Both 'add' and 'delete' are emitted during a replace operation.\n *\n * @constructor Inventory\n * @param {string} name [optional] Name of the inventory; used for debugging\n * @param {object} initialValues [optional] An Array-like Object of initial values to add\n * to the Inventory without emitting the 'add' event.\n * @returns {object} instanceof Inventory\n */\nexports.Inventory = function Inventory(name, initialValues, compare)\n{\n var ee = new EventEmitter(name || 'Inventory');\n var px;\n\n if (initialValues)\n {\n if (!Array.isArray(initialValues))\n initialValues = Array.from(initialValues);\n else\n initialValues = [].concat(initialValues);\n }\n \n px = new Proxy([].concat(initialValues || []), {\n get: (target, prop, receiver) => {\n let promiscuous = false; /* see default case */\n\n if (typeof prop !== 'symbol' && !isNaN(+prop) && !promiscuous)\n throw new ReferenceError('indexed access is not allowed');\n\n const locate = (element) => {\n const idx = target.indexOf(element);\n if (idx === -1)\n throw new Error('invalid inventory item');\n return idx;\n }\n \n switch(prop)\n {\n case inspect:\n {\n return `[Object Inventory <${name || 'anonymous'}, ${target.length} items>]`;\n }\n case 'fill':\n case 'copyWithin':\n case 'splice':\n {\n throw new Error(`method ${prop} is not allowed`);\n }\n case 'delete':\n {\n return (element) => {\n const idx = locate(element);\n target.splice(idx, 1)[0];\n ee.emit('delete', element);\n }\n }\n case 'replace':\n {\n return (old, neu) => {\n const idx = locate(old);\n ee.emit('delete', target[idx]);\n target[idx] = neu;\n ee.emit('add', target[idx]);\n };\n }\n case 'pop':\n case 'shift':\n {\n return () => {\n let el = target[prop]();\n ee.emit('delete', el);\n return el;\n }\n }\n case 'add': {\n return (el) => {\n ee.emit('add', el);\n target.push(el);\n return el;\n }\n }\n case 'push':\n case 'unshift':\n {\n return (el) => {\n ee.emit('add', el);\n return target[prop](el);\n }\n }\n case 'on':\n case 'addListener':\n case 'addEventListener':\n case 'removeListener':\n case 'removeEventListener':\n case 'debug':\n case 'debugLabel':\n {\n if (typeof ee[prop] === 'function')\n return ee[prop].bind(ee);\n return ee[prop];\n }\n case 'duplicate':\n {\n return (__name, __compare) => new exports.Inventory(__name || name, target, __compare || compare);\n }\n case 'top':\n {\n return () => target[0];\n }\n case 'count':\n {\n return (arg) => target.filter(arg).length;\n }\n default:\n {\n if (typeof target[prop] !== 'function')\n return target[prop];\n\n /* Allow internal methods, eg. \"push\", to use numeric properties */\n return function Inventory$pxWrapper() {\n promiscuous = true;\n const ret = target[prop].apply(target, arguments)\n promiscuous = false;\n return ret;\n }\n }\n }\n },\n deleteProperty: function Inventory_deleteProperty()\n {\n return false;\n },\n defineProperty: function Inventory_defineProperty()\n {\n return false;\n },\n getPrototypeOf: function Inventory_getPrototypeOf(target)\n {\n return exports.Inventory;\n }\n });\n\n return px;\n}\n\n\n//# sourceURL=webpack://dcp/./src/utils/inventory.js?");
5211
+ eval("/**\n * @file src/utils/inventory.js\n * Inventory method and related helpers, originally written for Supervisor2.\n *\n * @author Wes Garland, wes@kingsds.network\n * @date Mar 2021\n */\n\n\nconst { EventEmitter } = __webpack_require__(/*! dcp/common/dcp-events */ \"./src/common/dcp-events/index.js\");\nconst inspect = Symbol.for('nodejs.util.inspect.custom');\n\n/** \n * Inventory constructor. This is very much like an Array, but methods `splice`, `fill`, `copyWithin`,\n * and direct access to elements is prohibited.\n *\n * Methods added to Inventory which are not on Array:\n * - add: add an element to the Inventory\n * - delete: remove an element from the Inventory\n * - replace: replace one item in the inventory with another\n * - duplicate: return a new exports.Inventory, seeded with this Inventory's items\n *\n * Events 'add' and 'delete' are emitted whenever elements are added or deleted from\n * the inventory. Both 'add' and 'delete' are emitted during a replace operation.\n *\n * @constructor Inventory\n * @param {string} name [optional] Name of the inventory; used for debugging\n * @param {object} initialValues [optional] An Array-like Object of initial values to add\n * to the Inventory without emitting the 'add' event.\n * @returns {object} instanceof Inventory\n */\nexports.Inventory = function Inventory(name, initialValues, compare)\n{\n var ee = new EventEmitter(name || 'Inventory');\n var px;\n\n if (initialValues)\n {\n if (!Array.isArray(initialValues))\n initialValues = Array.from(initialValues);\n else\n initialValues = [].concat(initialValues);\n }\n \n px = new Proxy([].concat(initialValues || []), {\n get: (target, prop, receiver) => {\n let promiscuous = false; /* see default case */\n\n if (typeof prop !== 'symbol' && !isNaN(+prop) && !promiscuous)\n throw new ReferenceError('indexed access is not allowed');\n\n const locate = (element) => {\n const idx = target.indexOf(element);\n if (idx === -1)\n throw new Error('invalid inventory item');\n return idx;\n }\n \n switch(prop)\n {\n case inspect:\n {\n return `[Object Inventory <${name || 'anonymous'}, ${target.length} items>]`;\n }\n case 'fill':\n case 'copyWithin':\n case 'splice':\n {\n throw new Error(`method ${prop} is not allowed`);\n }\n case 'delete':\n {\n return (element) => {\n const idx = locate(element);\n target.splice(idx, 1)[0];\n ee.emit('delete', element);\n }\n }\n case 'replace':\n {\n return (old, neu) => {\n const idx = locate(old);\n ee.emit('delete', target[idx]);\n target[idx] = neu;\n ee.emit('add', target[idx]);\n };\n }\n case 'pop':\n case 'shift':\n {\n return () => {\n let el = target[prop]();\n ee.emit('delete', el);\n return el;\n }\n }\n case 'add': {\n return (el) => {\n ee.emit('add', el);\n target.push(el);\n return el;\n }\n }\n case 'push':\n case 'unshift':\n {\n return (el) => {\n ee.emit('add', el);\n return target[prop](el);\n }\n }\n case 'on':\n case 'addListener':\n case 'addEventListener':\n case 'removeListener':\n case 'removeEventListener':\n case 'debug':\n case 'debugLabel':\n {\n if (typeof ee[prop] === 'function')\n return ee[prop].bind(ee);\n return ee[prop];\n }\n case 'duplicate':\n {\n return (__name, __compare) => new exports.Inventory(__name || name, target, __compare || compare);\n }\n case 'top':\n {\n return () => target[0];\n }\n case 'count':\n {\n return (arg) => target.filter(arg).length;\n }\n default:\n {\n if (typeof target[prop] !== 'function')\n return target[prop];\n\n /* Allow internal methods, eg. \"push\", to use numeric properties */\n return function Inventory$pxWrapper() {\n promiscuous = true;\n const ret = target[prop].apply(target, arguments)\n promiscuous = false;\n return ret;\n }\n }\n }\n },\n deleteProperty: function Inventory_deleteProperty()\n {\n return false;\n },\n defineProperty: function Inventory_defineProperty()\n {\n return false;\n },\n getPrototypeOf: function Inventory_getPrototypeOf(target)\n {\n return exports.Inventory;\n }\n });\n\n return px;\n}\n\n\n//# sourceURL=webpack://dcp/./src/utils/inventory.js?");
5212
5212
 
5213
5213
  /***/ }),
5214
5214
 
@@ -1 +1 @@
1
- {"browser":["deny-node","kvin/kvin.js","script-load-wrapper","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"node":["kvin/kvin.js","sa-ww-simulation","script-load-wrapper","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"native":["deny-node","kvin/kvin.js","sa-ww-simulation","script-load-wrapper","native-event-loop","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"nodeTesting":["kvin/kvin.js","sa-ww-simulation","script-load-wrapper","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap","testing.js"],"testing":["deny-node","kvin/kvin.js","sa-ww-simulation","script-load-wrapper","native-event-loop","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap","testing.js"]}
1
+ {"browser":["deny-node","kvin/kvin.js","script-load-wrapper","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"node":["kvin/kvin.js","sa-ww-simulation","script-load-wrapper","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"native":["deny-node","kvin/kvin.js","sa-ww-simulation","script-load-wrapper","native-event-loop","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"webGpuNative":["deny-node","kvin/kvin.js","sa-ww-simulation","script-load-wrapper","native-event-loop","wrap-event-listeners","timer-classes","webgpu-worker-environment","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"nodeTesting":["kvin/kvin.js","sa-ww-simulation","script-load-wrapper","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap","testing.js"],"testing":["deny-node","kvin/kvin.js","sa-ww-simulation","script-load-wrapper","native-event-loop","wrap-event-listeners","timer-classes","event-loop-virtualization","unique-timing","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap","testing.js"]}
@@ -49,13 +49,28 @@ self.wrapScriptLoading({ scriptName: 'calculate-capabilities' }, function calcul
49
49
  });`
50
50
 
51
51
  webgpu =
52
+ typeof GPU !== 'undefined' ||
52
53
  (typeof navigator !== 'undefined' &&
53
54
  typeof navigator.gpu !== 'undefined');
54
55
 
55
56
  if (webgpu) {
56
57
  try {
57
- const adapter = await navigator.gpu.requestAdapter();
58
- await adapter.requestDevice();
58
+ // if we're in a standalone, we need to initialize a window before requesting adapter
59
+ // These symbols will have to be updated as the webGPU spec keeps updating and as we update our evaluator
60
+ if (typeof WebGPUWindow !== 'undefined') {
61
+ const gpuWindow = new WebGPUWindow({
62
+ width: 640,
63
+ height: 480,
64
+ title: 'DCP-evaluator',
65
+ visible: false,
66
+ });
67
+
68
+ const adapter = await GPU.requestAdapter({ window: gpuWindow });
69
+ await adapter.requestDevice(adapter.extensions);
70
+ } else {
71
+ const adapter = await navigator.gpu.requestAdapter();
72
+ await adapter.requestDevice();
73
+ }
59
74
  } catch (err) {
60
75
  // if glfw fails or the symbols exist but webgpu hasn't been
61
76
  // properly enabled (mozilla)
@@ -104,7 +119,7 @@ self.wrapScriptLoading({ scriptName: 'calculate-capabilities' }, function calcul
104
119
  }
105
120
 
106
121
  if(eval(testCode)(1) !== 1)
107
- useStrict = false;
122
+ useStrict = false;
108
123
 
109
124
  return {
110
125
  engine: {
@@ -83,9 +83,14 @@
83
83
  result: "success",
84
84
  });
85
85
 
86
- if (options.finalScript)
86
+ if (options.finalScript) {
87
87
  delete self.wrapScriptLoading;
88
88
 
89
+ // The 'sandboxLoaded' event is used by dcp-native; do not remove.
90
+ ring0PostMessage({
91
+ request: 'sandboxLoaded', // SAVE
92
+ })
93
+ }
89
94
  } catch (e) {
90
95
  ring0PostMessage({
91
96
  request: 'scriptLoaded',
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @file libexec/sandbox/webgpu-worker-environment.js
3
+ * @author Dominic Cerisano, dcerisano@kingsds.network
4
+ * @date May 2020
5
+ * @author Jason Erb, jason@kingsds.network
6
+ * @date February 2022
7
+ * @note Adapted from:
8
+ * https://github.com/Kings-Distributed-Systems/webgpu/blob/dcp/release/index.js
9
+ */
10
+
11
+ self.wrapScriptLoading({ scriptName: 'webgpu-evaluator' }, function webGpuWorkerEnvironment$$fn(protectedStorage, postMessage)
12
+ {
13
+ if (typeof GPU !== 'undefined') {
14
+ try {
15
+ if (typeof self.navigator === 'undefined')
16
+ {
17
+ self.navigator = {};
18
+ protectedStorage.createdNewNavigator = true;
19
+ }
20
+ self.navigator.gpu = GPU;
21
+
22
+ {
23
+ let devices = [];
24
+
25
+ //Timeouts for polyfills
26
+ //Negative numbers to signal clamping override in evaluator engine.
27
+ //nextTickTimeout is for process.nextTick() polyfill
28
+ //immediateTimeout is for setImmediate() polyfill
29
+
30
+ self.nextTickTimeout = -0;
31
+ self.immediateTimeout = -0;
32
+
33
+ function deviceTick()
34
+ {
35
+ if (devices) {
36
+ for (let ii = 0; ii < devices.length; ++ii) {
37
+ devices[ii].tick();
38
+ };
39
+ }
40
+ }
41
+
42
+ self.setTimeout(deviceTick, self.nextTickTimeout);
43
+
44
+ GPUAdapter.prototype.requestDevice = function() {
45
+ let args = arguments;
46
+
47
+ return new Promise((resolve, reject) => {
48
+ this._requestDevice(...args).then(device => {
49
+ device._onErrorCallback = function(type, msg) {
50
+ //Polyfill for process.nextTick
51
+ self.setTimeout(() => {
52
+ switch (type) {
53
+ case "Error": throw new Error(msg);
54
+ case "Type": throw new TypeError(msg);
55
+ case "Range": throw new RangeError(msg);
56
+ case "Reference": throw new ReferenceError(msg);
57
+ case "Internal": throw new InternalError(msg);
58
+ case "Syntax": throw new SyntaxError(msg);
59
+ default: throw new Error(msg);
60
+ };
61
+ }, self.immediateTimeout);
62
+ };
63
+
64
+ devices.push(device);
65
+ resolve(device);
66
+ });
67
+ });
68
+ };
69
+ }
70
+
71
+ //Return a promise instead of a callback
72
+
73
+ GPUFence.prototype.onCompletion = function(completionValue) {
74
+ return new Promise(resolve => {
75
+ //Polyfill for setImmediate
76
+ self.setTimeout(() => {
77
+ this._onCompletion(completionValue, resolve);
78
+ }, self.immediateTimeout);
79
+ });
80
+ };
81
+
82
+ GPUBuffer.prototype.mapReadAsync = function() {
83
+ return new Promise(resolve => {
84
+ //Polyfill for setImmediate
85
+ self.setTimeout(() => {
86
+ this._mapReadAsync(resolve);
87
+ }, self.immediateTimeout);
88
+ });
89
+ };
90
+
91
+ GPUBuffer.prototype.mapWriteAsync = function() {
92
+ return new Promise(resolve => {
93
+ //Polyfill for setImmediate
94
+ self.setTimeout(() => {
95
+ this._mapWriteAsync(resolve);
96
+ }, self.immediateTimeout);
97
+ });
98
+ };
99
+
100
+ GPUDevice.prototype.createBufferMappedAsync = function(descriptor) {
101
+ return new Promise(resolve => {
102
+ //Polyfill for setImmediate
103
+ self.setTimeout(() => {
104
+ this._createBufferMappedAsync(descriptor, resolve);
105
+ }, self.immediateTimeout);
106
+ });
107
+ };
108
+
109
+ GPUDevice.prototype.createBufferMapped = function(descriptor) {
110
+ return new Promise(resolve => {
111
+ //Polyfill for setImmediate
112
+ self.setTimeout(() => {
113
+ this._createBufferMapped(descriptor, resolve);
114
+ }, self.immediateTimeout);
115
+ });
116
+ };
117
+
118
+ } catch (err) {
119
+ console.log("ERROR: ", err);
120
+ }
121
+ }
122
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dcp-client",
3
- "version": "4.3.2-webgpu.0",
3
+ "version": "4.3.2-webgpu.1",
4
4
  "description": "Core libraries for accessing DCP network",
5
5
  "keywords": [
6
6
  "dcp"
@@ -50,7 +50,6 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@kingsds/eslint-config": "1.0.1",
53
- "@techdocs/cli": "1.4.6",
54
53
  "eslint": "7.30.0",
55
54
  "express": "^4.18.2",
56
55
  "peter": "^2.3.11"
@@ -1,74 +0,0 @@
1
- #! /usr/bin/env bash
2
- #
3
- # @file publish-docs.sh
4
- # @athor Brandon Christie <brandon@distributive.network>
5
- # @date Aug 2023
6
- #
7
- # @description Publishes the docs for each component
8
- # to backstage.
9
-
10
- set -euo pipefail
11
-
12
- cd "$(dirname "$0")/.."
13
-
14
- ROOT_DIR=$PWD
15
-
16
- echo "TechDocs Bucket Name: $TECHDOCS_S3_BUCKET_NAME"
17
- echo "Namespace: $ENTITY_NAMESPACE"
18
-
19
- ENTITY_KIND=$(yq ".kind" < catalog-info.yaml)
20
- echo "Kind: $ENTITY_KIND"
21
-
22
- ENTITY_NAME=$(yq ".metadata.name" < catalog-info.yaml)
23
- echo "Name: $ENTITY_NAME"
24
-
25
- TECHDOCS_REF=$(yq ".metadata.annotations.\"backstage.io/techdocs-ref\"" < catalog-info.yaml)
26
- echo "TechDocs Ref: $TECHDOCS_REF"
27
-
28
- # An example of the the techdocs-ref in the YAML file:
29
- # dir:./docs/dcp
30
- #
31
- # The Regex below will isolate the directory path giving the
32
- # result 'docs/dcp' for the given example.
33
- if [[ "$TECHDOCS_REF" =~ dir:\.(.*) ]]; then
34
- RELATIVE_DOCS_DIR="${BASH_REMATCH[1]%%[[:space:]]*}"
35
- DOCS_DIR="$ROOT_DIR/$RELATIVE_DOCS_DIR"
36
- fi
37
-
38
- # The techdocs-cli commands must be called in the directory where the
39
- # mkdocs.yml file is present.
40
- cd "$DOCS_DIR"
41
-
42
- # MkDocs requires an index.md or README.md file, if one does not exist it will
43
- # be generated automatically.
44
- if ! [ -f index.md ] && ! [ -f README.md ]; then
45
- if [ -z "$CI" ]; then
46
- AUTHOR="$(git config user.name) <$(git config user.email)>"
47
- else
48
- AUTHOR="$CI_COMMIT_AUTHOR"
49
- fi
50
-
51
- echo "README.md or index.md was not found and will be automatically generated."
52
- cat >> index.md <<EOF
53
- <!--
54
- @author $AUTHOR
55
- @date $(date)
56
- @machine $HOSTNAME
57
- @rev $(git rev-parse HEAD)
58
- -->
59
- > **Warning**: MkDocs requires a top level index.md or README.md (case sensitive)
60
- This index.md file has been generated automatically to ensure MkDocs works correctly
61
- EOF
62
- fi
63
-
64
- npx techdocs-cli generate --no-docker --verbose
65
-
66
- npx techdocs-cli publish \
67
- --publisher-type awsS3 \
68
- --storage-name "$TECHDOCS_S3_BUCKET_NAME" \
69
- --entity "$ENTITY_NAMESPACE"/"$ENTITY_KIND"/"$ENTITY_NAME" \
70
- --directory "$ROOT_DIR"/site
71
-
72
- rm -r "$ROOT_DIR"/site
73
-
74
- echo "View generated component: https://backstage.overwatch.distributive.network/docs/default/component/$ENTITY_NAME"
package/catalog-info.yaml DELETED
@@ -1,21 +0,0 @@
1
- # @file catalog-info.yml
2
- # @author Brandon Christie <brandon@distributive.network>
3
- # @date Mar 2023
4
- #
5
- # @description Lists all of the components and the paths to all
6
- # the documentation that will be published to backstage.
7
-
8
- apiVersion: backstage.io/v1alpha1
9
- kind: Component
10
- metadata:
11
- name: dcp-client
12
- description: Documentation for the dcp-client.
13
- tags:
14
- - documentation
15
- annotations:
16
- gitlab.com/project-id: '9874684'
17
- backstage.io/techdocs-ref: dir:./docs
18
- spec:
19
- type: library
20
- lifecycle: production
21
- owner: core
package/docs/mkdocs.yml DELETED
@@ -1,16 +0,0 @@
1
- # @file mkdocs.yml
2
- # @author Brandon Christie <brandon@distributive.network>
3
- # @date Aug 2023
4
- #
5
- # @description Determines how the component of name: 'dcp-client'
6
- # is formatted on backstage.
7
-
8
- site_name: dcp-client
9
- repo_url: https://gitlab.com/Distributed-Compute-Protocol/dcp-client
10
- edit_uri: edit/develop/docs
11
- docs_dir: .
12
- nav:
13
- - README.md
14
- plugins:
15
- - techdocs-core
16
- - same-dir