diff --git a/.gitignore b/.gitignore index 36d1d4093b3..860d761b8a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,12 @@ +# Generated content +src/dist/globals.js + +# pnpm used at the root level +package-lock.json + +# Typescript declaration files (which are generated) +**/*.d.ts + # Mac OS .DS_Store diff --git a/.husky/commit-msg b/.husky/commit-msg index 1a089f456d2..059157fee81 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -npx --no-install commitlint --edit $1 +npx --no-install commitlint --edit $1 || true diff --git a/package.json b/package.json index c81166ad7df..3ad13135035 100644 --- a/package.json +++ b/package.json @@ -53,18 +53,25 @@ "statements": 70 }, "dependencies": { + "@magenta/music": "^1.23.1", "@vernier/godirect": "^1.5.0", "arraybuffer-loader": "^1.0.6", "atob": "^2.1.2", + "browser-hrtime": "^1.1.8", "btoa": "^1.2.1", + "buffer": "^6.0.3", "canvas-toBlob": "^1.0.0", "decode-html": "^2.0.0", "diff-match-patch": "^1.0.4", + "events": "^3.3.0", + "fast-xml-parser": "^4.4.0", "format-message": "^6.2.1", "htmlparser2": "^3.10.0", "immutable": "^3.8.1", "jszip": "^3.1.5", + "microbit-web-bluetooth": "^0.6.0", "minilog": "^3.1.0", + "regenerator-runtime": "^0.14.1", "scratch-audio": "^1.0.6", "scratch-parser": "^5.1.1", "scratch-render": "^1.0.13", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000000..8a009b9acba --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,12662 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@magenta/music': + specifier: ^1.23.1 + version: 1.23.1(@tensorflow/tfjs-core@2.8.6)(seedrandom@2.4.3) + '@vernier/godirect': + specifier: ^1.5.0 + version: 1.8.3 + arraybuffer-loader: + specifier: ^1.0.6 + version: 1.0.8 + atob: + specifier: ^2.1.2 + version: 2.1.2 + browser-hrtime: + specifier: ^1.1.8 + version: 1.1.8 + btoa: + specifier: ^1.2.1 + version: 1.2.1 + buffer: + specifier: ^6.0.3 + version: 6.0.3 + canvas-toBlob: + specifier: ^1.0.0 + version: 1.0.0 + decode-html: + specifier: ^2.0.0 + version: 2.0.0 + diff-match-patch: + specifier: ^1.0.4 + version: 1.0.5 + events: + specifier: ^3.3.0 + version: 3.3.0 + fast-xml-parser: + specifier: ^4.4.0 + version: 4.4.0 + format-message: + specifier: ^6.2.1 + version: 6.2.4 + htmlparser2: + specifier: ^3.10.0 + version: 3.10.1 + immutable: + specifier: ^3.8.1 + version: 3.8.2 + jszip: + specifier: ^3.1.5 + version: 3.10.1 + microbit-web-bluetooth: + specifier: ^0.6.0 + version: 0.6.0 + minilog: + specifier: ^3.1.0 + version: 3.1.0 + regenerator-runtime: + specifier: ^0.14.1 + version: 0.14.1 + scratch-audio: + specifier: ^1.0.6 + version: 1.0.119 + scratch-parser: + specifier: ^5.1.1 + version: 5.2.1 + scratch-render: + specifier: ^1.0.13 + version: 1.0.142(scratch-render-fonts@1.0.47) + scratch-sb1-converter: + specifier: ^1.0.0 + version: 1.0.108 + scratch-storage: + specifier: ^2.3.5 + version: 2.3.118(webpack@5.91.0(webpack-cli@4.10.0)) + scratch-svg-renderer: + specifier: 2.3.45 + version: 2.3.45(scratch-render-fonts@1.0.47) + scratch-translate-extension-languages: + specifier: ^1.0.0 + version: 1.0.6 + text-encoding: + specifier: ^0.7.0 + version: 0.7.0 + uuid: + specifier: ^8.3.2 + version: 8.3.2 + web-worker: + specifier: ^1.3.0 + version: 1.3.0 + devDependencies: + '@babel/core': + specifier: 7.24.5 + version: 7.24.5 + '@babel/eslint-parser': + specifier: 7.24.5 + version: 7.24.5(@babel/core@7.24.5)(eslint@8.57.0) + '@babel/preset-env': + specifier: 7.24.5 + version: 7.24.5(@babel/core@7.24.5) + '@commitlint/cli': + specifier: 17.8.1 + version: 17.8.1 + '@commitlint/config-conventional': + specifier: 17.8.1 + version: 17.8.1 + adm-zip: + specifier: 0.4.11 + version: 0.4.11 + babel-loader: + specifier: 9.1.3 + version: 9.1.3(@babel/core@7.24.5)(webpack@5.91.0(webpack-cli@4.10.0)) + callsite: + specifier: 1.0.0 + version: 1.0.0 + copy-webpack-plugin: + specifier: 4.6.0 + version: 4.6.0 + docdash: + specifier: 1.2.0 + version: 1.2.0 + eslint: + specifier: 8.57.0 + version: 8.57.0 + eslint-config-scratch: + specifier: 9.0.8 + version: 9.0.8(@babel/eslint-parser@7.24.5(@babel/core@7.24.5)(eslint@8.57.0))(eslint@8.57.0) + expose-loader: + specifier: 1.0.3 + version: 1.0.3(webpack@5.91.0(webpack-cli@4.10.0)) + file-loader: + specifier: 6.2.0 + version: 6.2.0(webpack@5.91.0(webpack-cli@4.10.0)) + format-message-cli: + specifier: 6.2.4 + version: 6.2.4 + husky: + specifier: 8.0.3 + version: 8.0.3 + in-publish: + specifier: 2.0.1 + version: 2.0.1 + js-md5: + specifier: 0.7.3 + version: 0.7.3 + jsdoc: + specifier: 3.6.11 + version: 3.6.11 + json: + specifier: ^9.0.4 + version: 9.0.6 + pngjs: + specifier: 3.4.0 + version: 3.4.0 + scratch-blocks: + specifier: 1.1.114 + version: 1.1.114 + scratch-l10n: + specifier: 3.18.142 + version: 3.18.142 + scratch-render-fonts: + specifier: 1.0.47 + version: 1.0.47 + scratch-semantic-release-config: + specifier: 1.0.14 + version: 1.0.14(semantic-release@19.0.5) + scratch-webpack-configuration: + specifier: 1.3.0 + version: 1.3.0(@babel/preset-env@7.24.5(@babel/core@7.24.5))(babel-loader@9.1.3(@babel/core@7.24.5)(webpack@5.91.0(webpack-cli@4.10.0)))(webpack@5.91.0(webpack-cli@4.10.0)) + script-loader: + specifier: 0.7.2 + version: 0.7.2 + semantic-release: + specifier: 19.0.5 + version: 19.0.5 + stats.js: + specifier: 0.17.0 + version: 0.17.0 + tap: + specifier: 16.3.10 + version: 16.3.10(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5))(typescript@5.4.5) + webpack: + specifier: 5.91.0 + version: 5.91.0(webpack-cli@4.10.0) + webpack-cli: + specifier: 4.10.0 + version: 4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0) + webpack-dev-server: + specifier: 3.11.3 + version: 3.11.3(webpack-cli@4.10.0)(webpack@5.91.0) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.24.2': + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.24.4': + resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.24.5': + resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==} + engines: {node: '>=6.9.0'} + + '@babel/eslint-parser@7.24.5': + resolution: {integrity: sha512-gsUcqS/fPlgAw1kOtpss7uhY6E9SFFANQ6EFX5GTvzUwaV0+sGaZWk6xq22MOdeT9wfxyokW3ceCUvOiRtZciQ==} + engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 + + '@babel/generator@7.24.5': + resolution: {integrity: sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.22.5': + resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': + resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.23.6': + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.24.5': + resolution: {integrity: sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.22.15': + resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.2': + resolution: {integrity: sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + '@babel/helper-environment-visitor@7.22.20': + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.23.0': + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.22.5': + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.24.5': + resolution: {integrity: sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.3': + resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.24.5': + resolution: {integrity: sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.22.5': + resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.24.5': + resolution: {integrity: sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.22.20': + resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.24.1': + resolution: {integrity: sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-simple-access@7.24.5': + resolution: {integrity: sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-skip-transparent-expression-wrappers@7.22.5': + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.24.5': + resolution: {integrity: sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.24.1': + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.5': + resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.23.5': + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.24.5': + resolution: {integrity: sha512-/xxzuNvgRl4/HLNKvnFwdhdgN3cpLxgLROeLDl83Yx0AJ1SGvq1ak0OszTOjDfiB8Vx03eJbeDWh9r+jCCWttw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.24.5': + resolution: {integrity: sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.5': + resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.5': + resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.5': + resolution: {integrity: sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1': + resolution: {integrity: sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1': + resolution: {integrity: sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.1': + resolution: {integrity: sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-dynamic-import@7.8.3': + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-export-namespace-from@7.8.3': + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-assertions@7.24.1': + resolution: {integrity: sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.24.1': + resolution: {integrity: sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-arrow-functions@7.24.1': + resolution: {integrity: sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-generator-functions@7.24.3': + resolution: {integrity: sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.24.1': + resolution: {integrity: sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoped-functions@7.24.1': + resolution: {integrity: sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.24.5': + resolution: {integrity: sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.24.1': + resolution: {integrity: sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-static-block@7.24.4': + resolution: {integrity: sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + + '@babel/plugin-transform-classes@7.24.5': + resolution: {integrity: sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.24.1': + resolution: {integrity: sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.24.5': + resolution: {integrity: sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dotall-regex@7.24.1': + resolution: {integrity: sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-keys@7.24.1': + resolution: {integrity: sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dynamic-import@7.24.1': + resolution: {integrity: sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-exponentiation-operator@7.24.1': + resolution: {integrity: sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-export-namespace-from@7.24.1': + resolution: {integrity: sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-for-of@7.24.1': + resolution: {integrity: sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.24.1': + resolution: {integrity: sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-json-strings@7.24.1': + resolution: {integrity: sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.24.1': + resolution: {integrity: sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-logical-assignment-operators@7.24.1': + resolution: {integrity: sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-member-expression-literals@7.24.1': + resolution: {integrity: sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-amd@7.24.1': + resolution: {integrity: sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.24.1': + resolution: {integrity: sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-systemjs@7.24.1': + resolution: {integrity: sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.24.1': + resolution: {integrity: sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5': + resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-new-target@7.24.1': + resolution: {integrity: sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.24.1': + resolution: {integrity: sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.24.1': + resolution: {integrity: sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.24.5': + resolution: {integrity: sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.24.1': + resolution: {integrity: sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.24.1': + resolution: {integrity: sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.24.5': + resolution: {integrity: sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.24.5': + resolution: {integrity: sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.24.1': + resolution: {integrity: sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.24.5': + resolution: {integrity: sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.24.1': + resolution: {integrity: sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.24.1': + resolution: {integrity: sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-reserved-words@7.24.1': + resolution: {integrity: sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.24.1': + resolution: {integrity: sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.24.1': + resolution: {integrity: sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.24.1': + resolution: {integrity: sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.24.1': + resolution: {integrity: sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.24.5': + resolution: {integrity: sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-escapes@7.24.1': + resolution: {integrity: sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.24.1': + resolution: {integrity: sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.24.1': + resolution: {integrity: sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.24.1': + resolution: {integrity: sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.24.5': + resolution: {integrity: sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-modules@0.1.6-no-external-plugins': + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + + '@babel/regjsgen@0.8.0': + resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} + + '@babel/runtime@7.24.5': + resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.24.8': + resolution: {integrity: sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.24.0': + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.24.5': + resolution: {integrity: sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.5': + resolution: {integrity: sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==} + engines: {node: '>=6.9.0'} + + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + + '@commitlint/cli@17.8.1': + resolution: {integrity: sha512-ay+WbzQesE0Rv4EQKfNbSMiJJ12KdKTDzIt0tcK4k11FdsWmtwP0Kp1NWMOUswfIWo6Eb7p7Ln721Nx9FLNBjg==} + engines: {node: '>=v14'} + hasBin: true + + '@commitlint/config-conventional@17.8.1': + resolution: {integrity: sha512-NxCOHx1kgneig3VLauWJcDWS40DVjg7nKOpBEEK9E5fjJpQqLCilcnKkIIjdBH98kEO1q3NpE5NSrZ2kl/QGJg==} + engines: {node: '>=v14'} + + '@commitlint/config-validator@17.8.1': + resolution: {integrity: sha512-UUgUC+sNiiMwkyiuIFR7JG2cfd9t/7MV8VB4TZ+q02ZFkHoduUS4tJGsCBWvBOGD9Btev6IecPMvlWUfJorkEA==} + engines: {node: '>=v14'} + + '@commitlint/ensure@17.8.1': + resolution: {integrity: sha512-xjafwKxid8s1K23NFpL8JNo6JnY/ysetKo8kegVM7c8vs+kWLP8VrQq+NbhgVlmCojhEDbzQKp4eRXSjVOGsow==} + engines: {node: '>=v14'} + + '@commitlint/execute-rule@17.8.1': + resolution: {integrity: sha512-JHVupQeSdNI6xzA9SqMF+p/JjrHTcrJdI02PwesQIDCIGUrv04hicJgCcws5nzaoZbROapPs0s6zeVHoxpMwFQ==} + engines: {node: '>=v14'} + + '@commitlint/format@17.8.1': + resolution: {integrity: sha512-f3oMTyZ84M9ht7fb93wbCKmWxO5/kKSbwuYvS867duVomoOsgrgljkGGIztmT/srZnaiGbaK8+Wf8Ik2tSr5eg==} + engines: {node: '>=v14'} + + '@commitlint/is-ignored@17.8.1': + resolution: {integrity: sha512-UshMi4Ltb4ZlNn4F7WtSEugFDZmctzFpmbqvpyxD3la510J+PLcnyhf9chs7EryaRFJMdAKwsEKfNK0jL/QM4g==} + engines: {node: '>=v14'} + + '@commitlint/lint@17.8.1': + resolution: {integrity: sha512-aQUlwIR1/VMv2D4GXSk7PfL5hIaFSfy6hSHV94O8Y27T5q+DlDEgd/cZ4KmVI+MWKzFfCTiTuWqjfRSfdRllCA==} + engines: {node: '>=v14'} + + '@commitlint/load@17.8.1': + resolution: {integrity: sha512-iF4CL7KDFstP1kpVUkT8K2Wl17h2yx9VaR1ztTc8vzByWWcbO/WaKwxsnCOqow9tVAlzPfo1ywk9m2oJ9ucMqA==} + engines: {node: '>=v14'} + + '@commitlint/message@17.8.1': + resolution: {integrity: sha512-6bYL1GUQsD6bLhTH3QQty8pVFoETfFQlMn2Nzmz3AOLqRVfNNtXBaSY0dhZ0dM6A2MEq4+2d7L/2LP8TjqGRkA==} + engines: {node: '>=v14'} + + '@commitlint/parse@17.8.1': + resolution: {integrity: sha512-/wLUickTo0rNpQgWwLPavTm7WbwkZoBy3X8PpkUmlSmQJyWQTj0m6bDjiykMaDt41qcUbfeFfaCvXfiR4EGnfw==} + engines: {node: '>=v14'} + + '@commitlint/read@17.8.1': + resolution: {integrity: sha512-Fd55Oaz9irzBESPCdMd8vWWgxsW3OWR99wOntBDHgf9h7Y6OOHjWEdS9Xzen1GFndqgyoaFplQS5y7KZe0kO2w==} + engines: {node: '>=v14'} + + '@commitlint/resolve-extends@17.8.1': + resolution: {integrity: sha512-W/ryRoQ0TSVXqJrx5SGkaYuAaE/BUontL1j1HsKckvM6e5ZaG0M9126zcwL6peKSuIetJi7E87PRQF8O86EW0Q==} + engines: {node: '>=v14'} + + '@commitlint/rules@17.8.1': + resolution: {integrity: sha512-2b7OdVbN7MTAt9U0vKOYKCDsOvESVXxQmrvuVUZ0rGFMCrCPJWWP1GJ7f0lAypbDAhaGb8zqtdOr47192LBrIA==} + engines: {node: '>=v14'} + + '@commitlint/to-lines@17.8.1': + resolution: {integrity: sha512-LE0jb8CuR/mj6xJyrIk8VLz03OEzXFgLdivBytoooKO5xLt5yalc8Ma5guTWobw998sbR3ogDd+2jed03CFmJA==} + engines: {node: '>=v14'} + + '@commitlint/top-level@17.8.1': + resolution: {integrity: sha512-l6+Z6rrNf5p333SHfEte6r+WkOxGlWK4bLuZKbtf/2TXRN+qhrvn1XE63VhD8Oe9oIHQ7F7W1nG2k/TJFhx2yA==} + engines: {node: '>=v14'} + + '@commitlint/types@17.8.1': + resolution: {integrity: sha512-PXDQXkAmiMEG162Bqdh9ChML/GJZo6vU+7F03ALKDK8zYc6SuAr47LjG7hGYRqUOz+WK0dU7bQ0xzuqFMdxzeQ==} + engines: {node: '>=v14'} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@discoveryjs/json-ext@0.5.7': + resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} + engines: {node: '>=10.0.0'} + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.10.0': + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@magenta/music@1.23.1': + resolution: {integrity: sha512-MKIf5nU5fJg/j0y+zCeuQuhA5D4TD0hWv+crOpNQLq7TRJ5GQnlz4WuShYzSw/gXj2ncWuYGr6ftP9DvqSsQkA==} + + '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': + resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@octokit/auth-token@3.0.4': + resolution: {integrity: sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==} + engines: {node: '>= 14'} + + '@octokit/core@4.2.4': + resolution: {integrity: sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==} + engines: {node: '>= 14'} + + '@octokit/endpoint@7.0.6': + resolution: {integrity: sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==} + engines: {node: '>= 14'} + + '@octokit/graphql@5.0.6': + resolution: {integrity: sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==} + engines: {node: '>= 14'} + + '@octokit/openapi-types@18.1.1': + resolution: {integrity: sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw==} + + '@octokit/plugin-paginate-rest@6.1.2': + resolution: {integrity: sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==} + engines: {node: '>= 14'} + peerDependencies: + '@octokit/core': '>=4' + + '@octokit/plugin-retry@4.1.6': + resolution: {integrity: sha512-obkYzIgEC75r8+9Pnfiiqy3y/x1bc3QLE5B7qvv9wi9Kj0R5tGQFC6QMBg1154WQ9lAVypuQDGyp3hNpp15gQQ==} + engines: {node: '>= 14'} + peerDependencies: + '@octokit/core': '>=3' + + '@octokit/plugin-throttling@5.2.3': + resolution: {integrity: sha512-C9CFg9mrf6cugneKiaI841iG8DOv6P5XXkjmiNNut+swePxQ7RWEdAZRp5rJoE1hjsIqiYcKa/ZkOQ+ujPI39Q==} + engines: {node: '>= 14'} + peerDependencies: + '@octokit/core': ^4.0.0 + + '@octokit/request-error@3.0.3': + resolution: {integrity: sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==} + engines: {node: '>= 14'} + + '@octokit/request@6.2.8': + resolution: {integrity: sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==} + engines: {node: '>= 14'} + + '@octokit/tsconfig@1.0.2': + resolution: {integrity: sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==} + + '@octokit/types@9.3.2': + resolution: {integrity: sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==} + + '@pnpm/config.env-replace@1.1.0': + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + + '@pnpm/network.ca-file@1.0.2': + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + + '@pnpm/npm-conf@2.2.2': + resolution: {integrity: sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==} + engines: {node: '>=12'} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@semantic-release/changelog@6.0.3': + resolution: {integrity: sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0' + + '@semantic-release/commit-analyzer@9.0.2': + resolution: {integrity: sha512-E+dr6L+xIHZkX4zNMe6Rnwg4YQrWNXK+rNsvwOPpdFppvZO1olE2fIgWhv89TkQErygevbjsZFSIxp+u6w2e5g==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0-beta.1' + + '@semantic-release/error@3.0.0': + resolution: {integrity: sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==} + engines: {node: '>=14.17'} + + '@semantic-release/git@10.0.1': + resolution: {integrity: sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0' + + '@semantic-release/github@8.1.0': + resolution: {integrity: sha512-erR9E5rpdsz0dW1I7785JtndQuMWN/iDcemcptf67tBNOmBUN0b2YNOgcjYUnBpgRpZ5ozfBHrK7Bz+2ets/Dg==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0-beta.1' + + '@semantic-release/npm@9.0.2': + resolution: {integrity: sha512-zgsynF6McdzxPnFet+a4iO9HpAlARXOM5adz7VGVCvj0ne8wtL2ZOQoDV2wZPDmdEotDIbVeJjafhelZjs9j6g==} + engines: {node: '>=16 || ^14.17'} + peerDependencies: + semantic-release: '>=19.0.0' + + '@semantic-release/release-notes-generator@10.0.3': + resolution: {integrity: sha512-k4x4VhIKneOWoBGHkx0qZogNjCldLPRiAjnIpMnlUh6PtaWXp/T+C9U7/TaNDDtgDa5HMbHl4WlREdxHio6/3w==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0-beta.1' + + '@tensorflow/tfjs-backend-cpu@2.8.6': + resolution: {integrity: sha512-x9WTTE9p3Pon2D0d6HH1UCIJsU1w3v9sF3vxJcp+YStrjDefWoW5pwxHCckEKTRra7GWg3CwMKK3Si2dat4H1A==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 2.8.6 + + '@tensorflow/tfjs-backend-webgl@2.8.6': + resolution: {integrity: sha512-kPgm3Dim0Li5MleybYKSZVUCu91ipDjZtTA5RrJx/Dli115qwWdiRGOHYwsIEY61hZoE0m3amjWLUBxtwMW1Nw==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 2.8.6 + + '@tensorflow/tfjs-converter@2.8.6': + resolution: {integrity: sha512-Uv4YC66qjVC9UwBxz0IeLZ8KS2CReh63WlGRtHcSwDEYiwsa7cvp9H6lFSSPT7kiJmrK6JtHeJGIVcTuNnSt9w==} + peerDependencies: + '@tensorflow/tfjs-core': 2.8.6 + + '@tensorflow/tfjs-core@2.8.6': + resolution: {integrity: sha512-jS28M1POUOjnWgx3jp1v5D45DUQE8USsAHHkL/01z75KnYCAAmgqJSH4YKLiYACg3eBLWXH/KTcSc6dHAX7Kfg==} + engines: {yarn: '>= 1.3.2'} + + '@tensorflow/tfjs-data@2.8.6': + resolution: {integrity: sha512-zoDUfd5TfkYdviqu2bObwyJGXJiOvBckOTP9j36PUs6s+4DbTIDttyxdfeEaiiLX9ZUFU58CoW+3LI/dlFVyoQ==} + peerDependencies: + '@tensorflow/tfjs-core': 2.8.6 + seedrandom: ~2.4.3 + + '@tensorflow/tfjs-layers@2.8.6': + resolution: {integrity: sha512-fdZ0i/R2dIKmy8OB5tBAsm5IbAHfJpI6AlbjxpgoU3aWj1HCdDo+pMji928MkDJhP01ISgFTgw/7PseGNaUflw==} + peerDependencies: + '@tensorflow/tfjs-core': 2.8.6 + + '@tensorflow/tfjs@2.8.6': + resolution: {integrity: sha512-/Hk3YCAreNicuQJsAIG32UGHaQj8UwX8y8ZrKVb/CrXOhrRyZmxGSZt9KMVe8MDoydenuGhZCqJUIaWdIKIA5g==} + hasBin: true + + '@tonejs/midi@2.0.28': + resolution: {integrity: sha512-RII6YpInPsOZ5t3Si/20QKpNqB1lZ2OCFJSOzJxz38YdY/3zqDr3uaml4JuCWkdixuPqP1/TBnXzhQ39csyoVg==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/dompurify@3.0.5': + resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@8.56.10': + resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} + + '@types/estree@1.0.5': + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + + '@types/glob@7.2.0': + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/long@4.0.2': + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + + '@types/markdown-it@12.2.3': + resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/minimatch@5.1.2': + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + + '@types/minimist@1.2.5': + resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + + '@types/node-fetch@2.6.11': + resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} + + '@types/node@20.12.12': + resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + + '@types/node@20.5.1': + resolution: {integrity: sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==} + + '@types/node@8.10.40': + resolution: {integrity: sha512-RRSjdwz63kS4u7edIwJUn8NqKLLQ6LyqF/X4+4jp38MBT3Vwetewi2N4dgJEshLbDwNgOJXNYoOwzVZUSSLhkQ==} + + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + + '@types/offscreencanvas@2019.3.0': + resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/seedrandom@2.4.27': + resolution: {integrity: sha512-YvMLqFak/7rt//lPBtEHv3M4sRNA+HGxrhFZ+DQs9K2IkYJbNwVIb8avtJfhDiuaUBX/AW0jnjv48FV8h3u9bQ==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + + '@types/webgl-ext@0.0.30': + resolution: {integrity: sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==} + + '@types/webgl2@0.0.5': + resolution: {integrity: sha512-oGaKsBbxQOY5+aJFV3KECDhGaXt+yZJt2y/OZsnQGLRkH6Fvr7rv4pCt3SRH1somIHfej/c4u7NSpCyd9x+1Ow==} + + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + '@vernier/godirect@1.8.3': + resolution: {integrity: sha512-poS0LZ3jAjH36gIAI0aNBBdsGGbmt11VFbLO+eGDJ/JDSPtMu1iUStvOi0UM/ZH6Jyh34SjVd8Cnxu/Wmcb8iQ==} + + '@webassemblyjs/ast@1.12.1': + resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} + + '@webassemblyjs/floating-point-hex-parser@1.11.6': + resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} + + '@webassemblyjs/helper-api-error@1.11.6': + resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} + + '@webassemblyjs/helper-buffer@1.12.1': + resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} + + '@webassemblyjs/helper-numbers@1.11.6': + resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} + + '@webassemblyjs/helper-wasm-bytecode@1.11.6': + resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} + + '@webassemblyjs/helper-wasm-section@1.12.1': + resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} + + '@webassemblyjs/ieee754@1.11.6': + resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} + + '@webassemblyjs/leb128@1.11.6': + resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} + + '@webassemblyjs/utf8@1.11.6': + resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} + + '@webassemblyjs/wasm-edit@1.12.1': + resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} + + '@webassemblyjs/wasm-gen@1.12.1': + resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} + + '@webassemblyjs/wasm-opt@1.12.1': + resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} + + '@webassemblyjs/wasm-parser@1.12.1': + resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} + + '@webassemblyjs/wast-printer@1.12.1': + resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} + + '@webpack-cli/configtest@1.2.0': + resolution: {integrity: sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==} + peerDependencies: + webpack: 4.x.x || 5.x.x + webpack-cli: 4.x.x + + '@webpack-cli/info@1.5.0': + resolution: {integrity: sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==} + peerDependencies: + webpack-cli: 4.x.x + + '@webpack-cli/serve@1.7.0': + resolution: {integrity: sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==} + peerDependencies: + webpack-cli: 4.x.x + webpack-dev-server: '*' + peerDependenciesMeta: + webpack-dev-server: + optional: true + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + acorn-import-assertions@1.9.0: + resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} + peerDependencies: + acorn: ^8 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + + acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + + adm-zip@0.4.11: + resolution: {integrity: sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA==} + engines: {node: '>=0.3.0'} + + agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + ajv-errors@1.0.1: + resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==} + peerDependencies: + ajv: '>=5.0.0' + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@3.5.2: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + + align-text@0.1.4: + resolution: {integrity: sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==} + engines: {node: '>=0.10.0'} + + amdefine@1.0.1: + resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} + engines: {node: '>=0.4.2'} + + ansi-colors@3.2.4: + resolution: {integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + engines: {node: '>=14.16'} + + ansi-html-community@0.0.8: + resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==} + engines: {'0': node >= 0.8.0} + hasBin: true + + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + + ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansicolors@0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + + anymatch@2.0.0: + resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + append-transform@2.0.0: + resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} + engines: {node: '>=8'} + + aproba@1.2.0: + resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} + + archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + argv-formatter@1.0.0: + resolution: {integrity: sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==} + + arr-diff@4.0.0: + resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} + engines: {node: '>=0.10.0'} + + arr-flatten@1.1.0: + resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} + engines: {node: '>=0.10.0'} + + arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + array-flatten@2.1.2: + resolution: {integrity: sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==} + + array-flatten@3.0.0: + resolution: {integrity: sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA==} + + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array-union@1.0.2: + resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} + engines: {node: '>=0.10.0'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array-uniq@1.0.3: + resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} + engines: {node: '>=0.10.0'} + + array-unique@0.3.2: + resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} + engines: {node: '>=0.10.0'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + + array.prototype.toreversed@1.1.2: + resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==} + + array.prototype.tosorted@1.1.3: + resolution: {integrity: sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==} + + arraybuffer-loader@1.0.8: + resolution: {integrity: sha512-CwUVCcxCgcgZUu2w741OV6Xj1tvRVQebq22RCyGXiLgJOJ4e4M/59EPYdtK2MLfIN28t1TDvuh2ojstNq3Kh5g==} + engines: {node: '>= 4.0.0'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + + assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + + astral-regex@1.0.0: + resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} + engines: {node: '>=4'} + + async-each@1.0.6: + resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} + + async-hook-domain@2.0.4: + resolution: {integrity: sha512-14LjCmlK1PK8eDtTezR6WX8TMaYNIzBIsd2D1sGoGjgx0BuNMMoSdk7i/drlbtamy0AWv9yv2tkB+ASdmeqFIw==} + engines: {node: '>=10'} + + async-limiter@1.0.1: + resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + + async@2.6.4: + resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + atob@2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true + + audio-context@1.0.3: + resolution: {integrity: sha512-RH3/rM74f2ITlohhjgC7oYZVS97wtv/SEjXLCzEinnrIPIDxc39m2aFc6wmdkM0NYRKo1DMleYPMAIbnTRW0eA==} + deprecated: Depends on Web-Audio-API implementation. Use either web-audio-api, web-audio-js or web-audio-engine package. + + automation-events@7.0.7: + resolution: {integrity: sha512-eg7aK2P0jrq4QqnZRWXOQJDYs6lxZXK/erfZ/WPTVPP/YQlgt+J0KvIzTo86zYszkru2J/QCW1FFJYgJVd7TgA==} + engines: {node: '>=18.2.0'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + babel-loader@9.1.3: + resolution: {integrity: sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==} + engines: {node: '>= 14.15.0'} + peerDependencies: + '@babel/core': ^7.12.0 + webpack: '>=5' + + babel-plugin-extract-format-message@6.2.4: + resolution: {integrity: sha512-2nBVhei/madYmkgz2tY6BcCnoI9fNopyBsPqEVE1LAWSMwoxBFwECf35uBxiQDpKqIK/GKJ1BMRw7iN/ChqkWA==} + + babel-plugin-polyfill-corejs2@0.4.11: + resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.10.4: + resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.2: + resolution: {integrity: sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-transform-format-message@6.2.4: + resolution: {integrity: sha512-MlvlDq3eZbllHzbBHo+SLSgKEThdddVRitODffdSQH1N9TbjQ+VhXg/RNlI1R5vQddxusg/NPzzGMZ9lfeJW1g==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@0.0.8: + resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} + engines: {node: '>= 0.4'} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + base64-loader@1.0.0: + resolution: {integrity: sha512-p32+F8dg+ANGx7s8QsZS74ZPHfIycmC2yZcoerzFgbersIYWitPbbF39G6SBx3gyvzyLH5nt1ooocxr0IHuWKA==} + + base@0.11.2: + resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} + engines: {node: '>=0.10.0'} + + batch@0.6.1: + resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} + + before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + + big.js@5.2.2: + resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + + binary-extensions@1.13.1: + resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} + engines: {node: '>=0.10.0'} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bind-obj-methods@3.0.0: + resolution: {integrity: sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==} + engines: {node: '>=10'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bit-twiddle@1.0.2: + resolution: {integrity: sha512-B9UhK0DKFZhoTFcfvAzhqsjStvGJp9vYWf3+6SNTtdSQnvIgfkHbgHrg/e4+TH71N2GDu8tpmCVoyfrL1d7ntA==} + + bl@1.2.3: + resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + body-parser@1.20.2: + resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + bonjour@3.5.0: + resolution: {integrity: sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==} + + bottleneck@2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + braces@2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brfs@1.6.1: + resolution: {integrity: sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==} + hasBin: true + + browser-hrtime@1.1.8: + resolution: {integrity: sha512-kzXheikaJsBtzUBlyVtPIY5r0soQePzjwVwT4IlDpU2RvfB5Py52gpU98M77rgqMCheoSSZvrcrdj3t6cZ3suA==} + + browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + btoa@1.2.1: + resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==} + engines: {node: '>= 0.4.0'} + hasBin: true + + buffer-equal@0.0.1: + resolution: {integrity: sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==} + engines: {node: '>=0.4.0'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-indexof@1.1.1: + resolution: {integrity: sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cacache@10.0.4: + resolution: {integrity: sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==} + + cache-base@1.0.1: + resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} + engines: {node: '>=0.10.0'} + + caching-transform@4.0.0: + resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} + engines: {node: '>=8'} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsite@1.0.0: + resolution: {integrity: sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase-keys@6.2.2: + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} + + camelcase@1.2.1: + resolution: {integrity: sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==} + engines: {node: '>=0.10.0'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001621: + resolution: {integrity: sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==} + + canvas-toBlob@1.0.0: + resolution: {integrity: sha512-oU5bawygt/Nef9F+C49eTFmzXzz6yKdGqn6J1wn/LZQF5ulnnZVm0KIZzik85I6tjCbZFH6aa47j4bU2tkHxRw==} + + cardinal@2.1.1: + resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} + hasBin: true + + catharsis@0.9.0: + resolution: {integrity: sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==} + engines: {node: '>= 10'} + + center-align@0.1.3: + resolution: {integrity: sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==} + engines: {node: '>=0.10.0'} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + + chokidar@2.1.8: + resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} + deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + chrome-trace-event@1.0.3: + resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} + engines: {node: '>=6.0'} + + class-utils@0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cli-width@3.0.0: + resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} + engines: {node: '>= 10'} + + cliui@2.1.0: + resolution: {integrity: sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==} + + cliui@5.0.0: + resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone-deep@4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + + collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + colors@0.6.2: + resolution: {integrity: sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==} + engines: {node: '>=0.1.90'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@2.1.0: + resolution: {integrity: sha512-J2wnb6TKniXNOtoHS8TSrG9IOQluPrsmyAJ8oCUJOBmv+uLBCyPYAZkD2jFvw2DCzIXNnISIM01NIvr35TkBMQ==} + engines: {node: '>= 0.6.x'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + + compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + + compression@1.7.4: + resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + engines: {node: '>= 0.8.0'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + + connect-history-api-fallback@1.6.0: + resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} + engines: {node: '>=0.8'} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + conventional-changelog-angular@5.0.13: + resolution: {integrity: sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==} + engines: {node: '>=10'} + + conventional-changelog-angular@6.0.0: + resolution: {integrity: sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==} + engines: {node: '>=14'} + + conventional-changelog-conventionalcommits@6.1.0: + resolution: {integrity: sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==} + engines: {node: '>=14'} + + conventional-changelog-writer@5.0.1: + resolution: {integrity: sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==} + engines: {node: '>=10'} + hasBin: true + + conventional-commits-filter@2.0.7: + resolution: {integrity: sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==} + engines: {node: '>=10'} + + conventional-commits-parser@3.2.4: + resolution: {integrity: sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==} + engines: {node: '>=10'} + hasBin: true + + conventional-commits-parser@4.0.0: + resolution: {integrity: sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==} + engines: {node: '>=14'} + hasBin: true + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + + copy-concurrently@1.0.5: + resolution: {integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==} + deprecated: This package is no longer supported. + + copy-descriptor@0.1.1: + resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} + engines: {node: '>=0.10.0'} + + copy-webpack-plugin@4.6.0: + resolution: {integrity: sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==} + engines: {node: '>= 4'} + + core-js-compat@3.37.1: + resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} + + core-js@3.37.1: + resolution: {integrity: sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cosmiconfig-typescript-loader@4.4.0: + resolution: {integrity: sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw==} + engines: {node: '>=v14.21.3'} + peerDependencies: + '@types/node': '*' + cosmiconfig: '>=7' + ts-node: '>=10' + typescript: '>=4' + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + crc32@0.2.2: + resolution: {integrity: sha512-PFZEGbDUeoNbL2GHIEpJRQGheXReDody/9axKTxhXtQqIL443wnNigtVZO9iuCIMPApKZRv7k2xr8euXHqNxQQ==} + engines: {node: '>= 0.4.0'} + hasBin: true + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-fetch@3.1.8: + resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + + cross-spawn@6.0.5: + resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} + engines: {node: '>=4.8'} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + crypto-random-string@2.0.0: + resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} + engines: {node: '>=8'} + + css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + + cssstyle@4.0.1: + resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==} + engines: {node: '>=18'} + + cwise-compiler@1.1.3: + resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==} + + cwise-parser@1.0.3: + resolution: {integrity: sha512-nAe238ctwjt9l5exq9CQkHS1Tj6YRGAQxqfL4VaN1B2oqG1Ss0VVqIrBG/vyOgN301PI22wL6ZIhe/zA+BO56Q==} + + cwise@1.0.10: + resolution: {integrity: sha512-4OQ6FXVTRO2bk/OkIEt0rNqDk63aOv3Siny6ZD2/WN9CH7k8X6XyQdcip4zKg1WG+L8GP5t2zicXbDb+H7Y77Q==} + + cyclist@1.0.2: + resolution: {integrity: sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==} + + dargs@7.0.0: + resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} + engines: {node: '>=8'} + + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + + data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + + dateformat@3.0.3: + resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize-keys@1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + + decode-html@2.0.0: + resolution: {integrity: sha512-lVJ+EBozhAXA2nSQG+xAgcD0P5K3uejnIIvM09uoQfS8AALkQ+HhHcEUvKovXi0EIpIZWjm0y8X7ULjaJpgY9w==} + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + deep-equal@1.1.2: + resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==} + engines: {node: '>= 0.4'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + default-gateway@4.2.0: + resolution: {integrity: sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==} + engines: {node: '>=6'} + + default-require-extensions@3.0.1: + resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} + engines: {node: '>=8'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + define-property@0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + + define-property@1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + + define-property@2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + + del@4.1.1: + resolution: {integrity: sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==} + engines: {node: '>=6'} + + del@6.1.1: + resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} + engines: {node: '>=10'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + + diff-match-patch@1.0.5: + resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + dir-glob@2.2.2: + resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==} + engines: {node: '>=4'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dns-equal@1.0.0: + resolution: {integrity: sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==} + + dns-packet@1.3.4: + resolution: {integrity: sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==} + + dns-txt@2.0.2: + resolution: {integrity: sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==} + + docdash@1.2.0: + resolution: {integrity: sha512-IYZbgYthPTspgqYeciRJNPhSwL51yer7HAwDXhF5p+H7mTDbPvY3PCk/QDjNxdPCpWkaJVFC4t7iCNB/t9E5Kw==} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dom-serializer@0.2.2: + resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==} + + domelementtype@1.3.1: + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@2.4.2: + resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} + + dompurify@3.1.4: + resolution: {integrity: sha512-2gnshi6OshmuKil8rMZuQCGiUF3cUxHY3NGDzUAdUx/NPEe5DVnO8BDoAQouvgwnx0R/+a6jUn36Z0FSdq8vww==} + + domutils@1.7.0: + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} + + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + + dup@1.0.0: + resolution: {integrity: sha512-Bz5jxMMC0wgp23Zm15ip1x8IhYRqJvF3nFC0UInJUDkN1z4uNPk9jTnfCUJXbOGiQ1JbXLQsiV41Fb+HXcj5BA==} + + duplexer2@0.0.2: + resolution: {integrity: sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==} + + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + + duplexify@3.7.1: + resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.4.777: + resolution: {integrity: sha512-n02NCwLJ3wexLfK/yQeqfywCblZqLcXphzmid5e8yVPdtEcida7li0A5WQKghHNG0FeOMCzeFOzEbtAh5riXFw==} + + emoji-regex@7.0.3: + resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emojis-list@3.0.0: + resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} + engines: {node: '>= 4'} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + enhanced-resolve@5.16.1: + resolution: {integrity: sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==} + engines: {node: '>=10.13.0'} + + entities@1.1.2: + resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} + + entities@2.1.0: + resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==} + + entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + env-ci@5.5.0: + resolution: {integrity: sha512-o0JdWIbOLP+WJKIUt36hz1ImQQFuN92nhsfTkHHap+J8CiI8WgGpH/a9jEGHh4/TU5BUUGjlnKXNoDb57+ne+A==} + engines: {node: '>=10.17'} + + envinfo@7.13.0: + resolution: {integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==} + engines: {node: '>=4'} + hasBin: true + + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.0.19: + resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.5.3: + resolution: {integrity: sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escodegen@0.0.28: + resolution: {integrity: sha512-6ioQhg16lFs5c7XJlJFXIDxBjO4yRvXC9yK6dLNNGuhI3a/fJukHanPF6qtpjGDgAFzI8Wuq3PSIarWmaOq/5A==} + engines: {node: '>=0.4.0'} + hasBin: true + + escodegen@1.3.3: + resolution: {integrity: sha512-z9FWgKc48wjMlpzF5ymKS1AF8OIgnKLp9VyN7KbdtyrP/9lndwUFqCtMm+TAJmJf7KJFFYc4cFJfVTTGkKEwsA==} + engines: {node: '>=0.10.0'} + hasBin: true + + escodegen@1.9.1: + resolution: {integrity: sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==} + engines: {node: '>=4.0'} + hasBin: true + + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + eslint-config-scratch@9.0.8: + resolution: {integrity: sha512-Lc5nTlGt8NFNxkdWE7SRPGwhDl1NJ56w96H61noohaGuIlKv96HmqRluuOZ5jAZ5fWHktZIZJh7I+3Ce7fIVYA==} + peerDependencies: + '@babel/eslint-parser': ^7.11.0 + eslint: ^8.0.0 + + eslint-plugin-format-message@6.2.4: + resolution: {integrity: sha512-hibY1D1jd2GXFT0Pl5Mb1QGHQT/zSPJji+CQhWH1p6/r3Nub7sdZwxp2VUj8wGAvQSbn/tkepc2Ig7i450cAvQ==} + peerDependencies: + eslint: '>=2.0.0' + + eslint-plugin-react@7.34.1: + resolution: {integrity: sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-utils@1.4.3: + resolution: {integrity: sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==} + engines: {node: '>=6'} + + eslint-visitor-keys@1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + + eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@6.8.0: + resolution: {integrity: sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + hasBin: true + + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@6.2.1: + resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==} + engines: {node: '>=6.0.0'} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@1.0.4: + resolution: {integrity: sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==} + engines: {node: '>=0.4.0'} + hasBin: true + + esprima@1.1.1: + resolution: {integrity: sha512-qxxB994/7NtERxgXdFgLHIs9M6bhLXc6qtUmWZ3L8+gTQ9qaoyki2887P2IqAYsoENyr8SUbTutStDniOHSDHg==} + engines: {node: '>=0.4.0'} + hasBin: true + + esprima@1.2.5: + resolution: {integrity: sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + esprima@3.1.3: + resolution: {integrity: sha512-AWwVMNxwhN8+NIPQzAQZCm7RkLC4RbM3B1OobMuyp3i+w73X57KCKaVIxaRZb+DYCojq7rspo+fmuQfAboyhFg==} + engines: {node: '>=4'} + hasBin: true + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@1.3.2: + resolution: {integrity: sha512-OkbCPVUu8D9tbsLcUR+CKFRBbhZlogmkbWaP3BPERlkqzWL5Q6IdTz6eUk+b5cid2MTaCqJb2nNRGoJ8TpfPrg==} + engines: {node: '>=0.4.0'} + + estraverse@1.5.1: + resolution: {integrity: sha512-FpCjJDfmo3vsc/1zKSeqR5k42tcIhxFIlvq+h9j0fO2q/h2uLKyweq7rYJ+0CoVvrGQOxIS5wyBrW/+vF58BUQ==} + engines: {node: '>=0.4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@1.0.0: + resolution: {integrity: sha512-x/iYH53X3quDwfHRz4y8rn4XcEwwCJeWsul9pF1zldMbGtgOtMNBEOuYWwB1EQlK2LRa1fev3YAgym/RElp5Cg==} + engines: {node: '>=0.10.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + events-to-array@1.1.2: + resolution: {integrity: sha512-inRWzRY7nG+aXZxBzEqYKB3HPgwflZRopAjDCHv0whhRx+MTUr1ei0ICZUypdyE0HRm4L2d5VEcIqLD6yl+BFA==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + eventsource@2.0.2: + resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} + engines: {node: '>=12.0.0'} + + execa@1.0.0: + resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} + engines: {node: '>=6'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + expand-brackets@2.1.4: + resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} + engines: {node: '>=0.10.0'} + + exports-loader@0.7.0: + resolution: {integrity: sha512-RKwCrO4A6IiKm0pG3c9V46JxIHcDplwwGJn6+JJ1RcVnh/WSGJa0xkmk5cRVtgOPzCAtTMGj2F7nluh9L0vpSA==} + engines: {node: '>= 4'} + + expose-loader@1.0.3: + resolution: {integrity: sha512-gP6hs3vYeWIqyoVfsApGQcgCEpbcI1xe+celwI31zeDhXz2q03ycBC1+75IlQUGaYvj6rAloFIe/NIBnEElLsQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + express@4.19.2: + resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} + engines: {node: '>= 0.10.0'} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + + extglob@2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + + falafel@2.2.5: + resolution: {integrity: sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==} + engines: {node: '>=0.4.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-xml-parser@4.4.0: + resolution: {integrity: sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==} + hasBin: true + + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + + fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + + fft.js@4.0.4: + resolution: {integrity: sha512-f9c00hphOgeQTlDyavwTtu6RiK8AIFjD6+jvXkNkpeQ7rirK3uFWVpalkoS4LAwbdX7mfZ8aoBfFVQX1Re/8aw==} + + figures@2.0.0: + resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} + engines: {node: '>=4'} + + figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + + file-entry-cache@5.0.1: + resolution: {integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==} + engines: {node: '>=4'} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + file-loader@6.2.0: + resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + engines: {node: '>= 0.8'} + + find-cache-dir@1.0.0: + resolution: {integrity: sha512-46TFiBOzX7xq/PcSWfFwkyjpemdRnMe31UQF+os0y+1W3k95f6R4SEt02Hj4p3X0Mir9gfrkmOtshFidS0VPUg==} + engines: {node: '>=4'} + + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + + find-cache-dir@4.0.0: + resolution: {integrity: sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==} + engines: {node: '>=14.16'} + + find-up@2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + find-versions@4.0.0: + resolution: {integrity: sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==} + engines: {node: '>=10'} + + findit@2.0.0: + resolution: {integrity: sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==} + + findup@0.1.5: + resolution: {integrity: sha512-Udxo3C9A6alt2GZ2MNsgnIvX7De0V3VGxeP/x98NSVgSlizcDHdmJza61LI7zJy4OEtSiJyE72s0/+tBl5/ZxA==} + engines: {node: '>=0.6'} + hasBin: true + + flat-cache@2.0.1: + resolution: {integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==} + engines: {node: '>=4'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + flatted@2.0.2: + resolution: {integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==} + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + flush-write-stream@1.1.1: + resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} + + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + for-in@1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} + + foreground-child@2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + format-message-cli@6.2.4: + resolution: {integrity: sha512-qJHpv8vSJWb3iOn7YxcCXO/wy7bcRBLMq+5u1JZeoNHV6ipxeEt/bc4bcXpN62XgLYJ7UzOFDDdAcIOrMIr0iQ==} + hasBin: true + + format-message-estree-util@6.2.4: + resolution: {integrity: sha512-GymGOfLzVnuDiBONl7Bq00L3ff7kk6qoX2x90V1ZNyjjQMZdexS/4YXxSS00VicDpEMOCxvuO8oUNB/o1o0avA==} + + format-message-formats@6.2.4: + resolution: {integrity: sha512-smT/fAqBLqusWfWCKRAx6QBDAAbmYznWsIyTyk66COmvwt2Byiqd7SJe2ma9a5oV0kwRaOJpN/F4lr4YK/n6qQ==} + + format-message-generate-id@6.2.4: + resolution: {integrity: sha512-yx+sq5Thn0u5bMyy1qNkNA45nJSCskfOPXHx7KoDu/WCF/qudmXqvmuuS8ntz9qikH37ggAfiLM8Zrm0Fh+H7A==} + + format-message-interpret@6.2.4: + resolution: {integrity: sha512-dRvz9mXhITApyOtfuFEb/XqvCe1u6RMkQW49UJHXS8w2S8cAHCqq5LNDFK+QK6XVzcofROycLb/k1uybTAKt2w==} + + format-message-parse@6.2.4: + resolution: {integrity: sha512-k7WqXkEzgXkW4wkHdS6Cv2Ou0rIFtiDelZjgoe1saW4p7FT7zS8OeAUpAekhormqzpeecR97e4vBft1zMsfFOQ==} + + format-message-print@6.2.4: + resolution: {integrity: sha512-72j+ATEN13NFJ1hYaPcDVJEE37BD1P29plLIdCqEMwezVa1c7VSPgRB1eZnkoWxm4YKFgS770pJlE1ZczACqgQ==} + + format-message@6.2.4: + resolution: {integrity: sha512-/24zYeSRy2ZlEO2OIctm7jOHvMpoWf+uhqFCaqqyZKi1C229zAAy2E5vF4lSSaMH0a2kewPrOzq6xN4Yy7cQrw==} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fragment-cache@0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + from2-array@0.0.4: + resolution: {integrity: sha512-0G0cAp7sYLobH7ALsr835x98PU/YeVF7wlwxdWbCUaea7wsa7lJfKZUAo6p2YZGZ8F94luCuqHZS3JtFER6uPg==} + + from2@2.3.0: + resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + + fromentries@1.3.2: + resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + + fs-exists-cached@1.0.0: + resolution: {integrity: sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg==} + + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + + fs-write-stream-atomic@1.0.10: + resolution: {integrity: sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==} + deprecated: This package is no longer supported. + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@1.2.13: + resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} + engines: {node: '>= 4.0'} + os: [darwin] + deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function-loop@2.0.1: + resolution: {integrity: sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@4.1.0: + resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} + engines: {node: '>=6'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + + git-log-parser@1.2.0: + resolution: {integrity: sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==} + + git-raw-commits@2.0.11: + resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==} + engines: {node: '>=10'} + hasBin: true + + glob-parent@3.1.0: + resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + glob@5.0.15: + resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + + global-dirs@0.1.1: + resolution: {integrity: sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==} + engines: {node: '>=4'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@12.4.0: + resolution: {integrity: sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==} + engines: {node: '>=8'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globby@6.1.0: + resolution: {integrity: sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==} + engines: {node: '>=0.10.0'} + + globby@7.1.1: + resolution: {integrity: sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==} + engines: {node: '>=4'} + + google-closure-library@20190301.0.0: + resolution: {integrity: sha512-mpeszbnXpRhXZ0sPqUxBgUmk0RtmzrJRy3KFygp0Ih9JuRUjQTCLhwYQeIlK2vB2lShhY/KUo9E1Z1gvxDFxOQ==} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + grapheme-breaker@0.3.2: + resolution: {integrity: sha512-mB6rwkw1Z7z4z2RkFFTd/+q6Ug1gnCgjKAervAKgBeNI1mSr8E5EUWoYzFNOZsLHFArLfpk+O8X8qXC7uvuawQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + handle-thing@2.0.1: + resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} + + handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + hard-rejection@2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + has-value@0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + + has-value@1.0.0: + resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} + engines: {node: '>=0.10.0'} + + has-values@0.1.4: + resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} + engines: {node: '>=0.10.0'} + + has-values@1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.0'} + + has@1.0.4: + resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} + engines: {node: '>= 0.4.0'} + + hasha@5.2.2: + resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} + engines: {node: '>=8'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hook-std@2.0.0: + resolution: {integrity: sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==} + engines: {node: '>=8'} + + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + hpack.js@2.1.6: + resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} + + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + + html-entities@1.4.0: + resolution: {integrity: sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + htmlparser2@3.10.1: + resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} + + http-deceiver@1.2.7: + resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} + + http-errors@1.6.3: + resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} + engines: {node: '>= 0.6'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http-parser-js@0.5.8: + resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + http-proxy-middleware@0.19.1: + resolution: {integrity: sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==} + engines: {node: '>=4.0.0'} + + http-proxy@1.18.1: + resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} + engines: {node: '>=8.0.0'} + + https-proxy-agent@7.0.4: + resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} + engines: {node: '>= 14'} + + hull.js@0.2.11: + resolution: {integrity: sha512-WEmMRCFqoZA0d7bD9KY9RK0rTBKRfNqDExi8OvFz5A57hpywyc0Wd5N4egF9cU+E69p1KjE/fTIYU4CjOgXdZQ==} + deprecated: This package was deprecated on npmjs.com and now hosted on GitHub Packages. Visit package homepage for instructions. + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + husky@8.0.3: + resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} + engines: {node: '>=14'} + hasBin: true + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + iferr@0.1.5: + resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==} + + ify-loader@1.1.0: + resolution: {integrity: sha512-EiyC45FRIs+z4g98+jBzuYCfoM6TKG9p7Ek5YZUeM7rucNucaMZIseRj/5Q3I4ypkZXyC2wnU1RcYrVmshe2xw==} + + ignore@3.3.10: + resolution: {integrity: sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==} + + ignore@4.0.6: + resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} + engines: {node: '>= 4'} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + immutable@3.8.2: + resolution: {integrity: sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==} + engines: {node: '>=0.10.0'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + import-from@4.0.0: + resolution: {integrity: sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==} + engines: {node: '>=12.2'} + + import-local@2.0.0: + resolution: {integrity: sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==} + engines: {node: '>=6'} + hasBin: true + + import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + + imports-loader@0.8.0: + resolution: {integrity: sha512-kXWL7Scp8KQ4552ZcdVTeaQCZSLW+e6nJfp3cwUMB673T7Hr98Xjx5JK+ql7ADlJUvj1JS5O01RLbKoutN5QDQ==} + engines: {node: '>= 4'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + in-publish@2.0.1: + resolution: {integrity: sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==} + hasBin: true + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + inquirer@7.3.3: + resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} + engines: {node: '>=8.0.0'} + + internal-ip@4.3.0: + resolution: {integrity: sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==} + engines: {node: '>=6'} + + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + + interpret@2.2.0: + resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==} + engines: {node: '>= 0.10'} + + into-stream@6.0.0: + resolution: {integrity: sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==} + engines: {node: '>=10'} + + iota-array@1.0.0: + resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==} + + ip-regex@2.1.0: + resolution: {integrity: sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==} + engines: {node: '>=4'} + + ip@1.1.9: + resolution: {integrity: sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-absolute-url@3.0.3: + resolution: {integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==} + engines: {node: '>=8'} + + is-accessor-descriptor@1.0.1: + resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} + engines: {node: '>= 0.10'} + + is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-binary-path@1.0.1: + resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} + engines: {node: '>=0.10.0'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + + is-data-descriptor@1.0.1: + resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-descriptor@0.1.7: + resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} + engines: {node: '>= 0.4'} + + is-descriptor@1.0.3: + resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} + engines: {node: '>= 0.4'} + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + + is-glob@3.1.0: + resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@3.0.0: + resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-path-cwd@2.2.0: + resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} + engines: {node: '>=6'} + + is-path-in-cwd@2.1.0: + resolution: {integrity: sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==} + engines: {node: '>=6'} + + is-path-inside@2.1.0: + resolution: {integrity: sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==} + engines: {node: '>=6'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-plain-obj@1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + + is-stream@1.1.0: + resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} + engines: {node: '>=0.10.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-text-path@1.0.1: + resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==} + engines: {node: '>=0.10.0'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + + isarray@0.0.1: + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isobject@2.1.0: + resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} + engines: {node: '>=0.10.0'} + + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + + isomorphic-dompurify@2.11.0: + resolution: {integrity: sha512-PNGGCbbSH7+zF45UKu4Kh+yI8hm1bWA8kIZQow4KMImnjYQtrqJA0ZmwHamYUU7+M5tQ84z7xXMWmZF/v5t5eA==} + engines: {node: '>=18'} + + issue-parser@6.0.0: + resolution: {integrity: sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==} + engines: {node: '>=10.13'} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-hook@3.0.0: + resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} + engines: {node: '>=8'} + + istanbul-lib-instrument@4.0.3: + resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} + engines: {node: '>=8'} + + istanbul-lib-processinfo@2.0.3: + resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + + iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + + jackspeak@1.4.2: + resolution: {integrity: sha512-GHeGTmnuaHnvS+ZctRB01bfxARuu9wW83ENbuiweu07SFcVlZrJpcshSre/keGT7YGBhLHg/+rXCNSrsEHKU4Q==} + engines: {node: '>=8'} + + java-properties@1.0.2: + resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} + engines: {node: '>= 0.6.0'} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + js-md5@0.7.3: + resolution: {integrity: sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + js2xmlparser@4.0.2: + resolution: {integrity: sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==} + + jsdoc@3.6.11: + resolution: {integrity: sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==} + engines: {node: '>=12.0.0'} + hasBin: true + + jsdom@24.0.0: + resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-better-errors@1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + json@9.0.6: + resolution: {integrity: sha512-Nx+4WwMM1xadgqjjteOVEyjoIVq7fGH1hAlRDoxoq2tFzYsBYZDIKwYbyxolkTYwxsSOgAZD2ACLkeGjhFW2Jw==} + engines: {node: '>=0.10.0'} + hasBin: true + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + killable@1.0.1: + resolution: {integrity: sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==} + + kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + + kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + klaw@3.0.0: + resolution: {integrity: sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==} + + lazy-cache@1.0.4: + resolution: {integrity: sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==} + engines: {node: '>=0.10.0'} + + levn@0.3.0: + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} + engines: {node: '>= 0.8.0'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + libtap@1.4.1: + resolution: {integrity: sha512-S9v19shLTigoMn3c02V7LZ4t09zxmVP3r3RbEAwuHFYeKgF+ESFJxoQ0PMFKW4XdgQhcjVBEwDoopG6WROq/gw==} + engines: {node: '>=10'} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + linebreak@0.3.0: + resolution: {integrity: sha512-zt8pzlM3oq4moDN8U5mP1SbZ44yKV6dXCu44Ez6iTXmxUl8/jRFWeho2SDqL5YDBv0TBKPgU/XGovZwnXAKlOQ==} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + linkify-it@3.0.3: + resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==} + + load-json-file@4.0.0: + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} + engines: {node: '>=4'} + + loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + + loader-utils@1.4.2: + resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} + engines: {node: '>=4.0.0'} + + loader-utils@2.0.4: + resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} + engines: {node: '>=8.9.0'} + + locate-path@2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.capitalize@4.2.1: + resolution: {integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==} + + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + + lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + + lodash.flattendeep@4.4.0: + resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} + + lodash.isfunction@3.0.9: + resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} + + lodash.ismatch@4.4.0: + resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + + lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + + lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash.uniqby@4.7.0: + resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} + + lodash.upperfirst@4.3.1: + resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + loglevel@1.9.1: + resolution: {integrity: sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==} + engines: {node: '>= 0.6.0'} + + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + + longest@1.0.1: + resolution: {integrity: sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==} + engines: {node: '>=0.10.0'} + + lookup-closest-locale@6.2.0: + resolution: {integrity: sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + magic-string@0.22.5: + resolution: {integrity: sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==} + + make-dir@1.3.0: + resolution: {integrity: sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==} + engines: {node: '>=4'} + + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + map-cache@0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + + map-limit@0.0.1: + resolution: {integrity: sha512-pJpcfLPnIF/Sk3taPW21G/RQsEEirGaFpCW3oXRwH9dnFHPHNGjNyvh++rdmC2fNqEaTw2MhYJraoJWAHx8kEg==} + + map-obj@1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + + map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + + map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + + markdown-it-anchor@8.6.7: + resolution: {integrity: sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==} + peerDependencies: + '@types/markdown-it': '*' + markdown-it: '*' + + markdown-it@12.3.2: + resolution: {integrity: sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==} + hasBin: true + + marked-terminal@5.2.0: + resolution: {integrity: sha512-Piv6yNwAQXGFjZSaiNljyNFw7jKDdGrw70FSbtxEyldLsyeuV5ZHm/1wW++kWbrOF1VPnUgYOhB2oLL0ZpnekA==} + engines: {node: '>=14.13.1 || >=16.0.0'} + peerDependencies: + marked: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + + marked@4.3.0: + resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} + engines: {node: '>= 12'} + hasBin: true + + mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + + mdurl@1.0.1: + resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + memory-fs@0.4.1: + resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} + + meow@8.1.2: + resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} + engines: {node: '>=10'} + + merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + + merge-source-map@1.0.4: + resolution: {integrity: sha512-PGSmS0kfnTnMJCzJ16BLLCEe6oeYCamKFFdQKshi4BmM6FUwipjVOcBFGxqtQtirtAG4iZvHlqST9CpZKqlRjA==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + microbit-web-bluetooth@0.6.0: + resolution: {integrity: sha512-07weZxJk/1ccCbQB+xF/TW9TFW3eqaWaqWwQNXY7byNR4RgcEvQjlHbtlO390zHGCjHfuPyivvZG+gRY+TcZqQ==} + engines: {node: '>=8.14.0'} + + microee@0.0.6: + resolution: {integrity: sha512-/LdL3jiBWDJ3oQIRLgRhfeCZNE3patM1LiwCC124+/HHn10sI/G2OAyiMfTNzH5oYWoZBk0tRZADAUOv+0Wt0A==} + + micromatch@3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + + midi-file@1.2.4: + resolution: {integrity: sha512-B5SnBC6i2bwJIXTY9MElIydJwAmnKx+r5eJ1jknTLetzLflEl0GWveuBB6ACrQpecSRkOB6fhTx1PwXk2BVxnA==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + minilog@3.1.0: + resolution: {integrity: sha512-Xfm4jWjWzSAduvEWtuZX/8TMkxfJlCfH7XvikCZe3ptojYTBq1eoEs3rh9/3LNLOckUP86m+8l8+Iw5NU/pBww==} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimist-options@4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + + minimist@0.0.8: + resolution: {integrity: sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + mississippi@2.0.0: + resolution: {integrity: sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==} + engines: {node: '>=4.0.0'} + + mixin-deep@1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + modify-values@1.0.1: + resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} + engines: {node: '>=0.10.0'} + + move-concurrently@1.0.1: + resolution: {integrity: sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==} + deprecated: This package is no longer supported. + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + multicast-dns-service-types@1.1.0: + resolution: {integrity: sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==} + + multicast-dns@6.2.3: + resolution: {integrity: sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==} + hasBin: true + + multipipe@0.3.1: + resolution: {integrity: sha512-ZUcepNdMeKBRn/ksm2XTxFnhBaqnBJSZNqwajmiem6b7Rp3fNAAq+twYn3kqw9YMY7HJuc7I7OObX9cMgB1ANg==} + + mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + + nan@2.19.0: + resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} + + nanomatch@1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + ndarray-fft@1.0.3: + resolution: {integrity: sha512-p7OPcNAHP616TdoQdmroW666To530jY1q32Gy1DvK3fkaAQ4BuGu715UDDPIARkVQGhHC2qhbjwrhYG2eUQPCw==} + + ndarray-ops@1.2.2: + resolution: {integrity: sha512-BppWAFRjMYF7N/r6Ie51q6D4fs0iiGmeXIACKY66fLpnwIui3Wc3CXiD/30mgLbDjPpSLrsqcp3Z62+IcHZsDw==} + + ndarray-resample@1.0.1: + resolution: {integrity: sha512-wwrEyvIoKDZlZAKf/lXoQ/ChkLMt9pl2iiPmCOo6NELJ1XAIcF0/efCEhicBjBe2q+aD8s+khNcw7XbMvdL8Dg==} + + ndarray-scratch@1.2.0: + resolution: {integrity: sha512-a4pASwB1jQyJcKLYrwrladVfDZDUGc78qLJZbHyb1Q4rhte0URhzc6ALQpBcauwgov0sXLwZz3vYH5jKAhSMIg==} + + ndarray@1.0.19: + resolution: {integrity: sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==} + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + nerf-dart@1.0.0: + resolution: {integrity: sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==} + + nice-try@1.0.5: + resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + + node-emoji@1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + + node-fetch@2.6.13: + resolution: {integrity: sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-forge@0.10.0: + resolution: {integrity: sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==} + engines: {node: '>= 6.0.0'} + + node-preload@0.2.1: + resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} + engines: {node: '>=8'} + + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + normalize-package-data@3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + + normalize-path@2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + npm-normalize-package-bin@1.0.1: + resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + + npm-run-path@2.0.2: + resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} + engines: {node: '>=4'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npm@8.19.4: + resolution: {integrity: sha512-3HANl8i9DKnUA89P4KEgVNN28EjSeDCmvEqbzOAuxCFDzdBZzjUl99zgnGpOUumvW5lvJo2HKcjrsc+tfyv1Hw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + bundledDependencies: + - '@isaacs/string-locale-compare' + - '@npmcli/arborist' + - '@npmcli/ci-detect' + - '@npmcli/config' + - '@npmcli/fs' + - '@npmcli/map-workspaces' + - '@npmcli/package-json' + - '@npmcli/run-script' + - abbrev + - archy + - cacache + - chalk + - chownr + - cli-columns + - cli-table3 + - columnify + - fastest-levenshtein + - fs-minipass + - glob + - graceful-fs + - hosted-git-info + - ini + - init-package-json + - is-cidr + - json-parse-even-better-errors + - libnpmaccess + - libnpmdiff + - libnpmexec + - libnpmfund + - libnpmhook + - libnpmorg + - libnpmpack + - libnpmpublish + - libnpmsearch + - libnpmteam + - libnpmversion + - make-fetch-happen + - minimatch + - minipass + - minipass-pipeline + - mkdirp + - mkdirp-infer-owner + - ms + - node-gyp + - nopt + - npm-audit-report + - npm-install-checks + - npm-package-arg + - npm-pick-manifest + - npm-profile + - npm-registry-fetch + - npm-user-validate + - npmlog + - opener + - p-map + - pacote + - parse-conflict-json + - proc-log + - qrcode-terminal + - read + - read-package-json + - read-package-json-fast + - readdir-scoped-modules + - rimraf + - semver + - ssri + - tar + - text-table + - tiny-relative-date + - treeverse + - validate-npm-package-name + - which + - write-file-atomic + + nwsapi@2.2.10: + resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==} + + nyc@15.1.0: + resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} + engines: {node: '>=8.9'} + hasBin: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-copy@0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} + + object-inspect@0.4.0: + resolution: {integrity: sha512-8WvkvUZiKAjjsy/63rJjA7jw9uyF0CLVLjBKEfnPHE3Jxvs1LgwqL2OmJN+LliIX1vrzKW+AAu02Cc+xv27ncQ==} + + object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + + object-inspect@1.4.1: + resolution: {integrity: sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==} + + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@0.4.0: + resolution: {integrity: sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object-visit@1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.hasown@1.1.4: + resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==} + engines: {node: '>= 0.4'} + + object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + + once@1.3.3: + resolution: {integrity: sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + opener@1.5.2: + resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} + hasBin: true + + opn@5.5.0: + resolution: {integrity: sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==} + engines: {node: '>=4'} + + optionator@0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + own-or-env@1.0.2: + resolution: {integrity: sha512-NQ7v0fliWtK7Lkb+WdFqe6ky9XAzYmlkXthQrBbzlYbmFKoAYbDDcwmOm6q8kOuwSRXW8bdL5ORksploUJmWgw==} + + own-or@1.0.0: + resolution: {integrity: sha512-NfZr5+Tdf6MB8UI9GLvKRs4cXY8/yB0w3xtt84xFdWy8hkGjn+JFc60VhzS/hFRfbyxFcGYMTjnF4Me+RbbqrA==} + + p-each-series@2.2.0: + resolution: {integrity: sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==} + engines: {node: '>=8'} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + + p-is-promise@3.0.0: + resolution: {integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==} + engines: {node: '>=8'} + + p-limit@1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-map@3.0.0: + resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} + engines: {node: '>=8'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + p-reduce@2.1.0: + resolution: {integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==} + engines: {node: '>=8'} + + p-retry@3.0.1: + resolution: {integrity: sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==} + engines: {node: '>=6'} + + p-try@1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-hash@4.0.0: + resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} + engines: {node: '>=8'} + + pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + parallel-transform@1.2.0: + resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@4.0.0: + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + pascalcase@0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + + path-dirname@1.0.2: + resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-is-inside@1.0.2: + resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} + + path-key@2.0.1: + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} + engines: {node: '>=4'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@0.1.7: + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + + path-type@3.0.0: + resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} + engines: {node: '>=4'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pinkie-promise@2.0.1: + resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} + engines: {node: '>=0.10.0'} + + pinkie@2.0.4: + resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} + engines: {node: '>=0.10.0'} + + pkg-conf@2.1.0: + resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} + engines: {node: '>=4'} + + pkg-dir@2.0.0: + resolution: {integrity: sha512-ojakdnUgL5pzJYWw2AIDEupaQCX5OPbM688ZevubICjdIX01PRSYKqm33fJoCOJBRseYCTUlQRnBNX+Pchaejw==} + engines: {node: '>=4'} + + pkg-dir@3.0.0: + resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} + engines: {node: '>=6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pkg-dir@7.0.0: + resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==} + engines: {node: '>=14.16'} + + pngjs@3.4.0: + resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} + engines: {node: '>=4.0.0'} + + portfinder@1.0.32: + resolution: {integrity: sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==} + engines: {node: '>= 0.12.0'} + + posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + prelude-ls@1.1.2: + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} + engines: {node: '>= 0.8.0'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process-on-spawn@1.0.0: + resolution: {integrity: sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==} + engines: {node: '>=8'} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + + protobufjs@6.11.4: + resolution: {integrity: sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==} + hasBin: true + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + pseudomap@1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + + psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + + pump@2.0.1: + resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + + pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + + pumpify@1.5.1: + resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + q@1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + + qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + + qs@6.12.1: + resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==} + engines: {node: '>=0.6'} + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-lru@4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} + + quote-stream@0.0.0: + resolution: {integrity: sha512-m4VtvjAMx00wgAS6eOy50ZDat1EBQeFKBIrtF/oxUt0MenEI33y7runJcRiOihc+JBBIt2aFFJhILIh4e9shJA==} + + quote-stream@1.0.2: + resolution: {integrity: sha512-kKr2uQ2AokadPjvTyKJQad9xELbZwYzWlNfI3Uz2j/ib5u6H9lDP7fUUR//rMycd0gv4Z5P1qXMfXR8YpIxrjQ==} + hasBin: true + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + raw-loader@0.5.1: + resolution: {integrity: sha512-sf7oGoLuaYAScB4VGr0tzetsYlS8EJH6qnTCfQ/WVEa89hALQ4RQfCKt5xCyPQKPDUbVUAIP1QsxAwfAjlDp7Q==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + read-package-json@2.1.2: + resolution: {integrity: sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==} + deprecated: This package is no longer supported. Please use @npmcli/package-json instead. + + read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + + read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + + readable-stream@1.0.34: + resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} + + readable-stream@1.1.14: + resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@2.2.1: + resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} + engines: {node: '>=0.10'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + rechoir@0.7.1: + resolution: {integrity: sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==} + engines: {node: '>= 0.10'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + redeyed@2.1.1: + resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} + + reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + engines: {node: '>= 0.4'} + + regenerate-unicode-properties@10.1.1: + resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + regenerator-transform@0.15.2: + resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} + + regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + + regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + + regexpp@2.0.1: + resolution: {integrity: sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==} + engines: {node: '>=6.5.0'} + + regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + engines: {node: '>=4'} + + registry-auth-token@5.0.2: + resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} + engines: {node: '>=14'} + + regjsparser@0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + hasBin: true + + release-zalgo@1.0.0: + resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} + engines: {node: '>=4'} + + remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + + repeat-element@1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + requizzle@0.2.4: + resolution: {integrity: sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==} + + resolve-cwd@2.0.0: + resolution: {integrity: sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==} + engines: {node: '>=4'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@3.0.0: + resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} + engines: {node: '>=4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-global@1.0.0: + resolution: {integrity: sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==} + engines: {node: '>=8'} + + resolve-url@0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + ret@0.1.15: + resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} + engines: {node: '>=0.12'} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + right-align@0.1.3: + resolution: {integrity: sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==} + engines: {node: '>=0.10.0'} + + rimraf@2.6.3: + resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + hasBin: true + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + + rrweb-cssom@0.6.0: + resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} + + run-async@2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + run-queue@1.0.3: + resolution: {integrity: sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==} + + rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + schema-utils@0.4.7: + resolution: {integrity: sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==} + engines: {node: '>= 4'} + + schema-utils@1.0.0: + resolution: {integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==} + engines: {node: '>= 4'} + + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + + schema-utils@4.2.0: + resolution: {integrity: sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==} + engines: {node: '>= 12.13.0'} + + scratch-audio@1.0.119: + resolution: {integrity: sha512-dLYJ0citPAvK65H81McscuubCNab3DWhN7Qbif6OPp00kn9tStU2JNFL4PSyHlo3I2xkDMrlB7nFTxXpDvk15A==} + + scratch-blocks@1.1.114: + resolution: {integrity: sha512-dSAE22liViu5uwRto0FMPsW5yqnL1YhGnEQ0/yTmrJz20jrOnxUSSPFwB0sCPFqxLEQs4pKb5OLmeTF1nuILnQ==} + + scratch-l10n@3.18.142: + resolution: {integrity: sha512-xmAxwECPFBHjqk1onH6zNjeKprY/hpAoQ0oaSd8IEICAw+1ULtL+BQ665fFUGwYb96eFtGyxpz0Y8DwEs7nawQ==} + hasBin: true + + scratch-parser@5.2.1: + resolution: {integrity: sha512-O9acef/B5MAQSB6PrEGKtbmEL1AOVZf4mYZnR0sNlzRvqqaEd+fZDL5SM7E9uQP09dIghefrm6/xmgzQIJP9Wg==} + engines: {node: '>=8.0'} + + scratch-render-fonts@1.0.47: + resolution: {integrity: sha512-UE0ivb/CT5zInl9kwvdXLJGWvE7aZUWa4EEQ9u5hpiRxq8Y9RR5I57DBun3tr3d+KDQtd5dewjSCFNGRzQc3lg==} + + scratch-render@1.0.142: + resolution: {integrity: sha512-FXkMBPOMdQtFXrJZQTKUIFuMVBnq0uLiU8OhSQhns0ZxprUGXnaRywG5nUBz2mZRQ586WE/DtxHz9NooT/V5Ww==} + peerDependencies: + scratch-render-fonts: ^1.0.0 + + scratch-sb1-converter@1.0.108: + resolution: {integrity: sha512-5O/yXhN5Jf8IVqWo4QaCb75hk5AIDPTjjOIuf/HYB1uzwI6+UjskLzUda80gwz/yN/2nAWFmkE/BktpSseF6aA==} + + scratch-semantic-release-config@1.0.14: + resolution: {integrity: sha512-lEPnAsP614FBcxMrBSrCDxuAdvYlUAGthiiTpqm3rhNBCuPTvVbrNo22yXWVXY3+ZtlrSNfkVKBtBKagDlexJw==} + peerDependencies: + semantic-release: '>=19.0.2' + + scratch-storage@2.3.118: + resolution: {integrity: sha512-Zat/XHENrjqeHSHim2JTyeC3z3aGiVNua6gdZKl5EF1SE1XqQlWU1UD6oNV0QnujMUrO/rve8XRCaEKEPRfLyQ==} + + scratch-svg-renderer@2.3.45: + resolution: {integrity: sha512-zNbsfPbXQU8of4VyykikYMm/O5CofhlbL8tYQ2D4iAo1T7plNg1X5Cj2873FQFNcmT3rNN7GzgY6idlxCiQWnA==} + peerDependencies: + scratch-render-fonts: ^1.0.0 + + scratch-translate-extension-languages@1.0.6: + resolution: {integrity: sha512-lC0ohKbx1g+q5fvYUmG0sFxEdlWL7BUcUxkah5UzUAFE5eqhW+JS7U9bFm4HbwqSovuuI1Xpl4qyu/9yJtrW5w==} + + scratch-webpack-configuration@1.3.0: + resolution: {integrity: sha512-KEhAJzsfIq4nLyo+2CdjxRkKo7QfwJkMgTiL4vnF+4HidwLNpYsA/J0ToPqBG5PpBT3/q8KbZSxAXMInolOWgw==} + peerDependencies: + '@babel/preset-env': ^7.24.0 + babel-loader: ^9.1.3 + webpack: ^5.90.3 + + script-loader@0.7.2: + resolution: {integrity: sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA==} + + seedrandom@2.4.3: + resolution: {integrity: sha512-2CkZ9Wn2dS4mMUWQaXLsOAfGD+irMlLEeSP3cMxpGbgyOOzJGFa+MWCOMTOCMyZinHRPxyOj/S/C57li/1to6Q==} + + select-hose@2.0.0: + resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} + + selfsigned@1.10.14: + resolution: {integrity: sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==} + + semantic-release@19.0.5: + resolution: {integrity: sha512-NMPKdfpXTnPn49FDogMBi36SiBfXkSOJqCkk0E4iWOY1tusvvgBwqUmxTX1kmlT6kIYed9YwNKD1sfPpqa5yaA==} + engines: {node: '>=16 || ^14.17'} + hasBin: true + + semver-diff@3.1.1: + resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} + engines: {node: '>=8'} + + semver-regex@3.1.4: + resolution: {integrity: sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==} + engines: {node: '>=8'} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} + engines: {node: '>=10'} + hasBin: true + + send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + + serialize-javascript@1.9.1: + resolution: {integrity: sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + serve-index@1.9.1: + resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} + engines: {node: '>= 0.8.0'} + + serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + setprototypeof@1.1.0: + resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + + shallow-copy@0.0.1: + resolution: {integrity: sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==} + + shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signale@1.4.0: + resolution: {integrity: sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==} + engines: {node: '>=6'} + + slash@1.0.0: + resolution: {integrity: sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==} + engines: {node: '>=0.10.0'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@2.1.0: + resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} + engines: {node: '>=6'} + + snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + + snapdragon-util@3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + + snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + + sockjs-client@1.6.1: + resolution: {integrity: sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==} + engines: {node: '>=12'} + + sockjs@0.3.24: + resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} + + source-map-resolve@0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map-url@0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + + source-map@0.1.43: + resolution: {integrity: sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==} + engines: {node: '>=0.8.0'} + + source-map@0.5.0: + resolution: {integrity: sha512-gjGnxNN0K+/Pr4Mi4fs/pOtda10dKB6Wn9QvjOrH6v5TWsI7ghHuJUHoIgyM6DkUL5kr2GtPFGererzKpMBWfA==} + engines: {node: '>=0.10.0'} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + spawn-error-forwarder@1.0.0: + resolution: {integrity: sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==} + + spawn-wrap@2.0.0: + resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} + engines: {node: '>=8'} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.17: + resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} + + spdy-transport@3.0.0: + resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} + + spdy@4.0.2: + resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} + engines: {node: '>=6.0.0'} + + split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + + split2@1.0.0: + resolution: {integrity: sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==} + + split2@3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + + split@1.0.1: + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + ssri@5.3.0: + resolution: {integrity: sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + staffrender@0.2.1: + resolution: {integrity: sha512-qg7aaR7YX8TwFYf4p1pjvm3tT8SYLZDe/J2eF2+z2WmYC/PyldnJlsaPKi1qRm0xqQ8nCLziooGXvYRcl5LNew==} + + standardized-audio-context@25.3.75: + resolution: {integrity: sha512-N7/Si1d0kuo1umRnWOsQESqxJlkMxBZfdfNRo5HeE7pA0lmo6PNrMkOSiM0NutFxpwA+KcPexo5JkTWWAAUaNQ==} + + startaudiocontext@1.2.1: + resolution: {integrity: sha512-ooOQhOAoCwzMIRwWd9j7xF8kAMo1Wv7Zfw+q6dWDW5gxJUKx15HJXWDg89GMDqfdle9xsqPv+uioneX+bI643g==} + + static-eval@0.2.4: + resolution: {integrity: sha512-6dWWPfa/0+1zULdQi7ssT5EQZHsGK8LygBzhE/HdafNCo4e/Ibt7vLPfxBw9VcdVV+t0ARtN4ZAJKtApVc0A5Q==} + + static-eval@2.1.1: + resolution: {integrity: sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==} + + static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + + static-module@1.5.0: + resolution: {integrity: sha512-XTj7pQOHT33l77lK/Pu8UXqzI44C6LYAqwAc9hLTTESHRqJAFudBpReuopFPpoRr5CtOoSmGfFQC6FPlbDnyCw==} + + static-module@2.2.5: + resolution: {integrity: sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ==} + + stats.js@0.17.0: + resolution: {integrity: sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + stream-combiner2@1.1.1: + resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} + + stream-each@1.2.3: + resolution: {integrity: sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==} + + stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + + string-width@3.1.0: + resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} + engines: {node: '>=6'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string.prototype.matchall@4.0.11: + resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + engines: {node: '>= 0.4'} + + string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@0.10.31: + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-eof@1.0.0: + resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} + engines: {node: '>=0.10.0'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@6.1.0: + resolution: {integrity: sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==} + engines: {node: '>=6'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-hyperlinks@2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + table@5.4.6: + resolution: {integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==} + engines: {node: '>=6.0.0'} + + taffydb@2.6.2: + resolution: {integrity: sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==} + + tap-mocha-reporter@5.0.4: + resolution: {integrity: sha512-J+YMO8B7lq1O6Zxd/jeuG27vJ+Y4tLiRMKPSb7KR6FVh86k3Rq1TwYc2GKPyIjCbzzdMdReh3Vfz9L5cg1Z2Bw==} + engines: {node: '>= 8'} + hasBin: true + + tap-parser@11.0.2: + resolution: {integrity: sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg==} + engines: {node: '>= 8'} + hasBin: true + + tap-yaml@1.0.2: + resolution: {integrity: sha512-GegASpuqBnRNdT1U+yuUPZ8rEU64pL35WPBpCISWwff4dErS2/438barz7WFJl4Nzh3Y05tfPidZnH+GaV1wMg==} + + tap@16.3.10: + resolution: {integrity: sha512-q5Am+PpGHS6JSjk/Zn4bCRBihmZVM15v/MYXUy60wenw5HDe7pVrevLCEoMEz7tuw6jaPOJJqni1y8apN23IGw==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + coveralls: ^3.1.1 + flow-remove-types: '>=2.112.0' + ts-node: '>=8.5.2' + typescript: '>=3.7.2' + peerDependenciesMeta: + coveralls: + optional: true + flow-remove-types: + optional: true + ts-node: + optional: true + typescript: + optional: true + bundledDependencies: + - ink + - treport + - '@types/react' + - '@isaacs/import-jsx' + - react + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + tcompare@5.0.7: + resolution: {integrity: sha512-d9iddt6YYGgyxJw5bjsN7UJUO1kGOtjSlNy/4PoGYAjQS5pAT/hzIoLf1bZCw+uUxRmZJh7Yy1aA7xKVRT9B4w==} + engines: {node: '>=10'} + + temp-dir@2.0.0: + resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} + engines: {node: '>=8'} + + tempy@1.0.1: + resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} + engines: {node: '>=10'} + + terser-webpack-plugin@5.3.10: + resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@5.31.0: + resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==} + engines: {node: '>=10'} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-encoding@0.7.0: + resolution: {integrity: sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==} + deprecated: no longer maintained + + text-extensions@1.9.0: + resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} + engines: {node: '>=0.10'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + through2@0.4.2: + resolution: {integrity: sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==} + + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + + through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + thunky@1.1.0: + resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + + to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tonal-array@2.2.2: + resolution: {integrity: sha512-h6YIq20L0EEU4EsDoKHAjl5kD2EQn467VfV79QHAuybvNCJpqqRNsQ3QNvoQyir1BgDXaDUIN9FEmQJNiaaCKA==} + + tonal-chord@2.2.2: + resolution: {integrity: sha512-gOIXapi6Gx3ISRKdEJKEQjhDBiwjhaalyWSrN5rijGrSyyFFNZ+EVOfzcqLtnVAF9BgeO9Ca0eXCor3XpHdEJg==} + + tonal-dictionary@2.2.2: + resolution: {integrity: sha512-283ppJl/0lohhlVPMI6t5C6XwaP5Wx0egu9qfG9TLCT2tn4pRwYpXkzGufd9icvkJTgOylOum3+RxWmywUIPIg==} + + tonal-distance@2.2.2: + resolution: {integrity: sha512-ktA6OapCxaetXJb/JuXD5QwfyB7/G3y3ONby7Kkbezyffc57cnNfjdhlTR9XBR7eSFIY/J1KuhLwMx/qrffT4g==} + + tonal-interval@2.2.2: + resolution: {integrity: sha512-lrtDU8lH5IAX7YE63OhGGDRpVb4OoGxaN0wDu5XC3sUhXBwjSgNYpHY2D9JI2aWQ/Er9jhQbnw9b0ffkLy34+Q==} + + tonal-key@2.2.2: + resolution: {integrity: sha512-KIc0b8yPl2ATDxF/65P52tIIempNsAQrug0idpD0zFvs5F5cb1hp7Rh7JJ4gECwC/6a3Hgdd1jomI+TnJ7K98w==} + + tonal-note@2.2.2: + resolution: {integrity: sha512-RNK3Nb8PxBEW9yYGStcoczgE8bCYFZ5zfLvYJjvuzLWiwTQmqWOhTzONVobVCGFZ/jgDNwpBEKe/bngL3g3Xfw==} + + tonal-pcset@2.2.2: + resolution: {integrity: sha512-PSqhkxzckO6J27W0GxawHYln4wvfDJ7puDmccksyFOBo97UhLnpxiyvBekhiYpkuaMtoZLQC/KALAkEj7lcb+A==} + + tonal-roman-numeral@2.2.2: + resolution: {integrity: sha512-+auQNObpW3OvsSqlo+Cc+0otrlEhtbEgpzkPoKbTtkCva0P9oSkSz0OZ9fI73KQM5MsBs1XbB+olxppWkzYTFw==} + + tonal-scale@2.2.2: + resolution: {integrity: sha512-tDb3YCoTF50XOXq9kNhGB1JkInk7qAGN6GQnP/3xkGxkreFFRZyI58jfHlmWf/AH4+IKb/exsOmL6G8Ok/PCRw==} + + tonal@2.2.2: + resolution: {integrity: sha512-Ze2bQc6KhAf3FKM9HzEsQ4z8hZh4WYCOsCrryONqf/THGOrOpL9Cc8Uc0dq0OA2yK2JbD5FhZckEXNYyD9946A==} + + tone@14.9.17: + resolution: {integrity: sha512-+Qb7M4NMua+tb5Z52+MEVmjye0fjJuIFBePx423pqr9E6/lHDqZAG+fUAvo+Ujm48q0s9bVLRAyT1ETJJglNtg==} + + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@5.0.0: + resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} + engines: {node: '>=18'} + + transformation-matrix@1.15.3: + resolution: {integrity: sha512-ThJH58GNFKhCw3gIoOtwf3tNwuYjbyEeiGdeq4mNMYWdJctnI896KUqn6PVt7jmNVepqa1bcKQtnMB1HtjsDMA==} + + traverse@0.6.9: + resolution: {integrity: sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==} + engines: {node: '>= 0.4'} + + trim-newlines@3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + + trivial-deferred@1.1.2: + resolution: {integrity: sha512-vDPiDBC3hyP6O4JrJYMImW3nl3c03Tsj9fEXc7Qc/XKa1O7gf5ZtFfIR/E0dun9SnDHdwjna1Z2rSzYgqpxh/g==} + engines: {node: '>= 8'} + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + + twgl.js@4.24.0: + resolution: {integrity: sha512-JGVTxuV9dqaBmajXyvuZIlhCHrTbIaoNjQvtdoLHyK74OtbmNwZUj6rfdp+pz9htitI/tVxiVQ2nuw+KmD29vg==} + + type-check@0.3.2: + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} + engines: {node: '>= 0.8.0'} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.16.0: + resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} + engines: {node: '>=10'} + + type-fest@0.18.1: + resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} + engines: {node: '>=10'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + + typedarray-pool@1.2.0: + resolution: {integrity: sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ==} + + typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + + typedarray.prototype.slice@1.0.3: + resolution: {integrity: sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==} + engines: {node: '>= 0.4'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@1.0.6: + resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + + uglify-js@2.8.29: + resolution: {integrity: sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==} + engines: {node: '>=0.8.0'} + hasBin: true + + uglify-js@3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + + uglify-to-browserify@1.0.2: + resolution: {integrity: sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==} + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + underscore@1.13.6: + resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + unicode-canonical-property-names-ecmascript@2.0.0: + resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} + engines: {node: '>=4'} + + unicode-length@2.1.0: + resolution: {integrity: sha512-4bV582zTV9Q02RXBxSUMiuN/KHo5w4aTojuKTNT96DIKps/SIawFp7cS5Mu25VuY1AioGXrmYyzKZUzh8OqoUw==} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.1.0: + resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.1.0: + resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + engines: {node: '>=4'} + + unicode-trie@0.3.1: + resolution: {integrity: sha512-WgVuO0M2jDl7hVfbPgXv2LUrD81HM0bQj/bvLGiw6fJ4Zo8nNFnDrA0/hU2Te/wz6pjxCm5cxJwtLjo2eyV51Q==} + + union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + + uniq@1.0.1: + resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==} + + unique-filename@1.1.1: + resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} + + unique-slug@2.0.2: + resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + + unique-string@2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + + universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + + upath@1.2.0: + resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} + engines: {node: '>=4'} + + update-browserslist-db@1.0.16: + resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + urix@0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + + url-join@4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + + url@0.11.3: + resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + + use@3.1.1: + resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} + engines: {node: '>=0.10.0'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-compile-cache@2.4.0: + resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vlq@0.2.3: + resolution: {integrity: sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==} + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + watchpack@2.4.1: + resolution: {integrity: sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==} + engines: {node: '>=10.13.0'} + + wbuf@1.7.3: + resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} + + web-worker@1.3.0: + resolution: {integrity: sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + webpack-cli@4.10.0: + resolution: {integrity: sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + '@webpack-cli/generators': '*' + '@webpack-cli/migrate': '*' + webpack: 4.x.x || 5.x.x + webpack-bundle-analyzer: '*' + webpack-dev-server: '*' + peerDependenciesMeta: + '@webpack-cli/generators': + optional: true + '@webpack-cli/migrate': + optional: true + webpack-bundle-analyzer: + optional: true + webpack-dev-server: + optional: true + + webpack-dev-middleware@3.7.3: + resolution: {integrity: sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==} + engines: {node: '>= 6'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + webpack-dev-server@3.11.3: + resolution: {integrity: sha512-3x31rjbEQWKMNzacUZRE6wXvUFuGpH7vr0lIEbYpMAG9BOxi0928QU1BBswOAP3kg3H1O4hiS+sq4YyAn6ANnA==} + engines: {node: '>= 6.11.5'} + hasBin: true + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + webpack-log@2.0.0: + resolution: {integrity: sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==} + engines: {node: '>= 6'} + + webpack-merge@5.10.0: + resolution: {integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==} + engines: {node: '>=10.0.0'} + + webpack-node-externals@3.0.0: + resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} + engines: {node: '>=6'} + + webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + + webpack@5.91.0: + resolution: {integrity: sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + + websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.0.0: + resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} + engines: {node: '>=18'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wildcard@2.0.1: + resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + + window-size@0.1.0: + resolution: {integrity: sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==} + engines: {node: '>= 0.8.0'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wordwrap@0.0.2: + resolution: {integrity: sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==} + engines: {node: '>=0.4.0'} + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + worker-loader@2.0.0: + resolution: {integrity: sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==} + engines: {node: '>= 6.9.0 || >= 8.9.0'} + peerDependencies: + webpack: ^3.0.0 || ^4.0.0-alpha.0 || ^4.0.0 + + wrap-ansi@5.1.0: + resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} + engines: {node: '>=6'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + + write@1.0.3: + resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==} + engines: {node: '>=4'} + + ws@6.2.2: + resolution: {integrity: sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.17.0: + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + xmlcreate@2.0.4: + resolution: {integrity: sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==} + + xtend@2.1.2: + resolution: {integrity: sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==} + engines: {node: '>=0.4'} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yargs-parser@13.1.2: + resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==} + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@13.3.2: + resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yargs@3.10.0: + resolution: {integrity: sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@babel/code-frame@7.24.2': + dependencies: + '@babel/highlight': 7.24.5 + picocolors: 1.0.1 + + '@babel/compat-data@7.24.4': {} + + '@babel/core@7.24.5': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helpers': 7.24.5 + '@babel/parser': 7.24.5 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.5 + '@babel/types': 7.24.5 + convert-source-map: 2.0.0 + debug: 4.3.4(supports-color@6.1.0) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/eslint-parser@7.24.5(@babel/core@7.24.5)(eslint@8.57.0)': + dependencies: + '@babel/core': 7.24.5 + '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 + eslint: 8.57.0 + eslint-visitor-keys: 2.1.0 + semver: 6.3.1 + + '@babel/generator@7.24.5': + dependencies: + '@babel/types': 7.24.5 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + + '@babel/helper-annotate-as-pure@7.22.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-compilation-targets@7.23.6': + dependencies: + '@babel/compat-data': 7.24.4 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.23.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.24.5 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.24.5 + semver: 6.3.1 + + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-annotate-as-pure': 7.22.5 + regexpu-core: 5.3.2 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.5 + debug: 4.3.4(supports-color@6.1.0) + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-environment-visitor@7.22.20': {} + + '@babel/helper-function-name@7.23.0': + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.5 + + '@babel/helper-hoist-variables@7.22.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-member-expression-to-functions@7.24.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-module-imports@7.24.3': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-module-transforms@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-simple-access': 7.24.5 + '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-validator-identifier': 7.24.5 + + '@babel/helper-optimise-call-expression@7.22.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-plugin-utils@7.24.5': {} + + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.24.5 + + '@babel/helper-replace-supers@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.24.5 + '@babel/helper-optimise-call-expression': 7.22.5 + + '@babel/helper-simple-access@7.24.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-skip-transparent-expression-wrappers@7.22.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-split-export-declaration@7.24.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/helper-string-parser@7.24.1': {} + + '@babel/helper-validator-identifier@7.24.5': {} + + '@babel/helper-validator-option@7.23.5': {} + + '@babel/helper-wrap-function@7.24.5': + dependencies: + '@babel/helper-function-name': 7.23.0 + '@babel/template': 7.24.0 + '@babel/types': 7.24.5 + + '@babel/helpers@7.24.5': + dependencies: + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.5 + '@babel/types': 7.24.5 + transitivePeerDependencies: + - supports-color + + '@babel/highlight@7.24.5': + dependencies: + '@babel/helper-validator-identifier': 7.24.5 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@babel/parser@7.24.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.24.5(@babel/core@7.24.5) + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-arrow-functions@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.5) + + '@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.5) + + '@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-block-scoping@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-class-static-block@7.24.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.5) + + '@babel/plugin-transform-classes@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5) + '@babel/helper-split-export-declaration': 7.24.5 + globals: 11.12.0 + + '@babel/plugin-transform-computed-properties@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/template': 7.24.0 + + '@babel/plugin-transform-destructuring@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-dotall-regex@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-duplicate-keys@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-dynamic-import@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.5) + + '@babel/plugin-transform-exponentiation-operator@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.5) + + '@babel/plugin-transform-for-of@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + + '@babel/plugin-transform-function-name@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-json-strings@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5) + + '@babel/plugin-transform-literals@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-logical-assignment-operators@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5) + + '@babel/plugin-transform-member-expression-literals@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-modules-amd@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-simple-access': 7.24.5 + + '@babel/plugin-transform-modules-systemjs@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-validator-identifier': 7.24.5 + + '@babel/plugin-transform-modules-umd@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-new-target@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.5) + + '@babel/plugin-transform-numeric-separator@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.5) + + '@babel/plugin-transform-object-rest-spread@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-transform-parameters': 7.24.5(@babel/core@7.24.5) + + '@babel/plugin-transform-object-super@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5) + + '@babel/plugin-transform-optional-catch-binding@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.5) + + '@babel/plugin-transform-optional-chaining@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.5) + + '@babel/plugin-transform-parameters@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-private-property-in-object@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.5) + + '@babel/plugin-transform-property-literals@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-regenerator@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + regenerator-transform: 0.15.2 + + '@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-shorthand-properties@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-spread@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + + '@babel/plugin-transform-sticky-regex@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-template-literals@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-typeof-symbol@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-unicode-escapes@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-unicode-property-regex@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-unicode-regex@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-unicode-sets-regex@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/preset-env@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/compat-data': 7.24.4 + '@babel/core': 7.24.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.5) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.5) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-import-assertions': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.5) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.5) + '@babel/plugin-transform-arrow-functions': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-async-generator-functions': 7.24.3(@babel/core@7.24.5) + '@babel/plugin-transform-async-to-generator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-block-scoped-functions': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-block-scoping': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-class-static-block': 7.24.4(@babel/core@7.24.5) + '@babel/plugin-transform-classes': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-computed-properties': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-destructuring': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-dotall-regex': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-duplicate-keys': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-dynamic-import': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-exponentiation-operator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-export-namespace-from': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-for-of': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-function-name': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-json-strings': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-literals': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-logical-assignment-operators': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-member-expression-literals': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-amd': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-systemjs': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-umd': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.5) + '@babel/plugin-transform-new-target': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-numeric-separator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-object-rest-spread': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-object-super': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-optional-catch-binding': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-optional-chaining': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-parameters': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-private-methods': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-private-property-in-object': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-property-literals': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-regenerator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-reserved-words': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-shorthand-properties': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-spread': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-sticky-regex': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-template-literals': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-typeof-symbol': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-unicode-escapes': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-unicode-property-regex': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-unicode-regex': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-unicode-sets-regex': 7.24.1(@babel/core@7.24.5) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.5) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.5) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.5) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.5) + core-js-compat: 3.37.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/types': 7.24.5 + esutils: 2.0.3 + + '@babel/regjsgen@0.8.0': {} + + '@babel/runtime@7.24.5': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/runtime@7.24.8': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/template@7.24.0': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 + + '@babel/traverse@7.24.5': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.24.5 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 + debug: 4.3.4(supports-color@6.1.0) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.24.5': + dependencies: + '@babel/helper-string-parser': 7.24.1 + '@babel/helper-validator-identifier': 7.24.5 + to-fast-properties: 2.0.0 + + '@colors/colors@1.5.0': + optional: true + + '@commitlint/cli@17.8.1': + dependencies: + '@commitlint/format': 17.8.1 + '@commitlint/lint': 17.8.1 + '@commitlint/load': 17.8.1 + '@commitlint/read': 17.8.1 + '@commitlint/types': 17.8.1 + execa: 5.1.1 + lodash.isfunction: 3.0.9 + resolve-from: 5.0.0 + resolve-global: 1.0.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + + '@commitlint/config-conventional@17.8.1': + dependencies: + conventional-changelog-conventionalcommits: 6.1.0 + + '@commitlint/config-validator@17.8.1': + dependencies: + '@commitlint/types': 17.8.1 + ajv: 8.13.0 + + '@commitlint/ensure@17.8.1': + dependencies: + '@commitlint/types': 17.8.1 + lodash.camelcase: 4.3.0 + lodash.kebabcase: 4.1.1 + lodash.snakecase: 4.1.1 + lodash.startcase: 4.4.0 + lodash.upperfirst: 4.3.1 + + '@commitlint/execute-rule@17.8.1': {} + + '@commitlint/format@17.8.1': + dependencies: + '@commitlint/types': 17.8.1 + chalk: 4.1.2 + + '@commitlint/is-ignored@17.8.1': + dependencies: + '@commitlint/types': 17.8.1 + semver: 7.5.4 + + '@commitlint/lint@17.8.1': + dependencies: + '@commitlint/is-ignored': 17.8.1 + '@commitlint/parse': 17.8.1 + '@commitlint/rules': 17.8.1 + '@commitlint/types': 17.8.1 + + '@commitlint/load@17.8.1': + dependencies: + '@commitlint/config-validator': 17.8.1 + '@commitlint/execute-rule': 17.8.1 + '@commitlint/resolve-extends': 17.8.1 + '@commitlint/types': 17.8.1 + '@types/node': 20.5.1 + chalk: 4.1.2 + cosmiconfig: 8.3.6(typescript@5.4.5) + cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.4.5))(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5))(typescript@5.4.5) + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + lodash.uniq: 4.5.0 + resolve-from: 5.0.0 + ts-node: 10.9.2(@types/node@20.5.1)(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + + '@commitlint/message@17.8.1': {} + + '@commitlint/parse@17.8.1': + dependencies: + '@commitlint/types': 17.8.1 + conventional-changelog-angular: 6.0.0 + conventional-commits-parser: 4.0.0 + + '@commitlint/read@17.8.1': + dependencies: + '@commitlint/top-level': 17.8.1 + '@commitlint/types': 17.8.1 + fs-extra: 11.2.0 + git-raw-commits: 2.0.11 + minimist: 1.2.8 + + '@commitlint/resolve-extends@17.8.1': + dependencies: + '@commitlint/config-validator': 17.8.1 + '@commitlint/types': 17.8.1 + import-fresh: 3.3.0 + lodash.mergewith: 4.6.2 + resolve-from: 5.0.0 + resolve-global: 1.0.0 + + '@commitlint/rules@17.8.1': + dependencies: + '@commitlint/ensure': 17.8.1 + '@commitlint/message': 17.8.1 + '@commitlint/to-lines': 17.8.1 + '@commitlint/types': 17.8.1 + execa: 5.1.1 + + '@commitlint/to-lines@17.8.1': {} + + '@commitlint/top-level@17.8.1': + dependencies: + find-up: 5.0.0 + + '@commitlint/types@17.8.1': + dependencies: + chalk: 4.1.2 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@discoveryjs/json-ext@0.5.7': {} + + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.10.0': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.3.4(supports-color@6.1.0) + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.0': {} + + '@humanwhocodes/config-array@0.11.14': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.4(supports-color@6.1.0) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/sourcemap-codec@1.4.15': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + + '@magenta/music@1.23.1(@tensorflow/tfjs-core@2.8.6)(seedrandom@2.4.3)': + dependencies: + '@tensorflow/tfjs': 2.8.6(seedrandom@2.4.3) + '@tensorflow/tfjs-backend-webgl': 2.8.6(@tensorflow/tfjs-core@2.8.6) + '@tonejs/midi': 2.0.28 + fft.js: 4.0.4 + ndarray-resample: 1.0.1 + protobufjs: 6.11.4 + staffrender: 0.2.1 + tonal: 2.2.2 + tone: 14.9.17 + transitivePeerDependencies: + - '@tensorflow/tfjs-core' + - encoding + - seedrandom + + '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': + dependencies: + eslint-scope: 5.1.1 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@octokit/auth-token@3.0.4': {} + + '@octokit/core@4.2.4': + dependencies: + '@octokit/auth-token': 3.0.4 + '@octokit/graphql': 5.0.6 + '@octokit/request': 6.2.8 + '@octokit/request-error': 3.0.3 + '@octokit/types': 9.3.2 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + + '@octokit/endpoint@7.0.6': + dependencies: + '@octokit/types': 9.3.2 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.1 + + '@octokit/graphql@5.0.6': + dependencies: + '@octokit/request': 6.2.8 + '@octokit/types': 9.3.2 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + + '@octokit/openapi-types@18.1.1': {} + + '@octokit/plugin-paginate-rest@6.1.2(@octokit/core@4.2.4)': + dependencies: + '@octokit/core': 4.2.4 + '@octokit/tsconfig': 1.0.2 + '@octokit/types': 9.3.2 + + '@octokit/plugin-retry@4.1.6(@octokit/core@4.2.4)': + dependencies: + '@octokit/core': 4.2.4 + '@octokit/types': 9.3.2 + bottleneck: 2.19.5 + + '@octokit/plugin-throttling@5.2.3(@octokit/core@4.2.4)': + dependencies: + '@octokit/core': 4.2.4 + '@octokit/types': 9.3.2 + bottleneck: 2.19.5 + + '@octokit/request-error@3.0.3': + dependencies: + '@octokit/types': 9.3.2 + deprecation: 2.3.1 + once: 1.4.0 + + '@octokit/request@6.2.8': + dependencies: + '@octokit/endpoint': 7.0.6 + '@octokit/request-error': 3.0.3 + '@octokit/types': 9.3.2 + is-plain-object: 5.0.0 + node-fetch: 2.7.0 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + + '@octokit/tsconfig@1.0.2': {} + + '@octokit/types@9.3.2': + dependencies: + '@octokit/openapi-types': 18.1.1 + + '@pnpm/config.env-replace@1.1.0': {} + + '@pnpm/network.ca-file@1.0.2': + dependencies: + graceful-fs: 4.2.10 + + '@pnpm/npm-conf@2.2.2': + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + + '@semantic-release/changelog@6.0.3(semantic-release@19.0.5)': + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + fs-extra: 11.2.0 + lodash: 4.17.21 + semantic-release: 19.0.5 + + '@semantic-release/commit-analyzer@9.0.2(semantic-release@19.0.5)': + dependencies: + conventional-changelog-angular: 5.0.13 + conventional-commits-filter: 2.0.7 + conventional-commits-parser: 3.2.4 + debug: 4.3.4(supports-color@6.1.0) + import-from: 4.0.0 + lodash: 4.17.21 + micromatch: 4.0.7 + semantic-release: 19.0.5 + transitivePeerDependencies: + - supports-color + + '@semantic-release/error@3.0.0': {} + + '@semantic-release/git@10.0.1(semantic-release@19.0.5)': + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + debug: 4.3.4(supports-color@6.1.0) + dir-glob: 3.0.1 + execa: 5.1.1 + lodash: 4.17.21 + micromatch: 4.0.7 + p-reduce: 2.1.0 + semantic-release: 19.0.5 + transitivePeerDependencies: + - supports-color + + '@semantic-release/github@8.1.0(semantic-release@19.0.5)': + dependencies: + '@octokit/core': 4.2.4 + '@octokit/plugin-paginate-rest': 6.1.2(@octokit/core@4.2.4) + '@octokit/plugin-retry': 4.1.6(@octokit/core@4.2.4) + '@octokit/plugin-throttling': 5.2.3(@octokit/core@4.2.4) + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + debug: 4.3.4(supports-color@6.1.0) + dir-glob: 3.0.1 + fs-extra: 11.2.0 + globby: 11.1.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 + issue-parser: 6.0.0 + lodash: 4.17.21 + mime: 3.0.0 + p-filter: 2.1.0 + semantic-release: 19.0.5 + url-join: 4.0.1 + transitivePeerDependencies: + - encoding + - supports-color + + '@semantic-release/npm@9.0.2(semantic-release@19.0.5)': + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + execa: 5.1.1 + fs-extra: 11.2.0 + lodash: 4.17.21 + nerf-dart: 1.0.0 + normalize-url: 6.1.0 + npm: 8.19.4 + rc: 1.2.8 + read-pkg: 5.2.0 + registry-auth-token: 5.0.2 + semantic-release: 19.0.5 + semver: 7.6.2 + tempy: 1.0.1 + + '@semantic-release/release-notes-generator@10.0.3(semantic-release@19.0.5)': + dependencies: + conventional-changelog-angular: 5.0.13 + conventional-changelog-writer: 5.0.1 + conventional-commits-filter: 2.0.7 + conventional-commits-parser: 3.2.4 + debug: 4.3.4(supports-color@6.1.0) + get-stream: 6.0.1 + import-from: 4.0.0 + into-stream: 6.0.0 + lodash: 4.17.21 + read-pkg-up: 7.0.1 + semantic-release: 19.0.5 + transitivePeerDependencies: + - supports-color + + '@tensorflow/tfjs-backend-cpu@2.8.6(@tensorflow/tfjs-core@2.8.6)': + dependencies: + '@tensorflow/tfjs-core': 2.8.6 + '@types/seedrandom': 2.4.27 + seedrandom: 2.4.3 + + '@tensorflow/tfjs-backend-webgl@2.8.6(@tensorflow/tfjs-core@2.8.6)': + dependencies: + '@tensorflow/tfjs-backend-cpu': 2.8.6(@tensorflow/tfjs-core@2.8.6) + '@tensorflow/tfjs-core': 2.8.6 + '@types/offscreencanvas': 2019.3.0 + '@types/seedrandom': 2.4.27 + '@types/webgl-ext': 0.0.30 + '@types/webgl2': 0.0.5 + seedrandom: 2.4.3 + + '@tensorflow/tfjs-converter@2.8.6(@tensorflow/tfjs-core@2.8.6)': + dependencies: + '@tensorflow/tfjs-core': 2.8.6 + + '@tensorflow/tfjs-core@2.8.6': + dependencies: + '@types/offscreencanvas': 2019.3.0 + '@types/seedrandom': 2.4.27 + '@types/webgl-ext': 0.0.30 + node-fetch: 2.6.13 + seedrandom: 2.4.3 + transitivePeerDependencies: + - encoding + + '@tensorflow/tfjs-data@2.8.6(@tensorflow/tfjs-core@2.8.6)(seedrandom@2.4.3)': + dependencies: + '@tensorflow/tfjs-core': 2.8.6 + '@types/node-fetch': 2.6.11 + node-fetch: 2.6.13 + seedrandom: 2.4.3 + transitivePeerDependencies: + - encoding + + '@tensorflow/tfjs-layers@2.8.6(@tensorflow/tfjs-core@2.8.6)': + dependencies: + '@tensorflow/tfjs-core': 2.8.6 + + '@tensorflow/tfjs@2.8.6(seedrandom@2.4.3)': + dependencies: + '@tensorflow/tfjs-backend-cpu': 2.8.6(@tensorflow/tfjs-core@2.8.6) + '@tensorflow/tfjs-backend-webgl': 2.8.6(@tensorflow/tfjs-core@2.8.6) + '@tensorflow/tfjs-converter': 2.8.6(@tensorflow/tfjs-core@2.8.6) + '@tensorflow/tfjs-core': 2.8.6 + '@tensorflow/tfjs-data': 2.8.6(@tensorflow/tfjs-core@2.8.6)(seedrandom@2.4.3) + '@tensorflow/tfjs-layers': 2.8.6(@tensorflow/tfjs-core@2.8.6) + argparse: 1.0.10 + chalk: 4.1.2 + core-js: 3.37.1 + regenerator-runtime: 0.13.11 + yargs: 16.2.0 + transitivePeerDependencies: + - encoding + - seedrandom + + '@tonejs/midi@2.0.28': + dependencies: + array-flatten: 3.0.0 + midi-file: 1.2.4 + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/dompurify@3.0.5': + dependencies: + '@types/trusted-types': 2.0.7 + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 8.56.10 + '@types/estree': 1.0.5 + + '@types/eslint@8.56.10': + dependencies: + '@types/estree': 1.0.5 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.5': {} + + '@types/glob@7.2.0': + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 20.12.12 + + '@types/json-schema@7.0.15': {} + + '@types/linkify-it@5.0.0': {} + + '@types/long@4.0.2': {} + + '@types/markdown-it@12.2.3': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@2.0.0': {} + + '@types/minimatch@5.1.2': {} + + '@types/minimist@1.2.5': {} + + '@types/node-fetch@2.6.11': + dependencies: + '@types/node': 20.12.12 + form-data: 4.0.0 + + '@types/node@20.12.12': + dependencies: + undici-types: 5.26.5 + + '@types/node@20.5.1': {} + + '@types/node@8.10.40': {} + + '@types/normalize-package-data@2.4.4': {} + + '@types/offscreencanvas@2019.3.0': {} + + '@types/parse-json@4.0.2': {} + + '@types/seedrandom@2.4.27': {} + + '@types/trusted-types@2.0.7': {} + + '@types/web-bluetooth@0.0.20': {} + + '@types/webgl-ext@0.0.30': {} + + '@types/webgl2@0.0.5': {} + + '@ungap/structured-clone@1.2.0': {} + + '@vernier/godirect@1.8.3': {} + + '@webassemblyjs/ast@1.12.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + + '@webassemblyjs/floating-point-hex-parser@1.11.6': {} + + '@webassemblyjs/helper-api-error@1.11.6': {} + + '@webassemblyjs/helper-buffer@1.12.1': {} + + '@webassemblyjs/helper-numbers@1.11.6': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.11.6 + '@webassemblyjs/helper-api-error': 1.11.6 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.11.6': {} + + '@webassemblyjs/helper-wasm-section@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/wasm-gen': 1.12.1 + + '@webassemblyjs/ieee754@1.11.6': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.11.6': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.11.6': {} + + '@webassemblyjs/wasm-edit@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/helper-wasm-section': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-opt': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + '@webassemblyjs/wast-printer': 1.12.1 + + '@webassemblyjs/wasm-gen@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 + + '@webassemblyjs/wasm-opt@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + + '@webassemblyjs/wasm-parser@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-api-error': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 + + '@webassemblyjs/wast-printer@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@xtuc/long': 4.2.2 + + '@webpack-cli/configtest@1.2.0(webpack-cli@4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0))(webpack@5.91.0(webpack-cli@4.10.0))': + dependencies: + webpack: 5.91.0(webpack-cli@4.10.0) + webpack-cli: 4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0) + + '@webpack-cli/info@1.5.0(webpack-cli@4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0))': + dependencies: + envinfo: 7.13.0 + webpack-cli: 4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0) + + '@webpack-cli/serve@1.7.0(webpack-cli@4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0))(webpack-dev-server@3.11.3(webpack-cli@4.10.0)(webpack@5.91.0))': + dependencies: + webpack-cli: 4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0) + optionalDependencies: + webpack-dev-server: 3.11.3(webpack-cli@4.10.0)(webpack@5.91.0) + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + acorn-import-assertions@1.9.0(acorn@8.11.3): + dependencies: + acorn: 8.11.3 + + acorn-jsx@5.3.2(acorn@7.4.1): + dependencies: + acorn: 7.4.1 + + acorn-jsx@5.3.2(acorn@8.11.3): + dependencies: + acorn: 8.11.3 + + acorn-walk@8.3.2: {} + + acorn@7.4.1: {} + + acorn@8.11.3: {} + + adm-zip@0.4.11: {} + + agent-base@7.1.1: + dependencies: + debug: 4.3.4(supports-color@6.1.0) + transitivePeerDependencies: + - supports-color + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + ajv-errors@1.0.1(ajv@6.12.6): + dependencies: + ajv: 6.12.6 + + ajv-formats@2.1.1(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv-keywords@3.5.2(ajv@6.12.6): + dependencies: + ajv: 6.12.6 + + ajv-keywords@5.1.0(ajv@8.13.0): + dependencies: + ajv: 8.13.0 + fast-deep-equal: 3.1.3 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.13.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + align-text@0.1.4: + dependencies: + kind-of: 3.2.2 + longest: 1.0.1 + repeat-string: 1.6.1 + + amdefine@1.0.1: + optional: true + + ansi-colors@3.2.4: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-escapes@6.2.1: {} + + ansi-html-community@0.0.8: {} + + ansi-regex@2.1.1: {} + + ansi-regex@4.1.1: {} + + ansi-regex@5.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansicolors@0.3.2: {} + + anymatch@2.0.0(supports-color@6.1.0): + dependencies: + micromatch: 3.1.10(supports-color@6.1.0) + normalize-path: 2.1.1 + transitivePeerDependencies: + - supports-color + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + append-transform@2.0.0: + dependencies: + default-require-extensions: 3.0.1 + + aproba@1.2.0: {} + + archy@1.0.0: {} + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + argv-formatter@1.0.0: {} + + arr-diff@4.0.0: {} + + arr-flatten@1.1.0: {} + + arr-union@3.1.0: {} + + array-buffer-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + + array-flatten@1.1.1: {} + + array-flatten@2.1.2: {} + + array-flatten@3.0.0: {} + + array-ify@1.0.0: {} + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + optional: true + + array-union@1.0.2: + dependencies: + array-uniq: 1.0.3 + + array-union@2.1.0: {} + + array-uniq@1.0.3: {} + + array-unique@0.3.2: {} + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + optional: true + + array.prototype.flat@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + optional: true + + array.prototype.flatmap@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + optional: true + + array.prototype.toreversed@1.1.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + optional: true + + array.prototype.tosorted@1.1.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 + optional: true + + arraybuffer-loader@1.0.8: + dependencies: + loader-utils: 1.4.2 + + arraybuffer.prototype.slice@1.0.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + + arrify@1.0.1: {} + + assign-symbols@1.0.0: {} + + astral-regex@1.0.0: {} + + async-each@1.0.6: {} + + async-hook-domain@2.0.4: {} + + async-limiter@1.0.1: {} + + async@2.6.4: + dependencies: + lodash: 4.17.21 + + asynckit@0.4.0: {} + + atob@2.1.2: {} + + audio-context@1.0.3: {} + + automation-events@7.0.7: + dependencies: + '@babel/runtime': 7.24.8 + tslib: 2.6.3 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + babel-loader@9.1.3(@babel/core@7.24.5)(webpack@5.91.0(webpack-cli@4.10.0)): + dependencies: + '@babel/core': 7.24.5 + find-cache-dir: 4.0.0 + schema-utils: 4.2.0 + webpack: 5.91.0(webpack-cli@4.10.0) + + babel-plugin-extract-format-message@6.2.4: + dependencies: + format-message-estree-util: 6.2.4 + format-message-generate-id: 6.2.4 + format-message-parse: 6.2.4 + format-message-print: 6.2.4 + + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.5): + dependencies: + '@babel/compat-data': 7.24.4 + '@babel/core': 7.24.5 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.5) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.5): + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.5) + core-js-compat: 3.37.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.5): + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.5) + transitivePeerDependencies: + - supports-color + + babel-plugin-transform-format-message@6.2.4: + dependencies: + '@babel/helper-module-imports': 7.24.3 + '@babel/parser': 7.24.5 + format-message: 6.2.4 + format-message-estree-util: 6.2.4 + format-message-formats: 6.2.4 + format-message-generate-id: 6.2.4 + format-message-parse: 6.2.4 + lookup-closest-locale: 6.2.0 + source-map: 0.5.7 + + balanced-match@1.0.2: {} + + base64-js@0.0.8: {} + + base64-js@1.5.1: {} + + base64-loader@1.0.0: {} + + base@0.11.2: + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.1 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + + batch@0.6.1: {} + + before-after-hook@2.2.3: {} + + big.js@5.2.2: {} + + binary-extensions@1.13.1: {} + + binary-extensions@2.3.0: {} + + bind-obj-methods@3.0.0: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + optional: true + + bit-twiddle@1.0.2: {} + + bl@1.2.3: + dependencies: + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + + bluebird@3.7.2: {} + + body-parser@1.20.2(supports-color@6.1.0): + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9(supports-color@6.1.0) + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + bonjour@3.5.0: + dependencies: + array-flatten: 2.1.2 + deep-equal: 1.1.2 + dns-equal: 1.0.0 + dns-txt: 2.0.2 + multicast-dns: 6.2.3 + multicast-dns-service-types: 1.1.0 + + bottleneck@2.19.5: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + braces@2.3.2(supports-color@6.1.0): + dependencies: + arr-flatten: 1.1.0 + array-unique: 0.3.2 + extend-shallow: 2.0.1 + fill-range: 4.0.0 + isobject: 3.0.1 + repeat-element: 1.1.4 + snapdragon: 0.8.2(supports-color@6.1.0) + snapdragon-node: 2.1.1 + split-string: 3.1.0 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brfs@1.6.1: + dependencies: + quote-stream: 1.0.2 + resolve: 1.22.8 + static-module: 2.2.5 + through2: 2.0.5 + + browser-hrtime@1.1.8: {} + + browserslist@4.23.0: + dependencies: + caniuse-lite: 1.0.30001621 + electron-to-chromium: 1.4.777 + node-releases: 2.0.14 + update-browserslist-db: 1.0.16(browserslist@4.23.0) + + btoa@1.2.1: {} + + buffer-equal@0.0.1: {} + + buffer-from@1.1.2: {} + + buffer-indexof@1.1.1: {} + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bytes@3.0.0: {} + + bytes@3.1.2: {} + + cacache@10.0.4: + dependencies: + bluebird: 3.7.2 + chownr: 1.1.4 + glob: 7.2.3 + graceful-fs: 4.2.11 + lru-cache: 4.1.5 + mississippi: 2.0.0 + mkdirp: 0.5.6 + move-concurrently: 1.0.1 + promise-inflight: 1.0.1(bluebird@3.7.2) + rimraf: 2.7.1 + ssri: 5.3.0 + unique-filename: 1.1.1 + y18n: 4.0.3 + + cache-base@1.0.1: + dependencies: + collection-visit: 1.0.0 + component-emitter: 1.3.1 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + union-value: 1.0.1 + unset-value: 1.0.0 + + caching-transform@4.0.0: + dependencies: + hasha: 5.2.2 + make-dir: 3.1.0 + package-hash: 4.0.0 + write-file-atomic: 3.0.3 + + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + callsite@1.0.0: {} + + callsites@3.1.0: {} + + camelcase-keys@6.2.2: + dependencies: + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + + camelcase@1.2.1: {} + + camelcase@5.3.1: {} + + caniuse-lite@1.0.30001621: {} + + canvas-toBlob@1.0.0: {} + + cardinal@2.1.1: + dependencies: + ansicolors: 0.3.2 + redeyed: 2.1.1 + + catharsis@0.9.0: + dependencies: + lodash: 4.17.21 + + center-align@0.1.3: + dependencies: + align-text: 0.1.4 + lazy-cache: 1.0.4 + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.3.0: {} + + chardet@0.7.0: {} + + chokidar@2.1.8(supports-color@6.1.0): + dependencies: + anymatch: 2.0.0(supports-color@6.1.0) + async-each: 1.0.6 + braces: 2.3.2(supports-color@6.1.0) + glob-parent: 3.1.0 + inherits: 2.0.4 + is-binary-path: 1.0.1 + is-glob: 4.0.3 + normalize-path: 3.0.0 + path-is-absolute: 1.0.1 + readdirp: 2.2.1(supports-color@6.1.0) + upath: 1.2.0 + optionalDependencies: + fsevents: 1.2.13 + transitivePeerDependencies: + - supports-color + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chownr@1.1.4: {} + + chrome-trace-event@1.0.3: {} + + class-utils@0.3.6: + dependencies: + arr-union: 3.1.0 + define-property: 0.2.5 + isobject: 3.0.1 + static-extend: 0.1.2 + + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + + cli-width@3.0.0: {} + + cliui@2.1.0: + dependencies: + center-align: 0.1.3 + right-align: 0.1.3 + wordwrap: 0.0.2 + + cliui@5.0.0: + dependencies: + string-width: 3.1.0 + strip-ansi: 5.2.0 + wrap-ansi: 5.1.0 + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-deep@4.0.1: + dependencies: + is-plain-object: 2.0.4 + kind-of: 6.0.3 + shallow-clone: 3.0.1 + + collection-visit@1.0.0: + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + color-support@1.1.3: {} + + colorette@2.0.20: {} + + colors@0.6.2: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@2.1.0: {} + + commander@2.20.3: {} + + commander@7.2.0: {} + + common-path-prefix@3.0.0: {} + + commondir@1.0.1: {} + + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + + component-emitter@1.3.1: {} + + compressible@2.0.18: + dependencies: + mime-db: 1.52.0 + + compression@1.7.4(supports-color@6.1.0): + dependencies: + accepts: 1.3.8 + bytes: 3.0.0 + compressible: 2.0.18 + debug: 2.6.9(supports-color@6.1.0) + on-headers: 1.0.2 + safe-buffer: 5.1.2 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + concat-map@0.0.1: {} + + concat-stream@1.6.2: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + + connect-history-api-fallback@1.6.0: {} + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + conventional-changelog-angular@5.0.13: + dependencies: + compare-func: 2.0.0 + q: 1.5.1 + + conventional-changelog-angular@6.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-conventionalcommits@6.1.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-writer@5.0.1: + dependencies: + conventional-commits-filter: 2.0.7 + dateformat: 3.0.3 + handlebars: 4.7.8 + json-stringify-safe: 5.0.1 + lodash: 4.17.21 + meow: 8.1.2 + semver: 6.3.1 + split: 1.0.1 + through2: 4.0.2 + + conventional-commits-filter@2.0.7: + dependencies: + lodash.ismatch: 4.4.0 + modify-values: 1.0.1 + + conventional-commits-parser@3.2.4: + dependencies: + JSONStream: 1.3.5 + is-text-path: 1.0.1 + lodash: 4.17.21 + meow: 8.1.2 + split2: 3.2.2 + through2: 4.0.2 + + conventional-commits-parser@4.0.0: + dependencies: + JSONStream: 1.3.5 + is-text-path: 1.0.1 + meow: 8.1.2 + split2: 3.2.2 + + convert-source-map@1.9.0: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.0.6: {} + + cookie@0.6.0: {} + + copy-concurrently@1.0.5: + dependencies: + aproba: 1.2.0 + fs-write-stream-atomic: 1.0.10 + iferr: 0.1.5 + mkdirp: 0.5.6 + rimraf: 2.7.1 + run-queue: 1.0.3 + + copy-descriptor@0.1.1: {} + + copy-webpack-plugin@4.6.0: + dependencies: + cacache: 10.0.4 + find-cache-dir: 1.0.0 + globby: 7.1.1 + is-glob: 4.0.3 + loader-utils: 1.4.2 + minimatch: 3.1.2 + p-limit: 1.3.0 + serialize-javascript: 1.9.1 + + core-js-compat@3.37.1: + dependencies: + browserslist: 4.23.0 + + core-js@3.37.1: {} + + core-util-is@1.0.3: {} + + cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.4.5))(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5))(typescript@5.4.5): + dependencies: + '@types/node': 20.5.1 + cosmiconfig: 8.3.6(typescript@5.4.5) + ts-node: 10.9.2(@types/node@20.5.1)(typescript@5.4.5) + typescript: 5.4.5 + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + + cosmiconfig@8.3.6(typescript@5.4.5): + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.4.5 + + crc32@0.2.2: {} + + create-require@1.1.1: {} + + cross-fetch@3.1.8: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + cross-spawn@6.0.5: + dependencies: + nice-try: 1.0.5 + path-key: 2.0.1 + semver: 5.7.2 + shebang-command: 1.2.0 + which: 1.3.1 + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypto-random-string@2.0.0: {} + + css-tree@1.1.3: + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + + cssstyle@4.0.1: + dependencies: + rrweb-cssom: 0.6.0 + + cwise-compiler@1.1.3: + dependencies: + uniq: 1.0.1 + + cwise-parser@1.0.3: + dependencies: + esprima: 1.2.5 + uniq: 1.0.1 + + cwise@1.0.10: + dependencies: + cwise-compiler: 1.1.3 + cwise-parser: 1.0.3 + static-module: 1.5.0 + uglify-js: 2.8.29 + + cyclist@1.0.2: {} + + dargs@7.0.0: {} + + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + + data-view-buffer@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-offset@1.0.0: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + dateformat@3.0.3: {} + + debug@2.6.9(supports-color@6.1.0): + dependencies: + ms: 2.0.0 + optionalDependencies: + supports-color: 6.1.0 + + debug@3.2.7(supports-color@6.1.0): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 6.1.0 + + debug@4.3.4(supports-color@6.1.0): + dependencies: + ms: 2.1.2 + optionalDependencies: + supports-color: 6.1.0 + + decamelize-keys@1.1.1: + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + + decamelize@1.2.0: {} + + decimal.js@10.4.3: {} + + decode-html@2.0.0: {} + + decode-uri-component@0.2.2: {} + + deep-equal@1.1.2: + dependencies: + is-arguments: 1.1.1 + is-date-object: 1.0.5 + is-regex: 1.1.4 + object-is: 1.1.6 + object-keys: 1.1.1 + regexp.prototype.flags: 1.5.2 + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + default-gateway@4.2.0: + dependencies: + execa: 1.0.0 + ip-regex: 2.1.0 + + default-require-extensions@3.0.1: + dependencies: + strip-bom: 4.0.0 + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + define-property@0.2.5: + dependencies: + is-descriptor: 0.1.7 + + define-property@1.0.0: + dependencies: + is-descriptor: 1.0.3 + + define-property@2.0.2: + dependencies: + is-descriptor: 1.0.3 + isobject: 3.0.1 + + del@4.1.1: + dependencies: + '@types/glob': 7.2.0 + globby: 6.1.0 + is-path-cwd: 2.2.0 + is-path-in-cwd: 2.1.0 + p-map: 2.1.0 + pify: 4.0.1 + rimraf: 2.7.1 + + del@6.1.1: + dependencies: + globby: 11.1.0 + graceful-fs: 4.2.11 + is-glob: 4.0.3 + is-path-cwd: 2.2.0 + is-path-inside: 3.0.3 + p-map: 4.0.0 + rimraf: 3.0.2 + slash: 3.0.0 + + delayed-stream@1.0.0: {} + + depd@1.1.2: {} + + depd@2.0.0: {} + + deprecation@2.3.1: {} + + destroy@1.2.0: {} + + detect-node@2.1.0: {} + + diff-match-patch@1.0.5: {} + + diff@4.0.2: {} + + dir-glob@2.2.2: + dependencies: + path-type: 3.0.0 + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dns-equal@1.0.0: {} + + dns-packet@1.3.4: + dependencies: + ip: 1.1.9 + safe-buffer: 5.2.1 + + dns-txt@2.0.2: + dependencies: + buffer-indexof: 1.1.1 + + docdash@1.2.0: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + optional: true + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dom-serializer@0.2.2: + dependencies: + domelementtype: 2.3.0 + entities: 2.2.0 + + domelementtype@1.3.1: {} + + domelementtype@2.3.0: {} + + domhandler@2.4.2: + dependencies: + domelementtype: 1.3.1 + + dompurify@3.1.4: {} + + domutils@1.7.0: + dependencies: + dom-serializer: 0.2.2 + domelementtype: 1.3.1 + + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + + dup@1.0.0: {} + + duplexer2@0.0.2: + dependencies: + readable-stream: 1.1.14 + + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + + duplexify@3.7.1: + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 2.3.8 + stream-shift: 1.0.3 + + ee-first@1.1.1: {} + + electron-to-chromium@1.4.777: {} + + emoji-regex@7.0.3: {} + + emoji-regex@8.0.0: {} + + emojis-list@3.0.0: {} + + encodeurl@1.0.2: {} + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + enhanced-resolve@5.16.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + entities@1.1.2: {} + + entities@2.1.0: {} + + entities@2.2.0: {} + + entities@4.5.0: {} + + env-ci@5.5.0: + dependencies: + execa: 5.1.1 + fromentries: 1.3.2 + java-properties: 1.0.2 + + envinfo@7.13.0: {} + + errno@0.1.8: + dependencies: + prr: 1.0.1 + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.23.3: + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + es-iterator-helpers@1.0.19: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-set-tostringtag: 2.0.3 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + internal-slot: 1.0.7 + iterator.prototype: 1.1.2 + safe-array-concat: 1.1.2 + optional: true + + es-module-lexer@1.5.3: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.0.2: + dependencies: + hasown: 2.0.2 + optional: true + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + es6-error@4.1.1: {} + + escalade@3.1.2: {} + + escape-html@1.0.3: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + escodegen@0.0.28: + dependencies: + esprima: 1.0.4 + estraverse: 1.3.2 + optionalDependencies: + source-map: 0.6.1 + + escodegen@1.3.3: + dependencies: + esprima: 1.1.1 + estraverse: 1.5.1 + esutils: 1.0.0 + optionalDependencies: + source-map: 0.1.43 + + escodegen@1.9.1: + dependencies: + esprima: 3.1.3 + estraverse: 4.3.0 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.6.1 + + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + + eslint-config-scratch@9.0.8(@babel/eslint-parser@7.24.5(@babel/core@7.24.5)(eslint@8.57.0))(eslint@8.57.0): + dependencies: + '@babel/eslint-parser': 7.24.5(@babel/core@7.24.5)(eslint@8.57.0) + eslint: 8.57.0 + optionalDependencies: + eslint-plugin-react: 7.34.1(eslint@8.57.0) + + eslint-plugin-format-message@6.2.4(eslint@6.8.0): + dependencies: + eslint: 6.8.0 + format-message: 6.2.4 + format-message-estree-util: 6.2.4 + format-message-generate-id: 6.2.4 + format-message-parse: 6.2.4 + lookup-closest-locale: 6.2.0 + + eslint-plugin-react@7.34.1(eslint@8.57.0): + dependencies: + array-includes: 3.1.8 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.2 + array.prototype.toreversed: 1.1.2 + array.prototype.tosorted: 1.1.3 + doctrine: 2.1.0 + es-iterator-helpers: 1.0.19 + eslint: 8.57.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.8 + object.fromentries: 2.0.8 + object.hasown: 1.1.4 + object.values: 1.2.0 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.11 + optional: true + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-utils@1.4.3: + dependencies: + eslint-visitor-keys: 1.3.0 + + eslint-visitor-keys@1.3.0: {} + + eslint-visitor-keys@2.1.0: {} + + eslint-visitor-keys@3.4.3: {} + + eslint@6.8.0: + dependencies: + '@babel/code-frame': 7.24.2 + ajv: 6.12.6 + chalk: 2.4.2 + cross-spawn: 6.0.5 + debug: 4.3.4(supports-color@6.1.0) + doctrine: 3.0.0 + eslint-scope: 5.1.1 + eslint-utils: 1.4.3 + eslint-visitor-keys: 1.3.0 + espree: 6.2.1 + esquery: 1.5.0 + esutils: 2.0.3 + file-entry-cache: 5.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 5.1.2 + globals: 12.4.0 + ignore: 4.0.6 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + inquirer: 7.3.3 + is-glob: 4.0.3 + js-yaml: 3.14.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.3.0 + lodash: 4.17.21 + minimatch: 3.1.2 + mkdirp: 0.5.6 + natural-compare: 1.4.0 + optionator: 0.8.3 + progress: 2.0.3 + regexpp: 2.0.1 + semver: 6.3.1 + strip-ansi: 5.2.0 + strip-json-comments: 3.1.1 + table: 5.4.6 + text-table: 0.2.0 + v8-compile-cache: 2.4.0 + transitivePeerDependencies: + - supports-color + + eslint@8.57.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4(supports-color@6.1.0) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@6.2.1: + dependencies: + acorn: 7.4.1 + acorn-jsx: 5.3.2(acorn@7.4.1) + eslint-visitor-keys: 1.3.0 + + espree@9.6.1: + dependencies: + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 3.4.3 + + esprima@1.0.4: {} + + esprima@1.1.1: {} + + esprima@1.2.5: {} + + esprima@3.1.3: {} + + esprima@4.0.1: {} + + esquery@1.5.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@1.3.2: {} + + estraverse@1.5.1: {} + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + esutils@1.0.0: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + eventemitter3@4.0.7: {} + + events-to-array@1.1.2: {} + + events@3.3.0: {} + + eventsource@2.0.2: {} + + execa@1.0.0: + dependencies: + cross-spawn: 6.0.5 + get-stream: 4.1.0 + is-stream: 1.1.0 + npm-run-path: 2.0.2 + p-finally: 1.0.0 + signal-exit: 3.0.7 + strip-eof: 1.0.0 + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + expand-brackets@2.1.4(supports-color@6.1.0): + dependencies: + debug: 2.6.9(supports-color@6.1.0) + define-property: 0.2.5 + extend-shallow: 2.0.1 + posix-character-classes: 0.1.1 + regex-not: 1.0.2 + snapdragon: 0.8.2(supports-color@6.1.0) + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + exports-loader@0.7.0: + dependencies: + loader-utils: 1.4.2 + source-map: 0.5.0 + + expose-loader@1.0.3(webpack@5.91.0(webpack-cli@4.10.0)): + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.91.0(webpack-cli@4.10.0) + + express@4.19.2(supports-color@6.1.0): + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.2(supports-color@6.1.0) + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.6.0 + cookie-signature: 1.0.6 + debug: 2.6.9(supports-color@6.1.0) + depd: 2.0.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.2.0(supports-color@6.1.0) + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.11.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0(supports-color@6.1.0) + serve-static: 1.15.0(supports-color@6.1.0) + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend-shallow@3.0.2: + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + + extglob@2.0.4(supports-color@6.1.0): + dependencies: + array-unique: 0.3.2 + define-property: 1.0.0 + expand-brackets: 2.1.4(supports-color@6.1.0) + extend-shallow: 2.0.1 + fragment-cache: 0.2.1 + regex-not: 1.0.2 + snapdragon: 0.8.2(supports-color@6.1.0) + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + falafel@2.2.5: + dependencies: + acorn: 7.4.1 + isarray: 2.0.5 + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.7 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-xml-parser@4.4.0: + dependencies: + strnum: 1.0.5 + + fastest-levenshtein@1.0.16: {} + + fastestsmallesttextencoderdecoder@1.0.22: {} + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + faye-websocket@0.11.4: + dependencies: + websocket-driver: 0.7.4 + + fft.js@4.0.4: {} + + figures@2.0.0: + dependencies: + escape-string-regexp: 1.0.5 + + figures@3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + + file-entry-cache@5.0.1: + dependencies: + flat-cache: 2.0.1 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + file-loader@6.2.0(webpack@5.91.0(webpack-cli@4.10.0)): + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.91.0(webpack-cli@4.10.0) + + file-uri-to-path@1.0.0: + optional: true + + fill-range@4.0.0: + dependencies: + extend-shallow: 2.0.1 + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range: 2.1.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@1.2.0(supports-color@6.1.0): + dependencies: + debug: 2.6.9(supports-color@6.1.0) + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + find-cache-dir@1.0.0: + dependencies: + commondir: 1.0.1 + make-dir: 1.3.0 + pkg-dir: 2.0.0 + + find-cache-dir@3.3.2: + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + + find-cache-dir@4.0.0: + dependencies: + common-path-prefix: 3.0.0 + pkg-dir: 7.0.0 + + find-up@2.1.0: + dependencies: + locate-path: 2.0.0 + + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + find-up@6.3.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + + find-versions@4.0.0: + dependencies: + semver-regex: 3.1.4 + + findit@2.0.0: {} + + findup@0.1.5: + dependencies: + colors: 0.6.2 + commander: 2.1.0 + + flat-cache@2.0.1: + dependencies: + flatted: 2.0.2 + rimraf: 2.6.3 + write: 1.0.3 + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + + flat@5.0.2: {} + + flatted@2.0.2: {} + + flatted@3.3.1: {} + + flush-write-stream@1.1.1: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + + follow-redirects@1.15.6(debug@4.3.4(supports-color@6.1.0)): + optionalDependencies: + debug: 4.3.4(supports-color@6.1.0) + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + for-in@1.0.2: {} + + foreground-child@2.0.0: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 3.0.7 + + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + format-message-cli@6.2.4: + dependencies: + '@babel/core': 7.24.5 + babel-plugin-extract-format-message: 6.2.4 + babel-plugin-transform-format-message: 6.2.4 + commander: 2.20.3 + eslint: 6.8.0 + eslint-plugin-format-message: 6.2.4(eslint@6.8.0) + glob: 5.0.15 + js-yaml: 3.14.1 + mkdirp: 0.5.6 + safe-buffer: 5.2.1 + source-map: 0.5.7 + transitivePeerDependencies: + - supports-color + + format-message-estree-util@6.2.4: {} + + format-message-formats@6.2.4: {} + + format-message-generate-id@6.2.4: + dependencies: + crc32: 0.2.2 + format-message-parse: 6.2.4 + format-message-print: 6.2.4 + + format-message-interpret@6.2.4: + dependencies: + format-message-formats: 6.2.4 + lookup-closest-locale: 6.2.0 + + format-message-parse@6.2.4: {} + + format-message-print@6.2.4: {} + + format-message@6.2.4: + dependencies: + format-message-formats: 6.2.4 + format-message-interpret: 6.2.4 + format-message-parse: 6.2.4 + lookup-closest-locale: 6.2.0 + + forwarded@0.2.0: {} + + fragment-cache@0.2.1: + dependencies: + map-cache: 0.2.2 + + fresh@0.5.2: {} + + from2-array@0.0.4: + dependencies: + from2: 2.3.0 + + from2@2.3.0: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + + fromentries@1.3.2: {} + + fs-exists-cached@1.0.0: {} + + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-write-stream-atomic@1.0.10: + dependencies: + graceful-fs: 4.2.11 + iferr: 0.1.5 + imurmurhash: 0.1.4 + readable-stream: 2.3.8 + + fs.realpath@1.0.0: {} + + fsevents@1.2.13: + dependencies: + bindings: 1.5.0 + nan: 2.19.0 + optional: true + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function-loop@2.0.1: {} + + function.prototype.name@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + + functional-red-black-tree@1.0.1: {} + + functions-have-names@1.2.3: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-package-type@0.1.0: {} + + get-stream@4.1.0: + dependencies: + pump: 3.0.0 + + get-stream@6.0.1: {} + + get-symbol-description@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + get-value@2.0.6: {} + + git-log-parser@1.2.0: + dependencies: + argv-formatter: 1.0.0 + spawn-error-forwarder: 1.0.0 + split2: 1.0.0 + stream-combiner2: 1.1.1 + through2: 2.0.5 + traverse: 0.6.9 + + git-raw-commits@2.0.11: + dependencies: + dargs: 7.0.0 + lodash: 4.17.21 + meow: 8.1.2 + split2: 3.2.2 + through2: 4.0.2 + + glob-parent@3.1.0: + dependencies: + is-glob: 3.1.0 + path-dirname: 1.0.2 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob-to-regexp@0.4.1: {} + + glob@5.0.15: + dependencies: + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + global-dirs@0.1.1: + dependencies: + ini: 1.3.8 + + globals@11.12.0: {} + + globals@12.4.0: + dependencies: + type-fest: 0.8.1 + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + + globby@6.1.0: + dependencies: + array-union: 1.0.2 + glob: 7.2.3 + object-assign: 4.1.1 + pify: 2.3.0 + pinkie-promise: 2.0.1 + + globby@7.1.1: + dependencies: + array-union: 1.0.2 + dir-glob: 2.2.2 + glob: 7.2.3 + ignore: 3.3.10 + pify: 3.0.0 + slash: 1.0.0 + + google-closure-library@20190301.0.0: {} + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + graceful-fs@4.2.10: {} + + graceful-fs@4.2.11: {} + + grapheme-breaker@0.3.2: + dependencies: + brfs: 1.6.1 + unicode-trie: 0.3.1 + + graphemer@1.4.0: {} + + handle-thing@2.0.1: {} + + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.17.4 + + hard-rejection@2.1.0: {} + + has-bigints@1.0.2: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + has-value@0.3.1: + dependencies: + get-value: 2.0.6 + has-values: 0.1.4 + isobject: 2.1.0 + + has-value@1.0.0: + dependencies: + get-value: 2.0.6 + has-values: 1.0.0 + isobject: 3.0.1 + + has-values@0.1.4: {} + + has-values@1.0.0: + dependencies: + is-number: 3.0.0 + kind-of: 4.0.0 + + has@1.0.4: {} + + hasha@5.2.2: + dependencies: + is-stream: 2.0.1 + type-fest: 0.8.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hook-std@2.0.0: {} + + hosted-git-info@2.8.9: {} + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + hpack.js@2.1.6: + dependencies: + inherits: 2.0.4 + obuf: 1.1.2 + readable-stream: 2.3.8 + wbuf: 1.7.3 + + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + + html-entities@1.4.0: {} + + html-escaper@2.0.2: {} + + htmlparser2@3.10.1: + dependencies: + domelementtype: 1.3.1 + domhandler: 2.4.2 + domutils: 1.7.0 + entities: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + + http-deceiver@1.2.7: {} + + http-errors@1.6.3: + dependencies: + depd: 1.1.2 + inherits: 2.0.3 + setprototypeof: 1.1.0 + statuses: 1.5.0 + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + http-parser-js@0.5.8: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.1 + debug: 4.3.4(supports-color@6.1.0) + transitivePeerDependencies: + - supports-color + + http-proxy-middleware@0.19.1(debug@4.3.4(supports-color@6.1.0))(supports-color@6.1.0): + dependencies: + http-proxy: 1.18.1(debug@4.3.4(supports-color@6.1.0)) + is-glob: 4.0.3 + lodash: 4.17.21 + micromatch: 3.1.10(supports-color@6.1.0) + transitivePeerDependencies: + - debug + - supports-color + + http-proxy@1.18.1(debug@4.3.4(supports-color@6.1.0)): + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.15.6(debug@4.3.4(supports-color@6.1.0)) + requires-port: 1.0.0 + transitivePeerDependencies: + - debug + + https-proxy-agent@7.0.4: + dependencies: + agent-base: 7.1.1 + debug: 4.3.4(supports-color@6.1.0) + transitivePeerDependencies: + - supports-color + + hull.js@0.2.11: {} + + human-signals@2.1.0: {} + + husky@8.0.3: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + iferr@0.1.5: {} + + ify-loader@1.1.0: + dependencies: + bl: 1.2.3 + findup: 0.1.5 + from2-array: 0.0.4 + map-limit: 0.0.1 + multipipe: 0.3.1 + read-package-json: 2.1.2 + resolve: 1.22.8 + + ignore@3.3.10: {} + + ignore@4.0.6: {} + + ignore@5.3.1: {} + + immediate@3.0.6: {} + + immutable@3.8.2: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-from@4.0.0: {} + + import-local@2.0.0: + dependencies: + pkg-dir: 3.0.0 + resolve-cwd: 2.0.0 + + import-local@3.1.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imports-loader@0.8.0: + dependencies: + loader-utils: 1.4.2 + source-map: 0.6.1 + + imurmurhash@0.1.4: {} + + in-publish@2.0.1: {} + + indent-string@4.0.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.3: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + inquirer@7.3.3: + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + run-async: 2.4.1 + rxjs: 6.6.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + + internal-ip@4.3.0: + dependencies: + default-gateway: 4.2.0 + ipaddr.js: 1.9.1 + + internal-slot@1.0.7: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + + interpret@2.2.0: {} + + into-stream@6.0.0: + dependencies: + from2: 2.3.0 + p-is-promise: 3.0.0 + + iota-array@1.0.0: {} + + ip-regex@2.1.0: {} + + ip@1.1.9: {} + + ipaddr.js@1.9.1: {} + + is-absolute-url@3.0.3: {} + + is-accessor-descriptor@1.0.1: + dependencies: + hasown: 2.0.2 + + is-arguments@1.1.1: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-array-buffer@3.0.4: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + is-arrayish@0.2.1: {} + + is-async-function@2.0.0: + dependencies: + has-tostringtag: 1.0.2 + optional: true + + is-bigint@1.0.4: + dependencies: + has-bigints: 1.0.2 + + is-binary-path@1.0.1: + dependencies: + binary-extensions: 1.13.1 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.1.2: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-buffer@1.1.6: {} + + is-callable@1.2.7: {} + + is-core-module@2.13.1: + dependencies: + hasown: 2.0.2 + + is-data-descriptor@1.0.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 + + is-descriptor@0.1.7: + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + + is-descriptor@1.0.3: + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + + is-extendable@0.1.1: {} + + is-extendable@1.0.1: + dependencies: + is-plain-object: 2.0.4 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.0.2: + dependencies: + call-bind: 1.0.7 + optional: true + + is-fullwidth-code-point@2.0.0: {} + + is-fullwidth-code-point@3.0.0: {} + + is-generator-function@1.0.10: + dependencies: + has-tostringtag: 1.0.2 + optional: true + + is-glob@3.1.0: + dependencies: + is-extglob: 2.1.1 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: + optional: true + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-number@3.0.0: + dependencies: + kind-of: 3.2.2 + + is-number@7.0.0: {} + + is-obj@2.0.0: {} + + is-path-cwd@2.2.0: {} + + is-path-in-cwd@2.1.0: + dependencies: + is-path-inside: 2.1.0 + + is-path-inside@2.1.0: + dependencies: + path-is-inside: 1.0.2 + + is-path-inside@3.0.3: {} + + is-plain-obj@1.1.0: {} + + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + + is-plain-object@5.0.0: {} + + is-potential-custom-element-name@1.0.1: {} + + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-set@2.0.3: + optional: true + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-stream@1.1.0: {} + + is-stream@2.0.1: {} + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-text-path@1.0.1: + dependencies: + text-extensions: 1.9.0 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-typedarray@1.0.0: {} + + is-weakmap@2.0.2: + optional: true + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + is-weakset@2.0.3: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + optional: true + + is-windows@1.0.2: {} + + is-wsl@1.1.0: {} + + isarray@0.0.1: {} + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isobject@2.1.0: + dependencies: + isarray: 1.0.0 + + isobject@3.0.1: {} + + isomorphic-dompurify@2.11.0: + dependencies: + '@types/dompurify': 3.0.5 + dompurify: 3.1.4 + jsdom: 24.0.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + + issue-parser@6.0.0: + dependencies: + lodash.capitalize: 4.2.1 + lodash.escaperegexp: 4.1.2 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.uniqby: 4.7.0 + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-hook@3.0.0: + dependencies: + append-transform: 2.0.0 + + istanbul-lib-instrument@4.0.3: + dependencies: + '@babel/core': 7.24.5 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-processinfo@2.0.3: + dependencies: + archy: 1.0.0 + cross-spawn: 7.0.3 + istanbul-lib-coverage: 3.2.2 + p-map: 3.0.0 + rimraf: 3.0.2 + uuid: 8.3.2 + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.3.4(supports-color@6.1.0) + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + iterator.prototype@1.1.2: + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.6 + set-function-name: 2.0.2 + optional: true + + jackspeak@1.4.2: + dependencies: + cliui: 7.0.4 + + java-properties@1.0.2: {} + + jest-worker@27.5.1: + dependencies: + '@types/node': 20.12.12 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + js-md5@0.7.3: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + js2xmlparser@4.0.2: + dependencies: + xmlcreate: 2.0.4 + + jsdoc@3.6.11: + dependencies: + '@babel/parser': 7.24.5 + '@types/markdown-it': 12.2.3 + bluebird: 3.7.2 + catharsis: 0.9.0 + escape-string-regexp: 2.0.0 + js2xmlparser: 4.0.2 + klaw: 3.0.0 + markdown-it: 12.3.2 + markdown-it-anchor: 8.6.7(@types/markdown-it@12.2.3)(markdown-it@12.3.2) + marked: 4.3.0 + mkdirp: 1.0.4 + requizzle: 0.2.4 + strip-json-comments: 3.1.1 + taffydb: 2.6.2 + underscore: 1.13.6 + + jsdom@24.0.0: + dependencies: + cssstyle: 4.0.1 + data-urls: 5.0.0 + decimal.js: 10.4.3 + form-data: 4.0.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.10 + parse5: 7.1.2 + rrweb-cssom: 0.6.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.4 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + ws: 8.17.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + jsesc@0.5.0: {} + + jsesc@2.5.2: {} + + json-buffer@3.0.1: {} + + json-parse-better-errors@1.0.2: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stringify-safe@5.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + json@9.0.6: {} + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonparse@1.3.1: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.8 + array.prototype.flat: 1.3.2 + object.assign: 4.1.5 + object.values: 1.2.0 + optional: true + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + killable@1.0.1: {} + + kind-of@3.2.2: + dependencies: + is-buffer: 1.1.6 + + kind-of@4.0.0: + dependencies: + is-buffer: 1.1.6 + + kind-of@6.0.3: {} + + klaw@3.0.0: + dependencies: + graceful-fs: 4.2.11 + + lazy-cache@1.0.4: {} + + levn@0.3.0: + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + libtap@1.4.1: + dependencies: + async-hook-domain: 2.0.4 + bind-obj-methods: 3.0.0 + diff: 4.0.2 + function-loop: 2.0.1 + minipass: 3.3.6 + own-or: 1.0.0 + own-or-env: 1.0.2 + signal-exit: 3.0.7 + stack-utils: 2.0.6 + tap-parser: 11.0.2 + tap-yaml: 1.0.2 + tcompare: 5.0.7 + trivial-deferred: 1.1.2 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + linebreak@0.3.0: + dependencies: + base64-js: 0.0.8 + brfs: 1.6.1 + unicode-trie: 0.3.1 + + lines-and-columns@1.2.4: {} + + linkify-it@3.0.3: + dependencies: + uc.micro: 1.0.6 + + load-json-file@4.0.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 + + loader-runner@4.3.0: {} + + loader-utils@1.4.2: + dependencies: + big.js: 5.2.2 + emojis-list: 3.0.0 + json5: 1.0.2 + + loader-utils@2.0.4: + dependencies: + big.js: 5.2.2 + emojis-list: 3.0.0 + json5: 2.2.3 + + locate-path@2.0.0: + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + + lodash.camelcase@4.3.0: {} + + lodash.capitalize@4.2.1: {} + + lodash.debounce@4.0.8: {} + + lodash.escaperegexp@4.1.2: {} + + lodash.flattendeep@4.4.0: {} + + lodash.isfunction@3.0.9: {} + + lodash.ismatch@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + + lodash.kebabcase@4.1.1: {} + + lodash.merge@4.6.2: {} + + lodash.mergewith@4.6.2: {} + + lodash.snakecase@4.1.1: {} + + lodash.startcase@4.4.0: {} + + lodash.uniq@4.5.0: {} + + lodash.uniqby@4.7.0: {} + + lodash.upperfirst@4.3.1: {} + + lodash@4.17.21: {} + + loglevel@1.9.1: {} + + long@4.0.0: {} + + longest@1.0.1: {} + + lookup-closest-locale@6.2.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + optional: true + + lru-cache@4.1.5: + dependencies: + pseudomap: 1.0.2 + yallist: 2.1.2 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + magic-string@0.22.5: + dependencies: + vlq: 0.2.3 + + make-dir@1.3.0: + dependencies: + pify: 3.0.0 + + make-dir@3.1.0: + dependencies: + semver: 6.3.1 + + make-dir@4.0.0: + dependencies: + semver: 7.6.2 + + make-error@1.3.6: {} + + map-cache@0.2.2: {} + + map-limit@0.0.1: + dependencies: + once: 1.3.3 + + map-obj@1.0.1: {} + + map-obj@4.3.0: {} + + map-visit@1.0.0: + dependencies: + object-visit: 1.0.1 + + markdown-it-anchor@8.6.7(@types/markdown-it@12.2.3)(markdown-it@12.3.2): + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 12.3.2 + + markdown-it@12.3.2: + dependencies: + argparse: 2.0.1 + entities: 2.1.0 + linkify-it: 3.0.3 + mdurl: 1.0.1 + uc.micro: 1.0.6 + + marked-terminal@5.2.0(marked@4.3.0): + dependencies: + ansi-escapes: 6.2.1 + cardinal: 2.1.1 + chalk: 5.3.0 + cli-table3: 0.6.5 + marked: 4.3.0 + node-emoji: 1.11.0 + supports-hyperlinks: 2.3.0 + + marked@4.3.0: {} + + mdn-data@2.0.14: {} + + mdurl@1.0.1: {} + + media-typer@0.3.0: {} + + memory-fs@0.4.1: + dependencies: + errno: 0.1.8 + readable-stream: 2.3.8 + + meow@8.1.2: + dependencies: + '@types/minimist': 1.2.5 + camelcase-keys: 6.2.2 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.18.1 + yargs-parser: 20.2.9 + + merge-descriptors@1.0.1: {} + + merge-source-map@1.0.4: + dependencies: + source-map: 0.5.7 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + methods@1.1.2: {} + + microbit-web-bluetooth@0.6.0: + dependencies: + '@types/node': 8.10.40 + '@types/web-bluetooth': 0.0.20 + + microee@0.0.6: {} + + micromatch@3.1.10(supports-color@6.1.0): + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + braces: 2.3.2(supports-color@6.1.0) + define-property: 2.0.2 + extend-shallow: 3.0.2 + extglob: 2.0.4(supports-color@6.1.0) + fragment-cache: 0.2.1 + kind-of: 6.0.3 + nanomatch: 1.2.13(supports-color@6.1.0) + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2(supports-color@6.1.0) + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.7: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + midi-file@1.2.4: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + + mime@2.6.0: {} + + mime@3.0.0: {} + + mimic-fn@2.1.0: {} + + min-indent@1.0.1: {} + + minilog@3.1.0: + dependencies: + microee: 0.0.6 + + minimalistic-assert@1.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimist-options@4.1.0: + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + + minimist@0.0.8: {} + + minimist@1.2.8: {} + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + mississippi@2.0.0: + dependencies: + concat-stream: 1.6.2 + duplexify: 3.7.1 + end-of-stream: 1.4.4 + flush-write-stream: 1.1.1 + from2: 2.3.0 + parallel-transform: 1.2.0 + pump: 2.0.1 + pumpify: 1.5.1 + stream-each: 1.2.3 + through2: 2.0.5 + + mixin-deep@1.3.2: + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@1.0.4: {} + + modify-values@1.0.1: {} + + move-concurrently@1.0.1: + dependencies: + aproba: 1.2.0 + copy-concurrently: 1.0.5 + fs-write-stream-atomic: 1.0.10 + mkdirp: 0.5.6 + rimraf: 2.7.1 + run-queue: 1.0.3 + + ms@2.0.0: {} + + ms@2.1.2: {} + + ms@2.1.3: {} + + multicast-dns-service-types@1.1.0: {} + + multicast-dns@6.2.3: + dependencies: + dns-packet: 1.3.4 + thunky: 1.1.0 + + multipipe@0.3.1: + dependencies: + duplexer2: 0.1.4 + + mute-stream@0.0.8: {} + + nan@2.19.0: + optional: true + + nanomatch@1.2.13(supports-color@6.1.0): + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2(supports-color@6.1.0) + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + natural-compare@1.4.0: {} + + ndarray-fft@1.0.3: + dependencies: + bit-twiddle: 1.0.2 + cwise: 1.0.10 + ndarray: 1.0.19 + ndarray-ops: 1.2.2 + typedarray-pool: 1.2.0 + + ndarray-ops@1.2.2: + dependencies: + cwise-compiler: 1.1.3 + + ndarray-resample@1.0.1: + dependencies: + cwise: 1.0.10 + ndarray-fft: 1.0.3 + ndarray-ops: 1.2.2 + ndarray-scratch: 1.2.0 + + ndarray-scratch@1.2.0: + dependencies: + ndarray: 1.0.19 + ndarray-ops: 1.2.2 + typedarray-pool: 1.2.0 + + ndarray@1.0.19: + dependencies: + iota-array: 1.0.0 + is-buffer: 1.1.6 + + negotiator@0.6.3: {} + + neo-async@2.6.2: {} + + nerf-dart@1.0.0: {} + + nice-try@1.0.5: {} + + node-emoji@1.11.0: + dependencies: + lodash: 4.17.21 + + node-fetch@2.6.13: + dependencies: + whatwg-url: 5.0.0 + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-forge@0.10.0: {} + + node-preload@0.2.1: + dependencies: + process-on-spawn: 1.0.0 + + node-releases@2.0.14: {} + + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.8 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + + normalize-package-data@3.0.3: + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.13.1 + semver: 7.6.2 + validate-npm-package-license: 3.0.4 + + normalize-path@2.1.1: + dependencies: + remove-trailing-separator: 1.1.0 + + normalize-path@3.0.0: {} + + normalize-url@6.1.0: {} + + npm-normalize-package-bin@1.0.1: {} + + npm-run-path@2.0.2: + dependencies: + path-key: 2.0.1 + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + npm@8.19.4: {} + + nwsapi@2.2.10: {} + + nyc@15.1.0: + dependencies: + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + caching-transform: 4.0.0 + convert-source-map: 1.9.0 + decamelize: 1.2.0 + find-cache-dir: 3.3.2 + find-up: 4.1.0 + foreground-child: 2.0.0 + get-package-type: 0.1.0 + glob: 7.2.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-hook: 3.0.0 + istanbul-lib-instrument: 4.0.3 + istanbul-lib-processinfo: 2.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + make-dir: 3.1.0 + node-preload: 0.2.1 + p-map: 3.0.0 + process-on-spawn: 1.0.0 + resolve-from: 5.0.0 + rimraf: 3.0.2 + signal-exit: 3.0.7 + spawn-wrap: 2.0.0 + test-exclude: 6.0.0 + yargs: 15.4.1 + transitivePeerDependencies: + - supports-color + + object-assign@4.1.1: {} + + object-copy@0.1.0: + dependencies: + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + + object-inspect@0.4.0: {} + + object-inspect@1.13.1: {} + + object-inspect@1.4.1: {} + + object-is@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + + object-keys@0.4.0: {} + + object-keys@1.1.1: {} + + object-visit@1.0.1: + dependencies: + isobject: 3.0.1 + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + object.entries@1.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + optional: true + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + optional: true + + object.hasown@1.1.4: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + optional: true + + object.pick@1.3.0: + dependencies: + isobject: 3.0.1 + + object.values@1.2.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + optional: true + + obuf@1.1.2: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + on-headers@1.0.2: {} + + once@1.3.3: + dependencies: + wrappy: 1.0.2 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + opener@1.5.2: {} + + opn@5.5.0: + dependencies: + is-wsl: 1.1.0 + + optionator@0.8.3: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.5 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + os-tmpdir@1.0.2: {} + + own-or-env@1.0.2: + dependencies: + own-or: 1.0.0 + + own-or@1.0.0: {} + + p-each-series@2.2.0: {} + + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + + p-finally@1.0.0: {} + + p-is-promise@3.0.0: {} + + p-limit@1.3.0: + dependencies: + p-try: 1.0.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@4.0.0: + dependencies: + yocto-queue: 1.0.0 + + p-locate@2.0.0: + dependencies: + p-limit: 1.3.0 + + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + + p-map@2.1.0: {} + + p-map@3.0.0: + dependencies: + aggregate-error: 3.1.0 + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + + p-reduce@2.1.0: {} + + p-retry@3.0.1: + dependencies: + retry: 0.12.0 + + p-try@1.0.0: {} + + p-try@2.2.0: {} + + package-hash@4.0.0: + dependencies: + graceful-fs: 4.2.11 + hasha: 5.2.2 + lodash.flattendeep: 4.4.0 + release-zalgo: 1.0.0 + + pako@0.2.9: {} + + pako@1.0.11: {} + + parallel-transform@1.2.0: + dependencies: + cyclist: 1.0.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@4.0.0: + dependencies: + error-ex: 1.3.2 + json-parse-better-errors: 1.0.2 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.24.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse5@7.1.2: + dependencies: + entities: 4.5.0 + + parseurl@1.3.3: {} + + pascalcase@0.1.1: {} + + path-dirname@1.0.2: {} + + path-exists@3.0.0: {} + + path-exists@4.0.0: {} + + path-exists@5.0.0: {} + + path-is-absolute@1.0.1: {} + + path-is-inside@1.0.2: {} + + path-key@2.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@0.1.7: {} + + path-type@3.0.0: + dependencies: + pify: 3.0.0 + + path-type@4.0.0: {} + + picocolors@1.0.1: {} + + picomatch@2.3.1: {} + + pify@2.3.0: {} + + pify@3.0.0: {} + + pify@4.0.1: {} + + pinkie-promise@2.0.1: + dependencies: + pinkie: 2.0.4 + + pinkie@2.0.4: {} + + pkg-conf@2.1.0: + dependencies: + find-up: 2.1.0 + load-json-file: 4.0.0 + + pkg-dir@2.0.0: + dependencies: + find-up: 2.1.0 + + pkg-dir@3.0.0: + dependencies: + find-up: 3.0.0 + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + pkg-dir@7.0.0: + dependencies: + find-up: 6.3.0 + + pngjs@3.4.0: {} + + portfinder@1.0.32(supports-color@6.1.0): + dependencies: + async: 2.6.4 + debug: 3.2.7(supports-color@6.1.0) + mkdirp: 0.5.6 + transitivePeerDependencies: + - supports-color + + posix-character-classes@0.1.1: {} + + possible-typed-array-names@1.0.0: {} + + prelude-ls@1.1.2: {} + + prelude-ls@1.2.1: {} + + process-nextick-args@2.0.1: {} + + process-on-spawn@1.0.0: + dependencies: + fromentries: 1.3.2 + + progress@2.0.3: {} + + promise-inflight@1.0.1(bluebird@3.7.2): + optionalDependencies: + bluebird: 3.7.2 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + optional: true + + proto-list@1.2.4: {} + + protobufjs@6.11.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/long': 4.0.2 + '@types/node': 20.12.12 + long: 4.0.0 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + prr@1.0.1: {} + + pseudomap@1.0.2: {} + + psl@1.9.0: {} + + pump@2.0.1: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + pump@3.0.0: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + pumpify@1.5.1: + dependencies: + duplexify: 3.7.1 + inherits: 2.0.4 + pump: 2.0.1 + + punycode@1.4.1: {} + + punycode@2.3.1: {} + + q@1.5.1: {} + + qs@6.11.0: + dependencies: + side-channel: 1.0.6 + + qs@6.12.1: + dependencies: + side-channel: 1.0.6 + + querystringify@2.2.0: {} + + queue-microtask@1.2.3: {} + + quick-lru@4.0.1: {} + + quote-stream@0.0.0: + dependencies: + minimist: 0.0.8 + through2: 0.4.2 + + quote-stream@1.0.2: + dependencies: + buffer-equal: 0.0.1 + minimist: 1.2.8 + through2: 2.0.5 + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + range-parser@1.2.1: {} + + raw-body@2.5.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + raw-loader@0.5.1: {} + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + react-is@16.13.1: + optional: true + + read-package-json@2.1.2: + dependencies: + glob: 7.2.3 + json-parse-even-better-errors: 2.3.1 + normalize-package-data: 2.5.0 + npm-normalize-package-bin: 1.0.1 + + read-pkg-up@7.0.1: + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + + read-pkg@5.2.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + + readable-stream@1.0.34: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + + readable-stream@1.1.14: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@2.2.1(supports-color@6.1.0): + dependencies: + graceful-fs: 4.2.11 + micromatch: 3.1.10(supports-color@6.1.0) + readable-stream: 2.3.8 + transitivePeerDependencies: + - supports-color + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + rechoir@0.7.1: + dependencies: + resolve: 1.22.8 + + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + + redeyed@2.1.1: + dependencies: + esprima: 4.0.1 + + reflect.getprototypeof@1.0.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + which-builtin-type: 1.1.3 + optional: true + + regenerate-unicode-properties@10.1.1: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + + regenerator-runtime@0.13.11: {} + + regenerator-runtime@0.14.1: {} + + regenerator-transform@0.15.2: + dependencies: + '@babel/runtime': 7.24.5 + + regex-not@1.0.2: + dependencies: + extend-shallow: 3.0.2 + safe-regex: 1.1.0 + + regexp.prototype.flags@1.5.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + regexpp@2.0.1: {} + + regexpu-core@5.3.2: + dependencies: + '@babel/regjsgen': 0.8.0 + regenerate: 1.4.2 + regenerate-unicode-properties: 10.1.1 + regjsparser: 0.9.1 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.1.0 + + registry-auth-token@5.0.2: + dependencies: + '@pnpm/npm-conf': 2.2.2 + + regjsparser@0.9.1: + dependencies: + jsesc: 0.5.0 + + release-zalgo@1.0.0: + dependencies: + es6-error: 4.1.1 + + remove-trailing-separator@1.1.0: {} + + repeat-element@1.1.4: {} + + repeat-string@1.6.1: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + require-main-filename@2.0.0: {} + + requires-port@1.0.0: {} + + requizzle@0.2.4: + dependencies: + lodash: 4.17.21 + + resolve-cwd@2.0.0: + dependencies: + resolve-from: 3.0.0 + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@3.0.0: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve-global@1.0.0: + dependencies: + global-dirs: 0.1.1 + + resolve-url@0.2.1: {} + + resolve@1.22.8: + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + optional: true + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + ret@0.1.15: {} + + retry@0.12.0: {} + + reusify@1.0.4: {} + + right-align@0.1.3: + dependencies: + align-text: 0.1.4 + + rimraf@2.6.3: + dependencies: + glob: 7.2.3 + + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + rrweb-cssom@0.6.0: {} + + run-async@2.4.1: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + run-queue@1.0.3: + dependencies: + aproba: 1.2.0 + + rxjs@6.6.7: + dependencies: + tslib: 1.14.1 + + safe-array-concat@1.1.2: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-regex-test@1.0.3: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + + safe-regex@1.1.0: + dependencies: + ret: 0.1.15 + + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + + schema-utils@0.4.7: + dependencies: + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + schema-utils@1.0.0: + dependencies: + ajv: 6.12.6 + ajv-errors: 1.0.1(ajv@6.12.6) + ajv-keywords: 3.5.2(ajv@6.12.6) + + schema-utils@3.3.0: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + schema-utils@4.2.0: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.13.0 + ajv-formats: 2.1.1(ajv@8.13.0) + ajv-keywords: 5.1.0(ajv@8.13.0) + + scratch-audio@1.0.119: + dependencies: + audio-context: 1.0.3 + minilog: 3.1.0 + startaudiocontext: 1.2.1 + + scratch-blocks@1.1.114: + dependencies: + exports-loader: 0.7.0 + google-closure-library: 20190301.0.0 + imports-loader: 0.8.0 + scratch-l10n: 3.18.142 + + scratch-l10n@3.18.142: {} + + scratch-parser@5.2.1: + dependencies: + ajv: 6.12.6 + jszip: 3.10.1 + pify: 4.0.1 + + scratch-render-fonts@1.0.47: + dependencies: + base64-loader: 1.0.0 + + scratch-render@1.0.142(scratch-render-fonts@1.0.47): + dependencies: + grapheme-breaker: 0.3.2 + hull.js: 0.2.11 + ify-loader: 1.1.0 + linebreak: 0.3.0 + minilog: 3.1.0 + raw-loader: 0.5.1 + scratch-render-fonts: 1.0.47 + scratch-svg-renderer: 2.3.45(scratch-render-fonts@1.0.47) + twgl.js: 4.24.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + + scratch-sb1-converter@1.0.108: + dependencies: + js-md5: 0.7.3 + minilog: 3.1.0 + text-encoding: 0.7.0 + + scratch-semantic-release-config@1.0.14(semantic-release@19.0.5): + dependencies: + '@semantic-release/changelog': 6.0.3(semantic-release@19.0.5) + '@semantic-release/commit-analyzer': 9.0.2(semantic-release@19.0.5) + '@semantic-release/git': 10.0.1(semantic-release@19.0.5) + '@semantic-release/github': 8.1.0(semantic-release@19.0.5) + '@semantic-release/npm': 9.0.2(semantic-release@19.0.5) + '@semantic-release/release-notes-generator': 10.0.3(semantic-release@19.0.5) + semantic-release: 19.0.5 + transitivePeerDependencies: + - encoding + - supports-color + + scratch-storage@2.3.118(webpack@5.91.0(webpack-cli@4.10.0)): + dependencies: + '@babel/runtime': 7.24.5 + arraybuffer-loader: 1.0.8 + base64-js: 1.5.1 + cross-fetch: 3.1.8 + fastestsmallesttextencoderdecoder: 1.0.22 + js-md5: 0.7.3 + minilog: 3.1.0 + worker-loader: 2.0.0(webpack@5.91.0(webpack-cli@4.10.0)) + transitivePeerDependencies: + - encoding + - webpack + + scratch-svg-renderer@2.3.45(scratch-render-fonts@1.0.47): + dependencies: + base64-js: 1.5.1 + base64-loader: 1.0.0 + css-tree: 1.1.3 + fastestsmallesttextencoderdecoder: 1.0.22 + isomorphic-dompurify: 2.11.0 + minilog: 3.1.0 + scratch-render-fonts: 1.0.47 + transformation-matrix: 1.15.3 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + + scratch-translate-extension-languages@1.0.6: {} + + scratch-webpack-configuration@1.3.0(@babel/preset-env@7.24.5(@babel/core@7.24.5))(babel-loader@9.1.3(@babel/core@7.24.5)(webpack@5.91.0(webpack-cli@4.10.0)))(webpack@5.91.0(webpack-cli@4.10.0)): + dependencies: + '@babel/preset-env': 7.24.5(@babel/core@7.24.5) + babel-loader: 9.1.3(@babel/core@7.24.5)(webpack@5.91.0(webpack-cli@4.10.0)) + lodash.merge: 4.6.2 + webpack: 5.91.0(webpack-cli@4.10.0) + webpack-node-externals: 3.0.0 + + script-loader@0.7.2: + dependencies: + raw-loader: 0.5.1 + + seedrandom@2.4.3: {} + + select-hose@2.0.0: {} + + selfsigned@1.10.14: + dependencies: + node-forge: 0.10.0 + + semantic-release@19.0.5: + dependencies: + '@semantic-release/commit-analyzer': 9.0.2(semantic-release@19.0.5) + '@semantic-release/error': 3.0.0 + '@semantic-release/github': 8.1.0(semantic-release@19.0.5) + '@semantic-release/npm': 9.0.2(semantic-release@19.0.5) + '@semantic-release/release-notes-generator': 10.0.3(semantic-release@19.0.5) + aggregate-error: 3.1.0 + cosmiconfig: 7.1.0 + debug: 4.3.4(supports-color@6.1.0) + env-ci: 5.5.0 + execa: 5.1.1 + figures: 3.2.0 + find-versions: 4.0.0 + get-stream: 6.0.1 + git-log-parser: 1.2.0 + hook-std: 2.0.0 + hosted-git-info: 4.1.0 + lodash: 4.17.21 + marked: 4.3.0 + marked-terminal: 5.2.0(marked@4.3.0) + micromatch: 4.0.7 + p-each-series: 2.2.0 + p-reduce: 2.1.0 + read-pkg-up: 7.0.1 + resolve-from: 5.0.0 + semver: 7.6.2 + semver-diff: 3.1.1 + signale: 1.4.0 + yargs: 16.2.0 + transitivePeerDependencies: + - encoding + - supports-color + + semver-diff@3.1.1: + dependencies: + semver: 6.3.1 + + semver-regex@3.1.4: {} + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + + semver@7.6.2: {} + + send@0.18.0(supports-color@6.1.0): + dependencies: + debug: 2.6.9(supports-color@6.1.0) + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + serialize-javascript@1.9.1: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + serve-index@1.9.1(supports-color@6.1.0): + dependencies: + accepts: 1.3.8 + batch: 0.6.1 + debug: 2.6.9(supports-color@6.1.0) + escape-html: 1.0.3 + http-errors: 1.6.3 + mime-types: 2.1.35 + parseurl: 1.3.3 + transitivePeerDependencies: + - supports-color + + serve-static@1.15.0(supports-color@6.1.0): + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0(supports-color@6.1.0) + transitivePeerDependencies: + - supports-color + + set-blocking@2.0.0: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-value@2.0.1: + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + + setimmediate@1.0.5: {} + + setprototypeof@1.1.0: {} + + setprototypeof@1.2.0: {} + + shallow-clone@3.0.1: + dependencies: + kind-of: 6.0.3 + + shallow-copy@0.0.1: {} + + shebang-command@1.2.0: + dependencies: + shebang-regex: 1.0.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@1.0.0: {} + + shebang-regex@3.0.0: {} + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.1 + + signal-exit@3.0.7: {} + + signale@1.4.0: + dependencies: + chalk: 2.4.2 + figures: 2.0.0 + pkg-conf: 2.1.0 + + slash@1.0.0: {} + + slash@3.0.0: {} + + slice-ansi@2.1.0: + dependencies: + ansi-styles: 3.2.1 + astral-regex: 1.0.0 + is-fullwidth-code-point: 2.0.0 + + snapdragon-node@2.1.1: + dependencies: + define-property: 1.0.0 + isobject: 3.0.1 + snapdragon-util: 3.0.1 + + snapdragon-util@3.0.1: + dependencies: + kind-of: 3.2.2 + + snapdragon@0.8.2(supports-color@6.1.0): + dependencies: + base: 0.11.2 + debug: 2.6.9(supports-color@6.1.0) + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + transitivePeerDependencies: + - supports-color + + sockjs-client@1.6.1(supports-color@6.1.0): + dependencies: + debug: 3.2.7(supports-color@6.1.0) + eventsource: 2.0.2 + faye-websocket: 0.11.4 + inherits: 2.0.4 + url-parse: 1.5.10 + transitivePeerDependencies: + - supports-color + + sockjs@0.3.24: + dependencies: + faye-websocket: 0.11.4 + uuid: 8.3.2 + websocket-driver: 0.7.4 + + source-map-resolve@0.5.3: + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-url@0.4.1: {} + + source-map@0.1.43: + dependencies: + amdefine: 1.0.1 + optional: true + + source-map@0.5.0: {} + + source-map@0.5.7: {} + + source-map@0.6.1: {} + + spawn-error-forwarder@1.0.0: {} + + spawn-wrap@2.0.0: + dependencies: + foreground-child: 2.0.0 + is-windows: 1.0.2 + make-dir: 3.1.0 + rimraf: 3.0.2 + signal-exit: 3.0.7 + which: 2.0.2 + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.17 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.17 + + spdx-license-ids@3.0.17: {} + + spdy-transport@3.0.0(supports-color@6.1.0): + dependencies: + debug: 4.3.4(supports-color@6.1.0) + detect-node: 2.1.0 + hpack.js: 2.1.6 + obuf: 1.1.2 + readable-stream: 3.6.2 + wbuf: 1.7.3 + transitivePeerDependencies: + - supports-color + + spdy@4.0.2(supports-color@6.1.0): + dependencies: + debug: 4.3.4(supports-color@6.1.0) + handle-thing: 2.0.1 + http-deceiver: 1.2.7 + select-hose: 2.0.0 + spdy-transport: 3.0.0(supports-color@6.1.0) + transitivePeerDependencies: + - supports-color + + split-string@3.1.0: + dependencies: + extend-shallow: 3.0.2 + + split2@1.0.0: + dependencies: + through2: 2.0.5 + + split2@3.2.2: + dependencies: + readable-stream: 3.6.2 + + split@1.0.1: + dependencies: + through: 2.3.8 + + sprintf-js@1.0.3: {} + + ssri@5.3.0: + dependencies: + safe-buffer: 5.2.1 + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + staffrender@0.2.1: {} + + standardized-audio-context@25.3.75: + dependencies: + '@babel/runtime': 7.24.8 + automation-events: 7.0.7 + tslib: 2.6.3 + + startaudiocontext@1.2.1: {} + + static-eval@0.2.4: + dependencies: + escodegen: 0.0.28 + + static-eval@2.1.1: + dependencies: + escodegen: 2.1.0 + + static-extend@0.1.2: + dependencies: + define-property: 0.2.5 + object-copy: 0.1.0 + + static-module@1.5.0: + dependencies: + concat-stream: 1.6.2 + duplexer2: 0.0.2 + escodegen: 1.3.3 + falafel: 2.2.5 + has: 1.0.4 + object-inspect: 0.4.0 + quote-stream: 0.0.0 + readable-stream: 1.0.34 + shallow-copy: 0.0.1 + static-eval: 0.2.4 + through2: 0.4.2 + + static-module@2.2.5: + dependencies: + concat-stream: 1.6.2 + convert-source-map: 1.9.0 + duplexer2: 0.1.4 + escodegen: 1.9.1 + falafel: 2.2.5 + has: 1.0.4 + magic-string: 0.22.5 + merge-source-map: 1.0.4 + object-inspect: 1.4.1 + quote-stream: 1.0.2 + readable-stream: 2.3.8 + shallow-copy: 0.0.1 + static-eval: 2.1.1 + through2: 2.0.5 + + stats.js@0.17.0: {} + + statuses@1.5.0: {} + + statuses@2.0.1: {} + + stream-combiner2@1.1.1: + dependencies: + duplexer2: 0.1.4 + readable-stream: 2.3.8 + + stream-each@1.2.3: + dependencies: + end-of-stream: 1.4.4 + stream-shift: 1.0.3 + + stream-shift@1.0.3: {} + + string-width@3.1.0: + dependencies: + emoji-regex: 7.0.3 + is-fullwidth-code-point: 2.0.0 + strip-ansi: 5.2.0 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string.prototype.matchall@4.0.11: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.7 + regexp.prototype.flags: 1.5.2 + set-function-name: 2.0.2 + side-channel: 1.0.6 + optional: true + + string.prototype.trim@1.2.9: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + string.prototype.trimend@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string_decoder@0.10.31: {} + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + + strip-ansi@5.2.0: + dependencies: + ansi-regex: 4.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-eof@1.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + strnum@1.0.5: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@6.1.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-hyperlinks@2.3.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + symbol-tree@3.2.4: {} + + table@5.4.6: + dependencies: + ajv: 6.12.6 + lodash: 4.17.21 + slice-ansi: 2.1.0 + string-width: 3.1.0 + + taffydb@2.6.2: {} + + tap-mocha-reporter@5.0.4: + dependencies: + color-support: 1.1.3 + debug: 4.3.4(supports-color@6.1.0) + diff: 4.0.2 + escape-string-regexp: 2.0.0 + glob: 7.2.3 + tap-parser: 11.0.2 + tap-yaml: 1.0.2 + unicode-length: 2.1.0 + transitivePeerDependencies: + - supports-color + + tap-parser@11.0.2: + dependencies: + events-to-array: 1.1.2 + minipass: 3.3.6 + tap-yaml: 1.0.2 + + tap-yaml@1.0.2: + dependencies: + yaml: 1.10.2 + + tap@16.3.10(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5))(typescript@5.4.5): + dependencies: + chokidar: 3.6.0 + findit: 2.0.0 + foreground-child: 2.0.0 + fs-exists-cached: 1.0.0 + glob: 7.2.3 + isexe: 2.0.0 + istanbul-lib-processinfo: 2.0.3 + jackspeak: 1.4.2 + libtap: 1.4.1 + minipass: 3.3.6 + mkdirp: 1.0.4 + nyc: 15.1.0 + opener: 1.5.2 + rimraf: 3.0.2 + signal-exit: 3.0.7 + source-map-support: 0.5.21 + tap-mocha-reporter: 5.0.4 + tap-parser: 11.0.2 + tap-yaml: 1.0.2 + tcompare: 5.0.7 + which: 2.0.2 + optionalDependencies: + ts-node: 10.9.2(@types/node@20.5.1)(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + + tapable@2.2.1: {} + + tcompare@5.0.7: + dependencies: + diff: 4.0.2 + + temp-dir@2.0.0: {} + + tempy@1.0.1: + dependencies: + del: 6.1.1 + is-stream: 2.0.1 + temp-dir: 2.0.0 + type-fest: 0.16.0 + unique-string: 2.0.0 + + terser-webpack-plugin@5.3.10(webpack@5.91.0(webpack-cli@4.10.0)): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.31.0 + webpack: 5.91.0(webpack-cli@4.10.0) + + terser@5.31.0: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.11.3 + commander: 2.20.3 + source-map-support: 0.5.21 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + text-encoding@0.7.0: {} + + text-extensions@1.9.0: {} + + text-table@0.2.0: {} + + through2@0.4.2: + dependencies: + readable-stream: 1.0.34 + xtend: 2.1.2 + + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + + through2@4.0.2: + dependencies: + readable-stream: 3.6.2 + + through@2.3.8: {} + + thunky@1.1.0: {} + + tiny-inflate@1.0.3: {} + + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + + to-fast-properties@2.0.0: {} + + to-object-path@0.3.0: + dependencies: + kind-of: 3.2.2 + + to-regex-range@2.1.1: + dependencies: + is-number: 3.0.0 + repeat-string: 1.6.1 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + to-regex@3.0.2: + dependencies: + define-property: 2.0.2 + extend-shallow: 3.0.2 + regex-not: 1.0.2 + safe-regex: 1.1.0 + + toidentifier@1.0.1: {} + + tonal-array@2.2.2: + dependencies: + tonal-note: 2.2.2 + + tonal-chord@2.2.2: + dependencies: + tonal-dictionary: 2.2.2 + tonal-distance: 2.2.2 + tonal-note: 2.2.2 + tonal-pcset: 2.2.2 + + tonal-dictionary@2.2.2: + dependencies: + tonal-array: 2.2.2 + tonal-note: 2.2.2 + tonal-pcset: 2.2.2 + + tonal-distance@2.2.2: + dependencies: + tonal-interval: 2.2.2 + tonal-note: 2.2.2 + + tonal-interval@2.2.2: {} + + tonal-key@2.2.2: + dependencies: + tonal-array: 2.2.2 + tonal-distance: 2.2.2 + tonal-note: 2.2.2 + tonal-roman-numeral: 2.2.2 + + tonal-note@2.2.2: {} + + tonal-pcset@2.2.2: + dependencies: + tonal-array: 2.2.2 + tonal-interval: 2.2.2 + tonal-note: 2.2.2 + + tonal-roman-numeral@2.2.2: {} + + tonal-scale@2.2.2: + dependencies: + tonal-array: 2.2.2 + tonal-dictionary: 2.2.2 + tonal-distance: 2.2.2 + tonal-note: 2.2.2 + tonal-pcset: 2.2.2 + + tonal@2.2.2: + dependencies: + tonal-array: 2.2.2 + tonal-chord: 2.2.2 + tonal-dictionary: 2.2.2 + tonal-distance: 2.2.2 + tonal-interval: 2.2.2 + tonal-key: 2.2.2 + tonal-note: 2.2.2 + tonal-pcset: 2.2.2 + tonal-scale: 2.2.2 + + tone@14.9.17: + dependencies: + standardized-audio-context: 25.3.75 + tslib: 2.6.3 + + tough-cookie@4.1.4: + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + tr46@0.0.3: {} + + tr46@5.0.0: + dependencies: + punycode: 2.3.1 + + transformation-matrix@1.15.3: {} + + traverse@0.6.9: + dependencies: + gopd: 1.0.1 + typedarray.prototype.slice: 1.0.3 + which-typed-array: 1.1.15 + + trim-newlines@3.0.1: {} + + trivial-deferred@1.1.2: {} + + ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.5.1 + acorn: 8.11.3 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.4.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tslib@1.14.1: {} + + tslib@2.6.3: {} + + twgl.js@4.24.0: {} + + type-check@0.3.2: + dependencies: + prelude-ls: 1.1.2 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.16.0: {} + + type-fest@0.18.1: {} + + type-fest@0.20.2: {} + + type-fest@0.21.3: {} + + type-fest@0.6.0: {} + + type-fest@0.8.1: {} + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + typed-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + typed-array-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-byte-offset@1.0.2: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-length@1.0.6: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + + typedarray-pool@1.2.0: + dependencies: + bit-twiddle: 1.0.2 + dup: 1.0.0 + + typedarray-to-buffer@3.1.5: + dependencies: + is-typedarray: 1.0.0 + + typedarray.prototype.slice@1.0.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + typed-array-buffer: 1.0.2 + typed-array-byte-offset: 1.0.2 + + typedarray@0.0.6: {} + + typescript@5.4.5: {} + + uc.micro@1.0.6: {} + + uglify-js@2.8.29: + dependencies: + source-map: 0.5.7 + yargs: 3.10.0 + optionalDependencies: + uglify-to-browserify: 1.0.2 + + uglify-js@3.17.4: + optional: true + + uglify-to-browserify@1.0.2: + optional: true + + unbox-primitive@1.0.2: + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + + underscore@1.13.6: {} + + undici-types@5.26.5: {} + + unicode-canonical-property-names-ecmascript@2.0.0: {} + + unicode-length@2.1.0: + dependencies: + punycode: 2.3.1 + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.0 + unicode-property-aliases-ecmascript: 2.1.0 + + unicode-match-property-value-ecmascript@2.1.0: {} + + unicode-property-aliases-ecmascript@2.1.0: {} + + unicode-trie@0.3.1: + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + + union-value@1.0.1: + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + + uniq@1.0.1: {} + + unique-filename@1.1.1: + dependencies: + unique-slug: 2.0.2 + + unique-slug@2.0.2: + dependencies: + imurmurhash: 0.1.4 + + unique-string@2.0.0: + dependencies: + crypto-random-string: 2.0.0 + + universal-user-agent@6.0.1: {} + + universalify@0.2.0: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + unset-value@1.0.0: + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 + + upath@1.2.0: {} + + update-browserslist-db@1.0.16(browserslist@4.23.0): + dependencies: + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + urix@0.1.0: {} + + url-join@4.0.1: {} + + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + + url@0.11.3: + dependencies: + punycode: 1.4.1 + qs: 6.12.1 + + use@3.1.1: {} + + util-deprecate@1.0.2: {} + + utils-merge@1.0.1: {} + + uuid@3.4.0: {} + + uuid@8.3.2: {} + + v8-compile-cache-lib@3.0.1: {} + + v8-compile-cache@2.4.0: {} + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + vary@1.1.2: {} + + vlq@0.2.3: {} + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + watchpack@2.4.1: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + wbuf@1.7.3: + dependencies: + minimalistic-assert: 1.0.1 + + web-worker@1.3.0: {} + + webidl-conversions@3.0.1: {} + + webidl-conversions@7.0.0: {} + + webpack-cli@4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0): + dependencies: + '@discoveryjs/json-ext': 0.5.7 + '@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0))(webpack@5.91.0(webpack-cli@4.10.0)) + '@webpack-cli/info': 1.5.0(webpack-cli@4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0)) + '@webpack-cli/serve': 1.7.0(webpack-cli@4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0))(webpack-dev-server@3.11.3(webpack-cli@4.10.0)(webpack@5.91.0)) + colorette: 2.0.20 + commander: 7.2.0 + cross-spawn: 7.0.3 + fastest-levenshtein: 1.0.16 + import-local: 3.1.0 + interpret: 2.2.0 + rechoir: 0.7.1 + webpack: 5.91.0(webpack-cli@4.10.0) + webpack-merge: 5.10.0 + optionalDependencies: + webpack-dev-server: 3.11.3(webpack-cli@4.10.0)(webpack@5.91.0) + + webpack-dev-middleware@3.7.3(webpack@5.91.0(webpack-cli@4.10.0)): + dependencies: + memory-fs: 0.4.1 + mime: 2.6.0 + mkdirp: 0.5.6 + range-parser: 1.2.1 + webpack: 5.91.0(webpack-cli@4.10.0) + webpack-log: 2.0.0 + + webpack-dev-server@3.11.3(webpack-cli@4.10.0)(webpack@5.91.0): + dependencies: + ansi-html-community: 0.0.8 + bonjour: 3.5.0 + chokidar: 2.1.8(supports-color@6.1.0) + compression: 1.7.4(supports-color@6.1.0) + connect-history-api-fallback: 1.6.0 + debug: 4.3.4(supports-color@6.1.0) + del: 4.1.1 + express: 4.19.2(supports-color@6.1.0) + html-entities: 1.4.0 + http-proxy-middleware: 0.19.1(debug@4.3.4(supports-color@6.1.0))(supports-color@6.1.0) + import-local: 2.0.0 + internal-ip: 4.3.0 + ip: 1.1.9 + is-absolute-url: 3.0.3 + killable: 1.0.1 + loglevel: 1.9.1 + opn: 5.5.0 + p-retry: 3.0.1 + portfinder: 1.0.32(supports-color@6.1.0) + schema-utils: 1.0.0 + selfsigned: 1.10.14 + semver: 6.3.1 + serve-index: 1.9.1(supports-color@6.1.0) + sockjs: 0.3.24 + sockjs-client: 1.6.1(supports-color@6.1.0) + spdy: 4.0.2(supports-color@6.1.0) + strip-ansi: 3.0.1 + supports-color: 6.1.0 + url: 0.11.3 + webpack: 5.91.0(webpack-cli@4.10.0) + webpack-dev-middleware: 3.7.3(webpack@5.91.0(webpack-cli@4.10.0)) + webpack-log: 2.0.0 + ws: 6.2.2 + yargs: 13.3.2 + optionalDependencies: + webpack-cli: 4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + webpack-log@2.0.0: + dependencies: + ansi-colors: 3.2.4 + uuid: 3.4.0 + + webpack-merge@5.10.0: + dependencies: + clone-deep: 4.0.1 + flat: 5.0.2 + wildcard: 2.0.1 + + webpack-node-externals@3.0.0: {} + + webpack-sources@3.2.3: {} + + webpack@5.91.0(webpack-cli@4.10.0): + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.5 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + acorn: 8.11.3 + acorn-import-assertions: 1.9.0(acorn@8.11.3) + browserslist: 4.23.0 + chrome-trace-event: 1.0.3 + enhanced-resolve: 5.16.1 + es-module-lexer: 1.5.3 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.10(webpack@5.91.0(webpack-cli@4.10.0)) + watchpack: 2.4.1 + webpack-sources: 3.2.3 + optionalDependencies: + webpack-cli: 4.10.0(webpack-dev-server@3.11.3)(webpack@5.91.0) + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + websocket-driver@0.7.4: + dependencies: + http-parser-js: 0.5.8 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + + websocket-extensions@0.1.4: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.0.0: + dependencies: + tr46: 5.0.0 + webidl-conversions: 7.0.0 + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-boxed-primitive@1.0.2: + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + + which-builtin-type@1.1.3: + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 + optional: true + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 + optional: true + + which-module@2.0.1: {} + + which-typed-array@1.1.15: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wildcard@2.0.1: {} + + window-size@0.1.0: {} + + word-wrap@1.2.5: {} + + wordwrap@0.0.2: {} + + wordwrap@1.0.0: {} + + worker-loader@2.0.0(webpack@5.91.0(webpack-cli@4.10.0)): + dependencies: + loader-utils: 1.4.2 + schema-utils: 0.4.7 + webpack: 5.91.0(webpack-cli@4.10.0) + + wrap-ansi@5.1.0: + dependencies: + ansi-styles: 3.2.1 + string-width: 3.1.0 + strip-ansi: 5.2.0 + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + write-file-atomic@3.0.3: + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.7 + typedarray-to-buffer: 3.1.5 + + write@1.0.3: + dependencies: + mkdirp: 0.5.6 + + ws@6.2.2: + dependencies: + async-limiter: 1.0.1 + + ws@8.17.0: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + + xmlcreate@2.0.4: {} + + xtend@2.1.2: + dependencies: + object-keys: 0.4.0 + + xtend@4.0.2: {} + + y18n@4.0.3: {} + + y18n@5.0.8: {} + + yallist@2.1.2: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yaml@1.10.2: {} + + yargs-parser@13.1.2: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@20.2.9: {} + + yargs-parser@21.1.1: {} + + yargs@13.3.2: + dependencies: + cliui: 5.0.0 + find-up: 3.0.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 3.1.0 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 13.1.2 + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yargs@3.10.0: + dependencies: + camelcase: 1.2.1 + cliui: 2.1.0 + decamelize: 1.2.0 + window-size: 0.1.0 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + yocto-queue@1.0.0: {} diff --git a/src/blocks/scratch3_control.js b/src/blocks/scratch3_control.js index bfededec968..80155b3991b 100644 --- a/src/blocks/scratch3_control.js +++ b/src/blocks/scratch3_control.js @@ -1,7 +1,7 @@ const Cast = require('../util/cast'); class Scratch3ControlBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -19,9 +19,9 @@ class Scratch3ControlBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { control_repeat: this.repeat, control_repeat_until: this.repeatUntil, @@ -42,7 +42,7 @@ class Scratch3ControlBlocks { }; } - getHats () { + getHats() { return { control_start_as_clone: { restartExistingThreads: false @@ -50,7 +50,7 @@ class Scratch3ControlBlocks { }; } - repeat (args, util) { + repeat(args, util) { const times = Math.round(Cast.toNumber(args.TIMES)); // Initialize loop if (typeof util.stackFrame.loopCounter === 'undefined') { @@ -67,7 +67,7 @@ class Scratch3ControlBlocks { } } - repeatUntil (args, util) { + repeatUntil(args, util) { const condition = Cast.toBoolean(args.CONDITION); // If the condition is false (repeat UNTIL), start the branch. if (!condition) { @@ -75,7 +75,7 @@ class Scratch3ControlBlocks { } } - repeatWhile (args, util) { + repeatWhile(args, util) { const condition = Cast.toBoolean(args.CONDITION); // If the condition is true (repeat WHILE), start the branch. if (condition) { @@ -83,7 +83,7 @@ class Scratch3ControlBlocks { } } - forEach (args, util) { + forEach(args, util) { const variable = util.target.lookupOrCreateVariable( args.VARIABLE.id, args.VARIABLE.name); @@ -98,18 +98,18 @@ class Scratch3ControlBlocks { } } - waitUntil (args, util) { + waitUntil(args, util) { const condition = Cast.toBoolean(args.CONDITION); if (!condition) { util.yield(); } } - forever (args, util) { + forever(args, util) { util.startBranch(1, true); } - wait (args, util) { + wait(args, util) { if (util.stackTimerNeedsInit()) { const duration = Math.max(0, 1000 * Cast.toNumber(args.DURATION)); @@ -121,14 +121,14 @@ class Scratch3ControlBlocks { } } - if (args, util) { + if(args, util) { const condition = Cast.toBoolean(args.CONDITION); if (condition) { util.startBranch(1, false); } } - ifElse (args, util) { + ifElse(args, util) { const condition = Cast.toBoolean(args.CONDITION); if (condition) { util.startBranch(1, false); @@ -137,7 +137,7 @@ class Scratch3ControlBlocks { } } - stop (args, util) { + stop(args, util) { const option = args.STOP_OPTION; if (option === 'all') { util.stopAll(); @@ -149,7 +149,7 @@ class Scratch3ControlBlocks { } } - createClone (args, util) { + createClone(args, util) { // Cast argument to string args.CLONE_OPTION = Cast.toString(args.CLONE_OPTION); @@ -174,25 +174,25 @@ class Scratch3ControlBlocks { } } - deleteClone (args, util) { + deleteClone(args, util) { if (util.target.isOriginal) return; this.runtime.disposeTarget(util.target); this.runtime.stopForTarget(util.target); } - getCounter () { + getCounter() { return this._counter; } - clearCounter () { + clearCounter() { this._counter = 0; } - incrCounter () { + incrCounter() { this._counter++; } - allAtOnce (args, util) { + allAtOnce(args, util) { // Since the "all at once" block is implemented for compatiblity with // Scratch 2.0 projects, it behaves the same way it did in 2.0, which // is to simply run the contained script (like "if 1 = 1"). diff --git a/src/blocks/scratch3_data.js b/src/blocks/scratch3_data.js index 824831451c1..5363b37a02c 100644 --- a/src/blocks/scratch3_data.js +++ b/src/blocks/scratch3_data.js @@ -1,7 +1,7 @@ const Cast = require('../util/cast'); class Scratch3DataBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -11,9 +11,9 @@ class Scratch3DataBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { data_variable: this.getVariable, data_setvariableto: this.setVariableTo, @@ -35,13 +35,13 @@ class Scratch3DataBlocks { }; } - getVariable (args, util) { + getVariable(args, util) { const variable = util.target.lookupOrCreateVariable( args.VARIABLE.id, args.VARIABLE.name); return variable.value; } - setVariableTo (args, util) { + setVariableTo(args, util) { const variable = util.target.lookupOrCreateVariable( args.VARIABLE.id, args.VARIABLE.name); variable.value = args.VALUE; @@ -51,7 +51,7 @@ class Scratch3DataBlocks { } } - changeVariableBy (args, util) { + changeVariableBy(args, util) { const variable = util.target.lookupOrCreateVariable( args.VARIABLE.id, args.VARIABLE.name); const castedValue = Cast.toNumber(variable.value); @@ -64,7 +64,7 @@ class Scratch3DataBlocks { } } - changeMonitorVisibility (id, visible) { + changeMonitorVisibility(id, visible) { // Send the monitor blocks an event like the flyout checkbox event. // This both updates the monitor state and changes the isMonitored block flag. this.runtime.monitorBlocks.changeBlock({ @@ -74,23 +74,23 @@ class Scratch3DataBlocks { }, this.runtime); } - showVariable (args) { + showVariable(args) { this.changeMonitorVisibility(args.VARIABLE.id, true); } - hideVariable (args) { + hideVariable(args) { this.changeMonitorVisibility(args.VARIABLE.id, false); } - showList (args) { + showList(args) { this.changeMonitorVisibility(args.LIST.id, true); } - hideList (args) { + hideList(args) { this.changeMonitorVisibility(args.LIST.id, false); } - getListContents (args, util) { + getListContents(args, util) { const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); @@ -111,7 +111,7 @@ class Scratch3DataBlocks { for (let i = 0; i < list.value.length; i++) { const listItem = list.value[i]; if (!((typeof listItem === 'string') && - (listItem.length === 1))) { + (listItem.length === 1))) { allSingleLetters = false; break; } @@ -123,7 +123,7 @@ class Scratch3DataBlocks { } - addToList (args, util) { + addToList(args, util) { const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); if (list.value.length < Scratch3DataBlocks.LIST_ITEM_LIMIT) { @@ -132,7 +132,7 @@ class Scratch3DataBlocks { } } - deleteOfList (args, util) { + deleteOfList(args, util) { const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); const index = Cast.toListIndex(args.INDEX, list.value.length, true); @@ -146,14 +146,14 @@ class Scratch3DataBlocks { list._monitorUpToDate = false; } - deleteAllOfList (args, util) { + deleteAllOfList(args, util) { const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); list.value = []; return; } - insertAtList (args, util) { + insertAtList(args, util) { const item = args.ITEM; const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); @@ -172,7 +172,7 @@ class Scratch3DataBlocks { list._monitorUpToDate = false; } - replaceItemOfList (args, util) { + replaceItemOfList(args, util) { const item = args.ITEM; const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); @@ -184,7 +184,7 @@ class Scratch3DataBlocks { list._monitorUpToDate = false; } - getItemOfList (args, util) { + getItemOfList(args, util) { const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); const index = Cast.toListIndex(args.INDEX, list.value.length, false); @@ -194,7 +194,7 @@ class Scratch3DataBlocks { return list.value[index - 1]; } - getItemNumOfList (args, util) { + getItemNumOfList(args, util) { const item = args.ITEM; const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); @@ -222,13 +222,13 @@ class Scratch3DataBlocks { return 0; } - lengthOfList (args, util) { + lengthOfList(args, util) { const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); return list.value.length; } - listContainsItem (args, util) { + listContainsItem(args, util) { const item = args.ITEM; const list = util.target.lookupOrCreateList( args.LIST.id, args.LIST.name); @@ -249,7 +249,7 @@ class Scratch3DataBlocks { * Type representation for list variables. * @const {number} */ - static get LIST_ITEM_LIMIT () { + static get LIST_ITEM_LIMIT() { return 200000; } } diff --git a/src/blocks/scratch3_event.js b/src/blocks/scratch3_event.js index 10ceb10cc3d..8d46c2547bf 100644 --- a/src/blocks/scratch3_event.js +++ b/src/blocks/scratch3_event.js @@ -1,7 +1,7 @@ const Cast = require('../util/cast'); class Scratch3EventBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -20,9 +20,9 @@ class Scratch3EventBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { event_whentouchingobject: this.touchingObject, event_broadcast: this.broadcast, @@ -31,7 +31,7 @@ class Scratch3EventBlocks { }; } - getHats () { + getHats() { return { event_whenflagclicked: { restartExistingThreads: true @@ -62,23 +62,23 @@ class Scratch3EventBlocks { }; } - touchingObject (args, util) { + touchingObject(args, util) { return util.target.isTouchingObject(args.TOUCHINGOBJECTMENU); } - hatGreaterThanPredicate (args, util) { + hatGreaterThanPredicate(args, util) { const option = Cast.toString(args.WHENGREATERTHANMENU).toLowerCase(); const value = Cast.toNumber(args.VALUE); switch (option) { - case 'timer': - return util.ioQuery('clock', 'projectTimer') > value; - case 'loudness': - return this.runtime.audioEngine && this.runtime.audioEngine.getLoudness() > value; + case 'timer': + return util.ioQuery('clock', 'projectTimer') > value; + case 'loudness': + return this.runtime.audioEngine && this.runtime.audioEngine.getLoudness() > value; } return false; } - broadcast (args, util) { + broadcast(args, util) { const broadcastVar = util.runtime.getTargetForStage().lookupBroadcastMsg( args.BROADCAST_OPTION.id, args.BROADCAST_OPTION.name); if (broadcastVar) { @@ -89,7 +89,7 @@ class Scratch3EventBlocks { } } - broadcastAndWait (args, util) { + broadcastAndWait(args, util) { if (!util.stackFrame.broadcastVar) { util.stackFrame.broadcastVar = util.runtime.getTargetForStage().lookupBroadcastMsg( args.BROADCAST_OPTION.id, args.BROADCAST_OPTION.name); @@ -101,8 +101,8 @@ class Scratch3EventBlocks { // No - start hats for this broadcast. util.stackFrame.startedThreads = util.startHats( 'event_whenbroadcastreceived', { - BROADCAST_OPTION: broadcastOption - } + BROADCAST_OPTION: broadcastOption + } ); if (util.stackFrame.startedThreads.length === 0) { // Nothing was started. diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js index 18e163a9a99..e94ed21674e 100644 --- a/src/blocks/scratch3_looks.js +++ b/src/blocks/scratch3_looks.js @@ -17,7 +17,7 @@ const MathUtil = require('../util/math-util'); */ class Scratch3LooksBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -41,7 +41,7 @@ class Scratch3LooksBlocks { * The default bubble state, to be used when a target has no existing bubble state. * @type {BubbleState} */ - static get DEFAULT_BUBBLE_STATE () { + static get DEFAULT_BUBBLE_STATE() { return { drawableId: null, onSpriteRight: true, @@ -56,7 +56,7 @@ class Scratch3LooksBlocks { * The key to load & store a target's bubble-related state. * @type {string} */ - static get STATE_KEY () { + static get STATE_KEY() { return 'Scratch.looks'; } @@ -64,7 +64,7 @@ class Scratch3LooksBlocks { * Event name for a text bubble being created or updated. * @const {string} */ - static get SAY_OR_THINK () { + static get SAY_OR_THINK() { // There are currently many places in the codebase which explicitly refer to this event by the string 'SAY', // so keep this as the string 'SAY' for now rather than changing it to 'SAY_OR_THINK' and breaking things. return 'SAY'; @@ -74,7 +74,7 @@ class Scratch3LooksBlocks { * Limit for say bubble string. * @const {string} */ - static get SAY_BUBBLE_LIMIT () { + static get SAY_BUBBLE_LIMIT() { return 330; } @@ -82,16 +82,16 @@ class Scratch3LooksBlocks { * Limit for ghost effect * @const {object} */ - static get EFFECT_GHOST_LIMIT (){ - return {min: 0, max: 100}; + static get EFFECT_GHOST_LIMIT() { + return { min: 0, max: 100 }; } /** * Limit for brightness effect * @const {object} */ - static get EFFECT_BRIGHTNESS_LIMIT (){ - return {min: -100, max: 100}; + static get EFFECT_BRIGHTNESS_LIMIT() { + return { min: -100, max: 100 }; } /** @@ -99,7 +99,7 @@ class Scratch3LooksBlocks { * @returns {BubbleState} the mutable bubble state associated with that target. This will be created if necessary. * @private */ - _getBubbleState (target) { + _getBubbleState(target) { let bubbleState = target.getCustomState(Scratch3LooksBlocks.STATE_KEY); if (!bubbleState) { bubbleState = Clone.simple(Scratch3LooksBlocks.DEFAULT_BUBBLE_STATE); @@ -113,7 +113,7 @@ class Scratch3LooksBlocks { * @param {RenderedTarget} target - the target which has moved. * @private */ - _onTargetChanged (target) { + _onTargetChanged(target) { const bubbleState = this._getBubbleState(target); if (bubbleState.drawableId) { this._positionBubble(target); @@ -125,7 +125,7 @@ class Scratch3LooksBlocks { * @param {RenderedTarget} target - the target. * @private */ - _onTargetWillExit (target) { + _onTargetWillExit(target) { const bubbleState = this._getBubbleState(target); if (bubbleState.drawableId && bubbleState.skinId) { this.runtime.renderer.destroyDrawable(bubbleState.drawableId, StageLayering.SPRITE_LAYER); @@ -141,7 +141,7 @@ class Scratch3LooksBlocks { * Handle project start/stop by clearing all visible bubbles. * @private */ - _onResetBubbles () { + _onResetBubbles() { for (let n = 0; n < this.runtime.targets.length; n++) { const bubbleState = this._getBubbleState(this.runtime.targets[n]); bubbleState.text = ''; @@ -155,7 +155,7 @@ class Scratch3LooksBlocks { * @param {!Target} target Target whose bubble needs positioning. * @private */ - _positionBubble (target) { + _positionBubble(target) { if (!target.visible) return; const bubbleState = this._getBubbleState(target); const [bubbleWidth, bubbleHeight] = this.runtime.renderer.getCurrentSkinSize(bubbleState.drawableId); @@ -215,11 +215,11 @@ class Scratch3LooksBlocks { * @return {undefined} Early return if text is empty string. * @private */ - _renderBubble (target) { + _renderBubble(target) { if (!this.runtime.renderer) return; const bubbleState = this._getBubbleState(target); - const {type, text, onSpriteRight} = bubbleState; + const { type, text, onSpriteRight } = bubbleState; // Remove the bubble if target is not visible, or text is being set to blank. if (!target.visible || text === '') { @@ -245,7 +245,7 @@ class Scratch3LooksBlocks { * @return {string} The formatted text * @private */ - _formatBubbleText (text) { + _formatBubbleText(text) { if (text === '') return text; // Non-integers should be rounded to 2 decimal places (no more, no less), unless they're small enough that @@ -270,7 +270,7 @@ class Scratch3LooksBlocks { * @param {!string} text The text for the bubble, empty string clears the bubble. * @private */ - _updateBubble (target, type, text) { + _updateBubble(target, type, text) { const bubbleState = this._getBubbleState(target); bubbleState.type = type; bubbleState.text = this._formatBubbleText(text); @@ -280,9 +280,9 @@ class Scratch3LooksBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { looks_say: this.say, looks_sayforsecs: this.sayforsecs, @@ -290,7 +290,7 @@ class Scratch3LooksBlocks { looks_thinkforsecs: this.thinkforsecs, looks_show: this.show, looks_hide: this.hide, - looks_hideallsprites: () => {}, // legacy no-op block + looks_hideallsprites: () => { }, // legacy no-op block looks_switchcostumeto: this.switchCostume, looks_switchbackdropto: this.switchBackdrop, looks_switchbackdroptoandwait: this.switchBackdropAndWait, @@ -301,8 +301,8 @@ class Scratch3LooksBlocks { looks_cleargraphiceffects: this.clearEffects, looks_changesizeby: this.changeSize, looks_setsizeto: this.setSize, - looks_changestretchby: () => {}, // legacy no-op blocks - looks_setstretchto: () => {}, + looks_changestretchby: () => { }, // legacy no-op blocks + looks_setstretchto: () => { }, looks_gotofrontback: this.goToFrontBack, looks_goforwardbackwardlayers: this.goForwardBackwardLayers, looks_size: this.getSize, @@ -311,7 +311,7 @@ class Scratch3LooksBlocks { }; } - getMonitored () { + getMonitored() { return { looks_size: { isSpriteSpecific: true, @@ -327,12 +327,12 @@ class Scratch3LooksBlocks { }; } - say (args, util) { + say(args, util) { // @TODO in 2.0 calling say/think resets the right/left bias of the bubble this.runtime.emit(Scratch3LooksBlocks.SAY_OR_THINK, util.target, 'say', args.MESSAGE); } - sayforsecs (args, util) { + sayforsecs(args, util) { this.say(args, util); const target = util.target; const usageId = this._getBubbleState(target).usageId; @@ -348,11 +348,11 @@ class Scratch3LooksBlocks { }); } - think (args, util) { + think(args, util) { this.runtime.emit(Scratch3LooksBlocks.SAY_OR_THINK, util.target, 'think', args.MESSAGE); } - thinkforsecs (args, util) { + thinkforsecs(args, util) { this.think(args, util); const target = util.target; const usageId = this._getBubbleState(target).usageId; @@ -368,12 +368,12 @@ class Scratch3LooksBlocks { }); } - show (args, util) { + show(args, util) { util.target.setVisible(true); this._renderBubble(util.target); } - hide (args, util) { + hide(args, util) { util.target.setVisible(false); this._renderBubble(util.target); } @@ -386,7 +386,7 @@ class Scratch3LooksBlocks { * @param {boolean=} optZeroIndex Set to zero-index the requestedCostume. * @return {Array.} Any threads started by this switch. */ - _setCostume (target, requestedCostume, optZeroIndex) { + _setCostume(target, requestedCostume, optZeroIndex) { if (typeof requestedCostume === 'number') { // Numbers should be treated as costume indices, always target.setCostume(optZeroIndex ? requestedCostume : requestedCostume - 1); @@ -400,9 +400,9 @@ class Scratch3LooksBlocks { target.setCostume(target.currentCostume + 1); } else if (requestedCostume === 'previous costume') { target.setCostume(target.currentCostume - 1); - // Try to cast the string to a number (and treat it as a costume index) - // Pure whitespace should not be treated as a number - // Note: isNaN will cast the string to a number before checking if it's NaN + // Try to cast the string to a number (and treat it as a costume index) + // Pure whitespace should not be treated as a number + // Note: isNaN will cast the string to a number before checking if it's NaN } else if (!(isNaN(requestedCostume) || Cast.isWhiteSpace(requestedCostume))) { target.setCostume(optZeroIndex ? Number(requestedCostume) : Number(requestedCostume) - 1); } @@ -420,7 +420,7 @@ class Scratch3LooksBlocks { * @param {boolean=} optZeroIndex Set to zero-index the requestedBackdrop. * @return {Array.} Any threads started by this switch. */ - _setBackdrop (stage, requestedBackdrop, optZeroIndex) { + _setBackdrop(stage, requestedBackdrop, optZeroIndex) { if (typeof requestedBackdrop === 'number') { // Numbers should be treated as backdrop indices, always stage.setCostume(optZeroIndex ? requestedBackdrop : requestedBackdrop - 1); @@ -447,9 +447,9 @@ class Scratch3LooksBlocks { stage.setCostume(nextCostume); } - // Try to cast the string to a number (and treat it as a costume index) - // Pure whitespace should not be treated as a number - // Note: isNaN will cast the string to a number before checking if it's NaN + // Try to cast the string to a number (and treat it as a costume index) + // Pure whitespace should not be treated as a number + // Note: isNaN will cast the string to a number before checking if it's NaN } else if (!(isNaN(requestedBackdrop) || Cast.isWhiteSpace(requestedBackdrop))) { stage.setCostume(optZeroIndex ? Number(requestedBackdrop) : Number(requestedBackdrop) - 1); } @@ -461,21 +461,21 @@ class Scratch3LooksBlocks { }); } - switchCostume (args, util) { + switchCostume(args, util) { this._setCostume(util.target, args.COSTUME); } - nextCostume (args, util) { + nextCostume(args, util) { this._setCostume( util.target, util.target.currentCostume + 1, true ); } - switchBackdrop (args) { + switchBackdrop(args) { this._setBackdrop(this.runtime.getTargetForStage(), args.BACKDROP); } - switchBackdropAndWait (args, util) { + switchBackdropAndWait(args, util) { // Have we run before, starting threads? if (!util.stackFrame.startedThreads) { // No - switch the backdrop. @@ -513,31 +513,31 @@ class Scratch3LooksBlocks { } } - nextBackdrop () { + nextBackdrop() { const stage = this.runtime.getTargetForStage(); this._setBackdrop( stage, stage.currentCostume + 1, true ); } - clampEffect (effect, value) { + clampEffect(effect, value) { let clampedValue = value; switch (effect) { - case 'ghost': - clampedValue = MathUtil.clamp(value, - Scratch3LooksBlocks.EFFECT_GHOST_LIMIT.min, - Scratch3LooksBlocks.EFFECT_GHOST_LIMIT.max); - break; - case 'brightness': - clampedValue = MathUtil.clamp(value, - Scratch3LooksBlocks.EFFECT_BRIGHTNESS_LIMIT.min, - Scratch3LooksBlocks.EFFECT_BRIGHTNESS_LIMIT.max); - break; + case 'ghost': + clampedValue = MathUtil.clamp(value, + Scratch3LooksBlocks.EFFECT_GHOST_LIMIT.min, + Scratch3LooksBlocks.EFFECT_GHOST_LIMIT.max); + break; + case 'brightness': + clampedValue = MathUtil.clamp(value, + Scratch3LooksBlocks.EFFECT_BRIGHTNESS_LIMIT.min, + Scratch3LooksBlocks.EFFECT_BRIGHTNESS_LIMIT.max); + break; } return clampedValue; } - changeEffect (args, util) { + changeEffect(args, util) { const effect = Cast.toString(args.EFFECT).toLowerCase(); const change = Cast.toNumber(args.CHANGE); if (!Object.prototype.hasOwnProperty.call(util.target.effects, effect)) return; @@ -546,28 +546,28 @@ class Scratch3LooksBlocks { util.target.setEffect(effect, newValue); } - setEffect (args, util) { + setEffect(args, util) { const effect = Cast.toString(args.EFFECT).toLowerCase(); let value = Cast.toNumber(args.VALUE); value = this.clampEffect(effect, value); util.target.setEffect(effect, value); } - clearEffects (args, util) { + clearEffects(args, util) { util.target.clearEffects(); } - changeSize (args, util) { + changeSize(args, util) { const change = Cast.toNumber(args.CHANGE); util.target.setSize(util.target.size + change); } - setSize (args, util) { + setSize(args, util) { const size = Cast.toNumber(args.SIZE); util.target.setSize(size); } - goToFrontBack (args, util) { + goToFrontBack(args, util) { if (!util.target.isStage) { if (args.FRONT_BACK === 'front') { util.target.goToFront(); @@ -577,7 +577,7 @@ class Scratch3LooksBlocks { } } - goForwardBackwardLayers (args, util) { + goForwardBackwardLayers(args, util) { if (!util.target.isStage) { if (args.FORWARD_BACKWARD === 'forward') { util.target.goForwardLayers(Cast.toNumber(args.NUM)); @@ -587,11 +587,11 @@ class Scratch3LooksBlocks { } } - getSize (args, util) { + getSize(args, util) { return Math.round(util.target.size); } - getBackdropNumberName (args) { + getBackdropNumberName(args) { const stage = this.runtime.getTargetForStage(); if (args.NUMBER_NAME === 'number') { return stage.currentCostume + 1; @@ -600,7 +600,7 @@ class Scratch3LooksBlocks { return stage.getCostumes()[stage.currentCostume].name; } - getCostumeNumberName (args, util) { + getCostumeNumberName(args, util) { if (args.NUMBER_NAME === 'number') { return util.target.currentCostume + 1; } diff --git a/src/blocks/scratch3_motion.js b/src/blocks/scratch3_motion.js index d42dce463b3..780fb31a6bd 100644 --- a/src/blocks/scratch3_motion.js +++ b/src/blocks/scratch3_motion.js @@ -3,7 +3,7 @@ const MathUtil = require('../util/math-util'); const Timer = require('../util/timer'); class Scratch3MotionBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -13,9 +13,9 @@ class Scratch3MotionBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { motion_movesteps: this.moveSteps, motion_gotoxy: this.goToXY, @@ -36,15 +36,15 @@ class Scratch3MotionBlocks { motion_yposition: this.getY, motion_direction: this.getDirection, // Legacy no-op blocks: - motion_scroll_right: () => {}, - motion_scroll_up: () => {}, - motion_align_scene: () => {}, - motion_xscroll: () => {}, - motion_yscroll: () => {} + motion_scroll_right: () => { }, + motion_scroll_up: () => { }, + motion_align_scene: () => { }, + motion_xscroll: () => { }, + motion_yscroll: () => { } }; } - getMonitored () { + getMonitored() { return { motion_xposition: { isSpriteSpecific: true, @@ -61,7 +61,7 @@ class Scratch3MotionBlocks { }; } - moveSteps (args, util) { + moveSteps(args, util) { const steps = Cast.toNumber(args.STEPS); const radians = MathUtil.degToRad(90 - util.target.direction); const dx = steps * Math.cos(radians); @@ -69,13 +69,13 @@ class Scratch3MotionBlocks { util.target.setXY(util.target.x + dx, util.target.y + dy); } - goToXY (args, util) { + goToXY(args, util) { const x = Cast.toNumber(args.X); const y = Cast.toNumber(args.Y); util.target.setXY(x, y); } - getTargetXY (targetName, util) { + getTargetXY(targetName, util) { let targetX = 0; let targetY = 0; if (targetName === '_mouse_') { @@ -96,29 +96,29 @@ class Scratch3MotionBlocks { return [targetX, targetY]; } - goTo (args, util) { + goTo(args, util) { const targetXY = this.getTargetXY(args.TO, util); if (targetXY) { util.target.setXY(targetXY[0], targetXY[1]); } } - turnRight (args, util) { + turnRight(args, util) { const degrees = Cast.toNumber(args.DEGREES); util.target.setDirection(util.target.direction + degrees); } - turnLeft (args, util) { + turnLeft(args, util) { const degrees = Cast.toNumber(args.DEGREES); util.target.setDirection(util.target.direction - degrees); } - pointInDirection (args, util) { + pointInDirection(args, util) { const direction = Cast.toNumber(args.DIRECTION); util.target.setDirection(direction); } - pointTowards (args, util) { + pointTowards(args, util) { let targetX = 0; let targetY = 0; if (args.TOWARDS === '_mouse_') { @@ -141,7 +141,7 @@ class Scratch3MotionBlocks { util.target.setDirection(direction); } - glide (args, util) { + glide(args, util) { if (util.stackFrame.timer) { const timeElapsed = util.stackFrame.timer.timeElapsed(); if (timeElapsed < util.stackFrame.duration * 1000) { @@ -176,14 +176,14 @@ class Scratch3MotionBlocks { } } - glideTo (args, util) { + glideTo(args, util) { const targetXY = this.getTargetXY(args.TO, util); if (targetXY) { - this.glide({SECS: args.SECS, X: targetXY[0], Y: targetXY[1]}, util); + this.glide({ SECS: args.SECS, X: targetXY[0], Y: targetXY[1] }, util); } } - ifOnEdgeBounce (args, util) { + ifOnEdgeBounce(args, util) { const bounds = util.target.getBounds(); if (!bounds) { return; @@ -239,44 +239,44 @@ class Scratch3MotionBlocks { util.target.setXY(fencedPosition[0], fencedPosition[1]); } - setRotationStyle (args, util) { + setRotationStyle(args, util) { util.target.setRotationStyle(args.STYLE); } - changeX (args, util) { + changeX(args, util) { const dx = Cast.toNumber(args.DX); util.target.setXY(util.target.x + dx, util.target.y); } - setX (args, util) { + setX(args, util) { const x = Cast.toNumber(args.X); util.target.setXY(x, util.target.y); } - changeY (args, util) { + changeY(args, util) { const dy = Cast.toNumber(args.DY); util.target.setXY(util.target.x, util.target.y + dy); } - setY (args, util) { + setY(args, util) { const y = Cast.toNumber(args.Y); util.target.setXY(util.target.x, y); } - getX (args, util) { + getX(args, util) { return this.limitPrecision(util.target.x); } - getY (args, util) { + getY(args, util) { return this.limitPrecision(util.target.y); } - getDirection (args, util) { + getDirection(args, util) { return util.target.direction; } // This corresponds to snapToInteger in Scratch 2 - limitPrecision (coordinate) { + limitPrecision(coordinate) { const rounded = Math.round(coordinate); const delta = coordinate - rounded; const limitedCoord = (Math.abs(delta) < 1e-9) ? rounded : coordinate; diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js index 4fd6a7bf42b..988089f0c10 100644 --- a/src/blocks/scratch3_operators.js +++ b/src/blocks/scratch3_operators.js @@ -2,7 +2,7 @@ const Cast = require('../util/cast.js'); const MathUtil = require('../util/math-util.js'); class Scratch3OperatorsBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -12,9 +12,9 @@ class Scratch3OperatorsBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { operator_add: this.add, operator_subtract: this.subtract, @@ -37,47 +37,47 @@ class Scratch3OperatorsBlocks { }; } - add (args) { + add(args) { return Cast.toNumber(args.NUM1) + Cast.toNumber(args.NUM2); } - subtract (args) { + subtract(args) { return Cast.toNumber(args.NUM1) - Cast.toNumber(args.NUM2); } - multiply (args) { + multiply(args) { return Cast.toNumber(args.NUM1) * Cast.toNumber(args.NUM2); } - divide (args) { + divide(args) { return Cast.toNumber(args.NUM1) / Cast.toNumber(args.NUM2); } - lt (args) { + lt(args) { return Cast.compare(args.OPERAND1, args.OPERAND2) < 0; } - equals (args) { + equals(args) { return Cast.compare(args.OPERAND1, args.OPERAND2) === 0; } - gt (args) { + gt(args) { return Cast.compare(args.OPERAND1, args.OPERAND2) > 0; } - and (args) { + and(args) { return Cast.toBoolean(args.OPERAND1) && Cast.toBoolean(args.OPERAND2); } - or (args) { + or(args) { return Cast.toBoolean(args.OPERAND1) || Cast.toBoolean(args.OPERAND2); } - not (args) { + not(args) { return !Cast.toBoolean(args.OPERAND); } - random (args) { + random(args) { const nFrom = Cast.toNumber(args.FROM); const nTo = Cast.toNumber(args.TO); const low = nFrom <= nTo ? nFrom : nTo; @@ -90,11 +90,11 @@ class Scratch3OperatorsBlocks { return (Math.random() * (high - low)) + low; } - join (args) { + join(args) { return Cast.toString(args.STRING1) + Cast.toString(args.STRING2); } - letterOf (args) { + letterOf(args) { const index = Cast.toNumber(args.LETTER) - 1; const str = Cast.toString(args.STRING); // Out of bounds? @@ -104,18 +104,18 @@ class Scratch3OperatorsBlocks { return str.charAt(index); } - length (args) { + length(args) { return Cast.toString(args.STRING).length; } - contains (args) { + contains(args) { const format = function (string) { return Cast.toString(string).toLowerCase(); }; return format(args.STRING1).includes(format(args.STRING2)); } - mod (args) { + mod(args) { const n = Cast.toNumber(args.NUM1); const modulus = Cast.toNumber(args.NUM2); let result = n % modulus; @@ -124,28 +124,28 @@ class Scratch3OperatorsBlocks { return result; } - round (args) { + round(args) { return Math.round(Cast.toNumber(args.NUM)); } - mathop (args) { + mathop(args) { const operator = Cast.toString(args.OPERATOR).toLowerCase(); const n = Cast.toNumber(args.NUM); switch (operator) { - case 'abs': return Math.abs(n); - case 'floor': return Math.floor(n); - case 'ceiling': return Math.ceil(n); - case 'sqrt': return Math.sqrt(n); - case 'sin': return parseFloat(Math.sin((Math.PI * n) / 180).toFixed(10)); - case 'cos': return parseFloat(Math.cos((Math.PI * n) / 180).toFixed(10)); - case 'tan': return MathUtil.tan(n); - case 'asin': return (Math.asin(n) * 180) / Math.PI; - case 'acos': return (Math.acos(n) * 180) / Math.PI; - case 'atan': return (Math.atan(n) * 180) / Math.PI; - case 'ln': return Math.log(n); - case 'log': return Math.log(n) / Math.LN10; - case 'e ^': return Math.exp(n); - case '10 ^': return Math.pow(10, n); + case 'abs': return Math.abs(n); + case 'floor': return Math.floor(n); + case 'ceiling': return Math.ceil(n); + case 'sqrt': return Math.sqrt(n); + case 'sin': return parseFloat(Math.sin((Math.PI * n) / 180).toFixed(10)); + case 'cos': return parseFloat(Math.cos((Math.PI * n) / 180).toFixed(10)); + case 'tan': return MathUtil.tan(n); + case 'asin': return (Math.asin(n) * 180) / Math.PI; + case 'acos': return (Math.acos(n) * 180) / Math.PI; + case 'atan': return (Math.atan(n) * 180) / Math.PI; + case 'ln': return Math.log(n); + case 'log': return Math.log(n) / Math.LN10; + case 'e ^': return Math.exp(n); + case '10 ^': return Math.pow(10, n); } return 0; } diff --git a/src/blocks/scratch3_procedures.js b/src/blocks/scratch3_procedures.js index 0f2ec3642d5..22809d871c1 100644 --- a/src/blocks/scratch3_procedures.js +++ b/src/blocks/scratch3_procedures.js @@ -1,5 +1,5 @@ class Scratch3ProcedureBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -9,9 +9,9 @@ class Scratch3ProcedureBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { procedures_definition: this.definition, procedures_call: this.call, @@ -20,11 +20,11 @@ class Scratch3ProcedureBlocks { }; } - definition () { + definition() { // No-op: execute the blocks. } - call (args, util) { + call(args, util) { if (!util.stackFrame.executed) { const procedureCode = args.mutation.proccode; const paramNamesIdsAndDefaults = util.getProcedureParamNamesIdsAndDefaults(procedureCode); @@ -55,7 +55,7 @@ class Scratch3ProcedureBlocks { } } - argumentReporterStringNumber (args, util) { + argumentReporterStringNumber(args, util) { const value = util.getParam(args.VALUE); if (value === null) { // When the parameter is not found in the most recent procedure @@ -65,7 +65,7 @@ class Scratch3ProcedureBlocks { return value; } - argumentReporterBoolean (args, util) { + argumentReporterBoolean(args, util) { const value = util.getParam(args.VALUE); if (value === null) { // When the parameter is not found in the most recent procedure diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index 2b031307c83..ce19c3f03c3 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -3,7 +3,7 @@ const Timer = require('../util/timer'); const getMonitorIdForBlockWithArgs = require('../util/get-monitor-id'); class Scratch3SensingBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -49,9 +49,9 @@ class Scratch3SensingBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { sensing_touchingobject: this.touchingObject, sensing_touchingcolor: this.touchingColor, @@ -72,11 +72,11 @@ class Scratch3SensingBlocks { sensing_askandwait: this.askAndWait, sensing_answer: this.getAnswer, sensing_username: this.getUsername, - sensing_userid: () => {} // legacy no-op block + sensing_userid: () => { } // legacy no-op block }; } - getMonitored () { + getMonitored() { return { sensing_answer: { getId: () => 'answer' @@ -96,7 +96,7 @@ class Scratch3SensingBlocks { }; } - _onAnswer (answer) { + _onAnswer(answer) { this._answer = answer; const questionObj = this._questionList.shift(); if (questionObj) { @@ -110,15 +110,15 @@ class Scratch3SensingBlocks { } } - _resetAnswer () { + _resetAnswer() { this._answer = ''; } - _enqueueAsk (question, resolve, target, wasVisible, wasStage) { + _enqueueAsk(question, resolve, target, wasVisible, wasStage) { this._questionList.push([question, resolve, target, wasVisible, wasStage]); } - _askNextQuestion () { + _askNextQuestion() { if (this._questionList.length > 0) { const [question, _resolve, target, wasVisible, wasStage] = this._questionList[0]; // If the target is visible, emit a blank question and use the @@ -132,12 +132,12 @@ class Scratch3SensingBlocks { } } - _clearAllQuestions () { + _clearAllQuestions() { this._questionList = []; this.runtime.emit('QUESTION', null); } - _clearTargetQuestions (stopTarget) { + _clearTargetQuestions(stopTarget) { const currentlyAsking = this._questionList.length > 0 && this._questionList[0][2] === stopTarget; this._questionList = this._questionList.filter(question => ( question[2] !== stopTarget @@ -153,7 +153,7 @@ class Scratch3SensingBlocks { } } - askAndWait (args, util) { + askAndWait(args, util) { const _target = util.target; return new Promise(resolve => { const isQuestionAsked = this._questionList.length > 0; @@ -164,26 +164,26 @@ class Scratch3SensingBlocks { }); } - getAnswer () { + getAnswer() { return this._answer; } - touchingObject (args, util) { + touchingObject(args, util) { return util.target.isTouchingObject(args.TOUCHINGOBJECTMENU); } - touchingColor (args, util) { + touchingColor(args, util) { const color = Cast.toRgbColorList(args.COLOR); return util.target.isTouchingColor(color); } - colorTouchingColor (args, util) { + colorTouchingColor(args, util) { const maskColor = Cast.toRgbColorList(args.COLOR); const targetColor = Cast.toRgbColorList(args.COLOR2); return util.target.colorIsTouchingColor(targetColor, maskColor); } - distanceTo (args, util) { + distanceTo(args, util) { if (util.target.isStage) return 10000; let targetX = 0; @@ -206,50 +206,50 @@ class Scratch3SensingBlocks { return Math.sqrt((dx * dx) + (dy * dy)); } - setDragMode (args, util) { + setDragMode(args, util) { util.target.setDraggable(args.DRAG_MODE === 'draggable'); } - getTimer (args, util) { + getTimer(args, util) { return util.ioQuery('clock', 'projectTimer'); } - resetTimer (args, util) { + resetTimer(args, util) { util.ioQuery('clock', 'resetProjectTimer'); } - getMouseX (args, util) { + getMouseX(args, util) { return util.ioQuery('mouse', 'getScratchX'); } - getMouseY (args, util) { + getMouseY(args, util) { return util.ioQuery('mouse', 'getScratchY'); } - getMouseDown (args, util) { + getMouseDown(args, util) { return util.ioQuery('mouse', 'getIsDown'); } - current (args) { + current(args) { const menuOption = Cast.toString(args.CURRENTMENU).toLowerCase(); const date = new Date(); switch (menuOption) { - case 'year': return date.getFullYear(); - case 'month': return date.getMonth() + 1; // getMonth is zero-based - case 'date': return date.getDate(); - case 'dayofweek': return date.getDay() + 1; // getDay is zero-based, Sun=0 - case 'hour': return date.getHours(); - case 'minute': return date.getMinutes(); - case 'second': return date.getSeconds(); + case 'year': return date.getFullYear(); + case 'month': return date.getMonth() + 1; // getMonth is zero-based + case 'date': return date.getDate(); + case 'dayofweek': return date.getDay() + 1; // getDay is zero-based, Sun=0 + case 'hour': return date.getHours(); + case 'minute': return date.getMinutes(); + case 'second': return date.getSeconds(); } return 0; } - getKeyPressed (args, util) { + getKeyPressed(args, util) { return util.ioQuery('keyboard', 'getKeyIsDown', [args.KEY_OPTION]); } - daysSince2000 () { + daysSince2000() { const msPerDay = 24 * 60 * 60 * 1000; const start = new Date(2000, 0, 1); // Months are 0-indexed. const today = new Date(); @@ -259,7 +259,7 @@ class Scratch3SensingBlocks { return mSecsSinceStart / msPerDay; } - getLoudness () { + getLoudness() { if (typeof this.runtime.audioEngine === 'undefined') return -1; if (this.runtime.currentStepTime === null) return -1; @@ -274,11 +274,11 @@ class Scratch3SensingBlocks { return this._cachedLoudness; } - isLoud () { + isLoud() { return this.getLoudness() > 10; } - getAttributeOf (args) { + getAttributeOf(args) { let attrTarget; if (args.OBJECT === '_stage_') { @@ -296,24 +296,24 @@ class Scratch3SensingBlocks { // Generic attributes if (attrTarget.isStage) { switch (args.PROPERTY) { - // Scratch 1.4 support - case 'background #': return attrTarget.currentCostume + 1; + // Scratch 1.4 support + case 'background #': return attrTarget.currentCostume + 1; - case 'backdrop #': return attrTarget.currentCostume + 1; - case 'backdrop name': - return attrTarget.getCostumes()[attrTarget.currentCostume].name; - case 'volume': return attrTarget.volume; + case 'backdrop #': return attrTarget.currentCostume + 1; + case 'backdrop name': + return attrTarget.getCostumes()[attrTarget.currentCostume].name; + case 'volume': return attrTarget.volume; } } else { switch (args.PROPERTY) { - case 'x position': return attrTarget.x; - case 'y position': return attrTarget.y; - case 'direction': return attrTarget.direction; - case 'costume #': return attrTarget.currentCostume + 1; - case 'costume name': - return attrTarget.getCostumes()[attrTarget.currentCostume].name; - case 'size': return attrTarget.size; - case 'volume': return attrTarget.volume; + case 'x position': return attrTarget.x; + case 'y position': return attrTarget.y; + case 'direction': return attrTarget.direction; + case 'costume #': return attrTarget.currentCostume + 1; + case 'costume name': + return attrTarget.getCostumes()[attrTarget.currentCostume].name; + case 'size': return attrTarget.size; + case 'volume': return attrTarget.volume; } } @@ -328,7 +328,7 @@ class Scratch3SensingBlocks { return 0; } - getUsername (args, util) { + getUsername(args, util) { return util.ioQuery('userData', 'getUsername'); } } diff --git a/src/blocks/scratch3_sound.js b/src/blocks/scratch3_sound.js index 26df698e600..d753f2d76c3 100644 --- a/src/blocks/scratch3_sound.js +++ b/src/blocks/scratch3_sound.js @@ -9,7 +9,7 @@ const Clone = require('../util/clone'); const STORE_WAITING = true; class Scratch3SoundBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -39,7 +39,7 @@ class Scratch3SoundBlocks { * The key to load & store a target's sound-related state. * @type {string} */ - static get STATE_KEY () { + static get STATE_KEY() { return 'Scratch.sound'; } @@ -47,7 +47,7 @@ class Scratch3SoundBlocks { * The default sound-related state, to be used when a target has no existing sound state. * @type {SoundState} */ - static get DEFAULT_SOUND_STATE () { + static get DEFAULT_SOUND_STATE() { return { effects: { pitch: 0, @@ -60,8 +60,8 @@ class Scratch3SoundBlocks { * The minimum and maximum MIDI note numbers, for clamping the input to play note. * @type {{min: number, max: number}} */ - static get MIDI_NOTE_RANGE () { - return {min: 36, max: 96}; // C2 to C7 + static get MIDI_NOTE_RANGE() { + return { min: 36, max: 96 }; // C2 to C7 } /** @@ -69,24 +69,24 @@ class Scratch3SoundBlocks { * 100 beats at the default tempo of 60bpm is 100 seconds. * @type {{min: number, max: number}} */ - static get BEAT_RANGE () { - return {min: 0, max: 100}; + static get BEAT_RANGE() { + return { min: 0, max: 100 }; } /** The minimum and maximum tempo values, in bpm. * @type {{min: number, max: number}} */ - static get TEMPO_RANGE () { - return {min: 20, max: 500}; + static get TEMPO_RANGE() { + return { min: 20, max: 500 }; } /** The minimum and maximum values for each sound effect. * @type {{effect:{min: number, max: number}}} */ - static get EFFECT_RANGE () { + static get EFFECT_RANGE() { return { - pitch: {min: -360, max: 360}, // -3 to 3 octaves - pan: {min: -100, max: 100} // 100% left to 100% right + pitch: { min: -360, max: 360 }, // -3 to 3 octaves + pan: { min: -100, max: 100 } // 100% left to 100% right }; } @@ -95,7 +95,7 @@ class Scratch3SoundBlocks { * @returns {SoundState} the mutable sound state associated with that target. This will be created if necessary. * @private */ - _getSoundState (target) { + _getSoundState(target) { let soundState = target.getCustomState(Scratch3SoundBlocks.STATE_KEY); if (!soundState) { soundState = Clone.simple(Scratch3SoundBlocks.DEFAULT_SOUND_STATE); @@ -112,7 +112,7 @@ class Scratch3SoundBlocks { * @listens Runtime#event:targetWasCreated * @private */ - _onTargetCreated (newTarget, sourceTarget) { + _onTargetCreated(newTarget, sourceTarget) { if (sourceTarget) { const soundState = sourceTarget.getCustomState(Scratch3SoundBlocks.STATE_KEY); if (soundState && newTarget) { @@ -124,9 +124,9 @@ class Scratch3SoundBlocks { /** * Retrieve the block primitives implemented by this package. - * @return {object.} Mapping of opcode to Function. + * @return {Object.} Mapping of opcode to Function. */ - getPrimitives () { + getPrimitives() { return { sound_play: this.playSound, sound_playuntildone: this.playSoundAndWait, @@ -143,7 +143,7 @@ class Scratch3SoundBlocks { }; } - getMonitored () { + getMonitored() { return { sound_volume: { isSpriteSpecific: true, @@ -152,21 +152,21 @@ class Scratch3SoundBlocks { }; } - playSound (args, util) { + playSound(args, util) { // Don't return the promise, it's the only difference for AndWait this._playSound(args, util); } - playSoundAndWait (args, util) { + playSoundAndWait(args, util) { return this._playSound(args, util, STORE_WAITING); } - _playSound (args, util, storeWaiting) { + _playSound(args, util, storeWaiting) { const index = this._getSoundIndex(args.SOUND_MENU, util); if (index >= 0) { - const {target} = util; - const {sprite} = target; - const {soundId} = sprite.sounds[index]; + const { target } = util; + const { sprite } = target; + const { soundId } = sprite.sounds[index]; if (sprite.soundBank) { if (storeWaiting === STORE_WAITING) { this._addWaitingSound(target.id, soundId); @@ -178,21 +178,21 @@ class Scratch3SoundBlocks { } } - _addWaitingSound (targetId, soundId) { + _addWaitingSound(targetId, soundId) { if (!this.waitingSounds[targetId]) { this.waitingSounds[targetId] = new Set(); } this.waitingSounds[targetId].add(soundId); } - _removeWaitingSound (targetId, soundId) { + _removeWaitingSound(targetId, soundId) { if (!this.waitingSounds[targetId]) { return; } this.waitingSounds[targetId].delete(soundId); } - _getSoundIndex (soundName, util) { + _getSoundIndex(soundName, util) { // if the sprite has no sounds, return -1 const len = util.target.sprite.sounds.length; if (len === 0) { @@ -215,7 +215,7 @@ class Scratch3SoundBlocks { return -1; } - getSoundIndexByName (soundName, util) { + getSoundIndexByName(soundName, util) { const sounds = util.target.sprite.sounds; for (let i = 0; i < sounds.length; i++) { if (sounds[i].name === soundName) { @@ -226,7 +226,7 @@ class Scratch3SoundBlocks { return -1; } - stopAllSounds () { + stopAllSounds() { if (this.runtime.targets === null) return; const allTargets = this.runtime.targets; for (let i = 0; i < allTargets.length; i++) { @@ -234,7 +234,7 @@ class Scratch3SoundBlocks { } } - _stopAllSoundsForTarget (target) { + _stopAllSoundsForTarget(target) { if (target.sprite.soundBank) { target.sprite.soundBank.stopAllSounds(target); if (this.waitingSounds[target.id]) { @@ -243,7 +243,7 @@ class Scratch3SoundBlocks { } } - _stopWaitingSoundsForTarget (target) { + _stopWaitingSoundsForTarget(target) { if (target.sprite.soundBank) { if (this.waitingSounds[target.id]) { for (const soundId of this.waitingSounds[target.id].values()) { @@ -254,15 +254,15 @@ class Scratch3SoundBlocks { } } - setEffect (args, util) { + setEffect(args, util) { return this._updateEffect(args, util, false); } - changeEffect (args, util) { + changeEffect(args, util) { return this._updateEffect(args, util, true); } - _updateEffect (args, util, change) { + _updateEffect(args, util, change) { const effect = Cast.toString(args.EFFECT).toLowerCase(); const value = Cast.toNumber(args.VALUE); @@ -275,7 +275,7 @@ class Scratch3SoundBlocks { soundState.effects[effect] = value; } - const {min, max} = Scratch3SoundBlocks.EFFECT_RANGE[effect]; + const { min, max } = Scratch3SoundBlocks.EFFECT_RANGE[effect]; soundState.effects[effect] = MathUtil.clamp(soundState.effects[effect], min, max); this._syncEffectsForTarget(util.target); @@ -283,18 +283,18 @@ class Scratch3SoundBlocks { return Promise.resolve(); } - _syncEffectsForTarget (target) { + _syncEffectsForTarget(target) { if (!target || !target.sprite.soundBank) return; target.soundEffects = this._getSoundState(target).effects; target.sprite.soundBank.setEffects(target); } - clearEffects (args, util) { + clearEffects(args, util) { this._clearEffectsForTarget(util.target); } - _clearEffectsForTarget (target) { + _clearEffectsForTarget(target) { const soundState = this._getSoundState(target); for (const effect in soundState.effects) { if (!Object.prototype.hasOwnProperty.call(soundState.effects, effect)) continue; @@ -303,7 +303,7 @@ class Scratch3SoundBlocks { this._syncEffectsForTarget(target); } - _clearEffectsForAllTargets () { + _clearEffectsForAllTargets() { if (this.runtime.targets === null) return; const allTargets = this.runtime.targets; for (let i = 0; i < allTargets.length; i++) { @@ -311,17 +311,17 @@ class Scratch3SoundBlocks { } } - setVolume (args, util) { + setVolume(args, util) { const volume = Cast.toNumber(args.VOLUME); return this._updateVolume(volume, util); } - changeVolume (args, util) { + changeVolume(args, util) { const volume = Cast.toNumber(args.VOLUME) + util.target.volume; return this._updateVolume(volume, util); } - _updateVolume (volume, util) { + _updateVolume(volume, util) { volume = MathUtil.clamp(volume, 0, 100); util.target.volume = volume; this._syncEffectsForTarget(util.target); @@ -330,19 +330,19 @@ class Scratch3SoundBlocks { return Promise.resolve(); } - getVolume (args, util) { + getVolume(args, util) { return util.target.volume; } - soundsMenu (args) { + soundsMenu(args) { return args.SOUND_MENU; } - beatsMenu (args) { + beatsMenu(args) { return args.BEATS; } - effectsMenu (args) { + effectsMenu(args) { return args.EFFECT; } } diff --git a/src/dispatch/central-dispatch.js b/src/dispatch/central-dispatch.js index 9d9728a5205..d86aa010708 100644 --- a/src/dispatch/central-dispatch.js +++ b/src/dispatch/central-dispatch.js @@ -10,7 +10,7 @@ const log = require('../util/log'); * @see {WorkerDispatch} */ class CentralDispatch extends SharedDispatch { - constructor () { + constructor() { super(); /** @@ -18,7 +18,7 @@ class CentralDispatch extends SharedDispatch { * If the entry is a Worker, the service is provided by an object on that worker. * Otherwise, the service is provided locally and methods on the service will be called directly. * @see {setService} - * @type {object.} + * @type {Object.} */ this.services = {}; @@ -43,8 +43,8 @@ class CentralDispatch extends SharedDispatch { * @param {*} [args] - the arguments to be copied to the method, if any. * @returns {*} - the return value of the service method. */ - callSync (service, method, ...args) { - const {provider, isRemote} = this._getServiceProvider(service); + callSync(service, method, ...args) { + const { provider, isRemote } = this._getServiceProvider(service); if (provider) { if (isRemote) { throw new Error(`Cannot use 'callSync' on remote provider for service ${service}.`); @@ -63,7 +63,7 @@ class CentralDispatch extends SharedDispatch { * @param {string} service - a globally unique string identifying this service. Examples: 'vm', 'gui', 'extension9'. * @param {object} provider - a local object which provides this service. */ - setServiceSync (service, provider) { + setServiceSync(service, provider) { if (Object.prototype.hasOwnProperty.call(this.services, service)) { log.warn(`Central dispatch replacing existing service provider for ${service}`); } @@ -77,7 +77,7 @@ class CentralDispatch extends SharedDispatch { * @param {object} provider - a local object which provides this service. * @returns {Promise} - a promise which will resolve once the service is registered. */ - setService (service, provider) { + setService(service, provider) { /** Return a promise for consistency with {@link WorkerDispatch#setService} */ try { this.setServiceSync(service, provider); @@ -92,7 +92,7 @@ class CentralDispatch extends SharedDispatch { * The dispatcher will immediately attempt to "handshake" with the worker. * @param {Worker} worker - the worker to add into the dispatch system. */ - addWorker (worker) { + addWorker(worker) { if (this.workers.indexOf(worker) === -1) { this.workers.push(worker); worker.onmessage = this._onMessage.bind(this, worker); @@ -111,7 +111,7 @@ class CentralDispatch extends SharedDispatch { * @returns {{provider:(object|Worker), isRemote:boolean}} - the means to contact the service, if found * @protected */ - _getServiceProvider (service) { + _getServiceProvider(service) { const provider = this.services[service]; return provider && { provider, @@ -127,14 +127,14 @@ class CentralDispatch extends SharedDispatch { * @returns {Promise|undefined} - a promise for the results of this operation, if appropriate * @protected */ - _onDispatchMessage (worker, message) { + _onDispatchMessage(worker, message) { let promise; switch (message.method) { - case 'setService': - promise = this.setService(message.args[0], worker); - break; - default: - log.error(`Central dispatch received message for unknown method: ${message.method}`); + case 'setService': + promise = this.setService(message.args[0], worker); + break; + default: + log.error(`Central dispatch received message for unknown method: ${message.method}`); } return promise; } diff --git a/src/engine/block-utility.js b/src/engine/block-utility.js index 52384c5eca2..6e1e16b2d83 100644 --- a/src/engine/block-utility.js +++ b/src/engine/block-utility.js @@ -8,17 +8,17 @@ const Timer = require('../util/timer'); */ class BlockUtility { - constructor (sequencer = null, thread = null) { + constructor(sequencer = null, thread = null) { /** * A sequencer block primitives use to branch or start procedures with - * @type {?Sequencer} + * @type {?import("./sequencer")} */ this.sequencer = sequencer; /** * The block primitives thread with the block's target, stackFrame and * modifiable status. - * @type {?Thread} + * @type {?import("./thread")} */ this.thread = thread; @@ -29,17 +29,17 @@ class BlockUtility { /** * The target the primitive is working on. - * @type {Target} + * @type {import("./target")} */ - get target () { + get target() { return this.thread.target; } /** * The runtime the block primitive is running in. - * @type {Runtime} + * @type {import("./runtime")} */ - get runtime () { + get runtime() { return this.sequencer.runtime; } @@ -48,7 +48,7 @@ class BlockUtility { * This is useful in some cases where we need compatibility with Scratch 2 * @type {function} */ - get nowObj () { + get nowObj() { if (this.runtime) { return this._nowObj; } @@ -57,9 +57,9 @@ class BlockUtility { /** * The stack frame used by loop and other blocks to track internal state. - * @type {object} + * @type {import("./stackFrame")} */ - get stackFrame () { + get stackFrame() { const frame = this.thread.peekStackFrame(); if (frame.executionContext === null) { frame.executionContext = {}; @@ -71,7 +71,7 @@ class BlockUtility { * Check the stack timer and return a boolean based on whether it has finished or not. * @return {boolean} - true if the stack timer has finished. */ - stackTimerFinished () { + stackTimerFinished() { const timeElapsed = this.stackFrame.timer.timeElapsed(); if (timeElapsed < this.stackFrame.duration) { return false; @@ -83,7 +83,7 @@ class BlockUtility { * Check if the stack timer needs initialization. * @return {boolean} - true if the stack timer needs to be initialized. */ - stackTimerNeedsInit () { + stackTimerNeedsInit() { return !this.stackFrame.timer; } @@ -91,7 +91,7 @@ class BlockUtility { * Create and start a stack timer * @param {number} duration - a duration in milliseconds to set the timer for. */ - startStackTimer (duration) { + startStackTimer(duration) { if (this.nowObj) { this.stackFrame.timer = new Timer(this.nowObj); } else { @@ -104,14 +104,14 @@ class BlockUtility { /** * Set the thread to yield. */ - yield () { + yield() { this.thread.status = Thread.STATUS_YIELD; } /** * Set the thread to yield until the next tick of the runtime. */ - yieldTick () { + yieldTick() { this.thread.status = Thread.STATUS_YIELD_TICK; } @@ -120,14 +120,14 @@ class BlockUtility { * @param {number} branchNum Which branch to step to (i.e., 1, 2). * @param {boolean} isLoop Whether this block is a loop. */ - startBranch (branchNum, isLoop) { + startBranch(branchNum, isLoop) { this.sequencer.stepToBranch(this.thread, branchNum, isLoop); } /** * Stop all threads. */ - stopAll () { + stopAll() { this.sequencer.runtime.stopAll(); } @@ -135,14 +135,14 @@ class BlockUtility { * Stop threads other on this target other than the thread holding the * executed block. */ - stopOtherTargetThreads () { + stopOtherTargetThreads() { this.sequencer.runtime.stopForTarget(this.thread.target, this.thread); } /** * Stop this thread. */ - stopThisScript () { + stopThisScript() { this.thread.stopThisScript(); } @@ -150,7 +150,7 @@ class BlockUtility { * Start a specified procedure on this thread. * @param {string} procedureCode Procedure code for procedure to start. */ - startProcedure (procedureCode) { + startProcedure(procedureCode) { this.sequencer.stepToProcedure(this.thread, procedureCode); } @@ -159,7 +159,7 @@ class BlockUtility { * @param {string} procedureCode Procedure code for procedure to query. * @return {Array.} List of param names for a procedure. */ - getProcedureParamNamesAndIds (procedureCode) { + getProcedureParamNamesAndIds(procedureCode) { return this.thread.target.blocks.getProcedureParamNamesAndIds(procedureCode); } @@ -168,14 +168,14 @@ class BlockUtility { * @param {string} procedureCode Procedure code for procedure to query. * @return {Array.} List of param names for a procedure. */ - getProcedureParamNamesIdsAndDefaults (procedureCode) { + getProcedureParamNamesIdsAndDefaults(procedureCode) { return this.thread.target.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode); } /** * Initialize procedure parameters in the thread before pushing parameters. */ - initParams () { + initParams() { this.thread.initParams(); } @@ -184,7 +184,7 @@ class BlockUtility { * @param {string} paramName The procedure's parameter name. * @param {*} paramValue The procedure's parameter value. */ - pushParam (paramName, paramValue) { + pushParam(paramName, paramValue) { this.thread.pushParam(paramName, paramValue); } @@ -193,7 +193,7 @@ class BlockUtility { * @param {string} paramName The procedure's parameter name. * @return {*} The parameter's current stored value. */ - getParam (paramName) { + getParam(paramName) { return this.thread.getParam(paramName); } @@ -201,10 +201,10 @@ class BlockUtility { * Start all relevant hats. * @param {!string} requestedHat Opcode of hats to start. * @param {object=} optMatchFields Optionally, fields to match on the hat. - * @param {Target=} optTarget Optionally, a target to restrict to. - * @return {Array.} List of threads started by this function. + * @param {import("./target")=} optTarget Optionally, a target to restrict to. + * @return {Array.} List of threads started by this function. */ - startHats (requestedHat, optMatchFields, optTarget) { + startHats(requestedHat, optMatchFields, optTarget) { // Store thread and sequencer to ensure we can return to the calling block's context. // startHats may execute further blocks and dirty the BlockUtility's execution context // and confuse the calling block when we return to it. @@ -226,13 +226,13 @@ class BlockUtility { * @param {Array.<*>} args Arguments to pass to the device's function. * @return {*} The expected output for the device's function. */ - ioQuery (device, func, args) { + ioQuery(device, func, args) { // Find the I/O device and execute the query/function call. if ( this.sequencer.runtime.ioDevices[device] && this.sequencer.runtime.ioDevices[device][func]) { const devObject = this.sequencer.runtime.ioDevices[device]; - // TODO: verify correct `this` after switching from apply to spread + // TODO: verify correct `this` after switching from apply to spread // eslint-disable-next-line prefer-spread return devObject[func].apply(devObject, args); } diff --git a/src/engine/blocks-execute-cache.js b/src/engine/blocks-execute-cache.js index ffa8708b2aa..63167d28c3e 100644 --- a/src/engine/blocks-execute-cache.js +++ b/src/engine/blocks-execute-cache.js @@ -8,7 +8,7 @@ * A private method shared with execute to build an object containing the block * information execute needs and that is reset when other cached Blocks info is * reset. - * @param {Blocks} blocks Blocks containing the expected blockId + * @param {import("./blocks")} blocks Blocks containing the expected blockId * @param {string} blockId blockId for the desired execute cache */ exports.getCached = function () { diff --git a/src/engine/blocks-runtime-cache.js b/src/engine/blocks-runtime-cache.js index 3a3241e9730..9c6fa73d864 100644 --- a/src/engine/blocks-runtime-cache.js +++ b/src/engine/blocks-runtime-cache.js @@ -9,14 +9,14 @@ /** * A set of cached data about the top block of a script. - * @param {Blocks} container - Container holding the block and related data + * @param {import("./blocks")} container - Container holding the block and related data * @param {string} blockId - Id for whose block data is cached in this instance */ class RuntimeScriptCache { - constructor (container, blockId) { + constructor(container, blockId) { /** * Container with block data for blockId. - * @type {Blocks} + * @type {import("./blocks")} */ this.container = container; diff --git a/src/engine/blocks.js b/src/engine/blocks.js index cf1b2b7c4fd..3e3a50a1a47 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -3,7 +3,7 @@ const mutationAdapter = require('./mutation-adapter'); const xmlEscape = require('../util/xml-escape'); const MonitorRecord = require('./monitor-record'); const Clone = require('../util/clone'); -const {Map} = require('immutable'); +const { Map } = require('immutable'); const BlocksExecuteCache = require('./blocks-execute-cache'); const BlocksRuntimeCache = require('./blocks-runtime-cache'); const log = require('../util/log'); @@ -23,7 +23,7 @@ const getMonitorIdForBlockWithArgs = require('../util/get-monitor-id'); * should not request glows. This does not affect glows when clicking on a block to execute it. */ class Blocks { - constructor (runtime, optNoGlow) { + constructor(runtime, optNoGlow) { this.runtime = runtime; /** @@ -45,28 +45,28 @@ class Blocks { * @type {{inputs: {}, procedureParamNames: {}, procedureDefinitions: {}}} * @private */ - Object.defineProperty(this, '_cache', {writable: true, enumerable: false}); + Object.defineProperty(this, '_cache', { writable: true, enumerable: false }); this._cache = { /** * Cache block inputs by block id - * @type {object.>} + * @type {Object.>} */ inputs: {}, /** * Cache procedure Param Names by block id - * @type {object.>} + * @type {Object.>} */ procedureParamNames: {}, /** * Cache procedure definitions by block id - * @type {object.} + * @type {Object.} */ procedureDefinitions: {}, /** * A cache for execute to use and store on. Only available to * execute. - * @type {object.} + * @type {Object.} */ _executeCached: {}, @@ -79,7 +79,7 @@ class Blocks { /** * A cache of hat opcodes to collection of theads to execute. - * @type {object.} + * @type {Object.} */ scripts: {} }; @@ -101,7 +101,7 @@ class Blocks { * are prefixed with this string. * @const{string} */ - static get BRANCH_INPUT_PREFIX () { + static get BRANCH_INPUT_PREFIX() { return 'SUBSTACK'; } @@ -110,7 +110,7 @@ class Blocks { * @param {!string} blockId ID of block we have stored. * @return {?object} Metadata about the block, if it exists. */ - getBlock (blockId) { + getBlock(blockId) { return this._blocks[blockId]; } @@ -118,7 +118,7 @@ class Blocks { * Get all known top-level blocks that start scripts. * @return {Array.} List of block IDs. */ - getScripts () { + getScripts() { return this._scripts; } @@ -127,7 +127,7 @@ class Blocks { * @param {?string} id ID of block to get the next block for * @return {?string} ID of next block in the sequence */ - getNextBlock (id) { + getNextBlock(id) { const block = this._blocks[id]; return (typeof block === 'undefined') ? null : block.next; } @@ -138,7 +138,7 @@ class Blocks { * @param {?number} branchNum Which branch to select (e.g. for if-else). * @return {?string} ID of block in the branch. */ - getBranch (id, branchNum) { + getBranch(id, branchNum) { const block = this._blocks[id]; if (typeof block === 'undefined') return null; if (!branchNum) branchNum = 1; @@ -158,7 +158,7 @@ class Blocks { * @param {?object} block The block to query * @return {?string} the opcode corresponding to that block */ - getOpcode (block) { + getOpcode(block) { return (typeof block === 'undefined') ? null : block.opcode; } @@ -167,7 +167,7 @@ class Blocks { * @param {?object} block The block to query. * @return {?object} All fields and their values. */ - getFields (block) { + getFields(block) { return (typeof block === 'undefined') ? null : block.fields; } @@ -176,7 +176,7 @@ class Blocks { * @param {?object} block the block to query. * @return {?Array.} All non-branch inputs and their associated blocks. */ - getInputs (block) { + getInputs(block) { if (typeof block === 'undefined') return null; let inputs = this._cache.inputs[block.id]; if (typeof inputs !== 'undefined') { @@ -201,7 +201,7 @@ class Blocks { * @param {?object} block The block to query. * @return {?object} Mutation for the block. */ - getMutation (block) { + getMutation(block) { return (typeof block === 'undefined') ? null : block.mutation; } @@ -210,7 +210,7 @@ class Blocks { * @param {?string} id ID of block to query. * @return {?string} ID of top-level script block. */ - getTopLevelScript (id) { + getTopLevelScript(id) { let block = this._blocks[id]; if (typeof block === 'undefined') return null; while (block.parent !== null) { @@ -224,7 +224,7 @@ class Blocks { * @param {?string} name Name of procedure to query. * @return {?string} ID of procedure definition. */ - getProcedureDefinition (name) { + getProcedureDefinition(name) { const blockID = this._cache.procedureDefinitions[name]; if (typeof blockID !== 'undefined') { return blockID; @@ -251,7 +251,7 @@ class Blocks { * @param {?string} name Name of procedure to query. * @return {?Array.} List of param names for a procedure. */ - getProcedureParamNamesAndIds (name) { + getProcedureParamNamesAndIds(name) { return this.getProcedureParamNamesIdsAndDefaults(name).slice(0, 2); } @@ -260,7 +260,7 @@ class Blocks { * @param {?string} name Name of procedure to query. * @return {?Array.} List of param names for a procedure. */ - getProcedureParamNamesIdsAndDefaults (name) { + getProcedureParamNamesIdsAndDefaults(name) { const cachedNames = this._cache.procedureParamNames[name]; if (typeof cachedNames !== 'undefined') { return cachedNames; @@ -284,7 +284,7 @@ class Blocks { return null; } - duplicate () { + duplicate() { const newBlocks = new Blocks(this.runtime, this.forceNoGlow); newBlocks._blocks = Clone.simple(this._blocks); newBlocks._scripts = Clone.simple(this._scripts); @@ -298,7 +298,7 @@ class Blocks { * runtime interface. * @param {object} e Blockly "block" or "variable" event */ - blocklyListen (e) { + blocklyListen(e) { // Validate event if (typeof e !== 'object') return; if (typeof e.blockId !== 'string' && typeof e.varId !== 'string' && @@ -310,199 +310,199 @@ class Blocks { // UI event: clicked scripts toggle in the runtime. if (e.element === 'stackclick') { - this.runtime.toggleScript(e.blockId, {stackClick: true}); + this.runtime.toggleScript(e.blockId, { stackClick: true }); return; } // Block create/update/destroy switch (e.type) { - case 'create': { - const newBlocks = adapter(e); - // A create event can create many blocks. Add them all. - for (let i = 0; i < newBlocks.length; i++) { - this.createBlock(newBlocks[i]); - } - break; - } - case 'change': - this.changeBlock({ - id: e.blockId, - element: e.element, - name: e.name, - value: e.newValue - }); - break; - case 'move': - this.moveBlock({ - id: e.blockId, - oldParent: e.oldParentId, - oldInput: e.oldInputName, - newParent: e.newParentId, - newInput: e.newInputName, - newCoordinate: e.newCoordinate - }); - break; - case 'dragOutside': - this.runtime.emitBlockDragUpdate(e.isOutside); - break; - case 'endDrag': - this.runtime.emitBlockDragUpdate(false /* areBlocksOverGui */); - - // Drag blocks onto another sprite - if (e.isOutside) { + case 'create': { const newBlocks = adapter(e); - this.runtime.emitBlockEndDrag(newBlocks, e.blockId); - } - break; - case 'delete': - // Don't accept delete events for missing blocks, - // or shadow blocks being obscured. - if (!Object.prototype.hasOwnProperty.call(this._blocks, e.blockId) || - this._blocks[e.blockId].shadow) { - return; - } - // Inform any runtime to forget about glows on this script. - if (this._blocks[e.blockId].topLevel) { - this.runtime.quietGlow(e.blockId); - } - this.deleteBlock(e.blockId); - break; - case 'var_create': - // Check if the variable being created is global or local - // If local, create a local var on the current editing target, as long - // as there are no conflicts, and the current target is actually a sprite - // If global or if the editing target is not present or we somehow got - // into a state where a local var was requested for the stage, - // create a stage (global) var after checking for name conflicts - // on all the sprites. - if (e.isLocal && editingTarget && !editingTarget.isStage && !e.isCloud) { - if (!editingTarget.lookupVariableById(e.varId)) { - editingTarget.createVariable(e.varId, e.varName, e.varType); - this.emitProjectChanged(); - } - } else { - if (stage.lookupVariableById(e.varId)) { - // Do not re-create a variable if it already exists - return; - } - // Check for name conflicts in all of the targets - const allTargets = this.runtime.targets.filter(t => t.isOriginal); - for (const target of allTargets) { - if (target.lookupVariableByNameAndType(e.varName, e.varType, true)) { - return; - } - } - stage.createVariable(e.varId, e.varName, e.varType, e.isCloud); - this.emitProjectChanged(); - } - break; - case 'var_rename': - if (editingTarget && Object.prototype.hasOwnProperty.call(editingTarget.variables, e.varId)) { - // This is a local variable, rename on the current target - editingTarget.renameVariable(e.varId, e.newName); - // Update all the blocks on the current target that use - // this variable - editingTarget.blocks.updateBlocksAfterVarRename(e.varId, e.newName); - } else { - // This is a global variable - stage.renameVariable(e.varId, e.newName); - // Update all blocks on all targets that use the renamed variable - const targets = this.runtime.targets; - for (let i = 0; i < targets.length; i++) { - const currTarget = targets[i]; - currTarget.blocks.updateBlocksAfterVarRename(e.varId, e.newName); + // A create event can create many blocks. Add them all. + for (let i = 0; i < newBlocks.length; i++) { + this.createBlock(newBlocks[i]); } + break; } - this.emitProjectChanged(); - break; - case 'var_delete': { - const target = (editingTarget && Object.prototype.hasOwnProperty.call(editingTarget.variables, e.varId)) ? - editingTarget : stage; - target.deleteVariable(e.varId); - this.emitProjectChanged(); - break; - } - case 'comment_create': - if (this.runtime.getEditingTarget()) { - const currTarget = this.runtime.getEditingTarget(); - currTarget.createComment(e.commentId, e.blockId, e.text, - e.xy.x, e.xy.y, e.width, e.height, e.minimized); - - if (currTarget.comments[e.commentId].x === null && - currTarget.comments[e.commentId].y === null) { - // Block comments imported from 2.0 projects are imported with their - // x and y coordinates set to null so that scratch-blocks can - // auto-position them. If we are receiving a create event for these - // comments, then the auto positioning should have taken place. - // Update the x and y position of these comments to match the - // one from the event. - currTarget.comments[e.commentId].x = e.xy.x; - currTarget.comments[e.commentId].y = e.xy.y; + case 'change': + this.changeBlock({ + id: e.blockId, + element: e.element, + name: e.name, + value: e.newValue + }); + break; + case 'move': + this.moveBlock({ + id: e.blockId, + oldParent: e.oldParentId, + oldInput: e.oldInputName, + newParent: e.newParentId, + newInput: e.newInputName, + newCoordinate: e.newCoordinate + }); + break; + case 'dragOutside': + this.runtime.emitBlockDragUpdate(e.isOutside); + break; + case 'endDrag': + this.runtime.emitBlockDragUpdate(false /* areBlocksOverGui */); + + // Drag blocks onto another sprite + if (e.isOutside) { + const newBlocks = adapter(e); + this.runtime.emitBlockEndDrag(newBlocks, e.blockId); } - } - this.emitProjectChanged(); - break; - case 'comment_change': - if (this.runtime.getEditingTarget()) { - const currTarget = this.runtime.getEditingTarget(); - if (!Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { - log.warn(`Cannot change comment with id ${e.commentId} because it does not exist.`); + break; + case 'delete': + // Don't accept delete events for missing blocks, + // or shadow blocks being obscured. + if (!Object.prototype.hasOwnProperty.call(this._blocks, e.blockId) || + this._blocks[e.blockId].shadow) { return; } - const comment = currTarget.comments[e.commentId]; - const change = e.newContents_; - if (Object.prototype.hasOwnProperty.call(change, 'minimized')) { - comment.minimized = change.minimized; + // Inform any runtime to forget about glows on this script. + if (this._blocks[e.blockId].topLevel) { + this.runtime.quietGlow(e.blockId); } - if (Object.prototype.hasOwnProperty.call(change, 'width') && - Object.prototype.hasOwnProperty.call(change, 'height')) { - comment.width = change.width; - comment.height = change.height; + this.deleteBlock(e.blockId); + break; + case 'var_create': + // Check if the variable being created is global or local + // If local, create a local var on the current editing target, as long + // as there are no conflicts, and the current target is actually a sprite + // If global or if the editing target is not present or we somehow got + // into a state where a local var was requested for the stage, + // create a stage (global) var after checking for name conflicts + // on all the sprites. + if (e.isLocal && editingTarget && !editingTarget.isStage && !e.isCloud) { + if (!editingTarget.lookupVariableById(e.varId)) { + editingTarget.createVariable(e.varId, e.varName, e.varType); + this.emitProjectChanged(); + } + } else { + if (stage.lookupVariableById(e.varId)) { + // Do not re-create a variable if it already exists + return; + } + // Check for name conflicts in all of the targets + const allTargets = this.runtime.targets.filter(t => t.isOriginal); + for (const target of allTargets) { + if (target.lookupVariableByNameAndType(e.varName, e.varType, true)) { + return; + } + } + stage.createVariable(e.varId, e.varName, e.varType, e.isCloud); + this.emitProjectChanged(); } - if (Object.prototype.hasOwnProperty.call(change, 'text')) { - comment.text = change.text; + break; + case 'var_rename': + if (editingTarget && Object.prototype.hasOwnProperty.call(editingTarget.variables, e.varId)) { + // This is a local variable, rename on the current target + editingTarget.renameVariable(e.varId, e.newName); + // Update all the blocks on the current target that use + // this variable + editingTarget.blocks.updateBlocksAfterVarRename(e.varId, e.newName); + } else { + // This is a global variable + stage.renameVariable(e.varId, e.newName); + // Update all blocks on all targets that use the renamed variable + const targets = this.runtime.targets; + for (let i = 0; i < targets.length; i++) { + const currTarget = targets[i]; + currTarget.blocks.updateBlocksAfterVarRename(e.varId, e.newName); + } } this.emitProjectChanged(); + break; + case 'var_delete': { + const target = (editingTarget && Object.prototype.hasOwnProperty.call(editingTarget.variables, e.varId)) ? + editingTarget : stage; + target.deleteVariable(e.varId); + this.emitProjectChanged(); + break; } - break; - case 'comment_move': - if (this.runtime.getEditingTarget()) { - const currTarget = this.runtime.getEditingTarget(); - if (currTarget && !Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { - log.warn(`Cannot change comment with id ${e.commentId} because it does not exist.`); - return; + case 'comment_create': + if (this.runtime.getEditingTarget()) { + const currTarget = this.runtime.getEditingTarget(); + currTarget.createComment(e.commentId, e.blockId, e.text, + e.xy.x, e.xy.y, e.width, e.height, e.minimized); + + if (currTarget.comments[e.commentId].x === null && + currTarget.comments[e.commentId].y === null) { + // Block comments imported from 2.0 projects are imported with their + // x and y coordinates set to null so that scratch-blocks can + // auto-position them. If we are receiving a create event for these + // comments, then the auto positioning should have taken place. + // Update the x and y position of these comments to match the + // one from the event. + currTarget.comments[e.commentId].x = e.xy.x; + currTarget.comments[e.commentId].y = e.xy.y; + } } - const comment = currTarget.comments[e.commentId]; - const newCoord = e.newCoordinate_; - comment.x = newCoord.x; - comment.y = newCoord.y; - this.emitProjectChanged(); - } - break; - case 'comment_delete': - if (this.runtime.getEditingTarget()) { - const currTarget = this.runtime.getEditingTarget(); - if (!Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { - // If we're in this state, we have probably received - // a delete event from a workspace that we switched from - // (e.g. a delete event for a comment on sprite a's workspace - // when switching from sprite a to sprite b) - return; + break; + case 'comment_change': + if (this.runtime.getEditingTarget()) { + const currTarget = this.runtime.getEditingTarget(); + if (!Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { + log.warn(`Cannot change comment with id ${e.commentId} because it does not exist.`); + return; + } + const comment = currTarget.comments[e.commentId]; + const change = e.newContents_; + if (Object.prototype.hasOwnProperty.call(change, 'minimized')) { + comment.minimized = change.minimized; + } + if (Object.prototype.hasOwnProperty.call(change, 'width') && + Object.prototype.hasOwnProperty.call(change, 'height')) { + comment.width = change.width; + comment.height = change.height; + } + if (Object.prototype.hasOwnProperty.call(change, 'text')) { + comment.text = change.text; + } + this.emitProjectChanged(); } - delete currTarget.comments[e.commentId]; - if (e.blockId) { - const block = currTarget.blocks.getBlock(e.blockId); - if (!block) { - log.warn(`Could not find block referenced by comment with id: ${e.commentId}`); + break; + case 'comment_move': + if (this.runtime.getEditingTarget()) { + const currTarget = this.runtime.getEditingTarget(); + if (currTarget && !Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { + log.warn(`Cannot change comment with id ${e.commentId} because it does not exist.`); return; } - delete block.comment; + const comment = currTarget.comments[e.commentId]; + const newCoord = e.newCoordinate_; + comment.x = newCoord.x; + comment.y = newCoord.y; + + this.emitProjectChanged(); } + break; + case 'comment_delete': + if (this.runtime.getEditingTarget()) { + const currTarget = this.runtime.getEditingTarget(); + if (!Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { + // If we're in this state, we have probably received + // a delete event from a workspace that we switched from + // (e.g. a delete event for a comment on sprite a's workspace + // when switching from sprite a to sprite b) + return; + } + delete currTarget.comments[e.commentId]; + if (e.blockId) { + const block = currTarget.blocks.getBlock(e.blockId); + if (!block) { + log.warn(`Could not find block referenced by comment with id: ${e.commentId}`); + return; + } + delete block.comment; + } - this.emitProjectChanged(); - } - break; + this.emitProjectChanged(); + } + break; } } @@ -511,7 +511,7 @@ class Blocks { /** * Reset all runtime caches. */ - resetCache () { + resetCache() { this._cache.inputs = {}; this._cache.procedureParamNames = {}; this._cache.procedureDefinitions = {}; @@ -524,7 +524,7 @@ class Blocks { * Emit a project changed event if this is a block container * that can affect the project state. */ - emitProjectChanged () { + emitProjectChanged() { if (!this.forceNoGlow) { this.runtime.emitProjectChanged(); } @@ -534,7 +534,7 @@ class Blocks { * Block management: create blocks and scripts from a `create` event * @param {!object} block Blockly create event to be processed */ - createBlock (block) { + createBlock(block) { // Does the block already exist? // Could happen, e.g., for an unobscured shadow. if (Object.prototype.hasOwnProperty.call(this._blocks, block.id)) { @@ -560,127 +560,127 @@ class Blocks { * Block management: change block field values * @param {!object} args Blockly change event to be processed */ - changeBlock (args) { + changeBlock(args) { // Validate if (['field', 'mutation', 'checkbox'].indexOf(args.element) === -1) return; let block = this._blocks[args.id]; if (typeof block === 'undefined') return; switch (args.element) { - case 'field': - // TODO when the field of a monitored block changes, - // update the checkbox in the flyout based on whether - // a monitor for that current combination of selected parameters exists - // e.g. - // 1. check (current [v year]) - // 2. switch dropdown in flyout block to (current [v minute]) - // 3. the checkbox should become unchecked if we're not already - // monitoring current minute - - - // Update block value - if (!block.fields[args.name]) return; - if (args.name === 'VARIABLE' || args.name === 'LIST' || - args.name === 'BROADCAST_OPTION') { - // Get variable name using the id in args.value. - const variable = this.runtime.getEditingTarget().lookupVariableById(args.value); - if (variable) { - block.fields[args.name].value = variable.name; - block.fields[args.name].id = args.value; - } - } else { - // Changing the value in a dropdown - block.fields[args.name].value = args.value; - - // The selected item in the sensing of block menu needs to change based on the - // selected target. Set it to the first item in the menu list. - // TODO: (#1787) - if (block.opcode === 'sensing_of_object_menu') { - if (block.fields.OBJECT.value === '_stage_') { - this._blocks[block.parent].fields.PROPERTY.value = 'backdrop #'; - } else { - this._blocks[block.parent].fields.PROPERTY.value = 'x position'; + case 'field': + // TODO when the field of a monitored block changes, + // update the checkbox in the flyout based on whether + // a monitor for that current combination of selected parameters exists + // e.g. + // 1. check (current [v year]) + // 2. switch dropdown in flyout block to (current [v minute]) + // 3. the checkbox should become unchecked if we're not already + // monitoring current minute + + + // Update block value + if (!block.fields[args.name]) return; + if (args.name === 'VARIABLE' || args.name === 'LIST' || + args.name === 'BROADCAST_OPTION') { + // Get variable name using the id in args.value. + const variable = this.runtime.getEditingTarget().lookupVariableById(args.value); + if (variable) { + block.fields[args.name].value = variable.name; + block.fields[args.name].id = args.value; + } + } else { + // Changing the value in a dropdown + block.fields[args.name].value = args.value; + + // The selected item in the sensing of block menu needs to change based on the + // selected target. Set it to the first item in the menu list. + // TODO: (#1787) + if (block.opcode === 'sensing_of_object_menu') { + if (block.fields.OBJECT.value === '_stage_') { + this._blocks[block.parent].fields.PROPERTY.value = 'backdrop #'; + } else { + this._blocks[block.parent].fields.PROPERTY.value = 'x position'; + } + this.runtime.requestBlocksUpdate(); } - this.runtime.requestBlocksUpdate(); - } - const flyoutBlock = block.shadow && block.parent ? this._blocks[block.parent] : block; - if (flyoutBlock.isMonitored) { - this.runtime.requestUpdateMonitor(Map({ - id: flyoutBlock.id, - params: this._getBlockParams(flyoutBlock) - })); - } - } - break; - case 'mutation': - block.mutation = mutationAdapter(args.value); - break; - case 'checkbox': { - // A checkbox usually has a one to one correspondence with the monitor - // block but in the case of monitored reporters that have arguments, - // map the old id to a new id, creating a new monitor block if necessary - if (block.fields && Object.keys(block.fields).length > 0 && - block.opcode !== 'data_variable' && block.opcode !== 'data_listcontents') { - - // This block has an argument which needs to get separated out into - // multiple monitor blocks with ids based on the selected argument - const newId = getMonitorIdForBlockWithArgs(block.id, block.fields); - // Note: we're not just constantly creating a longer and longer id everytime we check - // the checkbox because we're using the id of the block in the flyout as the base - - // check if a block with the new id already exists, otherwise create - let newBlock = this.runtime.monitorBlocks.getBlock(newId); - if (!newBlock) { - newBlock = JSON.parse(JSON.stringify(block)); - newBlock.id = newId; - this.runtime.monitorBlocks.createBlock(newBlock); + const flyoutBlock = block.shadow && block.parent ? this._blocks[block.parent] : block; + if (flyoutBlock.isMonitored) { + this.runtime.requestUpdateMonitor(Map({ + id: flyoutBlock.id, + params: this._getBlockParams(flyoutBlock) + })); + } } + break; + case 'mutation': + block.mutation = mutationAdapter(args.value); + break; + case 'checkbox': { + // A checkbox usually has a one to one correspondence with the monitor + // block but in the case of monitored reporters that have arguments, + // map the old id to a new id, creating a new monitor block if necessary + if (block.fields && Object.keys(block.fields).length > 0 && + block.opcode !== 'data_variable' && block.opcode !== 'data_listcontents') { + + // This block has an argument which needs to get separated out into + // multiple monitor blocks with ids based on the selected argument + const newId = getMonitorIdForBlockWithArgs(block.id, block.fields); + // Note: we're not just constantly creating a longer and longer id everytime we check + // the checkbox because we're using the id of the block in the flyout as the base + + // check if a block with the new id already exists, otherwise create + let newBlock = this.runtime.monitorBlocks.getBlock(newId); + if (!newBlock) { + newBlock = JSON.parse(JSON.stringify(block)); + newBlock.id = newId; + this.runtime.monitorBlocks.createBlock(newBlock); + } - block = newBlock; // Carry on through the rest of this code with newBlock - } + block = newBlock; // Carry on through the rest of this code with newBlock + } - const wasMonitored = block.isMonitored; - block.isMonitored = args.value; + const wasMonitored = block.isMonitored; + block.isMonitored = args.value; - // Variable blocks may be sprite specific depending on the owner of the variable - let isSpriteLocalVariable = false; - if (block.opcode === 'data_variable') { - isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.VARIABLE.id]); - } else if (block.opcode === 'data_listcontents') { - isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.LIST.id]); - } + // Variable blocks may be sprite specific depending on the owner of the variable + let isSpriteLocalVariable = false; + if (block.opcode === 'data_variable') { + isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.VARIABLE.id]); + } else if (block.opcode === 'data_listcontents') { + isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.LIST.id]); + } - const isSpriteSpecific = isSpriteLocalVariable || - (Object.prototype.hasOwnProperty.call(this.runtime.monitorBlockInfo, block.opcode) && - this.runtime.monitorBlockInfo[block.opcode].isSpriteSpecific); - if (isSpriteSpecific) { - // If creating a new sprite specific monitor, the only possible target is - // the current editing one b/c you cannot dynamically create monitors. - // Also, do not change the targetId if it has already been assigned - block.targetId = block.targetId || this.runtime.getEditingTarget().id; - } else { - block.targetId = null; - } + const isSpriteSpecific = isSpriteLocalVariable || + (Object.prototype.hasOwnProperty.call(this.runtime.monitorBlockInfo, block.opcode) && + this.runtime.monitorBlockInfo[block.opcode].isSpriteSpecific); + if (isSpriteSpecific) { + // If creating a new sprite specific monitor, the only possible target is + // the current editing one b/c you cannot dynamically create monitors. + // Also, do not change the targetId if it has already been assigned + block.targetId = block.targetId || this.runtime.getEditingTarget().id; + } else { + block.targetId = null; + } - if (wasMonitored && !block.isMonitored) { - this.runtime.requestHideMonitor(block.id); - } else if (!wasMonitored && block.isMonitored) { - // Tries to show the monitor for specified block. If it doesn't exist, add the monitor. - if (!this.runtime.requestShowMonitor(block.id)) { - this.runtime.requestAddMonitor(MonitorRecord({ - id: block.id, - targetId: block.targetId, - spriteName: block.targetId ? this.runtime.getTargetById(block.targetId).getName() : null, - opcode: block.opcode, - params: this._getBlockParams(block), - // @todo(vm#565) for numerical values with decimals, some countries use comma - value: '', - mode: block.opcode === 'data_listcontents' ? 'list' : 'default' - })); + if (wasMonitored && !block.isMonitored) { + this.runtime.requestHideMonitor(block.id); + } else if (!wasMonitored && block.isMonitored) { + // Tries to show the monitor for specified block. If it doesn't exist, add the monitor. + if (!this.runtime.requestShowMonitor(block.id)) { + this.runtime.requestAddMonitor(MonitorRecord({ + id: block.id, + targetId: block.targetId, + spriteName: block.targetId ? this.runtime.getTargetById(block.targetId).getName() : null, + opcode: block.opcode, + params: this._getBlockParams(block), + // @todo(vm#565) for numerical values with decimals, some countries use comma + value: '', + mode: block.opcode === 'data_listcontents' ? 'list' : 'default' + })); + } } + break; } - break; - } } this.emitProjectChanged(); @@ -692,7 +692,7 @@ class Blocks { * Block management: move blocks from parent to parent * @param {!object} e Blockly move event to be processed */ - moveBlock (e) { + moveBlock(e) { if (!Object.prototype.hasOwnProperty.call(this._blocks, e.id)) { return; } @@ -769,7 +769,7 @@ class Blocks { * Block management: run all blocks. * @param {!object} runtime Runtime to run all blocks in. */ - runAllMonitored (runtime) { + runAllMonitored(runtime) { if (this._cache._monitored === null) { this._cache._monitored = Object.keys(this._blocks) .filter(blockId => this.getBlock(blockId).isMonitored) @@ -784,7 +784,7 @@ class Blocks { const monitored = this._cache._monitored; for (let i = 0; i < monitored.length; i++) { - const {blockId, target} = monitored[i]; + const { blockId, target } = monitored[i]; runtime.addMonitorScript(blockId, target); } } @@ -794,7 +794,7 @@ class Blocks { * with the given ID does not exist. * @param {!string} blockId Id of block to delete */ - deleteBlock (blockId) { + deleteBlock(blockId) { // @todo In runtime, stop threads running on this script. // Get block @@ -835,7 +835,7 @@ class Blocks { /** * Delete all blocks and their associated scripts. */ - deleteAllBlocks () { + deleteAllBlocks() { const blockIds = Object.keys(this._blocks); blockIds.forEach(blockId => this.deleteBlock(blockId)); } @@ -851,7 +851,7 @@ class Blocks { * for that ID. A variable reference contains the field referencing that variable * and also the type of the variable being referenced. */ - getAllVariableAndListReferences (optBlocks, optIncludeBroadcast) { + getAllVariableAndListReferences(optBlocks, optIncludeBroadcast) { const blocks = optBlocks ? optBlocks : this._blocks; const allReferences = Object.create(null); for (const blockId in blocks) { @@ -890,7 +890,7 @@ class Blocks { * @param {string} varId The id of the variable that was renamed * @param {string} newName The new name of the variable that was renamed */ - updateBlocksAfterVarRename (varId, newName) { + updateBlocksAfterVarRename(varId, newName) { const blocks = this._blocks; for (const blockId in blocks) { let varOrListField = null; @@ -912,7 +912,7 @@ class Blocks { * Keep blocks up to date after they are shared between targets. * @param {boolean} isStage If the new target is a stage. */ - updateTargetSpecificBlocks (isStage) { + updateTargetSpecificBlocks(isStage) { const blocks = this._blocks; for (const blockId in blocks) { if (isStage && blocks[blockId].opcode === 'event_whenthisspriteclicked') { @@ -933,7 +933,7 @@ class Blocks { * that was renamed. This can be one of 'sprite','costume', 'sound', or * 'backdrop'. */ - updateAssetName (oldName, newName, assetType) { + updateAssetName(oldName, newName, assetType) { let getAssetField; if (assetType === 'costume') { getAssetField = this._getCostumeField.bind(this); @@ -962,7 +962,7 @@ class Blocks { * @param {string} targetName The name of the target the variable belongs to. * @return {boolean} Returns true if any of the blocks were updated. */ - updateSensingOfReference (oldName, newName, targetName) { + updateSensingOfReference(oldName, newName, targetName) { const blocks = this._blocks; let blockUpdated = false; for (const blockId in blocks) { @@ -989,7 +989,7 @@ class Blocks { * Null if either a block with the given id doesn't exist or if a costume menu field * does not exist on the block with the given id. */ - _getCostumeField (blockId) { + _getCostumeField(blockId) { const block = this.getBlock(blockId); if (block && Object.prototype.hasOwnProperty.call(block.fields, 'COSTUME')) { return block.fields.COSTUME; @@ -1004,7 +1004,7 @@ class Blocks { * Null, if either a block with the given id doesn't exist or if a sound menu field * does not exist on the block with the given id. */ - _getSoundField (blockId) { + _getSoundField(blockId) { const block = this.getBlock(blockId); if (block && Object.prototype.hasOwnProperty.call(block.fields, 'SOUND_MENU')) { return block.fields.SOUND_MENU; @@ -1019,7 +1019,7 @@ class Blocks { * Null, if either a block with the given id doesn't exist or if a backdrop menu field * does not exist on the block with the given id. */ - _getBackdropField (blockId) { + _getBackdropField(blockId) { const block = this.getBlock(blockId); if (block && Object.prototype.hasOwnProperty.call(block.fields, 'BACKDROP')) { return block.fields.BACKDROP; @@ -1034,7 +1034,7 @@ class Blocks { * Null, if either a block with the given id doesn't exist or if a sprite menu field * does not exist on the block with the given id. */ - _getSpriteField (blockId) { + _getSpriteField(blockId) { const block = this.getBlock(blockId); if (!block) { return null; @@ -1058,7 +1058,7 @@ class Blocks { * @param {object} comments Map of comments referenced by id * @return {string} String of XML representing this object's blocks. */ - toXML (comments) { + toXML(comments) { return this._scripts.map(script => this.blockToXML(script, comments)).join(); } @@ -1069,7 +1069,7 @@ class Blocks { * @param {object} comments Map of comments referenced by id * @return {string} String of XML representing this block and any children. */ - blockToXML (blockId, comments) { + blockToXML(blockId, comments) { const block = this._blocks[blockId]; // block should exist, but currently some blocks' next property point // to a blockId for non-existent blocks. Until we track down that behavior, @@ -1148,7 +1148,7 @@ class Blocks { * @param {!object} mutation Object representing a mutation. * @return {string} XML string representing a mutation. */ - mutationToXML (mutation) { + mutationToXML(mutation) { let mutationString = `<${mutation.tagName}`; for (const prop in mutation) { if (prop === 'children' || prop === 'tagName') continue; @@ -1176,7 +1176,7 @@ class Blocks { * @param {!object} block Block to be paramified. * @return {!object} object of param key/values. */ - _getBlockParams (block) { + _getBlockParams(block) { const params = {}; for (const key in block.fields) { params[key] = block.fields[key].value; @@ -1195,7 +1195,7 @@ class Blocks { * @param {!object} defineBlock Outer define block. * @return {!object} internal definition block which has the mutation. */ - _getCustomBlockInternal (defineBlock) { + _getCustomBlockInternal(defineBlock) { if (defineBlock.inputs && defineBlock.inputs.custom_block) { return this._blocks[defineBlock.inputs.custom_block.block]; } @@ -1205,7 +1205,7 @@ class Blocks { * Helper to add a stack to `this._scripts`. * @param {?string} topBlockId ID of block that starts the script. */ - _addScript (topBlockId) { + _addScript(topBlockId) { const i = this._scripts.indexOf(topBlockId); if (i > -1) return; // Already in scripts. this._scripts.push(topBlockId); @@ -1217,12 +1217,49 @@ class Blocks { * Helper to remove a script from `this._scripts`. * @param {?string} topBlockId ID of block that starts the script. */ - _deleteScript (topBlockId) { + _deleteScript(topBlockId) { const i = this._scripts.indexOf(topBlockId); if (i > -1) this._scripts.splice(i, 1); // Update `topLevel` property on the top block. if (this._blocks[topBlockId]) this._blocks[topBlockId].topLevel = false; } + + /** PRG ADDITION BEGIN */ + + /** + * Get all of the IDs of current top blocks + * @returns {string[]} array of Top Block IDs + */ + getTopBlockIDs() { + return Object.keys(this._blocks).filter(id => this._blocks[id].topLevel); + } + + /** + * + * @param {string} ID + */ + isTopBlockID(ID) { + return this.getTopBlockIDs().includes(ID); + } + + /** + * NOTE: Also returns true if baseID === aboveID + * @param {?string} baseID ID of block to check from. + * @param {?string} aboveID ID of block that may or may not be above the baseID block. + * @return {boolean} Whether or a block with id = aboveID is 'above' the baseID block + */ + isBlockAbove(baseID, aboveID) { + if (baseID === aboveID) return true; + let block = this._blocks[baseID]; + if (typeof block === 'undefined') return null; + while (block.parent !== null) { + block = this._blocks[block.parent]; + if (block.id === aboveID) return true; + } + return false; + } + + /** PRG ADDITION END */ } /** diff --git a/src/engine/execute.js b/src/engine/execute.js index df0907a852e..dbbcc8d2501 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -2,8 +2,11 @@ const BlockUtility = require('./block-utility'); const BlocksExecuteCache = require('./blocks-execute-cache'); const log = require('../util/log'); const Thread = require('./thread'); -const {Map} = require('immutable'); +const { Map } = require('immutable'); const cast = require('../util/cast'); +/** PRG ADDITION BEGIN */ +const { blockIDKey } = require("../dist/globals"); +/** PRG ADDITION END */ /** * Single BlockUtility instance reused by execute for every pritimive ran. @@ -160,7 +163,7 @@ const handlePromise = (primitiveReportedValue, sequencer, thread, blockCached, l * @param {object} cached default set of cached values */ class BlockCached { - constructor (blockContainer, cached) { + constructor(blockContainer, cached) { /** * Block id in its parent set of blocks. * @type {string} @@ -277,9 +280,9 @@ class BlockCached { */ this._ops = []; - const {runtime} = blockUtility.sequencer; + const { runtime } = blockUtility.sequencer; - const {opcode, fields, inputs} = this; + const { opcode, fields, inputs } = this; // Assign opcode isHat and blockFunction data to avoid dynamic lookups. this._isHat = runtime.getIsHat(opcode); @@ -393,7 +396,7 @@ const _prepareBlockProfiling = function (profiler, blockCached) { /** * Execute a block. - * @param {!Sequencer} sequencer Which sequencer is executing. + * @param {!import("./sequencer")} sequencer Which sequencer is executing. * @param {!Thread} thread Thread which to read and execute. */ const execute = function (sequencer, thread) { @@ -429,7 +432,7 @@ const execute = function (sequencer, thread) { const reported = currentStackFrame.reported; // Reinstate all the previous values. for (; i < reported.length; i++) { - const {opCached: oldOpCached, inputValue} = reported[i]; + const { opCached: oldOpCached, inputValue } = reported[i]; const opCached = ops.find(op => op.id === oldOpCached); @@ -510,6 +513,10 @@ const execute = function (sequencer, thread) { // Inputs are set during previous steps in the loop. + /** PRG ADDITION BEGIN */ + blockUtility[blockIDKey] = opCached.id; + /** PRG ADDITION END */ + const primitiveReportedValue = blockFunction(argValues, blockUtility); // If it's a promise, wait until promise resolves. diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 452ff51c204..d4f13046d6d 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -1,5 +1,5 @@ const EventEmitter = require('events'); -const {OrderedMap} = require('immutable'); +const { OrderedMap } = require('immutable'); const uuid = require('uuid'); const ArgumentType = require('../extension-support/argument-type'); @@ -32,6 +32,11 @@ const Video = require('../io/video'); const StringUtil = require('../util/string-util'); const uid = require('../util/uid'); +/** PRG ADDITION BEGIN */ +const dispatch = require('../dispatch/central-dispatch'); +const { loadCostume } = require('../import/load-costume'); +/** PRG ADDITION END */ + const defaultBlockPackages = { scratch3_control: require('../blocks/scratch3_control'), scratch3_event: require('../blocks/scratch3_event'), @@ -48,7 +53,7 @@ const defaultExtensionColors = ['#0FBD8C', '#0DA57A', '#0B8E69']; /** * Information used for converting Scratch argument types into scratch-blocks data. - * @type {object.} + * @type {Object.} */ const ArgumentTypeMap = (() => { const map = {}; @@ -177,7 +182,7 @@ let rendererDrawProfilerId = -1; * @constructor */ class Runtime extends EventEmitter { - constructor () { + constructor() { super(); /** @@ -218,7 +223,7 @@ class Runtime extends EventEmitter { /** * Currently known editing target for the VM. - * @type {?Target} + * @type {?import("./target")} */ this._editingTarget = null; @@ -411,7 +416,7 @@ class Runtime extends EventEmitter { * Width of the stage, in pixels. * @const {number} */ - static get STAGE_WIDTH () { + static get STAGE_WIDTH() { return 480; } @@ -419,7 +424,7 @@ class Runtime extends EventEmitter { * Height of the stage, in pixels. * @const {number} */ - static get STAGE_HEIGHT () { + static get STAGE_HEIGHT() { return 360; } @@ -427,7 +432,7 @@ class Runtime extends EventEmitter { * Event name for glowing a script. * @const {string} */ - static get SCRIPT_GLOW_ON () { + static get SCRIPT_GLOW_ON() { return 'SCRIPT_GLOW_ON'; } @@ -435,7 +440,7 @@ class Runtime extends EventEmitter { * Event name for unglowing a script. * @const {string} */ - static get SCRIPT_GLOW_OFF () { + static get SCRIPT_GLOW_OFF() { return 'SCRIPT_GLOW_OFF'; } @@ -443,7 +448,7 @@ class Runtime extends EventEmitter { * Event name for glowing a block. * @const {string} */ - static get BLOCK_GLOW_ON () { + static get BLOCK_GLOW_ON() { return 'BLOCK_GLOW_ON'; } @@ -451,7 +456,7 @@ class Runtime extends EventEmitter { * Event name for unglowing a block. * @const {string} */ - static get BLOCK_GLOW_OFF () { + static get BLOCK_GLOW_OFF() { return 'BLOCK_GLOW_OFF'; } @@ -460,7 +465,7 @@ class Runtime extends EventEmitter { * to this project. * @const {string} */ - static get HAS_CLOUD_DATA_UPDATE () { + static get HAS_CLOUD_DATA_UPDATE() { return 'HAS_CLOUD_DATA_UPDATE'; } @@ -468,7 +473,7 @@ class Runtime extends EventEmitter { * Event name for turning on turbo mode. * @const {string} */ - static get TURBO_MODE_ON () { + static get TURBO_MODE_ON() { return 'TURBO_MODE_ON'; } @@ -476,7 +481,7 @@ class Runtime extends EventEmitter { * Event name for turning off turbo mode. * @const {string} */ - static get TURBO_MODE_OFF () { + static get TURBO_MODE_OFF() { return 'TURBO_MODE_OFF'; } @@ -485,7 +490,7 @@ class Runtime extends EventEmitter { * running). * @const {string} */ - static get PROJECT_START () { + static get PROJECT_START() { return 'PROJECT_START'; } @@ -494,7 +499,7 @@ class Runtime extends EventEmitter { * Used by the UI to indicate running status. * @const {string} */ - static get PROJECT_RUN_START () { + static get PROJECT_RUN_START() { return 'PROJECT_RUN_START'; } @@ -503,7 +508,7 @@ class Runtime extends EventEmitter { * Used by the UI to indicate not-running status. * @const {string} */ - static get PROJECT_RUN_STOP () { + static get PROJECT_RUN_STOP() { return 'PROJECT_RUN_STOP'; } @@ -512,7 +517,7 @@ class Runtime extends EventEmitter { * Used by blocks that need to reset state. * @const {string} */ - static get PROJECT_STOP_ALL () { + static get PROJECT_STOP_ALL() { return 'PROJECT_STOP_ALL'; } @@ -521,7 +526,7 @@ class Runtime extends EventEmitter { * Used by blocks that need to stop individual targets. * @const {string} */ - static get STOP_FOR_TARGET () { + static get STOP_FOR_TARGET() { return 'STOP_FOR_TARGET'; } @@ -529,7 +534,7 @@ class Runtime extends EventEmitter { * Event name for visual value report. * @const {string} */ - static get VISUAL_REPORT () { + static get VISUAL_REPORT() { return 'VISUAL_REPORT'; } @@ -537,7 +542,7 @@ class Runtime extends EventEmitter { * Event name for project loaded report. * @const {string} */ - static get PROJECT_LOADED () { + static get PROJECT_LOADED() { return 'PROJECT_LOADED'; } @@ -545,7 +550,7 @@ class Runtime extends EventEmitter { * Event name for report that a change was made that can be saved * @const {string} */ - static get PROJECT_CHANGED () { + static get PROJECT_CHANGED() { return 'PROJECT_CHANGED'; } @@ -553,7 +558,7 @@ class Runtime extends EventEmitter { * Event name for report that a change was made to an extension in the toolbox. * @const {string} */ - static get TOOLBOX_EXTENSIONS_NEED_UPDATE () { + static get TOOLBOX_EXTENSIONS_NEED_UPDATE() { return 'TOOLBOX_EXTENSIONS_NEED_UPDATE'; } @@ -561,7 +566,7 @@ class Runtime extends EventEmitter { * Event name for targets update report. * @const {string} */ - static get TARGETS_UPDATE () { + static get TARGETS_UPDATE() { return 'TARGETS_UPDATE'; } @@ -569,7 +574,7 @@ class Runtime extends EventEmitter { * Event name for monitors update. * @const {string} */ - static get MONITORS_UPDATE () { + static get MONITORS_UPDATE() { return 'MONITORS_UPDATE'; } @@ -577,7 +582,7 @@ class Runtime extends EventEmitter { * Event name for block drag update. * @const {string} */ - static get BLOCK_DRAG_UPDATE () { + static get BLOCK_DRAG_UPDATE() { return 'BLOCK_DRAG_UPDATE'; } @@ -585,7 +590,7 @@ class Runtime extends EventEmitter { * Event name for block drag end. * @const {string} */ - static get BLOCK_DRAG_END () { + static get BLOCK_DRAG_END() { return 'BLOCK_DRAG_END'; } @@ -593,7 +598,7 @@ class Runtime extends EventEmitter { * Event name for reporting that an extension was added. * @const {string} */ - static get EXTENSION_ADDED () { + static get EXTENSION_ADDED() { return 'EXTENSION_ADDED'; } @@ -601,7 +606,7 @@ class Runtime extends EventEmitter { * Event name for reporting that an extension as asked for a custom field to be added * @const {string} */ - static get EXTENSION_FIELD_ADDED () { + static get EXTENSION_FIELD_ADDED() { return 'EXTENSION_FIELD_ADDED'; } @@ -611,7 +616,7 @@ class Runtime extends EventEmitter { * available peripherals. * @const {string} */ - static get PERIPHERAL_LIST_UPDATE () { + static get PERIPHERAL_LIST_UPDATE() { return 'PERIPHERAL_LIST_UPDATE'; } @@ -620,7 +625,7 @@ class Runtime extends EventEmitter { * via Companion Device Manager (CDM) * @const {string} */ - static get USER_PICKED_PERIPHERAL () { + static get USER_PICKED_PERIPHERAL() { return 'USER_PICKED_PERIPHERAL'; } @@ -629,7 +634,7 @@ class Runtime extends EventEmitter { * This causes the status button in the blocks menu to indicate 'connected'. * @const {string} */ - static get PERIPHERAL_CONNECTED () { + static get PERIPHERAL_CONNECTED() { return 'PERIPHERAL_CONNECTED'; } @@ -638,7 +643,7 @@ class Runtime extends EventEmitter { * This causes the status button in the blocks menu to indicate 'disconnected'. * @const {string} */ - static get PERIPHERAL_DISCONNECTED () { + static get PERIPHERAL_DISCONNECTED() { return 'PERIPHERAL_DISCONNECTED'; } @@ -647,7 +652,7 @@ class Runtime extends EventEmitter { * This causes the peripheral connection modal to switch to an error state. * @const {string} */ - static get PERIPHERAL_REQUEST_ERROR () { + static get PERIPHERAL_REQUEST_ERROR() { return 'PERIPHERAL_REQUEST_ERROR'; } @@ -656,7 +661,7 @@ class Runtime extends EventEmitter { * This causes a 'peripheral connection lost' error alert to display. * @const {string} */ - static get PERIPHERAL_CONNECTION_LOST_ERROR () { + static get PERIPHERAL_CONNECTION_LOST_ERROR() { return 'PERIPHERAL_CONNECTION_LOST_ERROR'; } @@ -665,7 +670,7 @@ class Runtime extends EventEmitter { * This causes the peripheral connection modal to show a timeout state. * @const {string} */ - static get PERIPHERAL_SCAN_TIMEOUT () { + static get PERIPHERAL_SCAN_TIMEOUT() { return 'PERIPHERAL_SCAN_TIMEOUT'; } @@ -673,7 +678,7 @@ class Runtime extends EventEmitter { * Event name to indicate that the microphone is being used to stream audio. * @const {string} */ - static get MIC_LISTENING () { + static get MIC_LISTENING() { return 'MIC_LISTENING'; } @@ -681,7 +686,7 @@ class Runtime extends EventEmitter { * Event name for reporting that blocksInfo was updated. * @const {string} */ - static get BLOCKSINFO_UPDATE () { + static get BLOCKSINFO_UPDATE() { return 'BLOCKSINFO_UPDATE'; } @@ -689,7 +694,7 @@ class Runtime extends EventEmitter { * Event name when the runtime tick loop has been started. * @const {string} */ - static get RUNTIME_STARTED () { + static get RUNTIME_STARTED() { return 'RUNTIME_STARTED'; } @@ -697,7 +702,7 @@ class Runtime extends EventEmitter { * Event name when the runtime dispose has been called. * @const {string} */ - static get RUNTIME_DISPOSED () { + static get RUNTIME_DISPOSED() { return 'RUNTIME_DISPOSED'; } @@ -705,21 +710,21 @@ class Runtime extends EventEmitter { * Event name for reporting that a block was updated and needs to be rerendered. * @const {string} */ - static get BLOCKS_NEED_UPDATE () { + static get BLOCKS_NEED_UPDATE() { return 'BLOCKS_NEED_UPDATE'; } /** * How rapidly we try to step threads by default, in ms. */ - static get THREAD_STEP_INTERVAL () { + static get THREAD_STEP_INTERVAL() { return 1000 / 60; } /** * In compatibility mode, how rapidly we try to step threads, in ms. */ - static get THREAD_STEP_INTERVAL_COMPATIBILITY () { + static get THREAD_STEP_INTERVAL_COMPATIBILITY() { return 1000 / 30; } @@ -727,7 +732,7 @@ class Runtime extends EventEmitter { * How many clones can be created at a time. * @const {number} */ - static get MAX_CLONES () { + static get MAX_CLONES() { return 300; } @@ -735,7 +740,7 @@ class Runtime extends EventEmitter { // ----------------------------------------------------------------------------- // Helper function for initializing the addCloudVariable function - _initializeAddCloudVariable (newCloudDataManager) { + _initializeAddCloudVariable(newCloudDataManager) { // The addCloudVariable function return (() => { const hadCloudVarsBefore = this.hasCloudData(); @@ -747,7 +752,7 @@ class Runtime extends EventEmitter { } // Helper function for initializing the removeCloudVariable function - _initializeRemoveCloudVariable (newCloudDataManager) { + _initializeRemoveCloudVariable(newCloudDataManager) { return (() => { const hadCloudVarsBefore = this.hasCloudData(); newCloudDataManager.removeCloudVariable(); @@ -762,7 +767,7 @@ class Runtime extends EventEmitter { * @todo Prefix opcodes with package name. * @private */ - _registerBlockPackages () { + _registerBlockPackages() { for (const packageName in defaultBlockPackages) { if (Object.prototype.hasOwnProperty.call(defaultBlockPackages, packageName)) { // @todo pass a different runtime depending on package privilege? @@ -794,7 +799,7 @@ class Runtime extends EventEmitter { } } - getMonitorState () { + getMonitorState() { return this._monitorState; } @@ -805,16 +810,16 @@ class Runtime extends EventEmitter { * @returns {string} - the constructed ID. * @private */ - _makeExtensionMenuId (menuName, extensionId) { + _makeExtensionMenuId(menuName, extensionId) { return `${extensionId}_menu_${xmlEscape(menuName)}`; } /** * Create a context ("args") object for use with `formatMessage` on messages which might be target-specific. - * @param {Target} [target] - the target to use as context. If a target is not provided, default to the current + * @param {import("./target")} [target] - the target to use as context. If a target is not provided, default to the current * editing target or the stage. */ - makeMessageContextForTarget (target) { + makeMessageContextForTarget(target) { const context = {}; target = target || this.getEditingTarget() || this.getTargetForStage(); if (target) { @@ -827,7 +832,7 @@ class Runtime extends EventEmitter { * @param {ExtensionMetadata} extensionInfo - information about the extension (id, blocks, etc.) * @private */ - _registerExtensionPrimitives (extensionInfo) { + _registerExtensionPrimitives(extensionInfo) { const categoryInfo = { id: extensionInfo.id, name: maybeFormatMessage(extensionInfo.name), @@ -870,7 +875,7 @@ class Runtime extends EventEmitter { * @param {ExtensionMetadata} extensionInfo - new info (results of running getInfo) for an extension * @private */ - _refreshExtensionPrimitives (extensionInfo) { + _refreshExtensionPrimitives(extensionInfo) { const categoryInfo = this._blockInfo.find(info => info.id === extensionInfo.id); if (categoryInfo) { categoryInfo.name = maybeFormatMessage(extensionInfo.name); @@ -887,7 +892,7 @@ class Runtime extends EventEmitter { * @param {ExtensionMetadata} extensionInfo - the extension metadata to read * @private */ - _fillExtensionCategory (categoryInfo, extensionInfo) { + _fillExtensionCategory(categoryInfo, extensionInfo) { categoryInfo.blocks = []; categoryInfo.customFieldTypes = {}; categoryInfo.menus = []; @@ -932,7 +937,7 @@ class Runtime extends EventEmitter { } } } catch (e) { - log.error('Error parsing block: ', {block: blockInfo, error: e}); + log.error('Error parsing block: ', { block: blockInfo, error: e }); } } } @@ -944,18 +949,18 @@ class Runtime extends EventEmitter { * @returns {object} - an array of 2 element arrays or the original input function * @private */ - _convertMenuItems (menuItems) { + _convertMenuItems(menuItems) { if (typeof menuItems !== 'function') { const extensionMessageContext = this.makeMessageContextForTarget(); return menuItems.map(item => { const formattedItem = maybeFormatMessage(item, extensionMessageContext); switch (typeof formattedItem) { - case 'string': - return [formattedItem, formattedItem]; - case 'object': - return [maybeFormatMessage(item.text, extensionMessageContext), item.value]; - default: - throw new Error(`Can't interpret menu item: ${JSON.stringify(item)}`); + case 'string': + return [formattedItem, formattedItem]; + case 'object': + return [maybeFormatMessage(item.text, extensionMessageContext), item.value]; + default: + throw new Error(`Can't interpret menu item: ${JSON.stringify(item)}`); } }); } @@ -972,7 +977,7 @@ class Runtime extends EventEmitter { * @returns {object} - a JSON-esque object ready for scratch-blocks' consumption * @private */ - _buildMenuForScratchBlocks (menuName, menuInfo, categoryInfo) { + _buildMenuForScratchBlocks(menuName, menuInfo, categoryInfo) { const menuId = this._makeExtensionMenuId(menuName, categoryInfo.id); const menuItems = this._convertMenuItems(menuInfo.items); return { @@ -997,7 +1002,7 @@ class Runtime extends EventEmitter { }; } - _buildCustomFieldInfo (fieldName, fieldInfo, extensionId, categoryInfo) { + _buildCustomFieldInfo(fieldName, fieldInfo, extensionId, categoryInfo) { const extendedName = `${extensionId}_${fieldName}`; return { fieldName: fieldName, @@ -1027,7 +1032,7 @@ class Runtime extends EventEmitter { * @param {object} categoryInfo - The category the field belongs to (Used to set its colors) * @returns {object} - Object to be inserted into scratch-blocks */ - _buildCustomFieldTypeForScratchBlocks (fieldName, output, outputShape, categoryInfo) { + _buildCustomFieldTypeForScratchBlocks(fieldName, output, outputShape, categoryInfo) { return { json: { type: fieldName, @@ -1055,7 +1060,7 @@ class Runtime extends EventEmitter { * @returns {ConvertedBlockInfo} - the converted & original block information * @private */ - _convertForScratchBlocks (blockInfo, categoryInfo) { + _convertForScratchBlocks(blockInfo, categoryInfo) { if (blockInfo === '---') { return this._convertSeparatorForScratchBlocks(blockInfo); } @@ -1074,7 +1079,7 @@ class Runtime extends EventEmitter { * @returns {ConvertedBlockInfo} - the converted & original block information * @private */ - _convertBlockForScratchBlocks (blockInfo, categoryInfo) { + _convertBlockForScratchBlocks(blockInfo, categoryInfo) { const extendedOpcode = `${categoryInfo.id}_${blockInfo.opcode}`; const blockJSON = { @@ -1121,39 +1126,39 @@ class Runtime extends EventEmitter { } switch (blockInfo.blockType) { - case BlockType.COMMAND: - blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; - blockJSON.previousStatement = null; // null = available connection; undefined = hat - if (!blockInfo.isTerminal) { - blockJSON.nextStatement = null; // null = available connection; undefined = terminal - } - break; - case BlockType.REPORTER: - blockJSON.output = 'String'; // TODO: distinguish number & string here? - blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_ROUND; - break; - case BlockType.BOOLEAN: - blockJSON.output = 'Boolean'; - blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_HEXAGONAL; - break; - case BlockType.HAT: - case BlockType.EVENT: - if (!Object.prototype.hasOwnProperty.call(blockInfo, 'isEdgeActivated')) { - // if absent, this property defaults to true - blockInfo.isEdgeActivated = true; - } - blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; - blockJSON.nextStatement = null; // null = available connection; undefined = terminal - break; - case BlockType.CONDITIONAL: - case BlockType.LOOP: - blockInfo.branchCount = blockInfo.branchCount || 1; - blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; - blockJSON.previousStatement = null; // null = available connection; undefined = hat - if (!blockInfo.isTerminal) { + case BlockType.COMMAND: + blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; + blockJSON.previousStatement = null; // null = available connection; undefined = hat + if (!blockInfo.isTerminal) { + blockJSON.nextStatement = null; // null = available connection; undefined = terminal + } + break; + case BlockType.REPORTER: + blockJSON.output = 'String'; // TODO: distinguish number & string here? + blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_ROUND; + break; + case BlockType.BOOLEAN: + blockJSON.output = 'Boolean'; + blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_HEXAGONAL; + break; + case BlockType.HAT: + case BlockType.EVENT: + if (!Object.prototype.hasOwnProperty.call(blockInfo, 'isEdgeActivated')) { + // if absent, this property defaults to true + blockInfo.isEdgeActivated = true; + } + blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; blockJSON.nextStatement = null; // null = available connection; undefined = terminal - } - break; + break; + case BlockType.CONDITIONAL: + case BlockType.LOOP: + blockInfo.branchCount = blockInfo.branchCount || 1; + blockJSON.outputShape = ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE; + blockJSON.previousStatement = null; // null = available connection; undefined = hat + if (!blockInfo.isTerminal) { + blockJSON.nextStatement = null; // null = available connection; undefined = terminal + } + break; } const blockText = Array.isArray(blockInfo.text) ? blockInfo.text : [blockInfo.text]; @@ -1225,7 +1230,7 @@ class Runtime extends EventEmitter { * @returns {ConvertedBlockInfo} - the converted & original block information * @private */ - _convertSeparatorForScratchBlocks (blockInfo) { + _convertSeparatorForScratchBlocks(blockInfo) { return { info: blockInfo, xml: '' @@ -1240,9 +1245,9 @@ class Runtime extends EventEmitter { * @returns {ConvertedBlockInfo} - the converted & original button information * @private */ - _convertButtonForScratchBlocks (buttonInfo) { + _convertButtonForScratchBlocks(buttonInfo) { // for now we only support these pre-defined callbacks handled in scratch-blocks - const supportedCallbackKeys = ['MAKE_A_LIST', 'MAKE_A_PROCEDURE', 'MAKE_A_VARIABLE']; + const supportedCallbackKeys = ['MAKE_A_LIST', 'MAKE_A_PROCEDURE', 'MAKE_A_VARIABLE', /** PRG ADDITION BEGING */ 'EDIT_TEXT_MODEL', 'EDIT_TEXT_CLASSIFIER' /** PRG ADDITION END */]; if (supportedCallbackKeys.indexOf(buttonInfo.func) < 0) { log.error(`Custom button callbacks not supported yet: ${buttonInfo.func}`); } @@ -1261,7 +1266,7 @@ class Runtime extends EventEmitter { * @return {object} JSON blob for a scratch-blocks image field. * @private */ - _constructInlineImageJson (argInfo) { + _constructInlineImageJson(argInfo) { if (!argInfo.dataURI) { log.warn('Missing data URI in extension block with argument type IMAGE'); } @@ -1287,7 +1292,7 @@ class Runtime extends EventEmitter { * @return {string} scratch-blocks placeholder for the argument: '%1'. * @private */ - _convertPlaceholders (context, match, placeholder) { + _convertPlaceholders(context, match, placeholder) { // Sanitize the placeholder to ensure valid XML placeholder = placeholder.replace(/[<"&]/, '_'); @@ -1387,13 +1392,13 @@ class Runtime extends EventEmitter { /** * @returns {Array.} scratch-blocks XML for each category of extension blocks, in category order. - * @param {?Target} [target] - the active editing target (optional) + * @param {?import("./target")} [target] - the active editing target (optional) * @property {string} id - the category / extension ID * @property {string} xml - the XML text for this category, starting with `` and ending with `` */ - getBlocksXML (target) { + getBlocksXML(target) { return this._blockInfo.map(categoryInfo => { - const {name, color1, color2} = categoryInfo; + const { name, color1, color2 } = categoryInfo; // Filter out blocks that aren't supposed to be shown on this target, as determined by the block info's // `hideFromPalette` and `filter` properties. const paletteBlocks = categoryInfo.blocks.filter(block => { @@ -1429,8 +1434,7 @@ class Runtime extends EventEmitter { return { id: categoryInfo.id, - xml: `${ - paletteBlocks.map(block => block.xml).join('')}` + xml: `${paletteBlocks.map(block => block.xml).join('')}` }; }); } @@ -1438,7 +1442,7 @@ class Runtime extends EventEmitter { /** * @returns {Array.} - an array containing the scratch-blocks JSON information for each dynamic block. */ - getBlocksJSON () { + getBlocksJSON() { return this._blockInfo.reduce( (result, categoryInfo) => result.concat(categoryInfo.blocks.map(blockInfo => blockInfo.json)), []); } @@ -1446,7 +1450,7 @@ class Runtime extends EventEmitter { /** * One-time initialization for Scratch Link support. */ - _initScratchLink () { + _initScratchLink() { // Check that we're actually in a real browser, not Node.js or JSDOM, and we have a valid-looking origin. // note that `if (self?....)` will throw if `self` is undefined, so check for that first! if (typeof self !== 'undefined' && @@ -1478,9 +1482,9 @@ class Runtime extends EventEmitter { /** * Get a scratch link socket. * @param {string} type Either BLE or BT - * @returns {ScratchLinkSocket} The scratch link socket. + * @returns {import("../util/scratch-link-websocket")} The scratch link socket. */ - getScratchLinkSocket (type) { + getScratchLinkSocket(type) { const factory = this._linkSocketFactory || this._defaultScratchLinkSocketFactory; return factory(type); } @@ -1490,16 +1494,16 @@ class Runtime extends EventEmitter { * either BT or BLE. * @param {Function} factory The new factory for creating ScratchLink sockets. */ - configureScratchLinkSocketFactory (factory) { + configureScratchLinkSocketFactory(factory) { this._linkSocketFactory = factory; } /** * The default scratch link socket creator, using websockets to the installed device manager. * @param {string} type Either BLE or BT - * @returns {ScratchLinkSocket} The new scratch link socket (a WebSocket object) + * @returns {import("../util/scratch-link-websocket")} The new scratch link socket (a WebSocket object) */ - _defaultScratchLinkSocketFactory (type) { + _defaultScratchLinkSocketFactory(type) { const Scratch = self.Scratch; const ScratchLinkSafariSocket = Scratch && Scratch.ScratchLinkSafariSocket; // detect this every time in case the user turns on the extension after loading the page @@ -1513,7 +1517,7 @@ class Runtime extends EventEmitter { * @param {string} extensionId - the id of the extension. * @param {object} extension - the extension to register. */ - registerPeripheralExtension (extensionId, extension) { + registerPeripheralExtension(extensionId, extension) { this.peripheralExtensions[extensionId] = extension; } @@ -1521,7 +1525,7 @@ class Runtime extends EventEmitter { * Tell the specified extension to scan for a peripheral. * @param {string} extensionId - the id of the extension. */ - scanForPeripheral (extensionId) { + scanForPeripheral(extensionId) { if (this.peripheralExtensions[extensionId]) { this.peripheralExtensions[extensionId].scan(); } @@ -1532,7 +1536,7 @@ class Runtime extends EventEmitter { * @param {string} extensionId - the id of the extension. * @param {number} peripheralId - the id of the peripheral. */ - connectPeripheral (extensionId, peripheralId) { + connectPeripheral(extensionId, peripheralId) { if (this.peripheralExtensions[extensionId]) { this.peripheralExtensions[extensionId].connect(peripheralId); } @@ -1542,7 +1546,7 @@ class Runtime extends EventEmitter { * Disconnect from the extension's connected peripheral. * @param {string} extensionId - the id of the extension. */ - disconnectPeripheral (extensionId) { + disconnectPeripheral(extensionId) { if (this.peripheralExtensions[extensionId]) { this.peripheralExtensions[extensionId].disconnect(); } @@ -1553,7 +1557,7 @@ class Runtime extends EventEmitter { * @param {string} extensionId - the id of the extension. * @return {boolean} - whether the extension has a connected peripheral. */ - getPeripheralIsConnected (extensionId) { + getPeripheralIsConnected(extensionId) { let isConnected = false; if (this.peripheralExtensions[extensionId]) { isConnected = this.peripheralExtensions[extensionId].isConnected(); @@ -1565,7 +1569,7 @@ class Runtime extends EventEmitter { * Emit an event to indicate that the microphone is being used to stream audio. * @param {boolean} listening - true if the microphone is currently listening. */ - emitMicListening (listening) { + emitMicListening(listening) { this.emit(Runtime.MIC_LISTENING, listening); } @@ -1574,7 +1578,7 @@ class Runtime extends EventEmitter { * @param {!string} opcode The opcode to look up. * @return {Function} The function which implements the opcode. */ - getOpcodeFunction (opcode) { + getOpcodeFunction(opcode) { return this._primitives[opcode]; } @@ -1583,7 +1587,7 @@ class Runtime extends EventEmitter { * @param {!string} opcode The opcode to look up. * @return {boolean} True if the op is known to be a hat. */ - getIsHat (opcode) { + getIsHat(opcode) { return Object.prototype.hasOwnProperty.call(this._hats, opcode); } @@ -1592,7 +1596,7 @@ class Runtime extends EventEmitter { * @param {!string} opcode The opcode to look up. * @return {boolean} True if the op is known to be a edge-activated hat. */ - getIsEdgeActivatedHat (opcode) { + getIsEdgeActivatedHat(opcode) { return Object.prototype.hasOwnProperty.call(this._hats, opcode) && this._hats[opcode].edgeActivated; } @@ -1602,7 +1606,7 @@ class Runtime extends EventEmitter { * Attach the audio engine * @param {!AudioEngine} audioEngine The audio engine to attach */ - attachAudioEngine (audioEngine) { + attachAudioEngine(audioEngine) { this.audioEngine = audioEngine; } @@ -1610,7 +1614,7 @@ class Runtime extends EventEmitter { * Attach the renderer * @param {!RenderWebGL} renderer The renderer to attach */ - attachRenderer (renderer) { + attachRenderer(renderer) { this.renderer = renderer; this.renderer.setLayerGroupOrdering(StageLayering.LAYER_GROUPS); } @@ -1620,15 +1624,15 @@ class Runtime extends EventEmitter { * bitmaps to scratch 3 bitmaps. (Scratch 3 bitmaps are all bitmap resolution 2) * @param {!function} bitmapAdapter The adapter to attach */ - attachV2BitmapAdapter (bitmapAdapter) { + attachV2BitmapAdapter(bitmapAdapter) { this.v2BitmapAdapter = bitmapAdapter; } /** * Attach the storage module - * @param {!ScratchStorage} storage The storage module to attach + * @param {!import("scratch-storage")} storage The storage module to attach */ - attachStorage (storage) { + attachStorage(storage) { this.storage = storage; fetchWithTimeout.setFetch(storage.scratchFetch.scratchFetch); this.resetRunId(); @@ -1640,13 +1644,13 @@ class Runtime extends EventEmitter { /** * Create a thread and push it to the list of threads. * @param {!string} id ID of block that starts the stack. - * @param {!Target} target Target to run thread on. + * @param {!import("./target")} target Target to run thread on. * @param {?object} opts optional arguments * @param {?boolean} opts.stackClick true if the script was activated by clicking on the stack * @param {?boolean} opts.updateMonitor true if the script should update a monitor value * @return {!Thread} The newly created thread. */ - _pushThread (id, target, opts) { + _pushThread(id, target, opts) { const thread = new Thread(id); thread.target = target; thread.stackClick = Boolean(opts && opts.stackClick); @@ -1664,7 +1668,7 @@ class Runtime extends EventEmitter { * Stop a thread: stop running it immediately, and remove it from the thread list later. * @param {!Thread} thread Thread object to remove from actives */ - _stopThread (thread) { + _stopThread(thread) { // Mark the thread for later removal thread.isKilled = true; // Inform sequencer to stop executing that thread. @@ -1678,7 +1682,7 @@ class Runtime extends EventEmitter { * @param {!Thread} thread Thread object to restart. * @return {Thread} The restarted thread. */ - _restartThread (thread) { + _restartThread(thread) { const newThread = new Thread(thread.topBlock); newThread.target = thread.target; newThread.stackClick = thread.stackClick; @@ -1699,7 +1703,7 @@ class Runtime extends EventEmitter { * @param {?Thread} thread Thread object to check. * @return {boolean} True if the thread is active/running. */ - isActiveThread (thread) { + isActiveThread(thread) { return ( ( thread.stack.length > 0 && @@ -1712,7 +1716,7 @@ class Runtime extends EventEmitter { * @param {?Thread} thread Thread object to check. * @return {boolean} True if the thread is waiting */ - isWaitingThread (thread) { + isWaitingThread(thread) { return ( thread.status === Thread.STATUS_PROMISE_WAIT || thread.status === Thread.STATUS_YIELD_TICK || @@ -1728,7 +1732,7 @@ class Runtime extends EventEmitter { * @param {?boolean} opts.stackClick true if the user activated the stack by clicking, false if not. This * determines whether we show a visual report when turning on the script. */ - toggleScript (topBlockId, opts) { + toggleScript(topBlockId, opts) { opts = Object.assign({ target: this._editingTarget, stackClick: false @@ -1756,19 +1760,19 @@ class Runtime extends EventEmitter { /** * Enqueue a script that when finished will update the monitor for the block. * @param {!string} topBlockId ID of block that starts the script. - * @param {?Target} optTarget target Target to run script on. If not supplied, uses editing target. + * @param {?import("./target")} optTarget target Target to run script on. If not supplied, uses editing target. */ - addMonitorScript (topBlockId, optTarget) { + addMonitorScript(topBlockId, optTarget) { if (!optTarget) optTarget = this._editingTarget; for (let i = 0; i < this.threads.length; i++) { // Don't re-add the script if it's already running if (this.threads[i].topBlock === topBlockId && this.threads[i].status !== Thread.STATUS_DONE && - this.threads[i].updateMonitor) { + this.threads[i].updateMonitor) { return; } } // Otherwise add it. - this._pushThread(topBlockId, optTarget, {updateMonitor: true}); + this._pushThread(topBlockId, optTarget, { updateMonitor: true }); } /** @@ -1777,9 +1781,9 @@ class Runtime extends EventEmitter { * - the top block ID of the script. * - the target that owns the script. * @param {!Function} f Function to call for each script. - * @param {Target=} optTarget Optionally, a target to restrict to. + * @param {import("./target")=} optTarget Optionally, a target to restrict to. */ - allScriptsDo (f, optTarget) { + allScriptsDo(f, optTarget) { let targets = this.executableTargets; if (optTarget) { targets = [optTarget]; @@ -1794,7 +1798,7 @@ class Runtime extends EventEmitter { } } - allScriptsByOpcodeDo (opcode, f, optTarget) { + allScriptsByOpcodeDo(opcode, f, optTarget) { let targets = this.executableTargets; if (optTarget) { targets = [optTarget]; @@ -1812,10 +1816,10 @@ class Runtime extends EventEmitter { * Start all relevant hats. * @param {!string} requestedHatOpcode Opcode of hats to start. * @param {object=} optMatchFields Optionally, fields to match on the hat. - * @param {Target=} optTarget Optionally, a target to restrict to. + * @param {import("./target")=} optTarget Optionally, a target to restrict to. * @return {Array.} List of threads started by this function. */ - startHats (requestedHatOpcode, + startHats(requestedHatOpcode, optMatchFields, optTarget) { if (!Object.prototype.hasOwnProperty.call(this._hats, requestedHatOpcode)) { // No known hat with this opcode. @@ -1892,7 +1896,7 @@ class Runtime extends EventEmitter { /** * Dispose all targets. Return to clean state. */ - dispose () { + dispose() { this.stopAll(); // Deleting each target's variable's monitors. this.targets.forEach(target => { @@ -1928,9 +1932,9 @@ class Runtime extends EventEmitter { * Add a target to the runtime. This tracks the sprite pane * ordering of the target. The target still needs to be put * into the correct execution order after calling this function. - * @param {Target} target target to add + * @param {import("./target")} target target to add */ - addTarget (target) { + addTarget(target) { this.targets.push(target); this.executableTargets.push(target); } @@ -1941,11 +1945,11 @@ class Runtime extends EventEmitter { * A positve number will make the target execute earlier. A negative number * will make the target execute later in the order. * - * @param {Target} executableTarget target to move + * @param {import("./target")} executableTarget target to move * @param {number} delta number of positions to move target by * @returns {number} new position in execution order */ - moveExecutable (executableTarget, delta) { + moveExecutable(executableTarget, delta) { const oldIndex = this.executableTargets.indexOf(executableTarget); this.executableTargets.splice(oldIndex, 1); let newIndex = oldIndex + delta; @@ -1969,20 +1973,20 @@ class Runtime extends EventEmitter { * Infinity will set the target to execute first. 0 will set the target to * execute last (before the stage). * - * @param {Target} executableTarget target to move + * @param {import("./target")} executableTarget target to move * @param {number} newIndex position in execution order to place the target * @returns {number} new position in the execution order */ - setExecutablePosition (executableTarget, newIndex) { + setExecutablePosition(executableTarget, newIndex) { const oldIndex = this.executableTargets.indexOf(executableTarget); return this.moveExecutable(executableTarget, newIndex - oldIndex); } /** * Remove a target from the execution set. - * @param {Target} executableTarget target to remove + * @param {import("./target")} executableTarget target to remove */ - removeExecutable (executableTarget) { + removeExecutable(executableTarget) { const oldIndex = this.executableTargets.indexOf(executableTarget); if (oldIndex > -1) { this.executableTargets.splice(oldIndex, 1); @@ -1991,9 +1995,9 @@ class Runtime extends EventEmitter { /** * Dispose of a target. - * @param {!Target} disposingTarget Target to dispose of. + * @param {!import("./target")} disposingTarget Target to dispose of. */ - disposeTarget (disposingTarget) { + disposeTarget(disposingTarget) { this.targets = this.targets.filter(target => { if (disposingTarget !== target) return true; // Allow target to do dispose actions. @@ -2005,10 +2009,10 @@ class Runtime extends EventEmitter { /** * Stop any threads acting on the target. - * @param {!Target} target Target to stop threads for. + * @param {!import("./target")} target Target to stop threads for. * @param {Thread=} optThreadException Optional thread to skip. */ - stopForTarget (target, optThreadException) { + stopForTarget(target, optThreadException) { // Emit stop event to allow blocks to clean up any state. this.emit(Runtime.STOP_FOR_TARGET, target, optThreadException); @@ -2026,7 +2030,7 @@ class Runtime extends EventEmitter { /** * Reset the Run ID. Call this any time the project logically starts, stops, or changes identity. */ - resetRunId () { + resetRunId() { if (!this.storage) { // see also: attachStorage return; @@ -2039,7 +2043,7 @@ class Runtime extends EventEmitter { /** * Start all threads that start with the green flag. */ - greenFlag () { + greenFlag() { this.stopAll(); this.emit(Runtime.PROJECT_START); this.ioDevices.clock.resetProjectTimer(); @@ -2054,7 +2058,7 @@ class Runtime extends EventEmitter { /** * Stop "everything." */ - stopAll () { + stopAll() { // Emit stop event to allow blocks to clean up any state. this.emit(Runtime.PROJECT_STOP_ALL); @@ -2084,7 +2088,7 @@ class Runtime extends EventEmitter { * Repeatedly run `sequencer.stepThreads` and filter out * inactive threads after each iteration. */ - _step () { + _step() { if (this.profiler !== null) { if (stepProfilerId === -1) { stepProfilerId = this.profiler.idByName('Runtime._step'); @@ -2120,7 +2124,7 @@ class Runtime extends EventEmitter { // flag will still indicate that a script ran. this._emitProjectRunStatus( this.threads.length + doneThreads.length - - this._getMonitorThreadCount([...this.threads, ...doneThreads])); + this._getMonitorThreadCount([...this.threads, ...doneThreads])); // Store threads that completed this iteration for testing and other // internal purposes. this._lastStepDoneThreads = doneThreads; @@ -2160,7 +2164,7 @@ class Runtime extends EventEmitter { * @param {!Array.} threads The set of threads to look through. * @return {number} The number of monitor threads in threads. */ - _getMonitorThreadCount (threads) { + _getMonitorThreadCount(threads) { let count = 0; threads.forEach(thread => { if (thread.updateMonitor) count++; @@ -2171,15 +2175,15 @@ class Runtime extends EventEmitter { /** * Queue monitor blocks to sequencer to be run. */ - _pushMonitors () { + _pushMonitors() { this.monitorBlocks.runAllMonitored(this); } /** * Set the current editing target known by the runtime. - * @param {!Target} editingTarget New editing target. + * @param {!import("./target")} editingTarget New editing target. */ - setEditingTarget (editingTarget) { + setEditingTarget(editingTarget) { const oldEditingTarget = this._editingTarget; this._editingTarget = editingTarget; // Script glows must be cleared. @@ -2195,7 +2199,7 @@ class Runtime extends EventEmitter { * Set whether we are in 30 TPS compatibility mode. * @param {boolean} compatibilityModeOn True iff in compatibility mode. */ - setCompatibilityMode (compatibilityModeOn) { + setCompatibilityMode(compatibilityModeOn) { this.compatibilityMode = compatibilityModeOn; if (this._steppingInterval) { clearInterval(this._steppingInterval); @@ -2209,7 +2213,7 @@ class Runtime extends EventEmitter { * Looks at `this.threads` and notices which have turned on/off new glows. * @param {Array.=} optExtraThreads Optional list of inactive threads. */ - _updateGlows (optExtraThreads) { + _updateGlows(optExtraThreads) { const searchThreads = []; searchThreads.push(...this.threads); if (optExtraThreads) { @@ -2267,7 +2271,7 @@ class Runtime extends EventEmitter { * * @param {number} nonMonitorThreadCount The new nonMonitorThreadCount */ - _emitProjectRunStatus (nonMonitorThreadCount) { + _emitProjectRunStatus(nonMonitorThreadCount) { if (this._nonMonitorThreadCount === 0 && nonMonitorThreadCount > 0) { this.emit(Runtime.PROJECT_RUN_START); } @@ -2283,7 +2287,7 @@ class Runtime extends EventEmitter { * still be tracking glow data about it. * @param {!string} scriptBlockId Id of top-level block in script to quiet. */ - quietGlow (scriptBlockId) { + quietGlow(scriptBlockId) { const index = this._scriptGlowsPreviousFrame.indexOf(scriptBlockId); if (index > -1) { this._scriptGlowsPreviousFrame.splice(index, 1); @@ -2295,11 +2299,11 @@ class Runtime extends EventEmitter { * @param {?string} blockId ID for the block to update glow * @param {boolean} isGlowing True to turn on glow; false to turn off. */ - glowBlock (blockId, isGlowing) { + glowBlock(blockId, isGlowing) { if (isGlowing) { - this.emit(Runtime.BLOCK_GLOW_ON, {id: blockId}); + this.emit(Runtime.BLOCK_GLOW_ON, { id: blockId }); } else { - this.emit(Runtime.BLOCK_GLOW_OFF, {id: blockId}); + this.emit(Runtime.BLOCK_GLOW_OFF, { id: blockId }); } } @@ -2308,11 +2312,11 @@ class Runtime extends EventEmitter { * @param {?string} topBlockId ID for the top block to update glow * @param {boolean} isGlowing True to turn on glow; false to turn off. */ - glowScript (topBlockId, isGlowing) { + glowScript(topBlockId, isGlowing) { if (isGlowing) { - this.emit(Runtime.SCRIPT_GLOW_ON, {id: topBlockId}); + this.emit(Runtime.SCRIPT_GLOW_ON, { id: topBlockId }); } else { - this.emit(Runtime.SCRIPT_GLOW_OFF, {id: topBlockId}); + this.emit(Runtime.SCRIPT_GLOW_OFF, { id: topBlockId }); } } @@ -2320,7 +2324,7 @@ class Runtime extends EventEmitter { * Emit whether blocks are being dragged over gui * @param {boolean} areBlocksOverGui True if blocks are dragged out of blocks workspace, false otherwise */ - emitBlockDragUpdate (areBlocksOverGui) { + emitBlockDragUpdate(areBlocksOverGui) { this.emit(Runtime.BLOCK_DRAG_UPDATE, areBlocksOverGui); } @@ -2329,7 +2333,7 @@ class Runtime extends EventEmitter { * @param {Array.} blocks The set of blocks dragged to the GUI * @param {string} topBlockId The original id of the top block being dragged */ - emitBlockEndDrag (blocks, topBlockId) { + emitBlockEndDrag(blocks, topBlockId) { this.emit(Runtime.BLOCK_DRAG_END, blocks, topBlockId); } @@ -2338,16 +2342,16 @@ class Runtime extends EventEmitter { * @param {string} blockId ID for the block. * @param {string} value Value to show associated with the block. */ - visualReport (blockId, value) { - this.emit(Runtime.VISUAL_REPORT, {id: blockId, value: String(value)}); + visualReport(blockId, value) { + this.emit(Runtime.VISUAL_REPORT, { id: blockId, value: String(value) }); } /** * Add a monitor to the state. If the monitor already exists in the state, * updates those properties that are defined in the given monitor record. - * @param {!MonitorRecord} monitor Monitor to add. + * @param {!import("./monitor-record")} monitor Monitor to add. */ - requestAddMonitor (monitor) { + requestAddMonitor(monitor) { const id = monitor.get('id'); if (!this.requestUpdateMonitor(monitor)) { // update monitor if it exists in the state // if the monitor did not exist in the state, add it @@ -2362,7 +2366,7 @@ class Runtime extends EventEmitter { * the old monitor will keep its old value. * @return {boolean} true if monitor exists in the state and was updated, false if it did not exist. */ - requestUpdateMonitor (monitor) { + requestUpdateMonitor(monitor) { const id = monitor.get('id'); if (this._monitorState.has(id)) { this._monitorState = @@ -2383,7 +2387,7 @@ class Runtime extends EventEmitter { * not exist in the state. * @param {!string} monitorId ID of the monitor to remove. */ - requestRemoveMonitor (monitorId) { + requestRemoveMonitor(monitorId) { this._monitorState = this._monitorState.delete(monitorId); } @@ -2392,7 +2396,7 @@ class Runtime extends EventEmitter { * @param {!string} monitorId ID of the monitor to hide. * @return {boolean} true if monitor exists and was updated, false otherwise */ - requestHideMonitor (monitorId) { + requestHideMonitor(monitorId) { return this.requestUpdateMonitor(new Map([ ['id', monitorId], ['visible', false] @@ -2405,7 +2409,7 @@ class Runtime extends EventEmitter { * @param {!string} monitorId ID of the monitor to show. * @return {boolean} true if monitor exists and was updated, false otherwise */ - requestShowMonitor (monitorId) { + requestShowMonitor(monitorId) { return this.requestUpdateMonitor(new Map([ ['id', monitorId], ['visible', true] @@ -2417,16 +2421,16 @@ class Runtime extends EventEmitter { * the monitor already does not exist in the state. * @param {!string} targetId Remove all monitors with given target ID. */ - requestRemoveMonitorByTargetId (targetId) { + requestRemoveMonitorByTargetId(targetId) { this._monitorState = this._monitorState.filterNot(value => value.targetId === targetId); } /** * Get a target by its id. * @param {string} targetId Id of target to find. - * @return {?Target} The target, if found. + * @return {?import("./target")} The target, if found. */ - getTargetById (targetId) { + getTargetById(targetId) { for (let i = 0; i < this.targets.length; i++) { const target = this.targets[i]; if (target.id === targetId) { @@ -2438,9 +2442,9 @@ class Runtime extends EventEmitter { /** * Get the first original (non-clone-block-created) sprite given a name. * @param {string} spriteName Name of sprite to look for. - * @return {?Target} Target representing a sprite of the given name. + * @return {?import("./target")} Target representing a sprite of the given name. */ - getSpriteTargetByName (spriteName) { + getSpriteTargetByName(spriteName) { for (let i = 0; i < this.targets.length; i++) { const target = this.targets[i]; if (target.isStage) { @@ -2455,9 +2459,9 @@ class Runtime extends EventEmitter { /** * Get a target by its drawable id. * @param {number} drawableID drawable id of target to find - * @return {?Target} The target, if found + * @return {?import("./target")} The target, if found */ - getTargetByDrawableId (drawableID) { + getTargetByDrawableId(drawableID) { for (let i = 0; i < this.targets.length; i++) { const target = this.targets[i]; if (target.drawableID === drawableID) return target; @@ -2468,7 +2472,7 @@ class Runtime extends EventEmitter { * Update the clone counter to track how many clones are created. * @param {number} changeAmount How many clones have been created/destroyed. */ - changeCloneCounter (changeAmount) { + changeCloneCounter(changeAmount) { this._cloneCounter += changeAmount; } @@ -2476,14 +2480,14 @@ class Runtime extends EventEmitter { * Return whether there are clones available. * @return {boolean} True until the number of clones hits Runtime.MAX_CLONES. */ - clonesAvailable () { + clonesAvailable() { return this._cloneCounter < Runtime.MAX_CLONES; } /** * Handle that the project has loaded in the Virtual Machine. */ - handleProjectLoaded () { + handleProjectLoaded() { this.emit(Runtime.PROJECT_LOADED); this.resetRunId(); } @@ -2491,34 +2495,34 @@ class Runtime extends EventEmitter { /** * Report that the project has changed in a way that would affect serialization */ - emitProjectChanged () { + emitProjectChanged() { this.emit(Runtime.PROJECT_CHANGED); } /** * Report that a new target has been created, possibly by cloning an existing target. - * @param {Target} newTarget - the newly created target. - * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @param {import("./target")} newTarget - the newly created target. + * @param {import("./target")} [sourceTarget] - the target used as a source for the new clone, if any. * @fires Runtime#targetWasCreated */ - fireTargetWasCreated (newTarget, sourceTarget) { + fireTargetWasCreated(newTarget, sourceTarget) { this.emit('targetWasCreated', newTarget, sourceTarget); } /** * Report that a clone target is being removed. - * @param {Target} target - the target being removed + * @param {import("./target")} target - the target being removed * @fires Runtime#targetWasRemoved */ - fireTargetWasRemoved (target) { + fireTargetWasRemoved(target) { this.emit('targetWasRemoved', target); } /** * Get a target representing the Scratch stage, if one exists. - * @return {?Target} The target, if found. + * @return {?import("./target")} The target, if found. */ - getTargetForStage () { + getTargetForStage() { for (let i = 0; i < this.targets.length; i++) { const target = this.targets[i]; if (target.isStage) { @@ -2529,13 +2533,13 @@ class Runtime extends EventEmitter { /** * Get the editing target. - * @return {?Target} The editing target. + * @return {?import("./target")} The editing target. */ - getEditingTarget () { + getEditingTarget() { return this._editingTarget; } - getAllVarNamesOfType (varType) { + getAllVarNamesOfType(varType) { let varNames = []; for (const target of this.targets) { const targetVarNames = target.getAllVariableNamesInScopeByType(varType, true); @@ -2552,7 +2556,7 @@ class Runtime extends EventEmitter { * @property {Function} [labelFn] - function to generate the label for this opcode * @property {string} [label] - the label for this opcode if `labelFn` is absent */ - getLabelForOpcode (extendedOpcode) { + getLabelForOpcode(extendedOpcode) { const [category, opcode] = StringUtil.splitFirst(extendedOpcode, '_'); if (!(category && opcode)) return; @@ -2578,7 +2582,7 @@ class Runtime extends EventEmitter { * @param {string} optVarType The type of the variable to create. Defaults to Variable.SCALAR_TYPE. * @return {Variable} The new variable that was created. */ - createNewGlobalVariable (variableName, optVarId, optVarType) { + createNewGlobalVariable(variableName, optVarId, optVarType) { const varType = (typeof optVarType === 'string') ? optVarType : Variable.SCALAR_TYPE; const allVariableNames = this.getAllVarNamesOfType(varType); const newName = StringUtil.unusedName(variableName, allVariableNames); @@ -2592,16 +2596,16 @@ class Runtime extends EventEmitter { * Tell the runtime to request a redraw. * Use after a clone/sprite has completed some visible operation on the stage. */ - requestRedraw () { + requestRedraw() { this.redrawRequested = true; } /** * Emit a targets update at the end of the step if the provided target is * the original sprite - * @param {!Target} target Target requesting the targets update + * @param {!import("./target")} target Target requesting the targets update */ - requestTargetsUpdate (target) { + requestTargetsUpdate(target) { if (!target.isOriginal) return; this._refreshTargets = true; } @@ -2609,21 +2613,21 @@ class Runtime extends EventEmitter { /** * Emit an event that indicates that the blocks on the workspace need updating. */ - requestBlocksUpdate () { + requestBlocksUpdate() { this.emit(Runtime.BLOCKS_NEED_UPDATE); } /** * Emit an event that indicates that the toolbox extension blocks need updating. */ - requestToolboxExtensionsUpdate () { + requestToolboxExtensionsUpdate() { this.emit(Runtime.TOOLBOX_EXTENSIONS_NEED_UPDATE); } /** * Set up timers to repeatedly step in a browser. */ - start () { + start() { // Do not start if we are already running if (this._steppingInterval) return; @@ -2642,7 +2646,7 @@ class Runtime extends EventEmitter { * Quit the Runtime, clearing any handles which might keep the process alive. * Do not use the runtime after calling this method. This method is meant for test shutdown. */ - quit () { + quit() { clearInterval(this._steppingInterval); this._steppingInterval = null; } @@ -2652,7 +2656,7 @@ class Runtime extends EventEmitter { * @param {Profiler/FrameCallback} onFrame A callback handle passed a * profiling frame when the profiler reports its collected data. */ - enableProfiling (onFrame) { + enableProfiling(onFrame) { if (Profiler.available()) { this.profiler = new Profiler(onFrame); } @@ -2661,7 +2665,7 @@ class Runtime extends EventEmitter { /** * Turn off profiling. */ - disableProfiling () { + disableProfiling() { this.profiler = null; } @@ -2670,17 +2674,74 @@ class Runtime extends EventEmitter { * This value is helpful in certain instances for compatibility with Scratch 2, * which sometimes uses a `currentMSecs` timestamp value in Interpreter.as */ - updateCurrentMSecs () { + updateCurrentMSecs() { this.currentMSecs = Date.now(); } + + + /* PRG ADDITIONS BEGIN */ + + /** + * Get a refernce to the extension manager + * @returns {import("../extension-support/extension-manager")} + */ + getExtensionManager() { + // Bad form to access this method since it's naming (i.e. leading underscore) suggests it should be private + return dispatch._getServiceProvider("extensions")?.provider; + } + + /** + * Loads a costume asset in + */ + addCostume(costume) { + return loadCostume(costume.md5, costume, this) + } + + /** + * Event name for trigger the worskpace to update with a specified collection of new 'programatically added' blocks + * @const {string} + */ + static get ADD_BLOCKS_TO_WORKSPACE() { + return 'ADD_BLOCKS_TO_WORKSPACE'; + } + + /** + * Try to retrieve the audio engine attached to this runtime + * @returns {Promise} + */ + awaitAudioEngine() { + const maxAttempts = 5; + const attemptIntervalMs = 500; + const self = this; + return new Promise((resolve, reject) => { + let attempts = 0; + const interval = setInterval(() => { + const { audioEngine } = self; + if (audioEngine) { + clearInterval(interval); + resolve(audioEngine); + } + else if (++attempts > maxAttempts) { + reject(); + } + }, attemptIntervalMs); // (*) + }) + .catch(new Error('No Audio Context Detected')); + } + + addBlocksToWorkspace(xmlToAdd) { + this.emit(Runtime.ADD_BLOCKS_TO_WORKSPACE, xmlToAdd); + } + + /** PRG ADDITIONS END */ } /** * Event fired after a new target has been created, possibly by cloning an existing target. * * @event Runtime#targetWasCreated - * @param {Target} newTarget - the newly created target. - * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @param {import("./target")} newTarget - the newly created target. + * @param {import("./target")} [sourceTarget] - the target used as a source for the new clone, if any. */ module.exports = Runtime; diff --git a/src/engine/scratch-blocks-constants.js b/src/engine/scratch-blocks-constants.js index ee558549705..40117cce0ad 100644 --- a/src/engine/scratch-blocks-constants.js +++ b/src/engine/scratch-blocks-constants.js @@ -2,7 +2,7 @@ * These constants are copied from scratch-blocks/core/constants.js * @TODO find a way to require() these straight from scratch-blocks... maybe make a scratch-blocks/dist/constants.js? * @readonly - * @enum {int} + * @enum {number} */ const ScratchBlocksConstants = { /** diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index 504a3e078d1..9cd8f7e694a 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -48,7 +48,7 @@ class Sequencer { /** * Reference to the runtime owning this sequencer. - * @type {!Runtime} + * @type {!import("./runtime")} */ this.runtime = runtime; diff --git a/src/engine/target.js b/src/engine/target.js index 166e443697b..d48d2543636 100644 --- a/src/engine/target.js +++ b/src/engine/target.js @@ -4,7 +4,7 @@ const Blocks = require('./blocks'); const Variable = require('../engine/variable'); const Comment = require('../engine/comment'); const uid = require('../util/uid'); -const {Map} = require('immutable'); +const { Map } = require('immutable'); const log = require('../util/log'); const StringUtil = require('../util/string-util'); const VariableUtil = require('../util/variable-util'); @@ -18,11 +18,11 @@ const VariableUtil = require('../util/variable-util'); class Target extends EventEmitter { /** - * @param {Runtime} runtime Reference to the runtime. + * @param {import("./runtime")} runtime Reference to the runtime. * @param {?Blocks} blocks Blocks instance for the blocks owned by this target. * @constructor */ - constructor (runtime, blocks) { + constructor(runtime, blocks) { super(); if (!blocks) { @@ -31,7 +31,7 @@ class Target extends EventEmitter { /** * Reference to the runtime. - * @type {Runtime} + * @type {import("./runtime")} */ this.runtime = runtime; /** @@ -76,7 +76,7 @@ class Target extends EventEmitter { * Called when the project receives a "green flag." * @abstract */ - onGreenFlag () {} + onGreenFlag() { } /** * Return a human-readable name for this target. @@ -84,7 +84,7 @@ class Target extends EventEmitter { * @abstract * @returns {string} Human-readable name for the target. */ - getName () { + getName() { return this.id; } @@ -94,20 +94,20 @@ class Target extends EventEmitter { * @param {*} newValue Value to store for edge-activated hat. * @return {*} The old value for the edge-activated hat. */ - updateEdgeActivatedValue (blockId, newValue) { + updateEdgeActivatedValue(blockId, newValue) { const oldValue = this._edgeActivatedHatValues[blockId]; this._edgeActivatedHatValues[blockId] = newValue; return oldValue; } - hasEdgeActivatedValue (blockId) { + hasEdgeActivatedValue(blockId) { return Object.prototype.hasOwnProperty.call(this._edgeActivatedHatValues, blockId); } /** * Clear all edge-activaed hat values. */ - clearEdgeActivatedValues () { + clearEdgeActivatedValues() { this._edgeActivatedHatValues = {}; } @@ -118,7 +118,7 @@ class Target extends EventEmitter { * @param {string} name Name of the variable. * @return {!Variable} Variable object. */ - lookupOrCreateVariable (id, name) { + lookupOrCreateVariable(id, name) { let variable = this.lookupVariableById(id); if (variable) return variable; @@ -138,7 +138,7 @@ class Target extends EventEmitter { * @param {string} name Name of the variable. * @return {?Variable} Variable object. */ - lookupBroadcastMsg (id, name) { + lookupBroadcastMsg(id, name) { let broadcastMsg; if (id) { broadcastMsg = this.lookupVariableById(id); @@ -167,7 +167,7 @@ class Target extends EventEmitter { * @param {string} name Name of the variable. * @return {?Variable} Variable object. */ - lookupBroadcastByInputValue (name) { + lookupBroadcastByInputValue(name) { const vars = this.variables; for (const propName in vars) { if ((vars[propName].type === Variable.BROADCAST_MESSAGE_TYPE) && @@ -184,7 +184,7 @@ class Target extends EventEmitter { * @param {string} name Name of the variable. * @return {!Variable} Variable object. */ - lookupVariableById (id) { + lookupVariableById(id) { // If we have a local copy, return it. if (Object.prototype.hasOwnProperty.call(this.variables, id)) { return this.variables[id]; @@ -204,10 +204,10 @@ class Target extends EventEmitter { * was not found. * @param {string} name Name of the variable. * @param {string} type Type of the variable. Defaults to Variable.SCALAR_TYPE. - * @param {?bool} skipStage Optional flag to skip checking the stage + * @param {?boolean} skipStage Optional flag to skip checking the stage * @return {?Variable} Variable object if found, or null if not. */ - lookupVariableByNameAndType (name, type, skipStage) { + lookupVariableByNameAndType(name, type, skipStage) { if (typeof name !== 'string') return; if (typeof type !== 'string') type = Variable.SCALAR_TYPE; skipStage = skipStage || false; @@ -239,9 +239,9 @@ class Target extends EventEmitter { * Search begins for local lists; then look for globals. * @param {!string} id Id of the list. * @param {!string} name Name of the list. - * @return {!Varible} Variable object representing the found/created list. + * @return {!Variable} Variable object representing the found/created list. */ - lookupOrCreateList (id, name) { + lookupOrCreateList(id, name) { let list = this.lookupVariableById(id); if (list) return list; @@ -263,7 +263,7 @@ class Target extends EventEmitter { * @param {boolean} isCloud Whether the variable to create has the isCloud flag set. * Additional checks are made that the variable can be created as a cloud variable. */ - createVariable (id, name, type, isCloud) { + createVariable(id, name, type, isCloud) { if (!Object.prototype.hasOwnProperty.call(this.variables, id)) { const newVariable = new Variable(id, name, type, false); if (isCloud && this.isStage && this.runtime.canAddCloudVariable()) { @@ -287,7 +287,7 @@ class Target extends EventEmitter { * @param {number} height The height of the comment when it is full size * @param {boolean} minimized Whether the comment is minimized. */ - createComment (id, blockId, text, x, y, width, height, minimized) { + createComment(id, blockId, text, x, y, width, height, minimized) { if (!Object.prototype.hasOwnProperty.call(this.comments, id)) { const newComment = new Comment(id, text, x, y, width, height, minimized); @@ -298,7 +298,7 @@ class Target extends EventEmitter { blockWithComment.comment = id; } else { log.warn(`Could not find block with id ${blockId - } associated with commentId: ${id}`); + } associated with commentId: ${id}`); } } this.comments[id] = newComment; @@ -310,7 +310,7 @@ class Target extends EventEmitter { * @param {string} id Id of variable to rename. * @param {string} newName New name for the variable. */ - renameVariable (id, newName) { + renameVariable(id, newName) { if (Object.prototype.hasOwnProperty.call(this.variables, id)) { const variable = this.variables[id]; if (variable.id === id) { @@ -361,7 +361,7 @@ class Target extends EventEmitter { * Removes the variable with the given id from the dictionary of variables. * @param {string} id Id of variable to delete. */ - deleteVariable (id) { + deleteVariable(id) { if (Object.prototype.hasOwnProperty.call(this.variables, id)) { // Get info about the variable before deleting it const deletedVariableName = this.variables[id].name; @@ -383,7 +383,7 @@ class Target extends EventEmitter { * target-specific monitored blocks (e.g. local variables, global variables for the stage, x-position). * NOTE: This does not delete any of the stage monitors like backdrop name. */ - deleteMonitors () { + deleteMonitors() { this.runtime.requestRemoveMonitorByTargetId(this.id); let targetSpecificMonitorBlockIds; if (this.isStage) { @@ -407,7 +407,7 @@ class Target extends EventEmitter { * @return {?Variable} The duplicated variable, or null if * the original variable was not found. */ - duplicateVariable (id, optKeepOriginalId) { + duplicateVariable(id, optKeepOriginalId) { if (Object.prototype.hasOwnProperty.call(this.variables, id)) { const originalVariable = this.variables[id]; const newVariable = new Variable( @@ -434,7 +434,7 @@ class Target extends EventEmitter { * in this blocks container will be updated to refer to the corresponding new IDs. * @return {object} The duplicated dictionary of variables */ - duplicateVariables (optBlocks) { + duplicateVariables(optBlocks) { let allVarRefs; if (optBlocks) { allVarRefs = optBlocks.getAllVariableAndListReferences(); @@ -457,14 +457,14 @@ class Target extends EventEmitter { * @param {object} data An object with sprite info data to set. * @abstract */ - postSpriteInfo () {} + postSpriteInfo() { } /** * Retrieve custom state associated with this target and the provided state ID. * @param {string} stateId - specify which piece of state to retrieve. * @returns {*} the associated state, if any was found. */ - getCustomState (stateId) { + getCustomState(stateId) { return this._customState[stateId]; } @@ -473,7 +473,7 @@ class Target extends EventEmitter { * @param {string} stateId - specify which piece of state to store on this target. * @param {*} newValue - the state value to store. */ - setCustomState (stateId, newValue) { + setCustomState(stateId, newValue) { this._customState[stateId] = newValue; } @@ -481,7 +481,7 @@ class Target extends EventEmitter { * Call to destroy a target. * @abstract */ - dispose () { + dispose() { this._customState = {}; if (this.runtime) { @@ -497,10 +497,10 @@ class Target extends EventEmitter { * variables as well as any stage variables unless the skipStage flag is true. * For the stage, this is all stage variables. * @param {string} type The variable type to search for; defaults to Variable.SCALAR_TYPE - * @param {?bool} skipStage Optional flag to skip the stage. + * @param {?boolean} skipStage Optional flag to skip the stage. * @return {Array} A list of variable names */ - getAllVariableNamesInScopeByType (type, skipStage) { + getAllVariableNamesInScopeByType(type, skipStage) { if (typeof type !== 'string') type = Variable.SCALAR_TYPE; skipStage = skipStage || false; const targetVariables = Object.values(this.variables) @@ -524,7 +524,7 @@ class Target extends EventEmitter { * variable name in the references being updated should be replaced with this new name. * If this parameter is not provided or is '', no name change occurs. */ - mergeVariables (idToBeMerged, idToMergeWith, optReferencesToUpdate, optNewName) { + mergeVariables(idToBeMerged, idToMergeWith, optReferencesToUpdate, optNewName) { const referencesToChange = optReferencesToUpdate || // TODO should there be a separate helper function that traverses the blocks // for all references for a given ID instead of doing the below..? @@ -540,7 +540,7 @@ class Target extends EventEmitter { * that reference the given variable ID. The names and IDs of these variable * references will be updated to refer to the new (or pre-existing) global variable. */ - shareLocalVariableToStage (varId, varRefs) { + shareLocalVariableToStage(varId, varRefs) { if (!this.runtime) return; const variable = this.variables[varId]; if (!variable) { @@ -578,7 +578,7 @@ class Target extends EventEmitter { * @param {Target} sprite The sprite to share the variable with * @param {Array} varRefs A list of all the variable references currently being shared. */ - shareLocalVariableToSprite (varId, sprite, varRefs) { + shareLocalVariableToSprite(varId, sprite, varRefs) { if (!this.runtime) return; if (this.isStage) return; const variable = this.variables[varId]; @@ -629,7 +629,7 @@ class Target extends EventEmitter { * potential conflicting references to variables. * @param {Target} receivingTarget The target receiving the variables */ - resolveVariableSharingConflictsWithTarget (blocks, receivingTarget) { + resolveVariableSharingConflictsWithTarget(blocks, receivingTarget) { if (this.isStage) return; // Get all the variable references in the given list of blocks @@ -673,7 +673,7 @@ class Target extends EventEmitter { * All blocks that reference the local variable will be updated to use the new name. */ // TODO (#1360) This function is too long, add some helpers for the different chunks and cases... - fixUpVariableReferences () { + fixUpVariableReferences() { if (!this.runtime) return; // There's no runtime context to conflict with if (this.isStage) return; // Stage can't have variable conflicts with itself (and also can't be uploaded) const stage = this.runtime.getTargetForStage(); diff --git a/src/engine/thread.js b/src/engine/thread.js index 6094a8254e4..4d06d3f5b72 100644 --- a/src/engine/thread.js +++ b/src/engine/thread.js @@ -12,7 +12,7 @@ const _stackFrameFreeList = []; * @private */ class _StackFrame { - constructor (warpMode) { + constructor(warpMode) { /** * Whether this level of the stack is a loop. * @type {boolean} @@ -68,7 +68,7 @@ class _StackFrame { * Used to recycle. * @return {_StackFrame} this */ - reset () { + reset() { this.isLoop = false; this.warpMode = false; @@ -86,7 +86,7 @@ class _StackFrame { * @param {?boolean} warpMode defaults to current warpMode * @returns {_StackFrame} this */ - reuse (warpMode = this.warpMode) { + reuse(warpMode = this.warpMode) { this.reset(); this.warpMode = Boolean(warpMode); return this; @@ -97,7 +97,7 @@ class _StackFrame { * @param {boolean} warpMode Enable warpMode on this frame. * @returns {_StackFrame} The clean stack frame with correct warpMode setting. */ - static create (warpMode) { + static create(warpMode) { const stackFrame = _stackFrameFreeList.pop(); if (typeof stackFrame !== 'undefined') { stackFrame.warpMode = Boolean(warpMode); @@ -110,7 +110,7 @@ class _StackFrame { * Put a stack frame object into the recycle bin for reuse. * @param {_StackFrame} stackFrame The frame to reset and recycle. */ - static release (stackFrame) { + static release(stackFrame) { if (typeof stackFrame !== 'undefined') { _stackFrameFreeList.push(stackFrame.reset()); } @@ -123,7 +123,7 @@ class _StackFrame { * @constructor */ class Thread { - constructor (firstBlock) { + constructor(firstBlock) { /** * ID of top block of the thread * @type {!string} @@ -157,13 +157,13 @@ class Thread { /** * Target of this thread. - * @type {?Target} + * @type {?import("./target")} */ this.target = null; /** * The Blocks this thread will execute. - * @type {Blocks} + * @type {import("./blocks")} */ this.blockContainer = null; @@ -182,7 +182,7 @@ class Thread { /** * A timer for when the thread enters warp mode. * Substitutes the sequencer's count toward WORK_TIME on a per-thread basis. - * @type {?Timer} + * @type {?import("../util/timer")} */ this.warpTimer = null; @@ -195,7 +195,7 @@ class Thread { * stepping from block to block. * @const */ - static get STATUS_RUNNING () { + static get STATUS_RUNNING() { return 0; } @@ -204,7 +204,7 @@ class Thread { * execution is paused until the promise changes thread status. * @const */ - static get STATUS_PROMISE_WAIT () { + static get STATUS_PROMISE_WAIT() { return 1; } @@ -212,7 +212,7 @@ class Thread { * Thread status for yield. * @const */ - static get STATUS_YIELD () { + static get STATUS_YIELD() { return 2; } @@ -221,7 +221,7 @@ class Thread { * thread is resumed. * @const */ - static get STATUS_YIELD_TICK () { + static get STATUS_YIELD_TICK() { return 3; } @@ -230,7 +230,7 @@ class Thread { * Thread is in this state when there are no more blocks to execute. * @const */ - static get STATUS_DONE () { + static get STATUS_DONE() { return 4; } @@ -238,7 +238,7 @@ class Thread { * Push stack and update stack frames appropriately. * @param {string} blockId Block ID to push to stack. */ - pushStack (blockId) { + pushStack(blockId) { this.stack.push(blockId); // Push an empty stack frame, if we need one. // Might not, if we just popped the stack. @@ -253,7 +253,7 @@ class Thread { * (avoids popping and re-pushing a new stack frame - keeps the warpmode the same * @param {string} blockId Block ID to push to stack. */ - reuseStackForNextBlock (blockId) { + reuseStackForNextBlock(blockId) { this.stack[this.stack.length - 1] = blockId; this.stackFrames[this.stackFrames.length - 1].reuse(); } @@ -262,7 +262,7 @@ class Thread { * Pop last block on the stack and its stack frame. * @return {string} Block ID popped from the stack. */ - popStack () { + popStack() { _StackFrame.release(this.stackFrames.pop()); return this.stack.pop(); } @@ -270,7 +270,7 @@ class Thread { /** * Pop back down the stack frame until we hit a procedure call or the stack frame is emptied */ - stopThisScript () { + stopThisScript() { let blockID = this.peekStack(); while (blockID !== null) { const block = this.target.blocks.getBlock(blockID); @@ -292,24 +292,24 @@ class Thread { * Get top stack item. * @return {?string} Block ID on top of stack. */ - peekStack () { + peekStack() { return this.stack.length > 0 ? this.stack[this.stack.length - 1] : null; } /** * Get top stack frame. - * @return {?object} Last stack frame stored on this thread. + * @return {?_StackFrame} Last stack frame stored on this thread. */ - peekStackFrame () { + peekStackFrame() { return this.stackFrames.length > 0 ? this.stackFrames[this.stackFrames.length - 1] : null; } /** * Get stack frame above the current top. - * @return {?object} Second to last stack frame stored on this thread. + * @return {?_StackFrame} Second to last stack frame stored on this thread. */ - peekParentStackFrame () { + peekParentStackFrame() { return this.stackFrames.length > 1 ? this.stackFrames[this.stackFrames.length - 2] : null; } @@ -317,14 +317,14 @@ class Thread { * Push a reported value to the parent of the current stack frame. * @param {*} value Reported value to push. */ - pushReportedValue (value) { + pushReportedValue(value) { this.justReported = typeof value === 'undefined' ? null : value; } /** * Initialize procedure parameters on this stack frame. */ - initParams () { + initParams() { const stackFrame = this.peekStackFrame(); if (stackFrame.params === null) { stackFrame.params = {}; @@ -337,7 +337,7 @@ class Thread { * @param {!string} paramName Name of parameter. * @param {*} value Value to set for parameter. */ - pushParam (paramName, value) { + pushParam(paramName, value) { const stackFrame = this.peekStackFrame(); stackFrame.params[paramName] = value; } @@ -347,7 +347,7 @@ class Thread { * @param {!string} paramName Name of parameter. * @return {*} value Value for parameter. */ - getParam (paramName) { + getParam(paramName) { for (let i = this.stackFrames.length - 1; i >= 0; i--) { const frame = this.stackFrames[i]; if (frame.params === null) { @@ -365,7 +365,7 @@ class Thread { * Whether the current execution of a thread is at the top of the stack. * @return {boolean} True if execution is at top of the stack. */ - atStackTop () { + atStackTop() { return this.peekStack() === this.topBlock; } @@ -375,7 +375,7 @@ class Thread { * For example, this is used in a standard sequence of blocks, * where execution proceeds from one block to the next. */ - goToNextBlock () { + goToNextBlock() { const nextBlockId = this.target.blocks.getNextBlock(this.peekStack()); this.reuseStackForNextBlock(nextBlockId); } @@ -386,7 +386,7 @@ class Thread { * @param {!string} procedureCode Procedure code of procedure being called. * @return {boolean} True if the call appears recursive. */ - isRecursiveCall (procedureCode) { + isRecursiveCall(procedureCode) { let callCount = 5; // Max number of enclosing procedure calls to examine. const sp = this.stack.length - 1; for (let i = sp - 1; i >= 0; i--) { diff --git a/src/extension-support/define-messages.js b/src/extension-support/define-messages.js index 0ca9b4b5baa..6db39bbeccf 100644 --- a/src/extension-support/define-messages.js +++ b/src/extension-support/define-messages.js @@ -8,8 +8,8 @@ /** * This is a hook for extracting messages from extension source files. * This function simply returns the message descriptor map object that's passed in. - * @param {object.} messages - the messages to be defined - * @return {object.} - the input, unprocessed + * @param {Object.} messages - the messages to be defined + * @return {Object.} - the input, unprocessed */ const defineMessages = function (messages) { return messages; diff --git a/src/extension-support/extension-manager.js b/src/extension-support/extension-manager.js index 94ce3b1a085..ac9f3dd696a 100644 --- a/src/extension-support/extension-manager.js +++ b/src/extension-support/extension-manager.js @@ -1,8 +1,15 @@ const dispatch = require('../dispatch/central-dispatch'); const log = require('../util/log'); const maybeFormatMessage = require('../util/maybe-format-message'); - const BlockType = require('./block-type'); +/** BEGIN PRG Additions */ +const { tryInitExtension, tryGetExtensionConstructorFromBundle, tryGetAuxiliaryObjectFromLoadedBundle } = require('./prg/bundle-loader'); + +const tryRetrieveExtensionConstructor = async (extensionId) => + await extensionId in builtinExtensions + ? builtinExtensions[extensionId]() + : tryGetExtensionConstructorFromBundle(extensionId); +/** END PRG Additions */ // These extensions are currently built into the VM repository but should not be loaded at startup. // TODO: move these out into a separate repository? @@ -23,7 +30,14 @@ const builtinExtensions = { ev3: () => require('../extensions/scratch3_ev3'), makeymakey: () => require('../extensions/scratch3_makeymakey'), boost: () => require('../extensions/scratch3_boost'), - gdxfor: () => require('../extensions/scratch3_gdx_for') + gdxfor: () => require('../extensions/scratch3_gdx_for'), + /** BEGIN PRG Additions */ + speech2text: () => require('../extensions/scratch3_speech2text'), + arduinoRobot: () => require('../extensions/scratch3_arduinobot'), + gizmoRobot: () => require('../extensions/scratch3_gizmo'), + microbitRobot: () => require('../extensions/scratch3_microbot'), + musiccreation: () => require('../extensions/scratch3_musiccreation'), + /** END PRG Additions */ }; /** @@ -59,7 +73,7 @@ const builtinExtensions = { */ class ExtensionManager { - constructor (runtime) { + constructor(runtime) { /** * The ID number to provide to the next extension worker. * @type {int} @@ -106,7 +120,7 @@ class ExtensionManager { * @param {string} extensionID - the ID of the extension. * @returns {boolean} - true if loaded, false otherwise. */ - isExtensionLoaded (extensionID) { + isExtensionLoaded(extensionID) { return this._loadedExtensions.has(extensionID); } @@ -115,11 +129,10 @@ class ExtensionManager { * fail if the provided id is not does not match an internal extension. * @param {string} extensionId - the ID of an internal extension */ - loadExtensionIdSync (extensionId) { - if (!Object.prototype.hasOwnProperty.call(builtinExtensions, extensionId)) { - log.warn(`Could not find extension ${extensionId} in the built in extensions.`); - return; - } + async loadExtensionIdSync(extensionId) { + const extension = await tryRetrieveExtensionConstructor(extensionId); + + if (!extension) return log.warn(`Could not find extension ${extensionId} in the built in extensions.`); /** @TODO dupe handling for non-builtin extensions. See commit 670e51d33580e8a2e852b3b038bb3afc282f81b9 */ if (this.isExtensionLoaded(extensionId)) { @@ -128,8 +141,8 @@ class ExtensionManager { return; } - const extension = builtinExtensions[extensionId](); const extensionInstance = new extension(this.runtime); + await tryInitExtension(extensionInstance); const serviceName = this._registerInternalExtension(extensionInstance); this._loadedExtensions.set(extensionId, serviceName); } @@ -139,36 +152,43 @@ class ExtensionManager { * @param {string} extensionURL - the URL for the extension to load OR the ID of an internal extension * @returns {Promise} resolved once the extension is loaded and initialized or rejected on failure */ - loadExtensionURL (extensionURL) { - if (Object.prototype.hasOwnProperty.call(builtinExtensions, extensionURL)) { + async loadExtensionURL(extensionURL) { + const extension = await tryRetrieveExtensionConstructor(extensionURL); + + if (extension) { /** @TODO dupe handling for non-builtin extensions. See commit 670e51d33580e8a2e852b3b038bb3afc282f81b9 */ if (this.isExtensionLoaded(extensionURL)) { const message = `Rejecting attempt to load a second extension with ID ${extensionURL}`; log.warn(message); - return Promise.resolve(); + return; } - - const extension = builtinExtensions[extensionURL](); const extensionInstance = new extension(this.runtime); + await tryInitExtension(extensionInstance); const serviceName = this._registerInternalExtension(extensionInstance); this._loadedExtensions.set(extensionURL, serviceName); - return Promise.resolve(); + return; } return new Promise((resolve, reject) => { // If we `require` this at the global level it breaks non-webpack targets, including tests const worker = new Worker('./extension-worker.js'); - this.pendingExtensions.push({extensionURL, resolve, reject}); + this.pendingExtensions.push({ extensionURL, resolve, reject }); dispatch.addWorker(worker); }); } + /** Begin PRG Additions */ + getLoadedExtensionIDs() { return Array.from(this._loadedExtensions.keys()) } + getExtensionInstance(id) { return this._loadedExtensions.has(id) ? dispatch.services[this._loadedExtensions.get(id)] : undefined } + getAuxiliaryObject(extensionID, name) { return tryGetAuxiliaryObjectFromLoadedBundle(extensionID, name) }; + /** END PRG Additions */ + /** * Regenerate blockinfo for any loaded extensions * @returns {Promise} resolved once all the extensions have been reinitialized */ - refreshBlocks () { + refreshBlocks() { const allPromises = Array.from(this._loadedExtensions.values()).map(serviceName => dispatch.call(serviceName, 'getInfo') .then(info => { @@ -182,7 +202,7 @@ class ExtensionManager { return Promise.all(allPromises); } - allocateWorker () { + allocateWorker() { const id = this.nextExtensionWorker++; const workerInfo = this.pendingExtensions.shift(); this.pendingWorkers[id] = workerInfo; @@ -193,7 +213,7 @@ class ExtensionManager { * Synchronously collect extension metadata from the specified service and begin the extension registration process. * @param {string} serviceName - the name of the service hosting the extension. */ - registerExtensionServiceSync (serviceName) { + registerExtensionServiceSync(serviceName) { const info = dispatch.callSync(serviceName, 'getInfo'); this._registerExtensionInfo(serviceName, info); } @@ -202,7 +222,7 @@ class ExtensionManager { * Collect extension metadata from the specified service and begin the extension registration process. * @param {string} serviceName - the name of the service hosting the extension. */ - registerExtensionService (serviceName) { + registerExtensionService(serviceName) { dispatch.call(serviceName, 'getInfo').then(info => { this._registerExtensionInfo(serviceName, info); }); @@ -213,7 +233,7 @@ class ExtensionManager { * @param {int} id - the worker ID. * @param {*?} e - the error encountered during initialization, if any. */ - onWorkerInit (id, e) { + onWorkerInit(id, e) { const workerInfo = this.pendingWorkers[id]; delete this.pendingWorkers[id]; if (e) { @@ -228,7 +248,7 @@ class ExtensionManager { * @param {object} extensionObject - the extension object to register * @returns {string} The name of the registered extension service */ - _registerInternalExtension (extensionObject) { + _registerInternalExtension(extensionObject) { const extensionInfo = extensionObject.getInfo(); const fakeWorkerId = this.nextExtensionWorker++; const serviceName = `extension_${fakeWorkerId}_${extensionInfo.id}`; @@ -243,7 +263,7 @@ class ExtensionManager { * @param {ExtensionInfo} extensionInfo - the extension's metadata * @private */ - _registerExtensionInfo (serviceName, extensionInfo) { + _registerExtensionInfo(serviceName, extensionInfo) { extensionInfo = this._prepareExtensionInfo(serviceName, extensionInfo); dispatch.call('runtime', '_registerExtensionPrimitives', extensionInfo).catch(e => { log.error(`Failed to register primitives for extension on service ${serviceName}:`, e); @@ -256,7 +276,7 @@ class ExtensionManager { * @returns {string} - the sanitized text * @private */ - _sanitizeID (text) { + _sanitizeID(text) { return text.toString().replace(/[<"&]/, '_'); } @@ -268,7 +288,7 @@ class ExtensionManager { * @returns {ExtensionInfo} - a new extension info object with cleaned-up values * @private */ - _prepareExtensionInfo (serviceName, extensionInfo) { + _prepareExtensionInfo(serviceName, extensionInfo) { extensionInfo = Object.assign({}, extensionInfo); if (!/^[a-z0-9]+$/i.test(extensionInfo.id)) { throw new Error('Invalid extension id'); @@ -280,12 +300,12 @@ class ExtensionManager { try { let result; switch (blockInfo) { - case '---': // separator - result = '---'; - break; - default: // an ExtensionBlockMetadata object - result = this._prepareBlockInfo(serviceName, blockInfo); - break; + case '---': // separator + result = '---'; + break; + default: // an ExtensionBlockMetadata object + result = this._prepareBlockInfo(serviceName, blockInfo); + break; } results.push(result); } catch (e) { @@ -306,7 +326,7 @@ class ExtensionManager { * @returns {Array.} - a menuInfo object with all preprocessing done. * @private */ - _prepareMenuInfo (serviceName, menus) { + _prepareMenuInfo(serviceName, menus) { const menuNames = Object.getOwnPropertyNames(menus); for (let i = 0; i < menuNames.length; i++) { const menuName = menuNames[i]; @@ -339,7 +359,7 @@ class ExtensionManager { * @returns {Array} menu items ready for scratch-blocks. * @private */ - _getExtensionMenuItems (extensionObject, menuItemFunctionName) { + _getExtensionMenuItems(extensionObject, menuItemFunctionName) { // Fetch the items appropriate for the target currently being edited. This assumes that menus only // collect items when opened by the user while editing a particular target. const editingTarget = this.runtime.getEditingTarget() || this.runtime.getTargetForStage(); @@ -348,19 +368,24 @@ class ExtensionManager { // TODO: Fix this to use dispatch.call when extensions are running in workers. const menuFunc = extensionObject[menuItemFunctionName]; - const menuItems = menuFunc.call(extensionObject, editingTargetID).map( + + /** BEGIN PRG Additions */ + const menuResult = menuFunc.call(extensionObject, editingTargetID); + + const menuItems = menuResult.map( + /** END PRG Additions */ item => { item = maybeFormatMessage(item, extensionMessageContext); switch (typeof item) { - case 'object': - return [ - maybeFormatMessage(item.text, extensionMessageContext), - item.value - ]; - case 'string': - return [item, item]; - default: - return item; + case 'object': + return [ + maybeFormatMessage(item.text, extensionMessageContext), + item.value + ]; + case 'string': + return [item, item]; + default: + return item; } }); @@ -377,7 +402,7 @@ class ExtensionManager { * @returns {ExtensionBlockMetadata} - a new block info object which has values for all relevant optional fields. * @private */ - _prepareBlockInfo (serviceName, blockInfo) { + _prepareBlockInfo(serviceName, blockInfo) { blockInfo = Object.assign({}, { blockType: BlockType.COMMAND, terminal: false, @@ -388,49 +413,49 @@ class ExtensionManager { blockInfo.text = blockInfo.text || blockInfo.opcode; switch (blockInfo.blockType) { - case BlockType.EVENT: - if (blockInfo.func) { - log.warn(`Ignoring function "${blockInfo.func}" for event block ${blockInfo.opcode}`); - } - break; - case BlockType.BUTTON: - if (blockInfo.opcode) { - log.warn(`Ignoring opcode "${blockInfo.opcode}" for button with text: ${blockInfo.text}`); - } - break; - default: { - if (!blockInfo.opcode) { - throw new Error('Missing opcode for block'); - } - - const funcName = blockInfo.func ? this._sanitizeID(blockInfo.func) : blockInfo.opcode; + case BlockType.EVENT: + if (blockInfo.func) { + log.warn(`Ignoring function "${blockInfo.func}" for event block ${blockInfo.opcode}`); + } + break; + case BlockType.BUTTON: + if (blockInfo.opcode) { + log.warn(`Ignoring opcode "${blockInfo.opcode}" for button with text: ${blockInfo.text}`); + } + break; + default: { + if (!blockInfo.opcode) { + throw new Error('Missing opcode for block'); + } - const getBlockInfo = blockInfo.isDynamic ? - args => args && args.mutation && args.mutation.blockInfo : - () => blockInfo; - const callBlockFunc = (() => { - if (dispatch._isRemoteService(serviceName)) { + const funcName = blockInfo.func ? this._sanitizeID(blockInfo.func) : blockInfo.opcode; + + const getBlockInfo = blockInfo.isDynamic ? + args => args && args.mutation && args.mutation.blockInfo : + () => blockInfo; + const callBlockFunc = (() => { + if (dispatch._isRemoteService(serviceName)) { + return (args, util, realBlockInfo) => + dispatch.call(serviceName, funcName, args, util, realBlockInfo); + } + + // avoid promise latency if we can call direct + const serviceObject = dispatch.services[serviceName]; + if (!serviceObject[funcName]) { + // The function might show up later as a dynamic property of the service object + log.warn(`Could not find extension block function called ${funcName}`); + } return (args, util, realBlockInfo) => - dispatch.call(serviceName, funcName, args, util, realBlockInfo); - } + serviceObject[funcName](args, util, realBlockInfo); + })(); - // avoid promise latency if we can call direct - const serviceObject = dispatch.services[serviceName]; - if (!serviceObject[funcName]) { - // The function might show up later as a dynamic property of the service object - log.warn(`Could not find extension block function called ${funcName}`); - } - return (args, util, realBlockInfo) => - serviceObject[funcName](args, util, realBlockInfo); - })(); - - blockInfo.func = (args, util) => { - const realBlockInfo = getBlockInfo(args); - // TODO: filter args using the keys of realBlockInfo.arguments? maybe only if sandboxed? - return callBlockFunc(args, util, realBlockInfo); - }; - break; - } + blockInfo.func = (args, util) => { + const realBlockInfo = getBlockInfo(args); + // TODO: filter args using the keys of realBlockInfo.arguments? maybe only if sandboxed? + return callBlockFunc(args, util, realBlockInfo); + }; + break; + } } return blockInfo; diff --git a/src/extension-support/prg/block-relationships.js b/src/extension-support/prg/block-relationships.js new file mode 100644 index 00000000000..22b71a1cb7e --- /dev/null +++ b/src/extension-support/prg/block-relationships.js @@ -0,0 +1,70 @@ +import BlockUtility from '../../engine/block-utility.js'; +import Blocks from '../../engine/blocks.js'; +import { blockIDKey } from '../../dist/globals.js'; + +export const internalIDKey = "internal_blockID"; +const topBlockModifiers = 'topBlockModifiers'; + +/** + * Retrieves the Blocks object attached to the util's thread object + * @param {BlockUtilty} util + * @returns {Blocks} + */ +const getBlockContainer = (util) => util.thread.blockContainer; + +/** + * Get the ID of the block at the top of the 'chunk' that the block with ID = 'blockID' lives within + * @param {BlockUtility} util + * @param {string=} blockID + * @returns {string | null | undefined} + */ +export const getTopBlockID = (util, blockID = undefined) => + getBlockContainer(util).getTopLevelScript(blockID ?? util[blockIDKey]); + +/** + * Add a modifier to the given 'selfID' block's top block + * @param {BlockUtility} util + * @param {string | number | symbol} modifierKey + * @param {any} value + * @param {string=} blockID + * @returns + */ +export const addTopBlockModifier = (util, modifierKey, value, blockID = undefined) => { + blockID ??= util[blockIDKey]; + const topBlockID = getTopBlockID(util, blockID); + if (!topBlockID) return; + const entry = { value, sourceID: blockID }; + util[topBlockModifiers] + ? util[topBlockModifiers][topBlockID] + ? util[topBlockModifiers][topBlockID][modifierKey] = entry + : util[topBlockModifiers][topBlockID] = { [modifierKey]: entry } + : util[topBlockModifiers] = { [topBlockID]: { [modifierKey]: entry } } + let block_ids = Object.keys(getBlockContainer(util)._blocks); + for (const mod in util[topBlockModifiers]) { + // NOTE: The below check could likely use `getBlockContainer(util).isTopBlockID(mod)` instead. + // Check this later... + if (!block_ids.includes(mod)) { + delete util[topBlockModifiers][mod]; + } + } +} + +/** + * Get the modifier (denoted by it's 'modifierKey') applicable to the given block associated with 'selfID'. + * @param {BlockUtility} util + * @param {string | number | symbol} modifierKey + * @param {string=} blockID + * @returns + */ +export const getTopBlockModifier = (util, modifierKey, blockID = undefined) => { + blockID ??= util[blockIDKey]; + const topBlockID = getTopBlockID(util, blockID); + if (!topBlockID) return undefined; + if (!util[topBlockModifiers]) return undefined; + if (!util[topBlockModifiers][topBlockID]) return undefined; + + const modifier = util[topBlockModifiers][topBlockID][modifierKey]; + if (!modifier || !getBlockContainer(util).isBlockAbove(blockID, modifier.sourceID)) return; + + return modifier.value; +} \ No newline at end of file diff --git a/src/extension-support/prg/bundle-loader.js b/src/extension-support/prg/bundle-loader.js new file mode 100644 index 00000000000..bfa98d407e1 --- /dev/null +++ b/src/extension-support/prg/bundle-loader.js @@ -0,0 +1,97 @@ +import { FrameworkID, AuxiliaryExtensionInfo } from "../../dist/globals"; + +/** + * Initialize an extension (if it supports the PRG Framework strategy of initialization) + * @param {Extension} extension + * @returns + */ +export const tryInitExtension = (extension) => + extensionInit in extension + ? Promise.resolve(extension[extensionInit]()) + : Promise.resolve(); + +/** + * Try to retrieve the constructor of an Extension loaded from an external bundle + * @param {string} id ID of Extension (bundle) to load + * @returns {Constructor} + */ +export const tryGetExtensionConstructorFromBundle = async (id) => { + if (constructors.has(id)) return constructors.get(id); + + const success = await tryImportExtensionBundle(id, + { + onLoad: function () { + const { Extension, ...aux } = window[id]; + constructors.set(id, class extends Extension { + constructor(runtime) { super(runtime, ...window[AuxiliaryExtensionInfo][id]) } + }); + auxiliarObjects.set(id, aux); + }, + onError: () => console.log(`Unable to load bundle for ${id}`) + } + ); + + return success ? constructors.get(id) : undefined; +} + +/** + * Try to retrieve external objects loaded with a given Extension bundle + * @param {*} id + * @param {*} name + * @returns + */ +export const tryGetAuxiliaryObjectFromLoadedBundle = (id, name) => { + if (!auxiliarObjects.has(id)) return notLoadedError(); + const auxiliarContainer = auxiliarObjects.get(id); + return (name in auxiliarContainer) ? auxiliarContainer[name] : unknownPropertyError(); +} + +const extensionInit = "internal_init"; +const constructors = new Map(); +const auxiliarObjects = new Map(); + +const untilScriptLoaded = (endpoint, { onLoad, onError }) => { + var scriptTag = document.createElement('script'); + var host = location.href.split("?")[0]; + host = host.endsWith("/") ? host.slice(0, -1) : host; + scriptTag.src = `${host}/static/${endpoint}`; + return new Promise((resolve, reject) => { + scriptTag.onload = () => resolve(onLoad()); + scriptTag.onerror = () => reject(onError()) + document.body.appendChild(scriptTag); + }); +} + +const getEndPoint = (filename) => `extension-bundles/${filename}.js`; + +const getCommonObject = (id) => window[id]; + +const validateCommonObject = (id) => getCommonObject(id) + ? console.log(`'${id}' succesfully loaded!`) + : console.error(`Could not find '${id}' object after loading script`); + +const untilCommonObjects = (...IDs) => Promise.all( + IDs.map(id => getCommonObject(id) + ? Promise.resolve() + : untilScriptLoaded(getEndPoint(id), + { + onLoad: () => validateCommonObject(id), + onError: () => { throw new Error(`Could not load ${id}`) } + } + )) +); + +const tryImportExtensionBundle = async (id, callbacks) => { + try { + await untilCommonObjects(FrameworkID, AuxiliaryExtensionInfo); + await untilScriptLoaded(getEndPoint(id), callbacks); + return true; + } + catch (e) { + console.error(e); + return false; + } +} + +const notLoadedError = () => console.error("Tried to access auxiliar constructor of an extension bundle that wasn't already loaded."); +const unknownPropertyError = (name, id) => console.error(`The requested object '${name}' was not loaded with extension ${id}`); \ No newline at end of file diff --git a/src/extension-support/prg/xml-builder.js b/src/extension-support/prg/xml-builder.js new file mode 100644 index 00000000000..8befc7b3792 --- /dev/null +++ b/src/extension-support/prg/xml-builder.js @@ -0,0 +1,127 @@ +const Runtime = require('../../engine/runtime.js'); +const { XMLParser, XMLBuilder } = require('fast-xml-parser'); + +/// + +/** + * @param {{getInfo: () => ExtensionMetadata}} extension The extension from which the blocks to be created are from + * @param {Runtime} runtime + * @param {string[]} opcodes The opcodes to generate new blocks for + * @param {any[]} args The arguments to pass to the generated blocks + * @returns {string} + */ +export const generateXMLForBlockChunk = (extension, runtime, opcodes, args) => { + if (!validateOpcodesAndArgs(opcodes, args)) return ''; + + const { id, blocks, name } = extension.getInfo(); + const categoryInfo = runtime._blockInfo.find(info => info.id === id); + + if (!validateCategoryInfo(categoryInfo, name ? name : id)) return ''; + + const blocksByOpcode = generateBlockMap(opcodes, blocks); + + if (!validateBlockMap(blocksByOpcode)) return ''; + + const options = { ignoreAttributes: false }; + const parser = new XMLParser(options); + + const getXMLForOpcode = (opcode) => { + const block = blocksByOpcode[opcode]; + const { xml } = runtime._convertBlockForScratchBlocks(block, categoryInfo); + return parser.parse(xml); + }; + + let root; + let previous; + for (let index = 0; index < opcodes.length; index++) { + const xmlObj = getXMLForOpcode(opcodes[index]); + applyArgs(xmlObj, args[index]); + (index === 0) ? root = xmlObj : previous['block']['next'] = xmlObj; + previous = xmlObj; + } + + const builder = new XMLBuilder({ ...options, format: true }); + const xmlContent = builder.build(root); + return xmlContent; +} + +/** + * + * @param {any[]} opcodes + * @param {any[]} args + */ +const validateOpcodesAndArgs = (opcodes, args) => { + if (!opcodes || opcodes.length === 0) { + console.error(`No opcodes given`); + return false; + } + + if (opcodes.length !== args.length) { + console.error(`Given length of opcodes (${opcodes.length}) doesn't match given length of args (${args.length})`); + return false; + } + + return true; +} + +const validateCategoryInfo = (categoryInfo, categoryName) => { + if (categoryInfo === undefined) { + console.error(`Could not locate category info on runtime for extension: ${categoryName}`); + return false; + } + + return true; +} + +/** + * @typedef {Object} BlockMap + */ + +/** + * + * @param {string[]} opcodes + * @param {ExtensionBlockMetadata[]} blocks + * @returns {BlockMap} + */ +const generateBlockMap = (opcodes, blocks) => { + return [...new Set(opcodes)] + .map(op => { + const block = blocks.find(block => block.opcode === op); + return { opocde: op, block }; + }) + .reduce((acc, cur) => { + acc[cur.opocde] = cur.block; + return acc; + }, {}); +} + +/** + * + * @param {BlockMap} blockMap + */ +const validateBlockMap = (blockMap) => { + for (const opcode in blockMap) { + if (blockMap[opcode] === undefined) { + console.error(`No block with the opcode '${opcode}' could be found.`); + return false; + } + } + + return true; +} + +/** + * Add arguments in the appropriate fields of the XML-based js object + * @param {*} obj + * @param {*} args + */ +const applyArgs = (obj, args) => { + const nameKey = '@_name'; + const textKey = '#text'; + for (const key in args) { + const value = obj.block.value.find(o => o[nameKey] === key); + if (value) { + value.shadow.field[textKey] = args[key]; + } + } +} \ No newline at end of file diff --git a/src/extensions/scratch3_arduinobot/arduino_icon.png b/src/extensions/scratch3_arduinobot/arduino_icon.png new file mode 100644 index 00000000000..667bdf9ebbc Binary files /dev/null and b/src/extensions/scratch3_arduinobot/arduino_icon.png differ diff --git a/src/extensions/scratch3_arduinobot/index.js b/src/extensions/scratch3_arduinobot/index.js new file mode 100644 index 00000000000..b4f8d3f7fe1 --- /dev/null +++ b/src/extensions/scratch3_arduinobot/index.js @@ -0,0 +1,394 @@ +const Runtime = require('../../engine/runtime'); + +const ArgumentType = require('../../extension-support/argument-type'); +const BlockType = require('../../extension-support/block-type'); +const Clone = require('../../util/clone'); +const Cast = require('../../util/cast'); +const formatMessage = require('format-message'); +const Video = require('../../io/video'); + + +/** + * Url of icon to be displayed at the left edge of each extension block. + * Url of icon to be displayed in the toolbox menu for the extension category. + * @type {string} + */ +// eslint-disable-next-line max-len +const iconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAAA5CAYAAACVk20jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABJ0RVh0U29mdHdhcmUAZXpnaWYuY29toMOzWAAAEVxJREFUeJztm3lwXVd9xz/nLu++fZHek55WW7blJZbt1FkcJzWJWRJCmKSZdIbStJRQZhhgwElMYKZlkpZOaRgIxO7Q6bRMgU4hLJl2hjYEBxIgThxnMbET77YkS37an6S3L3c7/eNJsoUkW46dEIi/I83c+zu/s33v7/zO9ntwGZdxMRALJYQ/t/M24bpbNtT5E1Gfx0iXKqWs6VgAbWF/yKMI5bXx4uhkxTLfuua+6diX/fq9Pz5boC2kKaT7H+9f3d5w95pmmn0aUkqklAAoigLAzwdy/Nsrx5go1TiSkt2Kwrel5MO6WX7f8soQVSmoSIVGzaTP9NLmqTJu62jCxa+4DFselnvLnKp6qVNtHKDgaLR4qvRWvbR4qmTtWjPDms2gadBhVOh3Q6RDSSL5NCvVCU5WfDTqJhVXoSoVGjSTftNLu6fKmK3jES6+qfpWeMv0VH3UqxYOgoKj0OKpclQ0SLbviGQf2fat8xIEwntweILI+lYADj32GKldP0Px+9j6jR3oXi+juQLFqj2Tw3bdD5W+ft9Q/PNfedxfmsyUXnpG8fv9eIUgnc+xNNHA8PAw8XiccrmMKV3aAkF6BwZob29nYmICwzCI6zqD4+MsbWpibGyMSCSCaZoULYsl0SinB1I0L+skve5WkqdepefkYTqWLGF8fByv14tPURjP5+loaGB4eIj6+jiVSgXTdWgLBOmZp76BdJqGddeKU0uv+WtghiDlXPb2nuXNGLoOwODPnkTYFjKX45V/3gnAaKFM1XHPmKMm2gGqjr8FiRKJRPD7/Xg8HuLxBADxeBxd1/H7/YTDEVRVpampCUVRiEQiBAIBNE2jsbERKSWxWAzDMPD5fMRiMaSUJJNNKHrt2wpdo7m5GSEE4XD4rPriuK5LfX2tPp/PN6s+VVVn1ZdMJpGoczg4hwXB8fEcjtuIJkAoAunU5P54fH6bk+LJpfc8cFDmhjaU/WHGVlxNLhTHn58kEglj1yWZyOepOpKg4SHi1enPlGgLGxzPm4Q8KpbjUnYcAqogb0Pcp1O2XFygIWDQly3REfUxVDTBhROrttARNjicqZDw6dgIyqZDPKCRylVZVuenL28hhCTq1UnlyrSFDXpKFj5VwefRGCmU6YgF6J+szOnTOS3obKy/fztaPE7kyj9iwz0fq8ma44SNMxz7i5OxzaXDW64cfim85tizbBEjLD/2PO+SKRJHnmOwaNK1dAlefxB0Lw31cRxVJxSpJxAM4gmEaEs2YiketnStxlF1YrE6ItEIpqJjal4cVacgDExRq9cRGkOmgqPq2B4feHxUFQ1bD+CoOmOmQhFBRWiUhAdH1cm4OpaiUxYeClLDUjx0NLcilQu0oGzZpC9bZGU0gG/1WjY8/AgAtpRoQqF7PIctz+irtoXtSCQCXAfXdcF1sF2JRGI5Lr6poaGpClW7ZpJHhseRSPIVk9F8EYDnuwcASGUKVG0by3HJV2uTwXCuOKudxaoFQKFighDYrkthSjdTrtaIdB1Mx5kla44Eifm97E+NzilzUQQdHp3kk09OsnVlOxXLplC1iPgMJksVDg2l580zli4BIBWVnr4R0DycPj06k+7z1HzaaL5EYapjtjvtx86w7U7PmAIct/acnerYQqhMEb6Q7m/LKpY9I/Ppc60HFiBo586d4YKrBPeXFXalLV7uG6Y+4KVkWqSLZTKluWN1GuvWLiGbLdE/NMkNm1bx7L5erru6k8PHaxbxxMFuFFFbfpVMa8Fypr9yrnLuZVbQ8BA0dFwpifoMchWTdKFMayyEaTsIISiZFpNTbdZVBV1VKZkWmnqGlKDXM2/52oMPPvhl13XDqqpm6+vrIwCKomgFS8qE6vLBOgFYtf/pMkJgSdg1ObuwYqiOF08cQUjIxZfy9IEBJhtX8KtDKUxPaEZv2jouBby6StRnIITAchxaoyEc1yU81WFVEQj8CGCiVCHsNTD0GkGulDMWND1M5xDU0NBwD5BUFGVvY2PjddMJTedpWNF22fXS4CyZq2g03nY3uYpJRyTIqfEsw8PjDCdXzVvGu1a0zljTpcTaprmz7PqWxKz3lYnYHB1NUc4a7lMyXdclgKZprsczv5nNB1M488oPDY3j0VSOjkwQ9Rnz6jSE/IzmS3x2U5HOVtjf4+Wvfjw0k751ZTsPvPcamiJB9vQM8NATz5MulLnrypV85qaNBAydJw/18k+79lK2bKJ+g3q/b2qIVWuTBHL6j9ZoiIFsgdFCkVz5wnZG53TSbwTjxfLM87Blz6sjgKjP4OiYgqULTo2fcZ5XNNXz1Ttv5OPf28Xx0Un+8tor+Mkn7uSJQ73csKyZTzz2FEXT4uPXr+erd97EtsefpiUSJGR42HtqiM0dzYS8Hvb1j9CZiJKrmrTEghi6is+jcWgwfb4h7jv7ZdHroEuJkXyJTLnKF58a58PfSfPQMxMzaR/sWs6jv9xHMhzg8++7lp8f7eMnr3fz0eu6+IvvPME913XxtTtv4ks/3cPWlW00hgP0pLPEg34AEiE/pu3w7pXtxIN+NrY18v2Xj9AYCnAqnSUR8i3UrGlsCH9uxyPTL78Tgs6FXMWkORLk1ydO8+gzrzCYzbOxrRGvprIiEeOHvznKt194ncZwAMeVlE0bv0dHUxWChofA1DLipb4hNrQ2IBAYmopXV/EZGiVzfqs+G0Jy/zRJl3yITUO1quiVwiyZ5Q0Sr4thu5KiaXHX2np8Rj2piTQ/O1FbK/3XS4fZ9ek/xe/ROTo8zoevXsOR4XG+vGsv3/nIB/jeS4cYyBb40cdu5+Gfv8hkqcL6lgRPHzvFdR3N/PJ4P66UjOZLfP/lwwzlitzWtZxnjveTDAV4bWCMW7siSL9GZrTKybRDxXKwHWd6HdUDJITk/uj9O//zTSPInz5N47E9s2Qja/6YYFMjQcPDSL7IR69sY0Xran7TvX+GoELV5JZvPs6fXbWapfURHn7qRV7orc2W7935Q+66ciVt0RCf+fEv2J+q5XltYIy2WIiedJaQoSMRtWleQkskSG86i2m7dI+NAXDnVoexhjzRoxH+99Xa7NaTznBiZGJn5uv3bgs88M2kJu3XpOKobxpBC6E7nZl53vbkEbxaH5Ol0oxMEYLOhij/d7Cb1miIg0Np2mIhVEUhW67y3b0HqdgOEZ/BkrowfRM5AE5P5hfdhu3fKiFViWtlKFXPLOaEIn4FUPzqp4cj23ccQbyJQ2whbGxrJOIz6J/I8S8fWEpHaxcHul/l9u8fAmBVYx3xgA9DVVmdrMejqTRHAhSqFlXbYShX5OjwONly9bxbj4WQL7vzyqUrvhjbvmPMhS7gBgDN6/VqQgg0TfNr2uL58ix8WntOHB2ZIODRKJo2n/hJN7reT6lyZmlwZHicI8PjAOw9NbRQMW8OhNzowu6zRVogEPh7IURA13VT1/XHABRF8Q4UKg91TxaU3sL8Cytr/o8wAzMYJdPeNVvmj1I1rZk92LHxhfdibxfMawaDg4P+/37+ldyzqQl1Vyr7VrfpLcW65gTO0z9kbTLAyZ5Bko1+KmWb3R3vwfZ4rpp3TDU3N5ci23cUgfBb3N63HCfHJum0TYRSW0AqSBAuytTZ0VvupN9uKFs2k5EmjpxKITUP/eMOjurFNqYJuwximUG2bFyGbpus72xiWb0PvVI7YXxHW5BHVdnU0UT/qQR79p1AqhqHjqdwFA2r8bIFIUSNpFA+zfo1S1Acm6UtcZJhA82uzd7vaAuSktr5kaIyOlo7Uchmi1SrJu6U7byjCbJdl9F8iYE1W+kvZWHqkNHUPNgeL+C+swlypazt5RSNfLB+Xp13tA9aDC7IgvzDPcRGumsvrovYdDMVVNLmefYdv8dYFEGKgHpN4JayeNIpAGzb5iNJhW5L4wdDbzxESLGqqM7bY0/mKiqOZ/aR7KIICmoKD3R4eGJAof8s+Vd6LFz94u64YqcPEes/eFFlXCqU4m0Mdm2dJbsoH/Tgcg93Ny3+quj3ERc1iz3ab2Gpl+6W9O2IRVlQyXH595TJidIZZyyl5M+bNW6q+8NeKSyqd7YLJ0ouXsWLT605MSk1fjUpKTD/DesfCi7o81fa11BpXzPznikBLDzFK0IseIs5nZZtu4J8Y8eFNONNg6vqc2RzThTXr1//ScMwPlTy+LdkWq5QUM49CqXrUmxbPUsWO/AMH+haxpqVnfSdHuB/9rxM+urbEI5D+2tPcfuN19MQj7PvwAF+MZCjsPq6BUr/HUNx554oFgqFzmKxeCNMkKwUEOeJvjAtaxZB0cPP84W73s8dd9wxI7vh2hf53I5/JYTDNx76W1atqkV73PUnd7Dqu99l5yuvU+5Yd6m6dUlxziGWyWTmyBRF4ewoENOy0BwLe8o8r22p5/bbb5+VZ9OmTdx61R4a66Iz5AAIIbj77rt5/JW/ofuiuvHm4YKnINd1qVQqM8HkjuvSVBzldLgFgGXtrfNaXUd7O7FwcI5c13U6W5vnENSZiLG2ef5o2vkwkivO3MAui0fnxAOdD47r8tNDPf2OdL8kXbqEEPfCG1wHSSlrAZrUnFiTW+L0VNqBI8exLAtd12fpHzh0iGRdlPffcsussvL5PAd7+/F3dWBotZA4TRGcGJvkxNhvhbCdhXXNCRzpEvV5MW1n1mTQk87Qk55r/VtWtFIyLSzHxXJchIBc2aQ+4OPAwChS8IXc1+79AUBk+47r4SIImrYSKSV5cWbI9Q6k2LZtG8899xyWZaGqKjfffDP7TvYSUOC1/ft54YUXAAiHw2zevJlcsYRHVUiGAwxlCzRFQowVyjOEVc8KzmwM+cmUqwzlCoS9Br2lLK7rztKZD6oiODI8jiIEihAIIXBdl8JZ93RCshSAv/u2l3yu8Q0R5DgOlnVmcymBU94zZynZtrW8njrGiutvojUSJF2u8vLQBKUl66hYVfLZUTa+71bqvAb9kwX2jWQpL9tIVFWIeD2MFZSZUOGmSJCKZZMulIkHfQznily9pIlfnzhNwKPj0zV60hluWN4yEzYMtUDN+kBNPxkOzASCCmrRtcviUXrSGRLB2hV3plylORJkMFv4x8j2R99FPrcCWHJegiqVyhx/4rpz1z1l44xvKSeXU04uJw0cmRYuma0/E0DceFYZlsNAtkB5ihAAXVHIWDZeXSMR9DOcK9KTziCRFKoW6pQf9OuzuyElrGyIMZwrkgjWLM7QVBIhP2OFMomgj550BlVRCHt1MuUqnQ0xBrMFBcStU8UcQzV65xBkmqZmmmZZ1TRf2QghzzPNK9MBIpIHUN1ncNUvg7zlnJmmEJtIcUW5lwE3TIgKQoAivSSVHFU3SjhVQJU6jhAY3RVaZZjIQJYGN0BAWKjSpRUf5YHdJDxtjCWWAtCW2k+1/1laZQRfKkur9KPjYAibVhlEH9hNmxsmJsq4UmGJ0DFTu4n5lzEZawY4pqvKu9MPf2pywd5Htu/IsuibVXEy+8hnOwHC9+28VijyxcXk6ji+h9F9u+ns7GRycgJNq/3opK+vj87OToaGhohEIjU/l8+TSCTo6+ujvb2dfL4W7hIKhThx4gQd11zP4ZU3ArD6hR8xPjpCS0sLqVSKZDJJuVzGtm0ikQgnT55k9erVjI2NYRgGhmEwMDBA3dVb6F16zZDpuFeVHr1vCM7xg7oLI4iK47gbC4/edyS8fecXBfIfFpOptf8AbYUUZamhU5tVTCnwC5e8q+HHwhUqNhKfIsjZgqDiYAkNIR1UAWVXEFRgxJ+ge+lVAFx59Bf4pUXOFgQUBxsVpERXBQVHEFYciqh4ZC3Q3JTgV+BUuI3Blq692Ue2bZ5u47l80DHgmkUS5FVV5dXI9h3DIJecX72GVPsGUmxYrPqisX/1e99wXok8evb7ggRl+5s2R5an/+CDF34buYc/tfDi6zIu4zIuNf4f4wN4MwoAoHoAAAA1dEVYdENvbW1lbnQAQ29udmVydGVkIHdpdGggZXpnaWYuY29tIFNWRyB0byBQTkcgY29udmVydGVyLCnjIwAAAABJRU5ErkJggg=='; + + +// Core, Team, and Official extension classes should be registered statically with the Extension Manager. +// See: scratch-vm/src/extension-support/extension-manager.js +class ArduinoRobot { + constructor (runtime) { + /** + * Store this for later communication with the Scratch VM runtime. + * If this extension is running in a sandbox then `runtime` is an async proxy object. + * @type {Runtime} + */ + this.scratch_vm = runtime; + + this.robot = this; + + this._mStatus = 1; + this._mConnection = null; + this.CHROME_EXTENSION_ID = "jpehlabbcdkiocalmhikacglppfenoeo"; // "molfimodiodghknifkeikkldkogpapki"; APP ID on Chrome Web Store + + this.msg1 = {}; + this.msg2 = {}; + this.dist_read = 0; + + this.scratch_vm.on('PROJECT_STOP_ALL', this.stopMotors.bind(this)); + + this.connectToExtension(); + } + + /** + * @return {object} This extension's metadata. + */ + getInfo () { + return { + id: 'arduinoRobot', + name: formatMessage({ + id: 'arduinoRobot', + default: 'PRG Arduino Robot Blocks', + description: 'Extension using Gizmo Robot Chrome extension to communicate with Arduino robot' + }), + blockIconURI: iconURI, + menuIconURI: iconURI, + + blocks: [ + { + opcode: 'setLEDColor', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.setLEDColor', + default: 'set LED color [COLOR]', + description: 'Set the LED color' + }), + arguments: { + COLOR: { + type:ArgumentType.COLOR + // should I put a default color? + } + } + }, + { + opcode: 'ledOff', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.ledOff', + default: 'turn LED off', + description: 'Turn off the LED' + }), + arguments: { } + }, + { + opcode: 'readDistance', + blockType: BlockType.REPORTER, + text: formatMessage({ + id: 'arduinoBot.readDistance', + default: 'read distance', + description: 'Get distance read from ultrasonic distance sensor' + }), + arguments: { } + }, + { + opcode: 'driveForward', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.driveForward', + default: 'drive forward [NUM] second(s)', + description: 'The amount of time to drive forward for' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + { + opcode: 'driveBackward', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.driveBackward', + default: 'drive backward [NUM] second(s)', + description: 'The amount of time to drive backward for' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + { + opcode: 'turnLeft', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.turnLeft', + default: 'turn left [NUM] second(s)', + description: 'The amount of time to turn left for' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + { + opcode: 'turnRight', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.turnRight', + default: 'turn right [NUM] second(s)', + description: 'The amount of time to turn right for' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + } + } + } + // add blocks for speech? + ] + }; + } + + connectToExtension() { + // Save reference to robot for use later + var robot = this; + var boundMsgHandler = this.onMsgFromExtension.bind(this); + + // Attenpt to connect to the Gizmo Chrome Extension + chrome.runtime.sendMessage(this.CHROME_EXTENSION_ID, {message: "STATUS"}, function (response) { + if (response === undefined) { //Chrome app not found + // Must have the wrong extension ID (if extension was not downloaded from Chrome webstore, the extension id is not consistent) + console.log("Chrome app not found with extension ID: " + robot.CHROME_EXTENSION_ID); + + // Attempt to get the extension ID from local browser storage + robot.CHROME_EXTENSION_ID = window.localStorage.getItem('gizmo_extension_id'); + console.log("Stored extension ID: " + robot.CHROME_EXTENSION_ID); + if (robot.CHROME_EXTENSION_ID === undefined || robot.CHROME_EXTENSION_ID === "" || robot.CHROME_EXTENSION_ID === null) { + // If there is no extension ID in local browser storage, prompt user to enter one + robot.CHROME_EXTENSION_ID = window.prompt("Enter the correct Chrome Extension ID", "pnjoidacmeigcdbikhgjolnadkdiegca"); + } + robot._mStatus = 0; + // Try to connect to the Chrome extension again + robot.connectToExtension(); + } else if (response.status === false) { //Chrome app says not connected + console.log("Chome extension is not running"); // what does this mean? + robot._mStatus = 1; + } else {// Chrome app is connected + console.log("Chrome extension found"); + // Save the extension ID in local browser storage for next time + window.localStorage.setItem('gizmo_extension_id', robot.CHROME_EXTENSION_ID); + if (robot._mStatus !== 2) { + robot._mConnection = chrome.runtime.connect(robot.CHROME_EXTENSION_ID); + // Add listener that triggers onMsgFromExtension everytime the Chrome extension gets a message from the robot + robot._mConnection.onMessage.addListener(boundMsgHandler); + // We're not sure that it's working until we start receiving messages + robot._mStatus = 1; + } + } + }); + } + + /** + * Implement onMsgFromExtension + * @msg {chrome.runtime.Message} the message received from the connected Chrome extension + * When a message is received from the Chrome extension, and therefore the robot, this handles that message + */ + onMsgFromExtension (msg) { + if (this._mStatus == 1) { + console.log("Receiving messages from robot"); + } + this._mStatus = 2; + var buffer = msg.buffer; + + // The beginning of the buffer (from firmata) starts with 224, if this buffer starts with 224 it is the beginning of the message + if ( buffer[0]==224) { + this.messageParser(buffer); + last_reading = 0; // Last reading signifies that the last thing stored in the msg buffer is the first part of the message + } + + if (buffer[0] != 224 && last_reading == 0) { // Checking last reading makes sure that we don't concatenate the wrong part of the message + this.messageParser(buffer); + last_reading = 1; + } + } + + /** + * Implement messageParser + * @buf {byte buffer} a buffer containing a series of opcode keys and data value pairs + * @dist_read {int} the last reading from the ultrasonic distance sensor + * @msg1 {byte buffer} since the entire buffer does not always get transmitted in a message, this will store the first part of the buffer + * @msg2 {byte buffer} since the entire buffer does not always get transmitted in a message, this will store the second part of the buffer + */ + messageParser (buf) { + var msg = {}; + if (buf[0]==224){ + this.msg1 = buf; + } else if (buf[0] != 224) { + this.msg2 = buf; + } + msg.buffer = this.msg1.concat(this.msg2); + + if (msg.buffer.length > 10) { + msg.buffer = msg.buffer.slice(0,10); // The length of the buffer (from firmata) is only 10 bytes + } + if (msg.buffer.length == 10){ + if (msg.buffer[8] == 240) { // The opcode key before the ultrasonic distance reading data is 240 + this.dist_read = Math.round(msg.buffer[9] ); + } + // We currently don't read any other data from the robot, but if we did we would put it here + } + } + + /** + * + */ + setLEDColor (args) { + var h = args.COLOR; + + // Translate color arg to red, green, blue values + var rVal = parseInt("0x" + h[1] + h[2], 16); + var gVal = parseInt("0x" + h[3] + h[4], 16); + var bVal = parseInt("0x" + h[5] + h[6], 16); + + console.log("set LED color: " + args.COLOR); + console.log("R:" + rVal + " B:" + bVal + " G:" + gVal); + + // Send message + var msg = {} + msg.buffer = [204,rVal]; + this._mConnection.postMessage(msg); + + msg.buffer = [205,gVal]; + this._mConnection.postMessage(msg); + + msg.buffer = [206,bVal]; + this._mConnection.postMessage(msg); + + return; + } + + ledOff () { + console.log("LED off"); + var msg = {} + msg.buffer = [204,0]; + this._mConnection.postMessage(msg); + + msg.buffer = [205,0]; + this._mConnection.postMessage(msg); + + msg.buffer = [206,0]; + this._mConnection.postMessage(msg); + + return; + } + + /** + * Implement readDistance + * @returns {string} the distance, in cm, of the nearest object. -1 means error + */ + readDistance () { + var distance = this.dist_read; + if (distance == 0) { + distance = -1; + } + return distance; + } + + stopMotors () { + var msg = {}; + console.log("Sending 207 to stop servos"); + msg.buffer = [207,99]; + this._mConnection.postMessage(msg); + } + + /** + * Implement driveForward + * @secs {number} the number of seconds to drive forward + * @callback {function} the code to call when this function is done executing + */ + driveForward (args) { + var msg = {}; + var secs = args.NUM; + console.log("Sending 208 to drive forward, secs: " + secs); + msg.buffer = [208,99]; + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + + /** + * Implement driveBackward + * @secs {number} the number of seconds to drive backward + * @callback {function} the code to call when this function is done executing + */ + driveBackward (args) { + var msg = {}; + var secs = args.NUM; + console.log("Sending 209 to drive backward, secs: " + secs); + msg.buffer = [209,99]; + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + + /** + * Implement turnLeft + * @secs {number} the number of seconds to turn left + * @callback {function} the code to call when this function is done executing + */ + turnLeft (args) { + var msg = {}; + var secs = args.NUM; + console.log("Sending 210 to turn left, secs: " + secs); + msg.buffer = [210,99]; + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + + /** + * Implement turnRight + * @secs {number} the number of seconds to turn right + * @callback {function} the code to call when this function is done executing + */ + turnRight (args) { + var msg = {}; + var secs = args.NUM; + console.log("Sending 211 to turn right, secs: " + secs); + msg.buffer = [211,99]; + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + +} +module.exports = ArduinoRobot; \ No newline at end of file diff --git a/src/extensions/scratch3_gizmo/gizmo_icon.png b/src/extensions/scratch3_gizmo/gizmo_icon.png new file mode 100644 index 00000000000..50f3b719f6d Binary files /dev/null and b/src/extensions/scratch3_gizmo/gizmo_icon.png differ diff --git a/src/extensions/scratch3_gizmo/index.js b/src/extensions/scratch3_gizmo/index.js new file mode 100644 index 00000000000..a2894d39511 --- /dev/null +++ b/src/extensions/scratch3_gizmo/index.js @@ -0,0 +1,424 @@ +const Runtime = require('../../engine/runtime'); + +const ArgumentType = require('../../extension-support/argument-type'); +const BlockType = require('../../extension-support/block-type'); +const Clone = require('../../util/clone'); +const Cast = require('../../util/cast'); +const formatMessage = require('format-message'); +const Video = require('../../io/video'); + + +/** + * Url of icon to be displayed at the left edge of each extension block. + * Url of icon to be displayed in the toolbox menu for the extension category. + * @type {string} + */ +// eslint-disable-next-line max-len +const blockIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKcAAACbCAYAAAAHros6AAAnOUlEQVR42u2dB7gU1fXA7UmM/1jpXVAURAUbogI2AoqxANEYWyyJNVGjiR1ji0YxYlQeCIKIFKkqIKiUR++i9PLoPKS8QnlU4f7P7765z3nD7r6Z3dnH7s7s951vX9kyM/c3p91zzz3ssDR+fPnll/HIkSK/FqkkcrpIM5EbRB4QeUWk1xdffPGNyHyRTSK7RVaJDJX/PSPSWqSOyK9ifU/z5s0PCx8Z+ogTvKNFjhOpbIHXVKStyN0WWO8KZANExol8L7JaJE9kp/zvpxEjRqivvvpKjR49Wo0ZM0ZlZ2erSZMmqXHjxqlRo0ap4cOHH5DXbhdZJjJK3vOmyO0i54tUEDkq1vGFj8wE73CRY0SOF6ku0lCkuUg7kQdFXhJYuol8LjJFZLFIrsg2+d9egUoZ8L7++ms1duxYNWHCBDV16lQ1e/Zs9cMPP6jFixernJwctXr1arV+/Xr1448/qk2bNqnNmzfrn9esWaOWLFmivvvuOzV58mT17bffqpEjRyr5fIAtsDTtIPn9BUsTN7CO9/AQ2PTVdkdYJvJkkdoi54pcKfIHkcdE3pBB/1jkK5GZIsstc1uEtgM8IEGzffPNN1rLoe2mT5+u5syZo+bPn6+hWrFihQYsNze3BLwtW7aovLy8g4S/O8X+f4DdsGGDWrVqlVq4cKGaNWuWhh3wuQm4IeT4fhSZLtJTfn/UOqfaZbkDIbC2R9euXUuJz+AdZfl3FUXqiVwg0kbkLpGnRN6RwesnMkZkruXbYWZ3yf/2G/Aws2iq8ePHa601Y8YMNXfuXLVgwQK1dOlStXLlSrV27VoN3saNGzU8XsCLV+yfCexoXLTvvHnz9M1hcwcUroN1fmPk3DpbrkZTywU5OoQ1MpzHiBxl4Ozevfthn3/+uVv/7jciVUXOFLnEMmd/Eekog9BFZIjIRJEFIutECuV/e0RKmVn8O2Nm0ULff/+9WrRokVq+fLnWTuvWrdOaypjZ8gDPD2C5UbhpuIG4maZMmaLPlfPmGsj12CqyCHdEfn9ZpL1II5ETLYsSbGAFyM9EBmZlZT0mcsmHH354isD5S+sC1bQuVkuR34s8IvKaXMyPRIaLTBNZapmw7fK/fca/s5vZiRMnqmnTpmn/Dq0Szb+LZEJTCbxEYLW7A5w3Nx/Xg2vDdbLcgZ8sl2W2SB/5/UkrO1DXskDBcgcETCVAqt69e6v+/ftvGzJkyFw5UUzPHLlAK0S2WNHsfrt/Z8ws/h1mlkAB/w4tYffvytPMphuwxh3gOnHNuH5cS64rrozlDpDKWiuSLWPwgWWZLhWpZgWJmQuraMt9gwcP1hGsZWr0MxeGv3GxMLM4/suWLStlZkPwkucOcI253lx73B3GAnfAAna7ZbFGyFi9bgWPja2g8siMAbZLly4EH1rTYXIxM2hG/sYzFwYThPnlwuXn54fgHQJ3ANcHdwCXiCwEFgt3wEpn7bcCSYLK/lZOt62V6/2/tHUHBM4daEsuABcCMwOomBhANc47ZgaHHg3KXW1eH4J66IDFHSBTQdZi5syZetKAcbL81z1Wrney/PyhyENW7EAc8cu0AFbg3CoBUMSAxA4qd6pdo5LS4aIQjYagpo7/iuIgy8HEAkEo7oAtnVUkkiMyWsaxk8gd1uxWxZSc3RI484cOHVoKzkgnD4CACJAhqOkDrIfZrcEpN7slcG6WCF074W5P2g4qJ2sHFXDRtFwQgA9BTc10VozZrX0RZreusma3ji1Xd0Dg/JFo3Q2csUDlRPFJ8XkAFV81BDV93AGXs1tj3c5u+ZVKWjdo0CCt/hM9UUDF54kEKsEVJ07EGYKaHukslI5JZzGe9nSWjOtWkUUiZnaLdFYTM7PlF5yrBg4cmBCcsUAlDUU6yg4qZgSHPQQ1NU2/GQvG0ORcmSRAuQApY0iGxy6MrchcS5v6BmfOZ599pv2QZJ00J4nZIEcHqPg3nAxOeQjqoQWQa87YoyUx6ygT6gAw7YwNwRPmHX/UXnpIjpWZLGBlGpaaAepjZVxr+QnnkgEDBiQNzligkuoAVDMtSp4OE4Kzzh0bguofgORE8f1JM+F2Eblz/bnmgGYz1yW1EYCJO2ZmCYn4GRs+i3FkQmbr1q1q27ZtGmaBc6WVR/UNzgX9+/fXX1jeF5FnQOWkOTkuUgiqNwDt5pcxxALhJxKIotHQbGg4lADXletrNCCuFn4kgStRO+/hvUCMm8fnFxYWavi2b99eSvibEQAFdGoxBMwafsL5fb9+/codzkigcgyRQOXiYmqYDQkCqNH8P4DhZuaGpcAGHxCoSOcRXTsBNLWw/M+YX9J/mG/MuLmWbgCMJTY4c6yVCr7BObtv374lc+epMDAGVAYAk2JA5W4HVExSuoMaC0ACEM6PGxV/nKlJtBtazkxP2gEESq4L/jzXBr+RAIYxxaTbzW+8AJYFJ9/NKgWrWso3OKcDJxckFQfQCSp+kAEVjcBgMBAm25BKoJYVgHDc+N64L1gL/DsCC3sAgpgABFcHDYUV4X0AbPy/goICDYkTPr8AdAnnMqv43Dc4J3/66acazlTWQObYGFj8IrSJE1Sqdcob1FgA4rthQp0BCMcdLQAhQuYmRGOiOfEhTbAKgMnSfj7BuVTOp4qfcGb36dNH38npYh7toBJ94nehcQyomD9ABQw/QHUC6AxAOAZ8Ob6TQcLE2iNg++oAjhMTzc2Fz2gPQPiuRP2/QwUnPq3AucTvPOeYTz75RF+gdPXdygKVQKAsUKNFwCYAcUbAkQIQewRMkMJreQ/H5WcAksJwLraaVfgG52iWaKAB0j0CtlfiACNwAIrx34AWeIEFmCMFIGgzZwDijIBNAMKAoC0x23wfn1MeAUgKw7nQKr/zDc7hmQJnLFCByAmqPQCxA+gMQEwEDMBoUmcCOggAlgUnloJVtlbnE9/gHPbxxx9r05WpuUM7qARMgIpZtk/BDRs2TFGdhfk2WjVaBBw0+DzAOd9vOAf16tVLa4UgzMDYq27MWniEgmsmI/hfCKA3wYfGDRI45wmYp/gJZz/gRKMEdXoQUCm4ZhqX30Pg4obze2sFqG9wftKzZ0/tlwUZTkw61VlcgxC4uOGkZO4kP+H8SB46gg0qnPii1LQiIZzxwUlwKXB+Z3WK8Q3ObsBJIBBkONGarAggCg+BixvOOX7D+X6PHj303HVQ4SQwoqYV0x7CmRCcswTME3yDs2vXrp2BkwR0kOEkGCJiN/PXoXiDk5oA+qdaS4p9g/Ot7t276yqXoMLJHDlpJHKdIZzehWtmwTnDaovpG5yvAyczIEGFk1kfygbpfGLmvUOJC87pfsP5Mi0QmR8OMpyUDVK+FsIZH5xM9QqcU03jML/g7AiclHwFEU7OmYINygaZVzfz5aHEBecUazcT3+B8BjipxgkqnJSzUTZI8UcIZ0JwTvYbzn9069btAJXXQYWTWlYqs6hGCuGMD04KaOj/b9qD+wXn48DJOpagwkm5IJVZ1G6GsCUE5wS/4XxE4NzPoqmgwkm5IMUvFBGHsHkXJi4sOMebTnR+wfmAyE8U1AYZTopfWGAWwhYfnNTHsm2j2QTMLzjvE9nHkoagwkktK3BSFZ/JEO3YUaSKinbK8w5ds8qz/r2oyC84x/oN513AydqaoMJJLSvFL1zgTCw0BkrOc8a0qapH1y7qhWf+oZ7420Pq+aefVN2zPlDTp06R/2+JG1IbnN/a+837AedtIntZ1BVUOKllpb4AvynT4OR8pkyeqB76859Uk4b1VJ0qJ6laFY9XNUV45vfGDeqp+++5Q03MHlfyHq9wsj7LitZP9q2RrIB5i8geFvIHFU5qWYGTKbhMgpO02Ke9e6mmjRuqWpWKQTy16skHiQZW/n/B2WeoHt266Ojby3XgGlpwspnaWGsn56oJQypgts/KytrFKsOgwkm5IPUFlH1lCpzbxZ8c0LePOrt+bVW78okRoXQKr2tQt7rq3vUDT99lg9M0kT0gwpKN+0xSPi5ABc4bBM6ddKoIKpyUCwInKwgzAU4CnTmzZ6rLLjz3IDBrVTpBP59Ru4qqV72C/t2uUXn9+Y1OV+PHjnHtgxo4WXbNLJsN0n0ig6zdObwDKnC2FTiLWB4bVDgpF2QKl2uQCXBizp964tESEI3pPq1GRfXH39+oenbvqkZ/NUIN6NdHPfznu7W2tAOKib/3jlv18mg314NraPoAsKKCJdc2QBHWs7fyDKjA2Vrg3MECpaDCSbkgcOLa+Amn/qxyhh2tuWD+PHXJ+WeX0pqA+cqLz6kNG3LVzp07dQqJZ4IZ/MyzTqtZAijPuAMTs8fL64pcwUmOGMvD71R5WUl5O6C5Ih08ASpwXi1wboP6oMJJuSBwEhQmAifvZTB51muT9Lr4jVqT8XfASTacRQLc4M/6axjtpvz2W27Sx+M8Bo6V43v6ycdKwczPnd/+jys4OVcDp2lCwbosqxjEDuhGkZtcAypwXi5wbiVSDSqclAt269ZN90iKF078s/Xr16kvhg1Rzz31hLpNzOcN11ylOlx/jfrr/fdq7bRwwfykdw0Bpv+++bqqbTPpdaudonr37K41ZbT3jB/7rTqr3s/akzTTA/fe6aq+1cCJW2Rv0cPyFyv/aQd0jUgLV4AKnM0FzgIoDyqclAsCJ7NkXrWbAW3UyOHq5huvVfUl0MBnK5YTtJBTZMCbN22s3n37TW32kqVFuUle6fhcKX/zjDpV1Tejv4qqBTmHFTk56opLLijRnrz/+jZXajegrJuJ64ifaYfTfC7liNQsOABllWZdN3A2EzjzITyocFIuCJz0UPIKDZqF1EvjM+uWAiJaqgYt9pe7b1fLJXBIBqAA+Nbrr5Y6Fkz8sMEDtcmPXlmUrx687y5Vo8JvtPbk+Z7bb9EzR240J3CS8XGWHAIoqTpr60K7fGrfrjAanBcJnFtIBQQVTsoFgZPKLC/A8Nr+n/bWwYQzZcMA15G/RUp881oAxQ3w28QDYN9PeumbwP59mPpY/iPnMm3KZHXTta3UOfXrqLatWqrscWNdXQ+i+mhwmuwB0+MO7Uma6YGY5l3gPE/g3EQqIKhwUpEFnEDqFk5e98P3c1XLi8+TwS+dsjHJ7IubNNQ5Q/KJTniBh4DDdzgFwMmTJqhGp9cquTFwK54XP7isc+NY1qxerWZOn6ZWrVzh+tiAE9MdDU4+h5Y/1kZadkDZfePMWHCey+askB/UPX0w58CJ7+kWTi44qRknmCS3//bAfdrHW7RwgZr73RydV7y6edODouHmFzXWaR8/zTvHlSs+7R/a/U6bZsDEDx7Yv6+ryFtXK1kZB7ffaeAkFRdtJYEx76YPvk2yRI6MCKjA2UjgzOXDgwongRBw0iLbDShcaDRLq5bNDsolvvHqS/ozMa98FkKUPHvWDNX6iksP0qAfZr3vChpvgBbPED328P3qjx1u0N+xZcvmpOVc7XCWVTFvNfyyw1lgj96dcDYQONexRCGocJJCAk5SSm7gBKbscWNUw3o1fk69SADS/ndtiv3ICJ8BoMzI1K9VuQRMtNqD996VlOXInAefW9xvdEdS01f0NwVOtqsp66amdjZCcNRP5JiDABU46wuca2g9HVQ4Sb4DJzNFbgZRg9a3z0FBR6c3XouRrtmhcnKWl0rX4BK0EW26Zs3qtJ025biBE+VWFpxGe1pdkO1wFoo0jwRnPYFzFRP2QYUTcwSczLG7hfOTnj0Ois4/+jAraqLb1D3+6babS/KeQErQhG9aHrNHqQAnr6d+NoLv2e2gvdoFzlMFzhxULb5DEOEkymT6kuokN3DiTw4ZNOCgKcI3//1KGemaIpX1XmerfvIECVj+T918Y1u1ITc3IzQnFshtFVOEufe1ImeU0p4CZy2BcxkkBxVOZjaAk4oaV3AKgFMnT1Ln1K/tabqPz16/bp16ueOzqvXll6o7b+2g0z7b01Rr2tNEXuDkPQSfDs2JPO6Es4bAyeZGSYcz0kZUZsMAhN8jbdeX7GMiggROKuLdwFns2K9QV112UclMDKb6bjHZZfX3NIUW69au1ee7I43BtMNJzEJg6TrdJdaC9zjgHFeqY4jAWVXgXICKBZBkbq7K4JPwpsiEO43vpCcmmwXQfhDXgkQtPiCRM80OOKZkgsrnUpFFsTG+kGvzKoD957WXdYIdMBucWk190quHpzzptm3pXzsaD5xm2tfaWMsZGDUt0Z4CZ2WBcx5w+AWngQkgUd8AR+dg1ukQeKClWIpL8yxaD9Ibky5vtISxv4bfaUsIrKyQNJrVbzgpegFOvsMtnKYsrM/HH6mOz/5T+6BB7CcfL5y8j+xIBNP+tB3OCgLnXDSYH3Ca3kMEGfRZBzIGHjiZhWKO1WzHTHc3AEao1OF9aFdmakg3cLAACqx05CCjgEY1e0j6BSfOOTcFzRW8BCamfrN4/XdR4MC036TAydh6msmKbNpHm+XFwHmywDkb08qgJzLIAAaUaEH5XP1MtRMwmm2ZY/mUkXbnxbQzvciBAxCg8zN3nR+a1Kx/Yd063xVukFU+cDqaztrhXC9S38B5ksA5g2b98cBpIELbsVUKUNJfnZyX2Sbbj+2k0eqkevBVgRTBXUh0t2Oz/gU4+awQzvjgpEMf08Be308MEqFaqb2B84SsrKypbHNitnz2qi3Rjmg0TC/BBeY6GUGMuRHQxPiimHtuBG6MRD4TdwMfmJspyHAaN8Xs+ZlsOHkvblyEhPy/DZy/ETgnofW8wGk6ZeCroi2BhTxhtP3M/YaUYyVQonUhWhQfNV5flHlhbixuqqDCid9MNdOQgQPUc//8u06VuU2r4bIBJ+6X5woq8Tt5rwPO4fidwHmcwJlN8GL8QreLwoi00ZhEu7y3vOtBzZpztD5aFA3IyXo9DlwF4MQKBBHO7SJfDhui2l3XWp1es5K69IJz1PJlS3U9QDLhjNKQAVkkUgM4jxU4xxJNu4HTrLkhimZAUeXJSPF4bZtNjhQNTkQPZF6OhwuLBs5N42lEz2Ktkty1a5f6Yuhg3YpG90+qdIIuBVzjMjh0wun1+uE+RMh35ok0A85fCZxf47sxOG7ABErgTJU+8hwDFwjNCaCA6gVQgOZ8+IwgwLlDznHv3j3qp5/2qUED+qoLGtUvtbCNFaObxEVyCyfccA0JbrxeP14fISjaK3I7cP5S4PyKRHgsOE3zAQYRSbXdN4wfyhJVACW14caHRuvjkLNhAa/PRDj1WnJ5Rkvu27dP8di5s0i93/ltvZzDXgCN9nzk/ns8BUSJwhklGf8icB4jcH6J/4i2iRX88Bqi2lTdecMAig8JoGQRyppYAE4uBrNVG11qi7QBcrsF5N696sD+/co8Vq9aqR57+C+6qsq5AK94Mdy/XU8q2OFkgWA8cDIzFyFi/xg4jxY4h5EwNymgSOkionKCH3zMVK8y4njJHjA7VVbfUeDEpHD+gJy2cKLpRDDZu3fv1hrywIEDyv7YK5CO+GKYanPFZcXaMsLK0Pq1qqgRX37uCU6udyJwEjPwfgec3wLnUQLnIAbHJM2dg0eSGk1EVJ4OZXWmlTauCv5xrN3pAJK6AqwCP6eLVrR31qDAudiH/OkgIM1j0YL56slHH1YN61Yv1Q3EqTWbN22ili5Z7KmAJVE48fUjTGP+AJxHCpwDMGtOOPmZL0QDoV3cpppSBVCKTpj5AVJMRyRAARKrwGu48VIWRAtGs2Buz57YMJoHC/FYPtLsvEYHtTt0CjWpNFbwsjmtHU6WVscDp1mD5IBzDXAeIXB+SkBgnwo0+/MwaPwPnzMd17Uzdyvnp818pBwofiZ1BWQr+N3rhfWj91EpAC3RszUGRMtM7xe/sSwYefC6JYsXaSgvb3Z+yVr6sprH1qteUfXr87GnIhaOE3eQDEk8cJqOIRHWtOcD5+EyeB8TgdvhRIsQ+ZLcTteW3Mb/pG4AQAHV+RrgJInPJISXkjfqESkYRnJz1xcXDjs6ydnNr9MUb7dSOsCHELjgEwKhG40Y6bFVjomGXP98/K/q4sYNNZBeuhpf3eJilbN8mefKLAMnbX3igTNKIn4ncCI9mAIkFcCAUc1NeM/f0Dhe59xTsYsc54KJd6bAODembhEvcG4RGPHhftuymbrut5erW9tfr7p+8K5aKhqLgIQHkAEczwa6/YBnacB4ADwIyK2FauaMaeqdt17XrWQanFq92Hy7hNK+QO+tN16Nq5FZonDaNtkqVQBi4LxBZD1pIpYs8GW8kMGkyCLd29SYRf9dunTRWtSeoAdOtCbas6wlFs656G4f/E9rHNNNjkGmaeujD/1ZDRrQTy1bukSbSD8fu3bt1H7kqJFf6o4jN157tTrbylWW5VPG0pqYf1o0xgOnmaEjxRgPnLbtCe1wHjBwmm5z2ZhxpjIJghjQTFj0ZvK0uC5kHSgSMf8jyON8gdYLnHod0Yocde3VLUp1dNOQSGDBmvYLzzlT3XJTW9XxmX/oivkJ48eqxQsX6AILurrhU+7evUsHNwg/A3NhYYHa+OMGtSJnuZoza6YaPXK4+qhbF/05t/3+Bh3cMAdubop4gHT2beryv3fiWs/kB5xRNOd+O5x6yYbI+wLpPlIwlDNlUnMv/Bq0JwEeqSYz7UkwRMTuJUo1vTDZSoUuHpEAMUuAa1r7/dAn87yzTlMtmjZR117VQncIocnsnX9or4WfmTq8rlVL3XzhonMb6BkckuVAb+a+a3s02bGEz6Nlzbp18ZULJhHOfWaRm12uYesX5qkzaamw0Z4UeBAcAapZeEdGglynVzh1GkQCqvvvvqPM3pzOLnRG6+kms9aGVfaGs7Wt9olR9w5CSwNXlWKpWeXnn+1i/3tt6312Lc8eRZMmZMe9zER3ppNAGjhJ3fkYEBXZmyuYhHxvfE1K0TKxJSI3HdoTSIEVOEnAE/jF07MIU/jd7FlWK0T/NFo0EHk+rdrJ6twap6jLa5+ibqxbQd1Tv6J6vEEl9dxZldSrZ1dWr1nS8azK6gn5+33yf17XXF7fqHpxC52alU/SwRPtuBPtg58onKZttwPOLU7N2Ujg3MA/k7FMOFW2dSFyR3sy905wxOwY5xxvQy0ApUiXpqt1qpzoG5AGxgbVT1ZX1qmgIet0TmU19MKqavol1dTyFtVV7uU1VN4VNVThlTXUNku2X1Us/Lz1yuL/87olzaurCc2qqY+aVFaPNKyq3n39Fc+7tUWDk7lxMiE+JuFXOuF8ioAok7e3Jq+Jf4n2BEosBLNjXFy3lTjREunvvdMpqv/pOnK25GzRcB3qVVBvCIxfN62qQQQyJ3hIoQsxr91+ZXW1rVVtteXdF1Thls0JTyDwfiZrEoEzyvTlHDucLNeYiImLNMeeSdqTxXdE7aZyCTiZfksETi4yn/36K/+SSNo7oGjJevLcSjQkpjlbNBzazmhCtxDGlMurqYI2p6m8rq+prVs2+dKv0w4nNQzxwGncAgecI+1a8xK2fMn0DsemKMQERoCJj00ldyJwlgAq38G0If6cGx+0lsjp4kO2Fy3Z+7wqWkP6CmQJmFVVfvsmKn/QR2orgZ9P1Vd+wBllkVs3O5zPkttM1VpNPwUfhwsAnGhPnqkB9Wuw8ON69fhQ5zmjRfGY7roi10ug0u/8Kmpty+r+A4lcIdpSnvP/1k7lT8+2oPR3lzqaUSQCJ+6AMwEv8pQBk6Uao6OVzWVqT05j2vE/sRh+DhjCPHeH69uUpG3sJrxpzVNU53Mrq5VJg7J6sba8+QKV17OTKly3Wm3b4X9XEjucbpvvOoUaYQecu9iK0MB5ugzQ+qD06DTbWGPODZykMpKxJxBV553eeFU1O++sYi0q0fxtp1dUk8Wn9BLQePErkfx2jVVep6dUwbzZxdoySUXUicJJhiRCn3i2ITzPwNlOZF+Q9lwnv8m0JSYdOEkCJ2vwEKYhn3/6SfXS5eeoVS2qqe2i1bR288l0F7asqgqurq3y72yh8t5/SRX8MLPYh05yi0XT5x043XaGdpHjnCtSycD5Crm/TCjy8CKkLwycRO3JXKJh5q0LFs5VBb3+q/IeuVHl/66hKgDQllW0CdaQxQKW/2lzXQwj7yloVUfl33qxyvvXAyp/eD9VuHK52sp5lFPfz0TgNBVNEZZoDBQ5yixw+zwo/qbT7wROxI9o3ZUADTtdbNygCmZPUXn9u6q8Vx9ReQ+0Vfm3XKQKALZNPa0FC66upQpF9M+t66qCtmfoiDvvT1eo/L/fovLee1HlfzNMFS5frGs5tzEFWc5roOwL1OKBkzxzhJWXz5p2NFXoz0liOpEuc+la50mGAjgp/ijXZRpauxVpoLgpgLUwZ7Eq+G6ayp/0jUA3VBWMHqwKRw9S+V8PVfkTRqmCWZNUweIfdHCzlT0p6cihgTx03ZHtcLrtqW+XCNsO7hZpbeA8n+0Fg7aDmzPfSS2r1/6cvsMKZBaw24p2OqSo+H9o3hRaIZoInIxBhC2v2XKwpoGzHVVI9NUM2t6XBEVoTOA02wuGLRC9w2m2biED4qUzdJQlwdrfNHA+IQNzgMVJQYPTLAs2fic9e0I4yw9OlIFDayr7TsLA2TmIkXqkiJ3KmBC4+OF0u1VOjK7GVMSdVQKnDMxnVL1HW9ed6X4nPo/RnPEUHIdw/jw37hbOGCZ9qNkDUz9kUMY416wHbYMsAydJ+VRsrJBpcEZpt71f5M5Sm2TJoMykTI5kaFA3ZTXFH1QoBaUNol8zX2YfdQBzu8mY6YnggHOhSDUnnAvd9ObM5L3WTQEI7k3Q+8K7gRHXhyXVwEjDWLp1AJibTcZitDx85aBdgwXOZV5abmcanJgX0kjASSEIuc8QztIwUpzBBA1xCb2zCGQIJDHl+I3UJQCpG5coyqas60oFQjY4c4IMJxfbwEmLR7emKZOBBEbSbNyodPGgaoh6V2A0W0CymoAMj2lQ4WW6MkJh8X9FDg81ZwzNCZxenPpMgZHpU7Mhmdk9j7SagRH/kDoEiolN/YX9/W6/j++IMCO0WqThQWCGPmeeNkfG5wROL4nkdIaR8ydDQ30Bs4NMXwMjws9kMVjqy2t47Var810i1wbwI/iazxkwI8E5K1bL7aBE65moOe0wca5kZAhGMMloQ7QiMGKyMd2YcOoL0HB+wOgsjeN7HGBOFakcEUwLzrFhnjMrI3xOO0y0eEHh4OPRepygxSS9CWbYaY8pa/xK/Ev8TL9gjNRuBlchwvbV10YF04JzYJBniIgcDZzpFq3bYSK9Q9yAW0IZGudl7Yy2X6DYKJLNWnDAwLzaYUzm+aKBuQkimPNXRY6ICacMyrvMrWdq+xk3u7cZOFM9zxkr10i/fqsxwQEBcYvINPn5fZHbrDTNsSKN2B0Nn7K8zhM3KcI05TCRE2OCacH5ZJCrkuiRZKYvU22GKFauEbNs0jsCYqHIHJHuMtj3iDQWOd4eaNjkOnndZsx8Ms/VLN/gGB3mfLpIvahBkAPODkGu5zSL3FJlbj1WrtGkd2Swt4vME/lEBvdBkQtFTooCYyS5j8/A9CdjS0UDJsfrAPN768YpG0wLzgtlYDYTvQXN3yQyNZXwh6oqKVqukUAN80tELQNcJLJYZIAM6GMil4pUtPtsTon0sP2f9z0CoGhQP/eZ5zww5RE05gyRJq7BtOCs2qVLl/kMTCZ2litr52MidLN23a+uH/HmGk16RwZ1t0iOCL7ZUyJXiFQVOdILjC4AvUe+YxPnzWyPCZIS6RWFe4iP6QDzc5HTPB+vDMwv2F4wqKsvTY4TzUm6IxkmLlqukWlAK1jYK4O5WmSk/NzRWuDFOpqjE4WxDECR1vK9c3EXuB4cn8lxuj0/oMaMM+fuCHw2WedzYlzHbq1bfy2IEbs9UmcKE99uR4LrvV3mGvcJEOtFvpWfXxO5XuRUkV8kA0YXgPLdWXI824j4mZgANrMvkz0wc7ohZAtwQSyNb89h9mdb6oTOw4Kzg8hP3M1B6vhBTUGiOU6PucYJ8nMn+gCJ1LfSO+UCowtAWVTWSmSwHGcBsHEzwQQ+MGaf80LrY7rtU57y+v0WkORR3xa5zFS0J3Q+FpxniM+Vy10dlF5JOO2mV5JZt+5mY9YEc43HHUoYXQB6mKW90Xgvy/GPF1knsgNtL/KT5YJsE1khMsKaG79Z5AKRk309NwvOY2WAvs30xrHRGsjG6viRpFzjIQXSJaTIr62c5GWW69FepK3IxZZP/Iuknp+tP+cLQerPCVD2/pz4WUZresw19naba0yXh4d8aXLPzQZncxmkbZme7zSdPtgwy+5vog1NzWEyc43hIz5Aj5fBmsyePKQTMrknvL1MDiERz1oiUinlkWsMH/Fpz+dIqeBPZfJuGqbLh72Oc+jQoXvKM9cYPrzDea4M2kZ8qkzdh4ico4nSjYivvXnQoEG3y3nXKc9cY/hw8TjiiCMMnEcLnP3ouEZOKxO1J2bbrjVF9oiM6ty583EDBw4MgUxx7XmtDN7OTAuMuNEIeuyBkCUvWxvS6vMPH6kN53HsrGH2hswk7WmverdklUg9+8a04SP1AW0vg7gb7Zkp+62jNVkr5YCzcwhlemrPEfiemVAMYnrzOMD8UaRJCGd6AtqK7QapMknnXvGmbtMZoYu8J3JECGd6wnmUSBZTmlTYpKv2pPqIzRgcWnMt23eHYKY3oKfJoC6iEDldlw4zH+7QmMjzYRCU/nAit7MAjsQ85WHpZs7xmx1ac1qYOsocQI8ReZ9pTUrE0gVMijfMykobmFtF2oZaM7MArSKDPI6lHHRlS2XzzrHhZ9pL4mzyH5EjQzAzz7w3kcFeQnKe1YKpCCjHRGaBMrcIfuY3IhVCMDMX0N8KoLl0xmAtSSoBasCk/6Ppt2mTJRS1hOY88wFl9mgTgBJwpAKgHAPBGguyIoBJsv2aEMzgAEoLm1yKKPBBDzWYFEezsCwCmPkit4VgBg/Qa2jZzcwLuUQ0V3lrUbOKkiR7BB8TMO8OwQwuoOw4nI3GIjo2VUzJhtT4lzQqiFDMgWwQuTUEMwS0CvPUAkgRoLAozOyw4Dek5vMohOZmMHulO8CcT11ACGYIaEkFveWHzgIQOmkwH+8HpOb9VBZhwqkuoslrBCj3iwwTaRCCGT6cgOqOdSySE3CWY+rpokFzJ6AyPqldooFoB5ImD6ZzWRQokXU0wWUFaQhm+CgLUqrLnxGQvhPZS9A0ePBgnYMkuscsM72IZqW3EODyTNTNmnJSVCzTBUiKTqKYbzMd2dtelxmCGT7cQlpRpB3bZotsATA0KrDin7JGHhdg4MCBeh4cENGOpmemaeoaAcpNIn1ErrRcihDK8BE3pBSPnC/yosgkkTyBbr+Bzy4RQDT+5GaRbNwGkcZWvWmoLcOHb5AiJ4hcKvK4SF+R2VbqZydtGC0pEskVmWVpyEdFLnb6lCGUmf34f1GpPjibEzUWAAAAAElFTkSuQmCC'; + +// Core, Team, and Official extension classes should be registered statically with the Extension Manager. +// See: scratch-vm/src/extension-support/extension-manager.js +class GizmoRobot { + constructor (runtime) { + /** + * Store this for later communication with the Scratch VM runtime. + * If this extension is running in a sandbox then `runtime` is an async proxy object. + * @type {Runtime} + */ + this.scratch_vm = runtime; + + this.robot = this; + + this._mStatus = 1; + this._mConnection = null; + this.CHROME_EXTENSION_ID = "jpehlabbcdkiocalmhikacglppfenoeo"; // "molfimodiodghknifkeikkldkogpapki"; APP ID on Chrome Web Store + + this.msg1 = {}; + this.msg2 = {}; + this.dist_read = 0; + this.infrared_read = 0; + this.scratch_vm.on('PROJECT_STOP_ALL', this.stopMotors.bind(this)); + + this.connectToExtension(); + } + + /** + * @return {object} This extension's metadata. + */ + getInfo () { + return { + id: 'gizmoRobot', + name: formatMessage({ + id: 'gizmoRobot', + default: 'PRG Gizmo Robot', + description: 'Extension using Gizmo Robot Chrome extension to communicate with Gizmo robot' + }), + blockIconURI: blockIconURI, + menuIconURI: blockIconURI, + docsURI: 'https://aieducation.mit.edu/poppet.html', + + blocks: [ + { + opcode: 'setLEDColor', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.setLEDColor', + default: 'set LED color [COLOR]', + description: 'Set the LED color' + }), + arguments: { + COLOR: { + type:ArgumentType.COLOR + // should I put a default color? + } + } + }, + { + opcode: 'ledOff', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.ledOff', + default: 'turn LED off', + description: 'Turn off the LED' + }), + arguments: { } + }, + { + opcode: 'readDistance', + blockType: BlockType.REPORTER, + text: formatMessage({ + id: 'arduinoBot.readDistance', + default: 'read distance', + description: 'Get distance read from ultrasonic distance sensor' + }), + arguments: { } + }, + { + opcode: 'readInfrared', + blockType: BlockType.REPORTER, + text: formatMessage({ + id: 'arduinoBot.readInfrared', + default: 'read infrared sensor', + description: 'Get distance read from ultrasonic distance sensor' + }), + arguments: { } + }, + { + opcode: 'driveForward', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.driveForward', + default: 'drive forward [NUM] second(s)', + description: 'The amount of time to drive forward for' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + { + opcode: 'driveBackward', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.driveBackward', + default: 'drive backward [NUM] second(s)', + description: 'The amount of time to drive backward for' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + { + opcode: 'turnLeft', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.turnLeft', + default: 'turn left [NUM] second(s)', + description: 'The amount of time to turn left for' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + { + opcode: 'turnRight', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.turnRight', + default: 'turn right [NUM] second(s)', + description: 'The amount of time to turn right for' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + } + } + } + // add blocks for speech? + ] + }; + } + + connectToExtension() { + // Save reference to robot for use later + var robot = this; + var boundMsgHandler = this.onMsgFromExtension.bind(this); + + // Attenpt to connect to the Gizmo Chrome Extension + chrome.runtime.sendMessage(this.CHROME_EXTENSION_ID, {message: "STATUS"}, function (response) { + if (response === undefined) { //Chrome app not found + // Must have the wrong extension ID (if extension was not downloaded from Chrome webstore, the extension id is not consistent) + console.log("Chrome app not found with extension ID: " + robot.CHROME_EXTENSION_ID); + + // Attempt to get the extension ID from local browser storage + robot.CHROME_EXTENSION_ID = window.localStorage.getItem('gizmo_extension_id'); + console.log("Stored extension ID: " + robot.CHROME_EXTENSION_ID); + if (robot.CHROME_EXTENSION_ID === undefined || robot.CHROME_EXTENSION_ID === "" || robot.CHROME_EXTENSION_ID === null) { + // If there is no extension ID in local browser storage, prompt user to enter one + robot.CHROME_EXTENSION_ID = window.prompt("Enter the correct Chrome Extension ID", "pnjoidacmeigcdbikhgjolnadkdiegca"); + } + robot._mStatus = 0; + // Try to connect to the Chrome extension again + robot.connectToExtension(); + } else if (response.status === false) { //Chrome app says not connected + console.log("Chome extension is not running"); // what does this mean? + robot._mStatus = 1; + } else {// Chrome app is connected + console.log("Chrome extension found"); + // Save the extension ID in local browser storage for next time + window.localStorage.setItem('gizmo_extension_id', robot.CHROME_EXTENSION_ID); + if (robot._mStatus !== 2) { + robot._mConnection = chrome.runtime.connect(robot.CHROME_EXTENSION_ID); + // Add listener that triggers onMsgFromExtension everytime the Chrome extension gets a message from the robot + robot._mConnection.onMessage.addListener(boundMsgHandler); + // We're not sure that it's working until we start receiving messages + robot._mStatus = 1; + } + } + }); + } + + /** + * Implement onMsgFromExtension + * @msg {chrome.runtime.Message} the message received from the connected Chrome extension + * When a message is received from the Chrome extension, and therefore the robot, this handles that message + */ + onMsgFromExtension (msg) { + if (this._mStatus == 1) { + console.log("Receiving messages from robot"); + } + this._mStatus = 2; + var buffer = msg.buffer; + + // The beginning of the buffer (from firmata) starts with 224, if this buffer starts with 224 it is the beginning of the message + if ( buffer[0]==224) { + this.messageParser(buffer); + last_reading = 0; // Last reading signifies that the last thing stored in the msg buffer is the first part of the message + } + + if (buffer[0] != 224 && last_reading == 0) { // Checking last reading makes sure that we don't concatenate the wrong part of the message + this.messageParser(buffer); + last_reading = 1; + } + } + + /** + * Implement messageParser + * @buf {byte buffer} a buffer containing a series of opcode keys and data value pairs + * @dist_read {int} the last reading from the ultrasonic distance sensor + * @msg1 {byte buffer} since the entire buffer does not always get transmitted in a message, this will store the first part of the buffer + * @msg2 {byte buffer} since the entire buffer does not always get transmitted in a message, this will store the second part of the buffer + */ + messageParser (buf) { + var msg = {}; + if (buf[0]==224){ + this.msg1 = buf; + } else if (buf[0] != 224) { + this.msg2 = buf; + } + msg.buffer = this.msg1.concat(this.msg2); + + if (msg.buffer.length > 10) { + msg.buffer = msg.buffer.slice(0,10); // The length of the buffer (from firmata) is only 10 bytes + } + if (msg.buffer.length == 10){ + if (msg.buffer[8] == 240) { // The opcode key before the ultrasonic distance reading data is 240 + this.dist_read = Math.round(msg.buffer[9] ); + } + if (msg.buffer[0] == 224) { + this.infrared_read = Math.round(msg.buffer[1]); + } + // We currently don't read any other data from the robot, but if we did we would put it here + } + } + + /** + * + */ + setLEDColor (args) { + var h = args.COLOR; + + // Translate color arg to red, green, blue values + var rVal = parseInt("0x" + h[1] + h[2], 16); + var gVal = parseInt("0x" + h[3] + h[4], 16); + var bVal = parseInt("0x" + h[5] + h[6], 16); + + console.log("set LED color: " + args.COLOR); + console.log("R:" + rVal + " B:" + bVal + " G:" + gVal); + + // Send message + var msg = {} + msg.buffer = [204,rVal]; + this._mConnection.postMessage(msg); + + msg.buffer = [205,gVal]; + this._mConnection.postMessage(msg); + + msg.buffer = [206,bVal]; + this._mConnection.postMessage(msg); + + return; + } + + ledOff () { + console.log("LED off"); + var msg = {} + msg.buffer = [204,0]; + this._mConnection.postMessage(msg); + + msg.buffer = [205,0]; + this._mConnection.postMessage(msg); + + msg.buffer = [206,0]; + this._mConnection.postMessage(msg); + + return; + } + + /** + * Implement readDistance + * @returns {string} the distance, in cm, of the nearest object. -1 means error + */ + readDistance () { + var distance = this.dist_read; + if (distance == 0) { + distance = -1; + } + return distance; + } + + /** + * Implement readInfrared + * @returns {string} 0 if the object is detected or 1 if not + */ + readInfrared () { + var val = this.infrared_read; + if (val == 0) { + val = -1; + } + return val; + } + + /** + * Implement stopMotors + * @callback {function} the code to call when this function is done executing + */ + stopMotors () { + var msg = {}; + console.log("Sending 207 to stop servos"); + msg.buffer = [207,99]; + this._mConnection.postMessage(msg); + } + + /** + * Implement driveForward + * @secs {number} the number of seconds to drive forward + * @callback {function} the code to call when this function is done executing + */ + driveForward (args) { + var msg = {}; + var secs = args.NUM; + console.log("Sending 208 to drive forward, secs: " + secs); + msg.buffer = [208,99]; + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + + /** + * Implement driveBackward + * @secs {number} the number of seconds to drive backward + * @callback {function} the code to call when this function is done executing + */ + driveBackward (args) { + var msg = {}; + var secs = args.NUM; + console.log("Sending 209 to drive backward, secs: " + secs); + msg.buffer = [209,99]; + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + + /** + * Implement turnLeft + * @secs {number} the number of seconds to turn left + * @callback {function} the code to call when this function is done executing + */ + turnLeft (args) { + var msg = {}; + var secs = args.NUM; + console.log("Sending 210 to turn left, secs: " + secs); + msg.buffer = [210,99]; + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + + /** + * Implement turnRight + * @secs {number} the number of seconds to turn right + * @callback {function} the code to call when this function is done executing + */ + turnRight (args) { + var msg = {}; + var secs = args.NUM; + console.log("Sending 211 to turn right, secs: " + secs); + msg.buffer = [211,99]; + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + + +} +module.exports = GizmoRobot; \ No newline at end of file diff --git a/src/extensions/scratch3_microbot/index.js b/src/extensions/scratch3_microbot/index.js new file mode 100644 index 00000000000..77f3abfa98a --- /dev/null +++ b/src/extensions/scratch3_microbot/index.js @@ -0,0 +1,676 @@ +require("regenerator-runtime/runtime"); +const Runtime = require('../../engine/runtime'); + +const ArgumentType = require('../../extension-support/argument-type'); +const BlockType = require('../../extension-support/block-type'); +const formatMessage = require('format-message'); +const Cast = require('../../util/cast'); +const MathUtil = require('../../util/math-util'); + +const microbit = require("microbit-web-bluetooth"); + + + +const blockIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAKcElEQVR42u2cfXAU9RnHv7u3L3d7l9yR5PIGXO7MkQKaYiCUWqJhFGvRMk4JZXSc8aXVaSmiYlthVHQEW99FxiIdrVY6teiMdoa+ICqhIqgQAsjwMgYDOQKXl7uY17u9293b3f5x5JKYe8+FJGSfvzbP/n77e/azz+95nt9v90KoqgpN0hdSQ6AB1ABqADWAmmgANYAaQA2gJhpADeBEE2q8GPLaWzu/CslyiY4k9dOn5uijtXGd7+jWkaReVpT3Hrhv6d0awEFC07rgD+ZeYYnXprhwigUAvjj0zbjxQCLebozT7iDzK1ZUWCru2K7L//6MVC8ue45Blz8n6rlQ815QtuohOlXiEdy/AUqPa6y59Mkh6Q1345GNja6m7pHEQKNl3t0704EXat4L6fSOmOeEI1vHKzwAyNJR9MPFpRUPOu0ONm2A0xatWaTLm5WfDrzvAppA8AbiG03fC8CQNkDKZK2YrPAuRrhpifJERsuYywveJc7CqcIDMAyeLm82dEXzw39I/qjXkpr3QuW9lxfAdOABGAKPslWDnbsy7Jl8BxTeM3SqmO0gaA5U6c3jymup0YSn9JyLee67wpTfBQAQjmyF3HFqiJcRtDECjy5dAmbmcgQPvjjxl3Lx4IVjnD/5cE1zkWtyP34VBGcdKLJnLgc9cznk1kMXFdzEn8KJ4KUqqsSHvcxWDf7j1UM8UPr6/YgHhhX8xAaYaXgAIB7fBnbuSrBzV8aNgarEQ/z6/YkLcDTg9V9XlXjQtuqoU1TpcUHlvZDOfDiuyh5qPMCLrJ1bDw3EuUtx81N/BH3pjQBJQ2HMF5V6iKfeRchVm9kkMtrwxmSdobeA9daBde8GwVlBcFYofS1Jw0vaAy9HeJHQwBUPzIBvGxDc92Rmp/BowJs10wkAONfsBs8HAAAltqngOAO8HZ3o6OiMqcvLy4E1Lwc8H8C5ZndMXdLJa/qNacNLCDBw/O8nFUNWxp/64+tWAwBefe1tHKg7CgC4/9d3ori4EHv3HcDrb26PqVt2602ovvaHaGlpw+8ffSamLqXYmya8jG8mpFy6iGLkWLh4HAwG4+r6j4VBfaPpLgU8IMGO9MLqW2pYQ9aQokuR5dgXIwCC1CUcNMj3hpdvLAdSF54EYpCHooRA0Swomo2pC0kCQpIAkqTA6LmYupgxL0X7m78+aG10NXVkpIwxsAwWXncDCESHLkohfPbpbiT6ZFPPZQ9fC0e58Wi6wTDj6UbT/rQAyiERS2pW4Kc3LQDLRO8miCEAKj7d83FcTxyLJJJJ+9MCqKoq9HomMrgkSThxsgEcZ8AMpwMkSYJlKDA0DVUFiHGWRDJp/4jXwqIo4uFHnkZXdw8AYGbZFXhs3WqQJDkhkkim7E8KoMlkxKbnn8DBunrwUli3e8/+yOAA0HjmHDq7upGXm5PUoDUr7hmWRB5Zt3FYwoime+vtd/H6G9uGJIxouniSyP6H7v8FystnY80jGzIA0MihsMAKu20aTp3JzFb6WCWRuDUvHwByw8cOhw2FBVaYjNzIAba1e3Hfb9aiq7MTNStuBwAsvr4KO3d9GnmKztIS5EyxTJiVSDT7p04tipx/9MnnYc7ORlu7NzMxsK3di5AkDHgGw2DTC+uHBeGJshJJZL/fxyMQEDKbRAiCQDAoQhBDYBkKNE2j4uqrhpUBoiSBIMZfEhkN+1NeiWSqEB2rlUg69md0JRIQRHy86z8jXsqNVRLJlP0jqgNJXXgAgjbCcONmCHUvQ+44NWG2s/rtH5Mt/ciToo0wLH4JBGO6LLazRiJk2vBYy4gHHw/bWSN+LZBKEhkMjzn/CaSiKgQOvJDyFB7L7axUJWNJZDA8IhQA1boPin7KZbMSGfUYyFx9b3hXg/cCsoBA2Z0AoYOaxlcC4+mdyCUDKBzanLFBJ3USyaRMuiSSKZmUSSSTMimTCABUlblRU9kAZ0E39p+eii21c+EL0jHbOwu6sfaWgyjND//U4oP6MmzZnfi79XT7mfQSNi7bh0JzOLG19XBY/89r49pYVebGqhuOosDsh1+gsWV3BXYdd2Q+BlaVuXFv9bHgkSbzk+vfcVRyjHhi47J9cftsXLYf7T36Ix8cLHlo6ydlv6qpPI2qssRZcuOy/Wjp4k5s+2zG+offKqtcUt6kJtNv7S0H0RtkvEufXTB/6bML5je2Wy7UVDbEbF9o9mPDsv2oP5v75vbPS26rP5u3fdXiozDppcwDrKlswOlWy9E//DX09Mt/azh8zzNM1RybF86C7pheVGD240CDeX3NWtfml94Rt+0+Mf3Lm8qbEnpfgdmPs+3G9+564vTT//pM/GrHYduWRP0AYOEMN/5S61xT92Vtfd2XtfWb/vu91fHALyxzw9tnkB/cTD5w+2Ou9375HHtfa7exM5mxRpKFaafdQQKgAcDERs98/foLHrXdaXfoABi8vczhWO2/28/TRR5z2h00gKymNl1ton79oigq6bQ7dE67Q+ew9mb1h4FYYwVESgLAXLSRa+3mWpIdK+UYuPiq89f8+XfT/+ftZQ4vLm9ZmUyfdcsv1M2fWfRaUCK8i8vdK1u6ktuAWPWTsztm24o/cnnYHUsrWzd1+fVJ9XtqxbG3XzFdNcPTawjcueibpxK1t+X26f/9R8a953jub4typOvm2b1XnvUmv8JKWMZcaZffX3XDERRP8cGaFRjWxtPLoZvXY4oxgPBNEsgxBhCUKEzL6Ru+JydS8Ak0giKFgESDJFQoKmCgQzAwIfQEWETzmoBIwd2VNaStu8uEHGO4Buz06zHHFv0dRkefAZ1+PQx0KNK2eIoPLCUj2zDc275qzgcBFWv+cf3IyxgTK2KOzQufEM5kfpGF12eGPSf8DXN+No/87HDWiwYYALw+M6ym8AscAxO++X7xCTRM7EDQzht0Da8v/NWo1dQDAxNCocUXs+303IGHdaptOmYXnh/SLlZbV+fwnwJm6UXEm/ojqgM/PFmJQ81OPHfrtqT7bN23BE8seTflYLvz5DwYGQHLKz5Puo/XZ8aLtT+D1dSDuxbsGQIymmz48DbwIguOESJOcce8XaO3oVpZ8k3Em5KVVAAMFnuOB9as1MbimCBunn04vBmR40ls29Wfgxf1KMn1gBdY+MXUCvK4ANvPndpLzrLzALjBN2VPwrDBksgLYkn1jBMp90nVY2++8vAw3RlPeLNYVZSPAEgjKWP6ZCn4lF+gMdnE08spQb73RQB9aXtgo6tJcNodf8rWz3L//Br340UW3sExEkXrFFKSSUVHqkRfkJZ8QSZk5gS6hw9H+GyDQAclSs41BVmSUIn+toAKIUTJskKoQUknCxKlkISKb/sM0NMyyVAhXW+AlYosfgOgQlUJVadTSUWBKoQoudvPioPbenq5oIUTaRUqenhWKi3oyVIUqKpKREoLggDhF6hQb4CV9LRM9rctMPN6glChp2SdTqeSskwoAECSKnG61fzFR/XsGu+FhmONriYl7TImsjoYKJyZSeB8CoBQo6spqU8TCO1fgE7gDVUNoCYaQA2gBlADqAHURAOoAdQAagA10QCOgfwfNp/hXbfBMCAAAAAASUVORK5CYII='; +const _colors = ['red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'white', 'random']; +const _colors_protocol = ['G#','J#','H#','K#','I#','L#','M#']; + +const _songs = ['happy','sad','sleeping','angry','up', 'down', 'victory']; +const _songs_notes = [[64, 65, 67], // happy + [69, 67, 65, 62, 60], // sad + [60, 62, 64, 60, 60, 62, 64, 60], // sleeping + [67, 67, 67, 64, 64, 65, 65, 65, 62], // angry + [64, 65, 67, 69, 71, 72], // up + [72, 71, 69, 67, 65, 64], //down + [64, 67, 72]]; // victory +const _notes_protocol = ['1#','B1#', '2#','B2#', '3#','4#','B3#', '5#','B4#', '6#','B5#', '7#','8#',]; +const MIN_PIEZO_NOTE = 60; +const MAX_PIEZO_NOTE = 72; + +const _drive = ['forward', 'backward']; +const _turn = ['left', 'right']; + +const _button = ['A','B','A or B','A and B','neither A nor B']; +const _line_states = ['right side', 'left side', 'neither side', 'both sides']; + +const EXTENSION_ID = 'microbitRobot'; + + +// Core, Team, and Official extension classes should be registered statically with the Extension Manager. +// See: scratch-vm/src/extension-support/extension-manager.js +class MicrobitRobot { + constructor (runtime) { + /** + * Store this for later communication with the Scratch VM runtime. + * If this extension is running in a sandbox then `runtime` is an async proxy object. + * @type {Runtime} + */ + this.scratch_vm = runtime; + this.scratch_vm.registerPeripheralExtension(EXTENSION_ID, this); + this.scratch_vm.connectPeripheral(EXTENSION_ID, 0); + + this.robot = this; + + this._mStatus = 1; + this._mDevice = null; + this._mServices = null; + + this.dist_read = 0; + this.a_button = 0; + this.b_button = 0; + this.left_line = 0; + this.right_line = 0; + this.last_reading_time = 0; + + this.scratch_vm.on('PROJECT_STOP_ALL', this.resetRobot.bind(this)); + this.scratch_vm.on('CONNECT_MICROBIT_ROBOT', this.connectToBLE.bind(this)); + + console.log("Version: adding clear led display"); + } + + /** + * @return {object} This extension's metadata. + */ + getInfo () { + return { + id: EXTENSION_ID, + name: formatMessage({ + id: 'microbitRobot', + default: 'PRG Microbit Robot Blocks', + description: 'Extension using BLE to communicate with Microbit robot. Use hex file in https://sites.google.com/view/httyr-setup' + }), + showStatusButton: true, + blockIconURI: blockIconURI, + menuIconURI: blockIconURI, + + blocks: [ + { + func: 'CONNECT_MICROBIT_ROBOT', + blockType: BlockType.BUTTON, + text: 'Connect Robot' + }, + /*{ + opcode: 'sendCommand', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.sendCommand', + default: 'send comand [COMMAND]', + description: 'Send a particular command to the robot' + }), + arguments: { + COMMAND: { + type:ArgumentType.STRING, + defaultValue: "A#" + } + } + },*/ + '---', + { + opcode: 'writeLedString', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.writeLEDString', + default: 'display text [TEXT]', + description: 'Write string to LED display' + }), + arguments: { + TEXT: { + type: ArgumentType.STRING, + defaultValue: "Hello" + } + } + }, + { + opcode: 'setLedDisplay', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.setLEDDisplay', + default: 'display [MATRIX]', + description: 'Set the LED display' + }), + arguments: { + MATRIX: { + type: ArgumentType.MATRIX, + defaultValue: '0101010101100010101000100' + } + } + }, + { + opcode: 'clearLedDisplay', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.clearLEDDisplay', + default: 'clear display', + description: 'Clear LED display' + }) + }, + '---', + { + opcode: 'setRgbLedColor', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.setLEDColor', + default: 'set headlight color [COLOR]', + description: 'Set the RGB headlight color' + }), + arguments: { + COLOR: { + type:ArgumentType.STRING, + menu: 'COLORS', + defaultValue: "random" + } + } + }, + { + opcode: 'rgbLedOff', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.ledOff', + default: 'turn headlights off', + description: 'Turn off the LED' + }), + arguments: { } + }, + '---', + { + opcode: 'drive', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.driveForwardBackward', + default: 'drive [DIR] for [NUM] seconds', + description: 'Send command to robot to drive forward or backward' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + }, + DIR: { + type:ArgumentType.String, + menu: 'DIRS', + defaultValue: _drive[0] + } + } + }, + { + opcode: 'turn', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.turnRightLeft', + default: 'turn [TURN] for [NUM] seconds', + description: 'Send command to robot to turn right or left' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + }, + TURN: { + type:ArgumentType.String, + menu: 'TURNS', + defaultValue: _turn[0] + } + } + }, + { + opcode: 'stopMotors', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.stopMotors', + default: 'stop motors', + description: 'Stop both motors on the robot' + }) + }, + '---', + { + opcode: 'playMusic', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.playMusic', + default: 'play song [SONG]', + description: 'Play song using the piezo' + }), + arguments: { + SONG: { + type:ArgumentType.STRING, + menu: 'SONGS', + defaultValue: _songs[0] + } + } + }, + { + opcode: 'playNote', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'microbitBot.playNote', + default: 'play note [NOTE] for [NUM] seconds', + description: 'Play note using the piezo' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + }, + NOTE: { + type:ArgumentType.NOTE, + defaultValue: 60 + } + } + }, + '---', + { + opcode: 'whenButtonPressed', + text: formatMessage({ + id: 'arduinoBot.readButtonStatus', + default: 'when [BUTTON] button pressed', + description: 'Trigger when buttons on microbit are pressed' + }), + blockType: BlockType.HAT, + arguments: { + BUTTON: { + type:ArgumentType.String, + menu: 'BUTTON_STATES', + defaultValue: _button[0] + } + } + }, + { + opcode: 'readLineStatus', + blockType: BlockType.BOOLEAN, + text: formatMessage({ + id: 'arduinoBot.readLineSensorStatus', + default: 'line detected on [LINE]', + description: 'detect line sensor state' + }), + arguments: { + LINE: { + type:ArgumentType.String, + menu: 'LINE_STATES', + defaultValue: _line_states[0] + } + } + }, + { + opcode: 'readDistance', + blockType: BlockType.REPORTER, + text: formatMessage({ + id: 'arduinoBot.readDistance', + default: 'read distance', + description: 'Get distance read from ultrasonic distance sensor' + }) + } + ], + menus: { + SONGS: { + acceptReporters: false, + items: _songs + }, + COLORS: { + acceptReporters: false, + items: _colors + }, + DIRS: { + acceptReporters: false, + items: _drive + }, + TURNS: { + acceptReporters: false, + items: _turn + }, + BUTTON_STATES: { + acceptReporters: false, + items: _button + }, + LINE_STATES: { + acceptReporters: false, + items: _line_states + } + } + }; + } + + /* The following 4 functions have to exist for the peripherial indicator */ + connect() { + } + disconnect() { + } + scan() { + + } + isConnected() { + return (this._mStatus == 2); + } + + onDeviceDisconnected() { + console.log("Lost connection to robot"); + this.scratch_vm.emit(this.scratch_vm.constructor.PERIPHERAL_DISCONNECTED); + this._mDevice = null; + this._mServices = null; + this._mStatus = 1; + } + + async connectToBLE() { + console.log("Getting BLE device"); + + if (window.navigator.bluetooth) { + try { + this._mDevice = await microbit.requestMicrobit(window.navigator.bluetooth); + this._mServices = await microbit.getServices(this._mDevice); + console.log(this._mServices); + + if (this._mServices.deviceInformationService) { + this._mStatus = 2; + this.scratch_vm.emit(this.scratch_vm.constructor.PERIPHERAL_CONNECTED); + + if (this._mServices.uartService) { + this._mServices.uartService.addEventListener("receiveText", this.updateSensors.bind(this)); + this._mDevice.addEventListener("gattserverdisconnected", this.onDeviceDisconnected.bind(this)); + } + } + } catch(err) { + console.log(err); + if (err.message == "Bluetooth adapter not available.") alert("Your device does not support BLE connections. Please go to the robot setup instructions to install the Gizmo Robot Extension."); + } + } else { + alert("Error trying to connect to BLE devices. Please try again."); + } + } + + resetRobot() { + this.stopMotors(); + this.rgbLedOff(); + this.stopMusic(); + } + + /** + * RANDI just for testing out sending commands to robot via ble + */ + sendCommand (args) { + let command = args.COMMAND; + if (this._mServices) this._mServices.uartService.sendText(command); + else console.log("No device"); + } + + clearLedDisplay (args) { + let ledMatrix = [[false, false, false, false, false], + [false, false, false, false, false], + [false, false, false, false, false], + [false, false, false, false, false], + [false, false, false, false, false]]; + console.log("Clear led display"); + if (this._mServices) this._mServices.ledService.writeMatrixState(ledMatrix); + } + + setLedDisplay (args) { + let matrix = args.MATRIX; + let ledMatrix = [[false, false, false, false, false], + [false, false, false, false, false], + [false, false, false, false, false], + [false, false, false, false, false], + [false, false, false, false, false]]; + for (let i = 0; i < 5; i++) { + for (let j = 0; j < 5; j++) { + if (matrix[5*i+j] == 1) ledMatrix[i][j] = true; + } + } + console.log("Set led matrix: " + ledMatrix); + if (this._mServices) this._mServices.ledService.writeMatrixState(ledMatrix); + + } + + writeLedString (args) { + let text = args.TEXT; + console.log("Write led string: " + text); + if (this._mServices) this._mServices.ledService.writeText(text); + + } + + /** + * + */ + async playMusic (args) { + console.log("play song: " + args.SONG); + + // Translate song to index to get notes + let idxStr = _songs.indexOf(args.SONG); + let song_notes = _songs_notes[idxStr]; + + // Loop through notes and play them + let arg = {}; + + for (let i=0; i<_songs_notes[idxStr].length; i++) { + arg.NOTE = _songs_notes[idxStr][i]; + arg.NUM = 0.25; + await this.playNote(arg); + } + } + + /** + * + */ + playNote (args) { + console.log("play note: " + args.NOTE); + let secs = args.NUM; + let noteIdx = Cast.toNumber(args.NOTE); + noteIdx = MathUtil.clamp(noteIdx, MIN_PIEZO_NOTE, MAX_PIEZO_NOTE) - 60; + let note = _notes_protocol[noteIdx]; + console.log(noteIdx + " " + note); + + // Play song + if (this._mServices) this._mServices.uartService.sendText(note); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMusic(); + resolve(); + }, secs*1000); + }); + } + + stopMusic () { + console.log("Music off"); + if (this._mServices) this._mServices.uartService.sendText('O#'); + + return; + } + + /** + * + */ + setRgbLedColor (args) { + // Translate color to ble protocol command + let colorCmd = 0; + + if (args.COLOR == 'random') { + let idx = Math.floor(Math.random() * (_colors.length - 1)); + colorCmd = _colors_protocol[idx]; + } else { + colorCmd = _colors_protocol[_colors.indexOf(args.COLOR)]; + } + + console.log("set LED color: " + args.COLOR + " " + colorCmd); + // Send message + if (this._mServices) this._mServices.uartService.sendText(colorCmd); + + } + rgbLedOff () { + console.log("Headlights off: " + "O#"); + if (this._mServices) this._mServices.uartService.sendText('N#'); + + return; + } + + /** + * + */ + updateSensors (event) { + console.log("Got UART data: " + event.detail); + //console.log(event); + let readings = event.detail.split(",") + if (readings.length == 5) { + this.dist_read = parseInt(readings[0].substring(4)); + this.a_button = parseInt(readings[1]); + this.b_button = parseInt(readings[2]); + this.left_line = parseInt(readings[3]); + this.right_line = parseInt(readings[4]); + } + if (isNaN(this.dist_read)) this.dist_read = 0; + if (isNaN(this.a_button)) this.a_button = 0; + if (isNaN(this.b_button)) this.b_button = 0; + if (isNaN(this.left_line)) this.left_line = 0; + if (isNaN(this.right_line)) this.right_line = 0; + } + + /** + * Implement readDistance + * @returns {string} the distance, in cm, of the nearest object. -1 means error + */ + readDistance () { + let current_time = Date.now(); + if (current_time - this.last_reading_time > 250) { + console.log("Updating sensors"); + // send command to trigger distance read + if (this._mServices) this._mServices.uartService.sendText('W#'); + this.last_reading_time = current_time; + } + + let distance = this.dist_read; + if (distance == 0) { + distance = -1; + } + + return distance; + } + + /** + * Implement readButtonStaus + * @returns {string} t + */ + readButtonStatus (args) { + let current_time = Date.now(); + if (current_time - this.last_reading_time > 250) { + console.log("Updating sensors"); + // send command to trigger distance read + if (this._mServices) this._mServices.uartService.sendText('W#'); + this.last_reading_time = current_time; + } + + var state = args.BUTTON; + if (state == 'A') { + return this.a_button == 1; + } else if (state == 'B') { + return this.b_button == 1; + } else if (state == 'A or B') { + return (this.a_button == 1) || (this.b_button == 1); + } else if (state == 'A and B') { + return (this.a_button == 1) && (this.b_button == 1); + } else if (state == 'neither A nor B') { + return (this.a_button == 0) && (this.b_button == 0); + } + return false; // should never get here + } + /** + * Implement whenButtonPressed + */ + whenButtonPressed(args) { + return this.readButtonStatus(args); + } + + /** + * Implement readLineStatus + * @returns {string} t + */ + readLineStatus (args) { + let current_time = Date.now(); + if (current_time - this.last_reading_time > 250) { + console.log("Updating sensors"); + // send command to trigger distance read + if (this._mServices) this._mServices.uartService.sendText('W#'); + this.last_reading_time = current_time; + } + + var state = args.LINE; + + if (state == 'right side') { + return this.right_line == 1; + } else if (state == 'left side') { + return this.left_line == 1; + } else if (state == 'both sides') { + return (this.right_line == 1) && (this.left_line == 1); + } else if (state == 'neither side') { + return (this.right_line == 0) && (this.left_line == 0); + } + return false; // should never get here + } + + stopMotors () { + console.log("Sending stop motors"); + if (this._mServices) this._mServices.uartService.sendText('0#'); + } + + /** + * Implement drive to drive forward or backward + * @secs {number} the number of seconds to drive backward + * @dir {string} whether to turn "left" or "right" + * @callback {function} the code to call when this function is done executing + */ + drive (args) { + var msg = {}; + var secs = args.NUM; + var dir = args.DIR; + + if (dir == 'forward') { + console.log("Sending drive forward, secs: " + secs); + if (this._mServices) this._mServices.uartService.sendText('A#'); + } else { + console.log('Sending drive backward, secs: ' + secs); + if (this._mServices) this._mServices.uartService.sendText('B#'); + + } + if (this._mConnection != null) this._mConnection.postMessage(msg); + + if (secs == '') // if seconds is left blank, don't pump the brakes + return; + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + + /** + * Implement turn to turn left or right + * @secs {number} the number of seconds to turn left + * @dir {string} whether to turn "left" or "right" + * @callback {function} the code to call when this function is done executing + */ + turn(args) { + var msg = {}; + var secs = args.NUM; + var dir = args.TURN; + + if (dir == 'left') { + console.log("Sending turn left, secs: " + secs); + if (this._mServices) this._mServices.uartService.sendText('E#'); + } else { + console.log("Sending turn right, secs: " + secs); + if (this._mServices) this._mServices.uartService.sendText('D#'); + } + + if (this._mConnection != null) this._mConnection.postMessage(msg); + + if (secs == '') // if seconds is left blank, don't pump the brakes + return; + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*1000); + }); + } + +} +module.exports = MicrobitRobot; diff --git a/src/extensions/scratch3_microbot/index_usb.js b/src/extensions/scratch3_microbot/index_usb.js new file mode 100644 index 00000000000..f503f2c8488 --- /dev/null +++ b/src/extensions/scratch3_microbot/index_usb.js @@ -0,0 +1,537 @@ +const Runtime = require('../../engine/runtime'); + +const ArgumentType = require('../../extension-support/argument-type'); +const BlockType = require('../../extension-support/block-type'); +const Clone = require('../../util/clone'); +const Cast = require('../../util/cast'); +const formatMessage = require('format-message'); +const Video = require('../../io/video'); + + + +const blockIconURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAKcElEQVR42u2cfXAU9RnHv7u3L3d7l9yR5PIGXO7MkQKaYiCUWqJhFGvRMk4JZXSc8aXVaSmiYlthVHQEW99FxiIdrVY6teiMdoa+ICqhIqgQAsjwMgYDOQKXl7uY17u9293b3f5x5JKYe8+FJGSfvzbP/n77e/azz+95nt9v90KoqgpN0hdSQ6AB1ABqADWAmmgANYAaQA2gJhpADeBEE2q8GPLaWzu/CslyiY4k9dOn5uijtXGd7+jWkaReVpT3Hrhv6d0awEFC07rgD+ZeYYnXprhwigUAvjj0zbjxQCLebozT7iDzK1ZUWCru2K7L//6MVC8ue45Blz8n6rlQ815QtuohOlXiEdy/AUqPa6y59Mkh6Q1345GNja6m7pHEQKNl3t0704EXat4L6fSOmOeEI1vHKzwAyNJR9MPFpRUPOu0ONm2A0xatWaTLm5WfDrzvAppA8AbiG03fC8CQNkDKZK2YrPAuRrhpifJERsuYywveJc7CqcIDMAyeLm82dEXzw39I/qjXkpr3QuW9lxfAdOABGAKPslWDnbsy7Jl8BxTeM3SqmO0gaA5U6c3jymup0YSn9JyLee67wpTfBQAQjmyF3HFqiJcRtDECjy5dAmbmcgQPvjjxl3Lx4IVjnD/5cE1zkWtyP34VBGcdKLJnLgc9cznk1kMXFdzEn8KJ4KUqqsSHvcxWDf7j1UM8UPr6/YgHhhX8xAaYaXgAIB7fBnbuSrBzV8aNgarEQ/z6/YkLcDTg9V9XlXjQtuqoU1TpcUHlvZDOfDiuyh5qPMCLrJ1bDw3EuUtx81N/BH3pjQBJQ2HMF5V6iKfeRchVm9kkMtrwxmSdobeA9daBde8GwVlBcFYofS1Jw0vaAy9HeJHQwBUPzIBvGxDc92Rmp/BowJs10wkAONfsBs8HAAAltqngOAO8HZ3o6OiMqcvLy4E1Lwc8H8C5ZndMXdLJa/qNacNLCDBw/O8nFUNWxp/64+tWAwBefe1tHKg7CgC4/9d3ori4EHv3HcDrb26PqVt2602ovvaHaGlpw+8ffSamLqXYmya8jG8mpFy6iGLkWLh4HAwG4+r6j4VBfaPpLgU8IMGO9MLqW2pYQ9aQokuR5dgXIwCC1CUcNMj3hpdvLAdSF54EYpCHooRA0Swomo2pC0kCQpIAkqTA6LmYupgxL0X7m78+aG10NXVkpIwxsAwWXncDCESHLkohfPbpbiT6ZFPPZQ9fC0e58Wi6wTDj6UbT/rQAyiERS2pW4Kc3LQDLRO8miCEAKj7d83FcTxyLJJJJ+9MCqKoq9HomMrgkSThxsgEcZ8AMpwMkSYJlKDA0DVUFiHGWRDJp/4jXwqIo4uFHnkZXdw8AYGbZFXhs3WqQJDkhkkim7E8KoMlkxKbnn8DBunrwUli3e8/+yOAA0HjmHDq7upGXm5PUoDUr7hmWRB5Zt3FYwoime+vtd/H6G9uGJIxouniSyP6H7v8FystnY80jGzIA0MihsMAKu20aTp3JzFb6WCWRuDUvHwByw8cOhw2FBVaYjNzIAba1e3Hfb9aiq7MTNStuBwAsvr4KO3d9GnmKztIS5EyxTJiVSDT7p04tipx/9MnnYc7ORlu7NzMxsK3di5AkDHgGw2DTC+uHBeGJshJJZL/fxyMQEDKbRAiCQDAoQhBDYBkKNE2j4uqrhpUBoiSBIMZfEhkN+1NeiWSqEB2rlUg69md0JRIQRHy86z8jXsqNVRLJlP0jqgNJXXgAgjbCcONmCHUvQ+44NWG2s/rtH5Mt/ciToo0wLH4JBGO6LLazRiJk2vBYy4gHHw/bWSN+LZBKEhkMjzn/CaSiKgQOvJDyFB7L7axUJWNJZDA8IhQA1boPin7KZbMSGfUYyFx9b3hXg/cCsoBA2Z0AoYOaxlcC4+mdyCUDKBzanLFBJ3USyaRMuiSSKZmUSSSTMimTCABUlblRU9kAZ0E39p+eii21c+EL0jHbOwu6sfaWgyjND//U4oP6MmzZnfi79XT7mfQSNi7bh0JzOLG19XBY/89r49pYVebGqhuOosDsh1+gsWV3BXYdd2Q+BlaVuXFv9bHgkSbzk+vfcVRyjHhi47J9cftsXLYf7T36Ix8cLHlo6ydlv6qpPI2qssRZcuOy/Wjp4k5s+2zG+offKqtcUt6kJtNv7S0H0RtkvEufXTB/6bML5je2Wy7UVDbEbF9o9mPDsv2oP5v75vbPS26rP5u3fdXiozDppcwDrKlswOlWy9E//DX09Mt/azh8zzNM1RybF86C7pheVGD240CDeX3NWtfml94Rt+0+Mf3Lm8qbEnpfgdmPs+3G9+564vTT//pM/GrHYduWRP0AYOEMN/5S61xT92Vtfd2XtfWb/vu91fHALyxzw9tnkB/cTD5w+2Ou9375HHtfa7exM5mxRpKFaafdQQKgAcDERs98/foLHrXdaXfoABi8vczhWO2/28/TRR5z2h00gKymNl1ton79oigq6bQ7dE67Q+ew9mb1h4FYYwVESgLAXLSRa+3mWpIdK+UYuPiq89f8+XfT/+ftZQ4vLm9ZmUyfdcsv1M2fWfRaUCK8i8vdK1u6ktuAWPWTsztm24o/cnnYHUsrWzd1+fVJ9XtqxbG3XzFdNcPTawjcueibpxK1t+X26f/9R8a953jub4typOvm2b1XnvUmv8JKWMZcaZffX3XDERRP8cGaFRjWxtPLoZvXY4oxgPBNEsgxBhCUKEzL6Ru+JydS8Ak0giKFgESDJFQoKmCgQzAwIfQEWETzmoBIwd2VNaStu8uEHGO4Buz06zHHFv0dRkefAZ1+PQx0KNK2eIoPLCUj2zDc275qzgcBFWv+cf3IyxgTK2KOzQufEM5kfpGF12eGPSf8DXN+No/87HDWiwYYALw+M6ym8AscAxO++X7xCTRM7EDQzht0Da8v/NWo1dQDAxNCocUXs+303IGHdaptOmYXnh/SLlZbV+fwnwJm6UXEm/ojqgM/PFmJQ81OPHfrtqT7bN23BE8seTflYLvz5DwYGQHLKz5Puo/XZ8aLtT+D1dSDuxbsGQIymmz48DbwIguOESJOcce8XaO3oVpZ8k3Em5KVVAAMFnuOB9as1MbimCBunn04vBmR40ls29Wfgxf1KMn1gBdY+MXUCvK4ANvPndpLzrLzALjBN2VPwrDBksgLYkn1jBMp90nVY2++8vAw3RlPeLNYVZSPAEgjKWP6ZCn4lF+gMdnE08spQb73RQB9aXtgo6tJcNodf8rWz3L//Br340UW3sExEkXrFFKSSUVHqkRfkJZ8QSZk5gS6hw9H+GyDQAclSs41BVmSUIn+toAKIUTJskKoQUknCxKlkISKb/sM0NMyyVAhXW+AlYosfgOgQlUJVadTSUWBKoQoudvPioPbenq5oIUTaRUqenhWKi3oyVIUqKpKREoLggDhF6hQb4CV9LRM9rctMPN6glChp2SdTqeSskwoAECSKnG61fzFR/XsGu+FhmONriYl7TImsjoYKJyZSeB8CoBQo6spqU8TCO1fgE7gDVUNoCYaQA2gBlADqAHURAOoAdQAagA10QCOgfwfNp/hXbfBMCAAAAAASUVORK5CYII='; +const _colors = ['red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'white', 'random']; +const _icons = ['heart', 'check', 'X', 'smile', 'frown', 'ghost', 'triangle', 'diamond', 'square', 'checkers', 'note']; +const _drive = ['forward', 'backward']; +const _turn = ['left', 'right']; +const EXTENSION_ID = 'microbitRobot'; + +// Core, Team, and Official extension classes should be registered statically with the Extension Manager. +// See: scratch-vm/src/extension-support/extension-manager.js +class MicrobitRobot { + constructor (runtime) { + /** + * Store this for later communication with the Scratch VM runtime. + * If this extension is running in a sandbox then `runtime` is an async proxy object. + * @type {Runtime} + */ + this.scratch_vm = runtime; + this.scratch_vm.registerPeripheralExtension(EXTENSION_ID, this); + this.scratch_vm.connectPeripheral(EXTENSION_ID, 0); + + this.robot = this; + + this._mStatus = 1; + this._mConnection = null; + this._mConnectionTimeout = null; + this.CHROME_EXTENSION_ID = "jpehlabbcdkiocalmhikacglppfenoeo"; // "molfimodiodghknifkeikkldkogpapki"; APP ID on Chrome Web Store + + this.msg1 = {}; + this.msg2 = {}; + this.dist_read = 0; + this.a_button = 0; + this.b_button = 0; + this.left_line = 0; + this.right_line = 0; + this.last_reading = 0; + + + this.scratch_vm.on('PROJECT_STOP_ALL', this.resetRobot.bind(this)); + + this.connectToExtension(); + } + + /** + * @return {object} This extension's metadata. + */ + getInfo () { + return { + id: EXTENSION_ID, + name: formatMessage({ + id: 'microbitRobot', + default: 'PRG Microbit Robot Blocks', + description: 'Extension using Gizmo Robot Chrome extension to communicate with Microbit robot' + }), + showStatusButton: true, + blockIconURI: blockIconURI, + menuIconURI: blockIconURI, + + blocks: [ + { + opcode: 'setRgbLedColor', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.setLEDColor', + default: 'set headlight color [COLOR]', + description: 'Set the RGB headlight color' + }), + arguments: { + COLOR: { + type:ArgumentType.STRING, + menu: 'COLORS', + defaultValue: _colors[0] + // should I put a default color? + } + } + }, + { + opcode: 'rgbLedOff', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.ledOff', + default: 'turn headlights off', + description: 'Turn off the LED' + }), + arguments: { } + }, + { + opcode: 'setLEDDisplay', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.setLEDDisplay', + default: 'set LED display [ICON]', + description: 'Set the LED display to an icon' + }), + arguments: { + ICON: { + type:ArgumentType.STRING, + menu: 'ICONS', + defaultValue: _icons[0] + } + } + }, + { + opcode: 'ledDisplayOff', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.ledDisplayOff', + default: 'turn LED display off', + description: 'Turn off the LED display' + }), + arguments: { } + }, + { + opcode: 'drive', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.driveForwardBackward', + default: 'drive [DIR] for [NUM] steps', + description: 'Send command to robot to drive forward or backward' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 1 + }, + DIR: { + type:ArgumentType.String, + menu: 'DIRS', + defaultValue: _drive[0] + } + } + }, + { + opcode: 'turn', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'arduinoBot.turnRightLeft', + default: 'turn [TURN] [NUM] degrees', + description: 'Send command to robot to turn right or left' + }), + arguments: { + NUM: { + type:ArgumentType.NUMBER, + defaultValue: 90 + }, + TURN: { + type:ArgumentType.String, + menu: 'TURNS', + defaultValue: _turn[0] + } + } + }, + { + opcode: 'readDistance', + blockType: BlockType.REPORTER, + text: formatMessage({ + id: 'arduinoBot.readDistance', + default: 'read distance', + description: 'Get distance read from ultrasonic distance sensor' + }), + arguments: { } + }, + { + opcode: 'readButtonStatus', + blockType: BlockType.BOOLEAN, + text: formatMessage({ + id: 'arduinoBot.readButtonStatus', + default: '[BUTTON] button pressed', + description: 'Get distance read from ultrasonic distance sensor' + }), + arguments: { + BUTTON: { + type:ArgumentType.String, + menu: 'BUTTON_STATES', + defaultValue: 'A' + } + } + }, + { + opcode: 'readLineStatus', + blockType: BlockType.BOOLEAN, + text: formatMessage({ + id: 'arduinoBot.readLineSensorStatus', + default: 'line detected on [LINE]', + description: 'detect line sensor state' + }), + arguments: { + LINE: { + type:ArgumentType.String, + menu: 'LINE_STATES', + defaultValue: 'right' + } + } + } + // play sounds + // add blocks for speech? + ], + menus: { + COLORS: { + acceptReporters: false, + items: _colors + }, + ICONS: { + acceptReporters: false, + items: _icons + }, + DIRS: { + acceptReporters: false, + items: _drive + }, + TURNS: { + acceptReporters: false, + items: _turn + }, + BUTTON_STATES: { + acceptReporters: false, + items: ['A','B','A or B','A and B','neither A nor B'] + }, + LINE_STATES: { + acceptReporters: false, + items: ['right side', 'left side', 'neither side', 'both side'] + } + } + }; + } + isConnected() { + //console.log("isConnected status: " + this._mStatus); + return (this._mStatus == 2); + } + scan() { + console.log("microbitRobotScan"); + this.connectToExtension(); + } + connect() { + } + disconnect() { + console.log("Closing extension"); + chrome.runtime.sendMessage(this.CHROME_EXTENSION_ID, { close: true }); + } + disconnectedFromExtension() { + this._mStatus = 1; + console.log("Lost connection to robot"); + this.scratch_vm.emit(this.scratch_vm.constructor.PERIPHERAL_DISCONNECTED); + } + connectToExtension() { + // Can probably do this without Chrome extension + // VID is a Vendor ID. For the micro:bit this is 0x0d28, PID is a Product ID. For the micro:bit this is 0x0204 + // navigator.getUSBDevices https://developers.google.com/web/updates/2016/03/access-usb-devices-on-the-web + // https://developers.google.com/web/updates/2015/07/interact-with-ble-devices-on-the-web + + // Save reference to robot for use later + + var robot = this; + var boundMsgHandler = this.onMsgFromExtension.bind(this); + + // Attenpt to connect to the Gizmo Chrome Extension + chrome.runtime.sendMessage(this.CHROME_EXTENSION_ID, { launch: true }, function (response) { + if (response === undefined) { //Chrome app not found + // Must have the wrong extension ID (if extension was not downloaded from Chrome webstore, the extension id is not consistent) + console.log("Chrome app not found with extension ID: " + robot.CHROME_EXTENSION_ID); + + // Attempt to get the extension ID from local browser storage + robot.CHROME_EXTENSION_ID = window.localStorage.getItem('gizmo_extension_id'); + console.log("Stored extension ID: " + robot.CHROME_EXTENSION_ID); + if (robot.CHROME_EXTENSION_ID === undefined || robot.CHROME_EXTENSION_ID === "" || robot.CHROME_EXTENSION_ID === null) { + // If there is no extension ID in local browser storage, prompt user to enter one + robot.CHROME_EXTENSION_ID = window.prompt("Enter the correct Chrome Extension ID", "pnjoidacmeigcdbikhgjolnadkdiegca"); + } + robot._mStatus = 0; + // Try to connect to the Chrome extension again + robot.connectToExtension(); + } else if (response.status === false) { //Chrome app says not connected + console.log("Chome extension is not running"); // what does this mean? + robot._mStatus = 1; + } else {// Chrome app is connected + console.log("Chrome extension found"); + // Save the extension ID in local browser storage for next time + window.localStorage.setItem('gizmo_extension_id', robot.CHROME_EXTENSION_ID); + if (robot._mStatus !== 2) { + robot._mConnection = chrome.runtime.connect(robot.CHROME_EXTENSION_ID); + // Add listener that triggers onMsgFromExtension everytime the Chrome extension gets a message from the robot + robot._mConnection.onMessage.addListener(boundMsgHandler); + // We're not sure that it's working until we start receiving messages + robot._mStatus = 1; + } + } + }); + } + + /** + * Implement onMsgFromExtension + * @msg {chrome.runtime.Message} the message received from the connected Chrome extension + * When a message is received from the Chrome extension, and therefore the robot, this handles that message + */ + onMsgFromExtension (msg) { + if (this._mStatus == 1) { + console.log("Receiving messages from robot"); + } + + this._mStatus = 2; + this.scratch_vm.emit(this.scratch_vm.constructor.PERIPHERAL_CONNECTED); + var buffer = msg.buffer; + + // The beginning of the buffer (from firmata) starts with 224, if this buffer starts with 224 it is the beginning of the message + if (buffer[0]==224) { + this.messageParser(buffer); + this.last_reading = 0; // Last reading signifies that the last thing stored in the msg buffer is the first part of the message + } + + if (buffer[0] != 224 && this.last_reading == 0) { // Checking last reading makes sure that we don't concatenate the wrong part of the message + this.messageParser(buffer); + this.last_reading = 1; + } + + // Detect if the robot gets disconnected + if (this._mConnectionTimeout != null) clearTimeout(this._mConnectionTimeout); + this._mConnectionTimeout = setTimeout(this.disconnectedFromExtension.bind(this), 1000); + } + + /** + * Implement messageParser + * @buf {byte buffer} a buffer containing a series of opcode keys and data value pairs + * @dist_read {int} the last reading from the ultrasonic distance sensor + * @msg1 {byte buffer} since the entire buffer does not always get transmitted in a message, this will store the first part of the buffer + * @msg2 {byte buffer} since the entire buffer does not always get transmitted in a message, this will store the second part of the buffer + */ + messageParser (buf) { + var msg = {}; + if (buf[0]==224){ // RANDI these 200 numbers are arbitrary and could be changed here and in the microbit code + this.msg1 = buf; + } else if (buf[0] != 224) { + this.msg2 = buf; + } + msg.buffer = this.msg1.concat(this.msg2); + + if (msg.buffer.length > 10) { + msg.buffer = msg.buffer.slice(0,10); // The length of the buffer (from firmata) is only 10 bytes + } + if (msg.buffer.length == 10){ + if (msg.buffer[0] == 224) { // RANDI these 200 numbers are arbitrary and could be changed here and in the microbit code + this.a_button = Math.round(msg.buffer[1]); + } + if (msg.buffer[2] == 237) { + this.b_button = Math.round(msg.buffer[3]); + } + if (msg.buffer[4] == 238) { + this.left_line = Math.round(msg.buffer[5]); + } + if (msg.buffer[6] == 239) { + this.right_line = Math.round(msg.buffer[7]); + } + if (msg.buffer[8] == 240) { // The opcode key before the ultrasonic distance reading data is 240 + this.dist_read = Math.round(msg.buffer[9]); + } + } + } + resetRobot() { + this.stopMotors(); + this.rgbLedOff(); + this.ledDisplayOff(); + } + /** + * + */ + setRgbLedColor (args) { + console.log("set LED color: " + args.COLOR); + + // Translate color to index + var idxStr = (_colors.indexOf(args.COLOR) + 1).toString(16).charCodeAt(0); + + // Send message + var msg = {}; + msg.buffer = [76,idxStr,10]; + this._mConnection.postMessage(msg); + + } + rgbLedOff () { + console.log("Headlights off"); + var msg = {}; + msg.buffer = [76,48,10]; + this._mConnection.postMessage(msg); + + return; + } + + /** + * + */ + setLEDDisplay (args) { + console.log("set LED display: " + args.ICON); + + // Translate color to index + var idxStr = (_icons.indexOf(args.ICON) + 1).toString(16).charCodeAt(0); + // Send message + var msg = {}; + msg.buffer = [83,idxStr,10]; + this._mConnection.postMessage(msg); + + } + ledDisplayOff () { + console.log("LED display off"); + var msg = {}; + msg.buffer = [83,48,10]; + this._mConnection.postMessage(msg); + + return; + } + + /** + * Implement readDistance + * @returns {string} the distance, in cm, of the nearest object. -1 means error + */ + readDistance () { + var distance = this.dist_read; + if (distance == 0) { + distance = -1; + } + return distance; + } + + /** + * Implement readButtonStaus + * @returns {string} t + */ + readButtonStatus (args) { + var state = args.BUTTON; + + if (state == 'A') { + return this.a_button == 1; + } else if (state == 'B') { + return this.b_button == 1; + } else if (state == 'A or B') { + return (this.a_button == 1) || (this.b_button == 1); + } else if (state == 'A and B') { + return (this.a_button == 1) && (this.b_button == 1); + } else if (state == 'neither A nor B') { + return (this.a_button == 0) && (this.b_button == 0); + } + return false; // should never get here + } + + /** + * Implement readLineStatus + * @returns {string} t + */ + readLineStatus (args) { + var state = args.LINE; + + if (state == 'right') { + return this.right_line == 1; + } else if (state == 'left') { + return this.left_line == 1; + } else if (state == 'both') { + return (this.right_line == 1) && (this.left_line == 1); + } else if (state == 'neither') { + return (this.right_line == 0) && (this.left_line == 0); + } + return false; // should never get here + } + + stopMotors () { + var msg = {}; + console.log("Sending D0 to stop servos"); + msg.buffer = [68,48,10]; + this._mConnection.postMessage(msg); + } + + /** + * Implement drive to drive forward or backward + * @secs {number} the number of seconds to drive backward + * @dir {string} whether to turn "left" or "right" + * @callback {function} the code to call when this function is done executing + */ + drive (args) { + var msg = {}; + var secs = args.NUM; + var dir = args.DIR; + + if (dir == 'forward') { + console.log("Sending D1 to drive forward, steos: " + secs); + msg.buffer = [68,49,10]; + } else { + console.log('Sending D2 to drive backward, steps: ' + secs); + msg.buffer = [68,50,10]; + + } + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*100); + }); + } + + /** + * Implement turn to turn left or right + * @secs {number} the number of seconds to turn left + * @dir {string} whether to turn "left" or "right" + * @callback {function} the code to call when this function is done executing + */ + turn(args) { + var msg = {}; + var secs = args.NUM / 90; + var dir = args.TURN; + + if (dir == 'left') { + console.log("Sending D3 to turn left, steps: " + secs); + msg.buffer = [68,51,10]; + } else { + console.log("Sending D4 to turn right, steps: " + secs); + msg.buffer = [68,52,10]; + } + + this._mConnection.postMessage(msg); + + return new Promise(resolve => { + setTimeout(() => { + this.stopMotors(); + resolve(); + }, secs*450); + }); + } + +} +//module.exports = MicrobitRobot; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/analysishelpers.js b/src/extensions/scratch3_musiccreation/analysishelpers.js new file mode 100644 index 00000000000..4c535e121ae --- /dev/null +++ b/src/extensions/scratch3_musiccreation/analysishelpers.js @@ -0,0 +1,89 @@ +const Clone = require('../../util/clone'); +const Cast = require('../../util/cast'); +const formatMessage = require('format-message'); +const MathUtil = require('../../util/math-util'); +const Timer = require('../../util/timer'); +const log = require('../../util/log'); +const musicPlayers = require("./musicplayer"); + +class AnalysisHelpers { + constructor (runtime) { + this.runtime = runtime; + + this.musicPlayer = new musicPlayers(runtime); + + this.filenameToNote = { + 1: {instrument: "synth", volume: "piano", pitch: "60"}, + 2: {instrument: "cello", volume: "mezzo-piano", pitch: "65"}, + 3: {instrument: "piano", volume: "forte", pitch: "68"}, + 4: {instrument: "saxophone", volume: "forte", pitch: "72"}, + 5: {instrument: "clarinet", volume: "fortissimo", pitch: "60"}, + 6: {instrument: "bass", volume: "mezzo-forte", pitch: "63"} + } + + this.compareVolumes = { + "pianissimo": 0, + "piano": 1, + "mezzo-piano": 2, + "mezzo-forte": 3, + "forte": 4, + "fortissimo": 5 + } + + this.louder = ""; + this.higher = ""; + this.inst1 = ""; + this.inst2 = ""; + + } + + playFile (args, util) { + note1 = this.filenameToNote[Cast.toNumber(args.FILE)]; + this.play(note1, util); + } + + compareFiles (args, util) { + note1 = this.filenameToNote[Cast.toNumber(args.FILE1)]; + note2 = this.filenameToNote[Cast.toNumber(args.FILE2)]; + this.inst1 = note1.instrument; + this.inst2 = note2.instrument; + this.louder = (this.compareVolumes[note1.volume] == this.compareVolumes[note2.volume]) ? "equal" : ((this.compareVolumes[note1.volume] > this.compareVolumes[note2.volume]) ? args.FILE1 : args.FILE2); + this.higher = (note1.pitch == note2.pitch) ? "equal" : (note1.pitch > note2.pitch) ? args.FILE1 : args.FILE2; + } + + getLouder (util) { + return this.louder; + } + + getHigher (util) { + return this.higher; + } + + getInst1 (util) { + return this.inst1; + } + + getInst2 (util) { + return this.inst2; + } + + play (note, util) { + log.log(note.instrument); + this.musicPlayer._playNote(util, note.pitch, 0.25, note.instrument); + } + + getPitch (note, util) { + log.log("here"); + } + + getVolume (note, util) { + log.log("here"); + } + + getInstrument(note, util) { + log.log("here"); + } + +} + +module.exports = AnalysisHelpers; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/108.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/108.mp3 new file mode 100644 index 00000000000..a7c05073974 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/108.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/24.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/24.mp3 new file mode 100644 index 00000000000..3ee19ed18f6 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/24.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/36.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/36.mp3 new file mode 100644 index 00000000000..b680da226e2 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/36.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/48.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/48.mp3 new file mode 100644 index 00000000000..cf099153036 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/48.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/60.mp3 new file mode 100644 index 00000000000..adb7052b715 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/72.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/72.mp3 new file mode 100644 index 00000000000..27451fc6a19 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/72.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/84.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/84.mp3 new file mode 100644 index 00000000000..f32a1da73c9 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/84.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/96.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/96.mp3 new file mode 100644 index 00000000000..4efc40bf0c5 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/1-piano/96.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/10-clarinet/48.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/10-clarinet/48.mp3 new file mode 100644 index 00000000000..c7d46dbd66a Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/10-clarinet/48.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/10-clarinet/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/10-clarinet/60.mp3 new file mode 100644 index 00000000000..12460dfca0b Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/10-clarinet/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/36.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/36.mp3 new file mode 100755 index 00000000000..472afa8f99c Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/36.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/60.mp3 new file mode 100755 index 00000000000..92da76ce0b3 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/84.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/84.mp3 new file mode 100755 index 00000000000..7a961d0dfe2 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/11-saxophone/84.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/12-flute/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/12-flute/60.mp3 new file mode 100644 index 00000000000..0189b3effe2 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/12-flute/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/12-flute/72.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/12-flute/72.mp3 new file mode 100644 index 00000000000..7b57139bf7f Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/12-flute/72.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/13-wooden-flute/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/13-wooden-flute/60.mp3 new file mode 100644 index 00000000000..c898b844e6e Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/13-wooden-flute/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/13-wooden-flute/72.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/13-wooden-flute/72.mp3 new file mode 100644 index 00000000000..6a7a9e99e98 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/13-wooden-flute/72.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/36.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/36.mp3 new file mode 100644 index 00000000000..d8ff9f5ce05 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/36.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/48.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/48.mp3 new file mode 100644 index 00000000000..5592bc64979 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/48.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/60.mp3 new file mode 100644 index 00000000000..640f3de262f Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/14-bassoon/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/48.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/48.mp3 new file mode 100644 index 00000000000..0b87ef6e0bb Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/48.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/60.mp3 new file mode 100644 index 00000000000..489247955c6 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/72.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/72.mp3 new file mode 100644 index 00000000000..0e3074f4328 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/15-choir/72.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/16-vibraphone/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/16-vibraphone/60.mp3 new file mode 100644 index 00000000000..988f8231875 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/16-vibraphone/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/16-vibraphone/72.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/16-vibraphone/72.mp3 new file mode 100644 index 00000000000..ebdd5e0e673 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/16-vibraphone/72.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/17-music-box/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/17-music-box/60.mp3 new file mode 100644 index 00000000000..169df684f79 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/17-music-box/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/18-steel-drum/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/18-steel-drum/60.mp3 new file mode 100644 index 00000000000..e7b8585bb63 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/18-steel-drum/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/19-marimba/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/19-marimba/60.mp3 new file mode 100644 index 00000000000..54b7df80b9c Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/19-marimba/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/2-electric-piano/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/2-electric-piano/60.mp3 new file mode 100644 index 00000000000..d8d1abc1d61 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/2-electric-piano/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/108.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/108.mp3 new file mode 100644 index 00000000000..0f057f63e02 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/108.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/120.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/120.mp3 new file mode 100644 index 00000000000..5843dde5bea Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/120.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/24.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/24.mp3 new file mode 100644 index 00000000000..b76b3f1c518 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/24.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/36.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/36.mp3 new file mode 100644 index 00000000000..65cff8e5c72 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/36.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/48.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/48.mp3 new file mode 100644 index 00000000000..84cbb0ca717 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/48.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/60.mp3 new file mode 100644 index 00000000000..ec8171c70fc Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/72.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/72.mp3 new file mode 100644 index 00000000000..81d397253bf Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/72.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/84.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/84.mp3 new file mode 100644 index 00000000000..0fcd3efaa6d Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/84.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/96.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/96.mp3 new file mode 100644 index 00000000000..c3052fe0c42 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/20-synth-lead/96.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/21-synth-pad/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/21-synth-pad/60.mp3 new file mode 100644 index 00000000000..93ff1d94eb4 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/21-synth-pad/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/3-organ/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/3-organ/60.mp3 new file mode 100644 index 00000000000..a329b732cec Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/3-organ/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/4-guitar/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/4-guitar/60.mp3 new file mode 100644 index 00000000000..064672bb625 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/4-guitar/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/5-electric-guitar/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/5-electric-guitar/60.mp3 new file mode 100755 index 00000000000..f8558dee44d Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/5-electric-guitar/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/6-bass/36.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/6-bass/36.mp3 new file mode 100644 index 00000000000..d967d830ef5 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/6-bass/36.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/6-bass/48.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/6-bass/48.mp3 new file mode 100644 index 00000000000..5c8ce5664ef Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/6-bass/48.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/7-pizzicato/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/7-pizzicato/60.mp3 new file mode 100644 index 00000000000..589c6578678 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/7-pizzicato/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/36.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/36.mp3 new file mode 100644 index 00000000000..c337dedf2cd Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/36.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/48.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/48.mp3 new file mode 100644 index 00000000000..c4b556da2f4 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/48.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/60.mp3 new file mode 100644 index 00000000000..28aeded5178 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/8-cello/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/36.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/36.mp3 new file mode 100644 index 00000000000..95c289ba3e4 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/36.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/48.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/48.mp3 new file mode 100644 index 00000000000..2eee89d3b83 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/48.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/60.mp3 b/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/60.mp3 new file mode 100644 index 00000000000..4f00cf119d1 Binary files /dev/null and b/src/extensions/scratch3_musiccreation/assets/instruments/9-trombone/60.mp3 differ diff --git a/src/extensions/scratch3_musiccreation/fft.js b/src/extensions/scratch3_musiccreation/fft.js new file mode 100644 index 00000000000..ae7e7bacd9d --- /dev/null +++ b/src/extensions/scratch3_musiccreation/fft.js @@ -0,0 +1,421 @@ +const Clone = require('../../util/clone'); +const log = require('../../util/log'); +const Cast = require('../../util/cast'); +const Color = require('../../util/color'); +const RenderedTarget = require('../../sprites/rendered-target'); +const StageLayering = require('../../engine/stage-layering'); + +const letters = require('./letters'); +const symbols = require('./symbols'); +const { updateVariableIdentifiers } = require('../../util/variable-util'); + +var coord, x, y, colors, freqs, freq, amps, midi, inst, harmonic, pitch, k, coeff, hPitch, exists, f, fr, amp, maxFreq, maxAmp, ratio, ratioAmp, signal, staff, dur; + + +class FFT { + constructor(runtime) { + this.runtime = runtime; + + /** + * The ID of the renderer Skin corresponding to the pen layer. + * @type {int} + * @private + */ + this._penSkinId = -1; + + /** + * The ID of the renderer Drawable corresponding to the pen layer. + * @type {int} + * @private + */ + this._penDrawableId = -1; + this.black = '0x000000'; + + this.noteList = []; + + this.axisStartX = -200; + this.axisStartY = -150; + this.xAxisLength = 400; + this.yAxisLength = 300; + + this._onTargetCreated = this._onTargetCreated.bind(this); + this.runtime.on('targetWasCreated', this._onTargetCreated); + + this._onTargetMoved = this._onTargetMoved.bind(this); + + this.harmonics = { + "Piano": [[1, 1], [3, 0.42], [4, 0.22]], //DONE + "Guitar": [[1, 0.55], [2, 0.47], [3, 0.68], [4, 0.24]], + "Bass": [[1, 1], [3, 0.78], [4, 0.22]], + "Cello": [[1, 1], [2, 0.47], [3, 0.24], [4, 0.15]], //DONE + "Saxophone": [[1, 1], [2, 0.38], [3, 0.14], [4, 0.02]], //DONE + "Clarinet": [[1, 0.57], [2, 0.87], [3, 0.23], [4, 0]], //DONE + "Synth": [[1, 1], [2, 0], [3, 0], [4, 0]] //DONE + } + + this.letters = { + 'a': letters.a, + 'b': letters.b, + 'c': letters.c, + 'd': letters.d, + 'e': letters.e, + 'f': letters.f, + 'g': letters.g, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'k': letters.k, + 'l': letters.l, + 'm': letters.m, + 'n': letters.n, + 'o': letters.o, + 'p': letters.p, + 'q': letters.q, + 'r': letters.r, + 's': letters.s, + 't': letters.t, + 'u': letters.u, + 'v': letters.v, + 'w': letters.w, + 'x': letters.x, + 'y': letters.y, + 'z': letters.z + } + + this.spacing = { + 'a': 59.03383897316219, + 'b': 35.666277712952166, + 'c': 55.59820426487096, + 'd': 51.65460910151694, + 'e': 33.821470245040814, + 'f': 35.05134189031503, + 'g': 62.10851808634772, + 'h': 51.65460910151691, + 'i': 0.0, + 'j': 27.057176196032685, + 'k': 44.275379229871646, + 'l': 33.20653442240376, + 'm': 76.86697782963824, + 'n': 57.803967327887975, + 'o': 62.108518086347715, + 'p': 35.05134189031503, + 'q': 62.72345390898482, + 'r': 34.305274971941685, + 's': 39.62850729517402, + 't': 51.03967327887982, + 'u': 50.42473745624271, + 'v': 52.88448074679113, + 'w': 88.55075845974329, + 'x': 45.50525087514586, + 'y': 47.350058343057185, + 'z': 55.959159859976694 + } + } + + /** + * The key to load & store a target's music-related state. + * @type {string} + */ + static get VIZ_STATE_KEY() { + return 'Scratch.musicviz'; + } + + static get DEFAULT_PEN_STATE() { + return { + penDown: false, + color: 66.66, + saturation: 100, + brightness: 100, + transparency: 0, + _shade: 50, // Used only for legacy `change shade by` blocks + penAttributes: { + color4f: [0, 0, 1, 1], + diameter: 1 + } + }; + } + + /** + * The minimum and maximum allowed pen size. + * The maximum is twice the diagonal of the stage, so that even an + * off-stage sprite can fill it. + * @type {{min: number, max: number}} + */ + static get PEN_SIZE_RANGE() { + return { min: 1, max: 1200 }; + } + + /** + * When a music-playing Target is cloned, clone the music state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated(newTarget, sourceTarget) { + if (sourceTarget) { + const penState = sourceTarget.getCustomState(FFT.VIZ_STATE_KEY); + if (penState) { + newTarget.setCustomState(FFT.VIZ_STATE_KEY, Clone.simple(penState)); + if (penState.penDown) { + newTarget.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + } + } + + _onTargetMoved(target, oldX, oldY, isForce) { + // Only move the pen if the movement isn't forced (ie. dragged). + if (!isForce) { + let penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + const penState = this._getPenState(target); + this.runtime.renderer.penLine(penSkinId, penState.penAttributes, oldX, oldY, target.x, target.y); + this.runtime.requestRedraw(); + } + } + } + + _getPenLayerID() { + if (this._penSkinId < 0 && this.runtime.renderer) { + this._penSkinId = this.runtime.renderer.createPenSkin(); + this._penDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); + this.runtime.renderer.updateDrawableProperties(this._penDrawableId, { skinId: this._penSkinId }); + } + return this._penSkinId; + } + + _getWavePenLayerID() { + if (this.wavePen < 0 && this.runtime.renderer) { + this.wavePen = this.runtime.renderer.createPenSkin(); + this.wavePenDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); + this.runtime.renderer.updateDrawableProperties(this.wavePenDrawableId, { skinId: this.wavePen }); + } + return this.wavePen; + } + + _getPenState(target) { + let penState = target.getCustomState(FFT.VIZ_STATE_KEY); + if (!penState) { + penState = Clone.simple(FFT.DEFAULT_PEN_STATE); + target.setCustomState(FFT.VIZ_STATE_KEY, penState); + } + return penState; + } + + testFreqViz(noteList, args, util) { + this.setPenColorToColor(this.black, util); + this.noteList = noteList; + this.clear(); + this.drawAxes(args, util); + this.drawFFT(args, util); + + } + + + labelAxes(args, util) { + this.setPenColorToColor(this.black, util); + this.drawString('frequency', this.axisStartX + this.xAxisLength - 70, this.axisStartY - 5, 0.8, args, util); + this.drawString('intensity', this.axisStartX - 30, this.axisStartY + this.yAxisLength + 20, 0.8, args, util); + + this.drawString('frequencies', this.axisStartX + this.xAxisLength / 2 - 70, this.axisStartY + this.yAxisLength + 20, 1, args, util); + } + + + drawString(str, xstart, ystart, size, args, util) { + for (var i in str) { + xstart += 5 * size; + if (i >= 1) { + xstart += this.spacing[str[i - 1]] / 5 * size; + } + this.drawLetter(str[i], xstart, ystart, size, args, util); + } + + } + + drawLetter(letter, xstart, ystart, size, args, util) { + letter = letters[letter]; + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0] / 5 * size + xstart; + y = -coord[1] / 5 * size + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0] / 5 * size + xstart + 1; + y = -coord[1] / 5 * size + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + } + + drawFFT(args, util) { + colors = ['0xff0000', '0x0000ff', '0x00ff00', '0xffa500']; + this.setPenColorToColor(colors[1], util); + freqs = []; + amps = []; + for (let i in this.noteList) { + midi = this.noteList[i][0]; + inst = this.noteList[i][2]; + harmonic = this.harmonics[inst]; + pitch = 2 ** ((midi - 69) / 12) * 440; + for (let i in harmonic) { + k = harmonic[i][0]; + coeff = harmonic[i][1]; + hPitch = pitch * k; + exists = false; + for (f in freqs) { + fr = freqs[f]; + if (Math.abs(hPitch - fr) < 10 ** -9) { + amps[f] += coeff; + exists = true; + } + } + if (!exists) { + amp = coeff; + freqs.push(hPitch); + amps.push(amp); + } + + } + } + maxFreq = Math.max(...freqs); + maxAmp = Math.max(...amps); + for (let i in freqs) { + freq = freqs[i]; + amp = amps[i]; + ratio = freq / maxFreq; + ratioAmp = amp / maxAmp; + this.penUp(args, util); + util.target.setXY(this.axisStartX + ratio * this.xAxisLength, this.axisStartY); + this.penDown(args, util); + util.target.setXY(this.axisStartX + ratio * this.xAxisLength, this.axisStartY + this.yAxisLength * ratioAmp); + this.penUp(args, util); + } + } + + drawAxes(args, util) { + util.target.setXY(this.axisStartX, this.axisStartY + this.yAxisLength); + this.penDown(args, util); + util.target.setXY(this.axisStartX, this.axisStartY); + this.penUp(args, util); + util.target.setXY(this.axisStartX, this.axisStartY); + this.penDown(args, util); + util.target.setXY(this.axisStartX + this.xAxisLength, this.axisStartY); + this.penUp(args, util); + this.labelAxes(args, util); + } + + + convertSignalToMusicList(args, util) { + signal = []; + for (var i in this.noteList) { + freq = this.noteList[i][0]; + staff = pitchToStaff[freq]; + dur = this.noteList[i][1] * 4; + amp = this.noteList[i][3]; + signal.push([staff, dur, amp]); + } + return signal; + } + + penUp(args, util) { + const penState = this._getPenState(util.target); + if (penState.penDown) { + penState.penDown = false; + util.target.removeListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + + penDown(args, util, penSkinId) { + const penState = this._getPenState(util.target); + if (!penState.penDown) { + penState.penDown = true; + util.target.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + + penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penPoint(penSkinId, penState.penAttributes, util.target.x, util.target.y); + this.runtime.requestRedraw(); + } + } + + /** + * The pen "set pen color to {color}" block sets the pen to a particular RGB color. + * The transparency is reset to 0. + * @param {object} args - the block arguments. + * @property {int} COLOR - the color to set, expressed as a 24-bit RGB value (0xRRGGBB). + * @param {object} util - utility object provided by the runtime. + */ + setPenColorToColor(newColor, util) { + const penState = this._getPenState(util.target); + const rgb = Cast.toRgbColorObject(newColor); + const hsv = Color.rgbToHsv(rgb); + penState.color = (hsv.h / 360) * 100; + penState.saturation = hsv.s * 100; + penState.brightness = hsv.v * 100; + if (rgb.hasOwnProperty('a')) { + penState.transparency = 100 * (1 - (rgb.a / 255.0)); + } else { + penState.transparency = 0; + } + + // Set the legacy "shade" value the same way scratch 2 did. + penState._shade = penState.brightness / 2; + + this._updatePenColor(penState); + } + + /** + * Update the cached color from the color, saturation, brightness and transparency values + * in the provided PenState object. + * @param {PenState} penState - the pen state to update. + * @private + */ + _updatePenColor(penState) { + const rgb = Color.hsvToRgb({ + h: penState.color * 360 / 100, + s: penState.saturation / 100, + v: penState.brightness / 100 + }); + penState.penAttributes.color4f[0] = rgb.r / 255.0; + penState.penAttributes.color4f[1] = rgb.g / 255.0; + penState.penAttributes.color4f[2] = rgb.b / 255.0; + penState.penAttributes.color4f[3] = this._transparencyToAlpha(penState.transparency); + } + + /** + * Convert a pen transparency value to an alpha value. + * Alpha ranges from 0 to 1, where 0 is transparent and 1 is opaque. + * Transparency ranges from 0 to 100, where 0 is opaque and 100 is transparent. + * @param {number} transparency - the input transparency value. + * @returns {number} the alpha value. + * @private + */ + _transparencyToAlpha(transparency) { + return 1.0 - (transparency / 100.0); + } + + /** + * The pen "clear" block clears the pen layer's contents. + */ + clear() { + const penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penClear(penSkinId); + this.runtime.requestRedraw(); + } + } + +} + +module.exports = FFT; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/freqtonote.js b/src/extensions/scratch3_musiccreation/freqtonote.js new file mode 100644 index 00000000000..030754c5e6d --- /dev/null +++ b/src/extensions/scratch3_musiccreation/freqtonote.js @@ -0,0 +1,14 @@ +class FreqToNote { + /** + * Returns the string representation of @param note + * @param {number} note + */ + static freqToNote(note) { + let symbols = ["c", "cS", "d", "eF", "e", "f", "fS", "g", "gS", "a", "bF", "b"]; + let res = symbols[note % 12]; + let d = Math.floor((note - 60) / 12); + return res + `${note >= 12 ? 4 + d : '00'}`; + } +} + +module.exports = FreqToNote; diff --git a/src/extensions/scratch3_musiccreation/index.js b/src/extensions/scratch3_musiccreation/index.js new file mode 100644 index 00000000000..b1fea273358 --- /dev/null +++ b/src/extensions/scratch3_musiccreation/index.js @@ -0,0 +1,871 @@ +const ArgumentType = require('../../extension-support/argument-type'); +const BlockType = require('../../extension-support/block-type'); +const Clone = require('../../util/clone'); +const Cast = require('../../util/cast'); +const formatMessage = require('format-message'); +const BlockUtility = require('../../engine/block-utility'); +const log = require('../../util/log'); + +const VizHelpers = require('./vizhelpers'); +const MusicCreationHelpers = require('./musiccreationhelpers'); +const MusicAccompanimentHelpers = require('./musicaccompanimenthelpers'); +const MusicPlayers = require('./musicplayer') +const textRender = require('./textrender'); +const regeneratorRuntime = require("regenerator-runtime"); //do not delete +const { generateXMLForBlockChunk } = require('../../extension-support/prg/xml-builder'); +const { internalIDKey, addTopBlockModifier, getTopBlockModifier } = require('../../extension-support/prg/block-relationships'); + +const givenBeatValues = ["1/4", "1/2", "1", "2", "3", "4", "8"]; +const instrumentModifierKey = 'instrument'; +const maxNotesForCompleteGen = 20; +const volumeModifierKey = 'volume'; + +class Scratch3MusicCreation { + constructor(runtime) { + this.runtime = runtime; + this.beats = givenBeatValues.map(this.beatsToSecs); + + // whole, whole, half, whole, whole, whole, half + this.majorScale = [0, 2, 4, 5, 7, 9, 11, 12]; + + // whole, half, whole, whole, half, whole, whole + this.minorScale = [0, 2, 3, 5, 7, 8, 10, 12]; + + // whole, whole, whole plus half, whole, whole plus half + this.pentatonicScale = [0, 2, 4, 7, 9, 12]; + + this.musicPlayer = new MusicPlayers(runtime); + this.vizHelper = new VizHelpers(runtime); + this.musicCreationHelper = new MusicCreationHelpers(runtime); + const validNoteDurations = this.beats.map(item => parseFloat(item.value)); + const beatsPerSec = Scratch3MusicCreation.beatPerSec(); + this.musicAccompanimentHelper = new MusicAccompanimentHelpers(runtime, validNoteDurations, beatsPerSec); + + this.noteList = []; + this.wavenoteList = []; + this.magentaNoteList = []; + + this.volumes = [{ text: "pianissimo", value: '15' }, + { text: "piano", value: '30' }, + { text: "mezzo-piano", value: '45' }, + { text: "mezzo-forte", value: '60' }, + { text: "forte", value: '85' }, + { text: "fortissimo", value: '100' }]; + + this.files = [{ text: "mystery 1", value: '1' }, + { text: "mystery 2", value: '2' }, + { text: "mystery 3", value: '3' }, + { text: "mystery 4", value: '4' }, + { text: "mystery 5", value: '5' }, + { text: "mystery 6", value: '6' }]; + + this.displayOptions = [{ text: "sheet music", value: '1' }, + { text: "waveform", value: '2' }, + { text: "frequencies", value: '3' }, + { text: "frequencies over time", value: '4' }]; + + this.createNotesRNNSettings = [{ text: "include", value: '1' }, + { text: "exclude", value: '0' }]; + + this._visStatus = [{ text: "off", value: '0' }, + { text: "on", value: '1' }]; + + this.textRenderer = new textRender(runtime); + + this._playNoteForPicker = this._playNoteForPicker.bind(this); + this.runtime.on('PLAY_NOTE', this._playNoteForPicker); + + this._onTargetCreated = this._onTargetCreated.bind(this); + this.runtime.on('targetWasCreated', this._onTargetCreated); + this.runtime.setMaxListeners(Infinity); + } + + + /** + * The key to load & store a target's music-related state. + * @type {string} + */ + static get STATE_KEY() { + return 'Scratch.musiccreation'; + } + + /** + * When a music-playing Target is cloned, clone the music state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated(newTarget, sourceTarget) { + if (sourceTarget) { + const musicState = sourceTarget.getCustomState(Scratch3MusicCreation.STATE_KEY); + if (musicState) { + newTarget.setCustomState(Scratch3MusicCreation.STATE_KEY, Clone.simple(musicState)); + } + } + } + + /** + * Create data for a menu in scratch-blocks format, consisting of an array of objects with text and + * value properties. The text is a translated string, and the value is one-indexed. + * @param {object[]} info - An array of info objects each having a name property. + * @return {array} - An array of objects with text and value properties. + * @private + */ + _buildMenu(info) { + return info.map((entry, index) => { + const obj = {}; + obj.text = entry.name; + obj.value = String(index + 1); + return obj; + }); + } + + + /** + * An array of info about each instrument. + * @type {object[]} + * @param {string} name - the translatable name to display in the instruments menu. + * @param {string} dirName - the name of the directory containing audio samples for this instrument. + * @param {number} [releaseTime] - an optional duration for the release portion of each note. + * @param {number[]} samples - an array of numbers representing the MIDI note number for each + * sampled sound used to play this instrument. + */ + get INSTRUMENT_INFO() { + return [ + { + name: formatMessage({ + id: 'musiccreation.instrumentPiano', + default: 'Piano', + description: 'Sound of a piano' + }), + dirName: '1-piano', + releaseTime: 0.5, + samples: [24, 36, 48, 60, 72, 84, 96, 108] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentGuitar', + default: 'Guitar', + description: 'Sound of an accoustic guitar' + }), + dirName: '4-guitar', + releaseTime: 0.5, + samples: [60] + }, { + name: formatMessage({ + id: 'music.instrumentBass', + default: 'Bass', + description: 'Sound of an accoustic upright bass' + }), + dirName: '6-bass', + releaseTime: 0.25, + samples: [36, 48] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentCello', + default: 'Cello', + description: 'Sound of a cello being played with a bow' + }), + dirName: '8-cello', + releaseTime: 0.1, + samples: [36, 48, 60] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentSaxophone', + default: 'Saxophone', + description: 'Sound of a saxophone being played' + }), + dirName: '11-saxophone', + samples: [36, 60, 84] + }, + { + name: formatMessage({ + id: 'music.instrumentClarinet', + default: 'Clarinet', + description: 'Sound of a clarinet being played' + }), + dirName: '10-clarinet', + samples: [48, 60] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentSynthLead', + default: 'Synth', + description: 'Sound of a "lead" synthesizer being played' + }), + dirName: '20-synth-lead', + releaseTime: 0.1, + samples: [60] + } + ]; + } + + /** + * Converts a numeric decimal representation to its fractional form stored in a string + * @param {number} value + * @returns {string} + */ + static convertDecimalToFraction(value) { + const gcd = function (a, b) { + if (b < 0.0000001) return a;// Since there is a limited precision we need to limit the value. + return gcd(b, Math.floor(a % b)); + }; + + const len = value.toString().length - 2; + + let denominator = Math.pow(10, len); + let numerator = value * denominator; + + const divisor = gcd(numerator, denominator); + + numerator = Math.round(numerator / divisor); + denominator = Math.round(denominator / divisor); + + + return denominator === 1 ? `${numerator}` : `${numerator}/${denominator}`; + } + + /** + * Convert a fraction stored in a string to it's numeric decimal form + * @param {string} value + * @returns {number} + */ + static convertFractionToDecimal(value) { + const parts = value.split("/"); + if (parts.length === 1) return parseInt(parts); + return parseInt(parts[0], 10) / parseInt(parts[1], 10); + } + + static beatPerSec() { + return 2; + }; + + /** + * Convert an amount of seconds into how many beats it is (assuming 4 beats per second) + * @param {number | string} beats + * @param {number} beatPerSec + * @returns {{text: string, value: number | string }} text represents the calculated number of beats, while value is still in seconds + */ + beatsToSecs(beats) { + const ratio = Scratch3MusicCreation.beatPerSec(); + const secs = (typeof beats === 'number' ? beats : Scratch3MusicCreation.convertFractionToDecimal(beats)) / ratio; + return { text: `${beats}`, value: `${secs}` }; + } + + /** + * Convert an amount of seconds into how many beats it is (assuming 4 beats per second) + * @param {number | string} secs + * @param {number} beatPerSec + * @returns {{text: string, value: number | string }} text represents the calculated number of beats, while value is still in seconds + */ + secsToBeats(secs) { + const ratio = Scratch3MusicCreation.beatPerSec(); + const beats = (typeof secs === 'number' ? secs : parseFloat(secs)) * ratio; + return { text: Scratch3MusicCreation.convertDecimalToFraction(beats), value: secs }; + }; + + + getInfo() { + return { + id: 'musiccreation', + name: 'Music Creation', + blocks: [ + { + opcode: 'resetMusic', + blockType: BlockType.COMMAND, + text: 'reset music' + }, + { + opcode: 'toggleVisMode', + blockType: BlockType.COMMAND, + text: 'set visualization mode to [STATUS] with [FORMAT]', + arguments: { + STATUS: { + type: ArgumentType.NUMBER, + defaultValue: '1', + menu: "STATUS" + }, + FORMAT: { + type: ArgumentType.NUMBER, + defaultValue: '1', + menu: "FORMAT" + } + } + }, + { + opcode: 'playNote', + blockType: BlockType.COMMAND, + text: 'play note [NOTE] for [SECS] beats', + arguments: { + NOTE: { + type: ArgumentType.NOTE, + defaultValue: 60 + }, + SECS: { + type: ArgumentType.NUMBER, + defaultValue: 0.5, + menu: "BEATS" + } + } + }, + { + opcode: 'setInstrument', + blockType: BlockType.COMMAND, + text: 'set instrument to [INSTRUMENT]', + arguments: { + INSTRUMENT: { + type: ArgumentType.NUMBER, + defaultValue: 1, + menu: "INSTRUMENT" + } + } + }, + { + opcode: 'setInstrumentForBelow', + blockType: BlockType.COMMAND, + text: 'set instrument for below blocks to [INSTRUMENT]', + arguments: { + INSTRUMENT: { + type: ArgumentType.NUMBER, + defaultValue: 1, + menu: "INSTRUMENT" + } + } + }, + { + opcode: 'getInstrument', + text: formatMessage({ + id: 'musiccreation.getInstrument', + default: 'instrument', + description: 'get the current instrument' + }), + blockType: BlockType.REPORTER + }, + { + opcode: 'setVolume', + blockType: BlockType.COMMAND, + text: 'set volume to [VOLUME]', + arguments: { + VOLUME: { + type: ArgumentType.NUMBER, + defaultValue: 60, + menu: "VOLUME" + } + } + }, + { + opcode: 'setVolumeForBelow', + blockType: BlockType.COMMAND, + text: 'set volume for below blocks to [VOLUME]', + arguments: { + VOLUME: { + type: ArgumentType.NUMBER, + defaultValue: 60, + menu: "VOLUME" + } + } + }, + { + opcode: 'getVolume', + text: formatMessage({ + id: 'musiccreation.getVolume', + default: 'volume', + description: 'get the current volume' + }), + blockType: BlockType.REPORTER + }, + { + opcode: 'roundNoteToScale', + text: formatMessage({ + id: 'musiccreation.toScaleNote', + default: 'Round [NOTE] to [SCALE] [TYPE] scale', + description: 'scale a note value to the closest note withing a given scale' + }), + blockType: BlockType.REPORTER, + arguments: { + NOTE: { + type: ArgumentType.NOTE, + defaultValue: 60 + }, + SCALE: { + type: ArgumentType.NUMBER, + defaultValue: "0", + menu: "SCALE_NOTES" + }, + TYPE: { + type: ArgumentType.STRING, + defaultValue: "Major", + menu: "SCALE_TYPES" + } + } + }, + { + opcode: 'playNoteList', + blockType: BlockType.COMMAND, + text: 'play notes [A][B][C] for [SECS] beats', + arguments: { + A: { + type: ArgumentType.NOTE, + defaultValue: 60 + }, + B: { + type: ArgumentType.NOTE, + + defaultValue: 64 + }, + C: { + type: ArgumentType.NOTE, + defaultValue: 67 + }, + SECS: { + type: ArgumentType.NUMBER, + defaultValue: 0.5, + menu: "BEATS" + } + } + }, + { + opcode: 'testMagentaRNN', + text: formatMessage({ + id: 'musiccreation.testMagentaRNN', + default: 'complete music with [STEPS] steps and [TEMP] temperature', + description: 'test Magenta RNN' + }), + blockType: BlockType.COMMAND, + arguments: { + STEPS: { + type: ArgumentType.NUMBER, + defaultValue: 20 + }, + TEMP: { + type: ArgumentType.NUMBER, + defaultValue: 1.5 + }, + }, + }, + { + opcode: 'createNotesRNN', + text: formatMessage({ + id: 'musiccreation.createNotesRNN', + default: 'complete & add blocks for [STEPS] steps, [TEMP] temp., and [SETTING] blocks for input notes', + description: 'create notes Magenta MVAE' + }), + blockType: BlockType.COMMAND, + arguments: { + STEPS: { + type: ArgumentType.NUMBER, + defaultValue: 20 + }, + TEMP: { + type: ArgumentType.NUMBER, + defaultValue: 1.5 + }, + SETTING: { + type: ArgumentType.NUMBER, + defaultValue: 0, + menu: 'SETTING' + } + } + }, + { + opcode: 'testMagentaMVAE', + text: formatMessage({ + id: 'musiccreation.testMagentaMVAE', + default: 'generate new music', + description: 'test Magenta MVAE' + }), + blockType: BlockType.COMMAND + }, + { + opcode: 'createNotesMVAE', + text: formatMessage({ + id: 'musiccreation.createNotesMVAE', + default: 'add new music blocks', + description: 'create notes Magenta MVAE' + }), + blockType: BlockType.COMMAND + }, + ], + menus: { + VOLUME: { + acceptReporters: true, + items: this.volumes + }, + INSTRUMENT: { + acceptReporters: true, + items: this._buildMenu(this.INSTRUMENT_INFO) + }, + FILES: { + acceptReporters: true, + items: this.files + }, + BEATS: { + acceptReporters: true, + items: this.beats + }, + FORMAT: { + acceptReporters: true, + items: this.displayOptions + }, + STATUS: { + acceptReporters: true, + items: this._visStatus + }, + SETTING: { + acceptReporters: false, + items: this.createNotesRNNSettings + }, + SCALE_NOTES: { + acceptReporters: false, + items: [ + { text: 'C', value: '0' }, + { text: 'C#', value: '1' }, + { text: 'D', value: '2' }, + { text: 'D#', value: '3' }, + { text: 'E', value: '4' }, + { text: 'F', value: '5' }, + { text: 'F#', value: '6' }, + { text: 'G', value: '7' }, + { text: 'G#', value: '8' }, + { text: 'A', value: '9' }, + { text: 'A#', value: '10' }, + { text: 'B', value: '11' }] + }, + SCALE_TYPES: { + acceptReporters: false, + items: ["Major", "Minor", "Pentatonic"] + }, + } + }; + } + + resetMusic(args, util) { + this.noteList = []; + this.wavenoteList = []; + this.magentaNoteList = []; + this.vizHelper.clearNoteBuffers(); + this.vizHelper.requestViz(null, util); + } + + toggleVisMode(args, util) { + this.vizHelper.toggleVisMode(args, util); + } + + /** + * Select an instrument for playing notes. + * @param {object} args - the block arguments. + * @param {object} util - utility object provided by the runtime. + * @property {int} INSTRUMENT - the number of the instrument to select. + */ + setInstrument(args, util) { + this.musicCreationHelper._setInstrument(args.INSTRUMENT, util, false); + } + + /** + * Select an instrument for playing notes. + * @param {object} args - the block arguments. + * @param {BlockUtility} util - utility object provided by the runtime. + * @property {int} INSTRUMENT - the number of the instrument to select. + */ + setInstrumentForBelow(args, util) { + addTopBlockModifier(util, instrumentModifierKey, Cast.toNumber(args.INSTRUMENT) - 1); // instruments are one-indexed + } + + setVolumeForBelow(args, util) { + let vol_n = Cast.toNumber(args.VOLUME); + addTopBlockModifier(util, volumeModifierKey, vol_n); + } + + + /** + * + * @param {array} raw_note - magenta note [freq,duration,inst,volume] + * @returns information about the note as an object, in a form + * consumable by this.musicCreationHelper + */ + rawNoteToNoteArg(raw_note) { + if (raw_note.length < 2) return; + var note_num = String(raw_note[0]); + var secs = String(raw_note[1]); + return { mutation: undefined, NOTE: note_num, SECS: secs }; + } + + /** + * Prepares the magenta notes to be played + * @param {Array[]} magenta_notes + * @returns an object with 'notes' and 'args' fields + */ + _prepare(magenta_notes) { + var inst = this.getInstrument(); + magenta_notes.forEach(x => { + x[2] = inst; + }); + var args = magenta_notes.map(x => { + return this.rawNoteToNoteArg(x); + }); + return { notes: magenta_notes, args: args }; + } + + /** + * + * @param {number} hi - highest freq. acceptable for Magenta RNN + * @param {number} low - lowest freq. acceptable for Magenta RNN + * @param {array} notes - array of notes that will be adjusted in-place + */ + adjustFreqsToRange(hi, low, notes) { + notes.map( + (note) => { + let freq = note[0]; + if (freq < low) { + const diff = low - freq; + note[0] += (Math.ceil(diff / 12.0) * 12); + } else if (freq > hi) { + const diff = freq - hi; + note[0] -= (Math.ceil(diff / 12.0) * 12); + } + }); + return notes; + } + + /** + * Asynchronous function that gets the created notes from Magenta and initializes + * playing the sequence. + * @param {boolean} RNN - true if 'complete music', false if 'generate new music' + * @param {array} args - arguments to be given to the music helper + * @param {BlockUtility} utils + * @param {number} inst - instrument to play on, represented as a number + * @param {function({mutation: any; NOTE: string; SECS: string;}[]): void} processNotes A callback function invoked with the generated notes as an argument + * @private + */ + async _getAndPlayMagentaNotes(RNN, args, utils, inst, vol, processNotes) { + let magenta_notes = null; + let valid = true; + if (RNN) { + if (this.noteList.length > 0) { + const low = 48; + const hi = 83; + //copy the noteList so that it doesn't change + const adjusted_notes = this.adjustFreqsToRange(hi, low, JSON.parse(JSON.stringify(this.noteList))); + magenta_notes = await this.musicAccompanimentHelper.testMagentaRNN(adjusted_notes, args, utils); + + } else valid = false; + } else { + magenta_notes = await this.musicAccompanimentHelper.testMagentaMVAE(utils); + } + if (valid) { + const prepared_notes = this._prepare(magenta_notes); + this.magentaNoteList = prepared_notes['notes']; + if (processNotes) processNotes(prepared_notes.args); + this.musicCreationHelper.playNotes(prepared_notes, utils, inst, vol, this.vizHelper); + } else utils.stackFrame.duration = 0; + } + + + getInstrumentForBlock(util) { + const modifierInst = getTopBlockModifier(util, instrumentModifierKey); + return (modifierInst !== undefined && modifierInst !== null) ? modifierInst : this.musicCreationHelper._getMusicState(util.target).currentInstrument; + } + + getVolumeForBlock(util) { + const modifierVol = getTopBlockModifier(util, volumeModifierKey); + return modifierVol ? modifierVol : this.musicCreationHelper.findNumberForVolume(this.getVolume(util)); + } + + /** + * Used to get the generated sequence of notes from Magenta and + * play it. + * @param {boolean} RNN - true if 'complete music', false if 'generate new music' + * @param {array} args - arguments to be given to the music helper + * @param {BlockUtility} utils + * @param {function(any[][]): void} processNotes + */ + getAndPlayMagentaNotes(RNN, args, util, processNotes) { + const inst = this.getInstrumentForBlock(util); + const vol = this.getVolumeForBlock(util); + if (util.stackTimerNeedsInit()) { + // get timer running for a large amount of time (will be handled) + util.startStackTimer(Number.MAX_SAFE_INTEGER); + util.yield(); + this._getAndPlayMagentaNotes(RNN, args, util, inst, vol, processNotes); + } + else if (!util.stackTimerFinished()) { + util.yield(); + } + } + + /** + * Generates and plays a sequence of notes based off of the notes + * that have recently been played and the current instrument + * @param {array} args - array of magenta notes [freq,duration,inst,?] + * @param {BlockUtility} utils + */ + testMagentaRNN(args, utils) { + this.getAndPlayMagentaNotes(true, args, utils); + } + + /** + * Generates and plays a sequence of notes, using the + * current instrument. + * @param {array} args - array of magenta notes [freq,duration,inst,?] + * @param {BlockUtility} utils + */ + testMagentaMVAE(args, utils) { + this.getAndPlayMagentaNotes(false, args, utils); + } + + /** + * + * current instrument. + * @param {array} args - array of magenta notes [freq,duration,inst,?] + * @param {BlockUtility} utils + */ + createNotesMVAE(args, utils) { + const { runtime } = utils + this.getAndPlayMagentaNotes(false, args, utils, (notes) => { + const blockArgs = notes.map(note => { + const { NOTE, SECS } = note; + return { NOTE, SECS: `${SECS}` }; + }); + const opcodes = blockArgs.map(_ => 'playNote'); + const xml = generateXMLForBlockChunk(this, runtime, opcodes, blockArgs); + runtime.addBlocksToWorkspace(xml); + }); + } + + createNotesRNN(args, utils) { + const { runtime } = utils; + this.getAndPlayMagentaNotes(true, args, utils, (notes) => { + let blockArgs = notes.map(note => { + const { NOTE, SECS } = note; + return { NOTE, SECS: `${SECS}` }; + }); + + const includeOldNotes = Cast.toBoolean(args.SETTING); + if (includeOldNotes) { + const oldNotes = this.noteList + .map(note => { return { NOTE: Cast.toString(note[0]), SECS: Cast.toString(note[1]) } }) + .slice(-maxNotesForCompleteGen); //limit number of notes included in the generated chunk + if (this.noteList.length > maxNotesForCompleteGen) { + alert(`Only displaying the last ${maxNotesForCompleteGen} notes in the generated chunk of blocks. Press 'reset music' to clear note list.`); + } + blockArgs = oldNotes.concat(blockArgs); + + } + + const opcodes = blockArgs.map(_ => 'playNote'); + const xml = generateXMLForBlockChunk(this, runtime, opcodes, blockArgs); + runtime.addBlocksToWorkspace(xml); + }); + } + + getInstrument(util) { + return this.musicCreationHelper.getInstrument(util); + } + + + _playNoteForPicker(noteNum, category) { + if (category !== this.getInfo().name) return; + const util = { + runtime: this.runtime, + target: this.runtime.getEditingTarget() + }; + const inst = this.musicCreationHelper._getMusicState(util.target).currentInstrument; + const vol = this.musicCreationHelper.findNumberForVolume(this.musicCreationHelper.getVolume(util)); + this.musicCreationHelper._playNote(util, noteNum, 0.25, inst, vol); + } + + /** + * Set the current tempo to a new value. + * @param {object} args - the block arguments. + * @param {BlockUtility} util - the block utility. + * @property {number} TEMPO - the tempo, in beats per minute. + * @param {BlockUtility} util + */ + setVolume(args, util) { + const volume = Cast.toNumber(args.VOLUME); + this.musicCreationHelper._updateVolume(volume, util); + } + + /** + * @param {number[]} arr + * @param {number} query + */ + getClosestEntry(arr, query) { + const initial = { delta: Number.MAX_SAFE_INTEGER, index: -1 }; + const closestIndex = arr + .map((item, index) => ({ delta: Math.abs(item - query), index })) + .reduce((previous, current) => current.delta < previous.delta ? current : previous, initial) + .index; + return arr[closestIndex]; + } + + /** + * Scales a note value to a given scale + * @param {{NOTE: number, SCALE: string}} args + * @param {BlockUtility} util + */ + roundNoteToScale(args, util) { + const { NOTE, SCALE, TYPE } = args; + const note = parseFloat(NOTE); + const octave = Math.floor(note / 12); + let root = parseInt(SCALE) + octave * 12; + root = root < note ? root : root - 12; + const offsets = TYPE === 'Major' ? this.majorScale : TYPE === 'Pentatonic' ? this.pentatonicScale : this.minorScale; + const rounded = root + this.getClosestEntry(offsets, note - root); + return rounded; + } + + getVolume(util) { + return this.musicCreationHelper.getVolume(util); + } + + playNote(args, util) { + const inst = this.getInstrumentForBlock(util); + const vol = this.getVolumeForBlock(util); + const toAdd = this.musicCreationHelper.playNote(args, util, inst, vol); + if (toAdd.length == 3) { + this.noteList.push(toAdd); + toAdd.push(vol); + this.vizHelper.requestViz(toAdd, util); + this.wavenoteList.push(toAdd); + } + } + + playNoteList(args, util) { + const notes = [Cast.toNumber(args.A), Cast.toNumber(args.B), Cast.toNumber(args.C)].filter(note => note > 0); + if (notes.length === 0) return; + const _args = notes.map(_ => JSON.parse(JSON.stringify(args))); + const inst = this.getInstrumentForBlock(util); + const vol = this.getVolumeForBlock(util); + let beats = Cast.toNumber(args.SECS); + beats = this.musicCreationHelper._clampBeats(beats); + let instName = this.INSTRUMENT_INFO[inst].name; + + const visualizeByIndex = (index) => { + let toAdd = [_args[index].NOTE, beats, instName]; + this.noteList.push(toAdd); + toAdd.push(vol); + this.vizHelper.requestViz(toAdd, util); + this.wavenoteList.push(toAdd); + } + + _args.forEach((arg, index) => arg.NOTE = notes[index]); + + for (let i = 1; i < notes.length; i++) { + if (this.musicCreationHelper.stackTimerNeedsInit(util)) { + this.musicCreationHelper.internalPlayNote(_args[i], util, inst, vol, false); + visualizeByIndex(i); + } + + } + + this.playNote(_args[0], util, inst, vol); + } +} + +module.exports = Scratch3MusicCreation; + + diff --git a/src/extensions/scratch3_musiccreation/letters.js b/src/extensions/scratch3_musiccreation/letters.js new file mode 100644 index 00000000000..668c2c5a003 --- /dev/null +++ b/src/extensions/scratch3_musiccreation/letters.js @@ -0,0 +1,40 @@ +module.exports = { + 'a': [[0.0, 69.40170940170941], [27.672112018669765, 0.0], [59.03383897316219, 70.0], [51.654609101516925, 47.863247863247864], [6.149358226371049, 47.26495726495726]], + 'b': [[0.6149358226371078, 70.0], [0.0, 0.0], [3.6896149358226467, 0.0], [11.068844807467912, 0.0], [22.75262543757293, 0.0], [27.672112018669793, 1.9090909090909138], [32.59159859976663, 5.090909090909103], [34.43640606767795, 10.81818181818183], [34.43640606767795, 15.90909090909092], [33.82147024504084, 22.909090909090917], [28.90198366394401, 26.0909090909091], [23.982497082847146, 28.63636363636364], [18.448074679113176, 30.545454545454554], [11.68378063010502, 31.818181818181824], [4.919486581096862, 31.818181818181824], [1.8448074679113233, 31.818181818181824], [0.6149358226371078, 31.818181818181824], [12.913652275379235, 32.45454545454546], [22.137689614935823, 35.63636363636364], [28.90198366394401, 38.18181818181819], [33.206534422403735, 41.36363636363637], [35.666277712952166, 44.545454545454554], [35.666277712952166, 50.90909090909092], [35.05134189031506, 56.000000000000014], [33.82147024504084, 62.363636363636374], [28.2870478413069, 67.45454545454547], [23.982497082847146, 68.09090909090911], [13.528588098016343, 69.36363636363636], [7.994165694282373, 70.0], [0.0, 70.0]], + 'c': [[13.603815937149307, 65.0], [22.475869809203175, 68.75], [33.713804713804734, 70.0], [44.3602693602694, 68.125], [55.006734006734064, 63.75000000000001], [44.3602693602694, 68.125], [33.713804713804734, 70.0], [23.06734006734007, 68.75], [14.1952861952862, 65.0], [7.097643097643129, 56.875], [1.1829405162739022, 45.625], [0.0, 33.75], [1.7744107744107964, 21.250000000000007], [8.872053872053925, 10.625000000000007], [19.518518518518533, 1.8750000000000007], [31.347923681257043, 0.0], [43.76879910213245, 1.2500000000000029], [55.59820426487096, 6.25]], + 'd': [[1.8448074679113233, 68.03738317757009], [0.0, 1.3084112149532667], [14.143523920653479, 0.0], [25.212368728121362, 1.3084112149532667], [36.89614935822641, 5.887850467289719], [44.890315052508754, 12.429906542056068], [51.03967327887983, 21.588785046728965], [51.65460910151694, 32.05607476635514], [49.809801633605616, 45.794392523364486], [45.50525087514586, 56.915887850467286], [38.126021003500625, 62.80373831775701], [31.976662777129548, 66.72897196261681], [18.140606767794623, 69.34579439252336], [2.459743290548431, 70.0]], + 'e': [[1.2298716452742156, 68.71559633027523], [0.6149358226371078, 1.926605504587154], [33.206534422403706, 0.0], [1.2298716452742156, 1.284403669724774], [0.0, 34.03669724770643], [33.206534422403706, 34.67889908256881], [0.0, 34.03669724770643], [1.8448074679113233, 70.0], [33.821470245040814, 70.0]], + 'f': [[0.0, 70.0], [0.0, 0.0], [35.05134189031503, 0.0], [0.0, 0.0], [0.0, 31.875000000000007], [35.05134189031503, 31.875000000000007]], + 'g': [[16.603267211201867, 66.72897196261681], [26.44224037339557, 70.0], [38.12602100350059, 68.69158878504673], [50.4247374562427, 62.14953271028035], [59.0338389731622, 51.028037383177555], [60.878646441073506, 37.94392523364484], [36.896149358226374, 37.94392523364484], [62.10851808634772, 37.2897196261682], [59.0338389731622, 52.33644859813082], [50.4247374562427, 63.45794392523363], [38.12602100350059, 70.0], [27.057176196032678, 70.0], [17.218203033838975, 67.38317757009345], [4.919486581096848, 54.29906542056074], [0.0, 38.598130841121474], [0.6149358226371078, 25.51401869158879], [6.764294049008171, 12.429906542056075], [18.44807467911319, 2.6168224299065184], [32.591598599766634, 0.0], [46.73512252042007, 1.9626168224299116], [57.189031505250874, 8.504672897196254]], + 'h': [[0.0, 68.22033898305085], [0.0, 0.0], [0.0, 33.813559322033896], [51.65460910151691, 34.40677966101695], [51.65460910151691, 1.1864406779661043], [51.65460910151691, 70.0]], + 'i': [[0.0, 70.0], [0.0, 0.0]], + 'j': [[7.994165694282401, 69.41176470588238], [0.0, 60.58823529411765], [8.609101516919509, 70.0], [20.907817969661608, 68.23529411764709], [25.82730455075847, 58.82352941176473], [27.057176196032685, 0.0]], + 'k': [[0.0, 69.42622950819673], [1.2298716452742156, 0.0], [0.0, 37.295081967213136], [43.04550758459743, 0.5737704918032802], [1.2298716452742156, 37.86885245901641], [44.275379229871646, 70.0]], + 'l': [[0.0, 69.39655172413792], [0.0, 0.0], [0.6149358226371078, 70.0], [33.20653442240376, 69.39655172413792]], + 'm': [[0.0, 69.42622950819673], [0.0, 0.0], [38.12602100350057, 68.85245901639347], [76.86697782963824, 0.5737704918032802], [76.86697782963824, 70.0]], + 'n': [[0.0, 68.86178861788618], [0.0, 0.0], [57.803967327887975, 70.0], [57.803967327887975, 0.5691056910569123]], + 'o': [[12.298716452742127, 65.33333333333339], [4.304550758459754, 55.33333333333336], [0.0, 42.00000000000005], [0.6149358226371078, 28.666666666666682], [5.53442240373397, 14.666666666666705], [18.448074679113176, 2.6666666666666736], [38.740956826137705, 0.0], [52.88448074679113, 6.000000000000016], [61.493582263710636, 20.000000000000053], [62.108518086347715, 36.6666666666667], [57.18903150525088, 53.33333333333336], [46.12018669778297, 64.00000000000004], [33.206534422403735, 70.0], [20.907817969661608, 68.66666666666666], [11.68378063010502, 64.66666666666671]], + 'p': [[0.6149358226371078, 70.0], [0.0, 0.0], [19.063010501750284, 0.0], [30.746791131855332, 7.583333333333303], [35.05134189031503, 16.916666666666664], [34.43640606767798, 27.416666666666643], [28.90198366394401, 35.58333333333333], [19.677946324387392, 37.33333333333334], [0.6149358226371078, 37.33333333333334]], + 'q': [[15.988331388564745, 57.016129032258085], [6.7642940490081855, 46.29032258064516], [0.0, 33.87096774193551], [0.6149358226371078, 18.62903225806451], [10.453908984830832, 7.338709677419372], [26.442240373395578, 0.0], [44.275379229871646, 2.2580645161290374], [56.574095682613745, 9.03225806451615], [62.72345390898482, 22.58064516129032], [62.72345390898482, 36.693548387096804], [57.18903150525085, 46.854838709677416], [47.350058343057185, 52.500000000000014], [38.12602100350057, 42.338709677419345], [61.49358226371061, 70.0], [47.96499416569429, 53.06451612903227], [37.51108518086346, 58.70967741935481], [27.057176196032685, 59.274193548387075], [15.988331388564745, 57.016129032258085]], + 'r': [[0.0, 70.0], [0.0, 0.0], [13.012345679012356, 0.0], [24.25028058361397, 2.393162393162442], [28.3905723905724, 9.572649572649595], [29.57351290684619, 17.350427350427374], [27.2076318742985, 24.529914529914524], [17.744107744107737, 29.31623931623935], [5.323232323232332, 29.91452991452992], [0.0, 34.97218573119902], [34.305274971941685, 70.0]], + 's': [[0.0, 61.44104803493453], [8.280583613916974, 67.5545851528385], [20.109988776655428, 70.0], [30.756453423120092, 68.1659388646288], [38.14983164983164, 60.82969432314406], [39.62850729517402, 49.82532751091703], [33.12233445566778, 41.572052401746724], [21.292929292929216, 33.62445414847156], [8.872053872053925, 24.14847161572052], [4.731762065095381, 14.366812227074217], [8.280583613916974, 5.196506550218391], [15.378226711560046, 0.9170305676856295], [23.65881032547702, 0.0], [32.235129068462356, 2.4454148471615023], [38.741301907968705, 7.641921397379893]], + 't': [[24.597432905484244, 70.0], [24.597432905484244, 0.0], [0.0, 0.0], [51.03967327887982, 0.0]], + 'u': [[6.1493582263710636, 66.37931034482763], [1.2298716452742156, 56.12068965517243], [0.6149358226371078, 48.27586206896556], [0.0, 0.603448275862071], [1.2298716452742156, 47.67241379310349], [1.2298716452742156, 56.12068965517243], [6.764294049008171, 66.9827586206897], [17.218203033838975, 69.39655172413799], [31.361726954492426, 70.0], [44.27537922987163, 64.56896551724142], [50.42473745624271, 51.89655172413793], [49.8098016336056, 0.0]], + 'v': [[26.442240373395578, 70.0], [0.0, 0.0], [26.442240373395578, 70.0], [52.88448074679113, 0.0]], + 'w': [[20.2928821470245, 70.0], [0.0, 0.0], [20.2928821470245, 70.0], [44.275379229871646, 1.1290322580645196], [68.25787631271879, 70.0], [88.55075845974329, 0.5645161290322598]], + 'x': [[0.0, 68.87096774193547], [43.66044340723454, 0.0], [21.522753792298715, 32.74193548387096], [0.0, 0.0], [21.522753792298715, 32.74193548387096], [45.50525087514586, 70.0]], + 'y': [[23.982497082847203, 70.0], [23.367561260210095, 32.66666666666666], [0.0, 0.0], [23.367561260210095, 32.66666666666666], [47.350058343057185, 0.0]], + 'z': [[2.459743290548431, 70.0], [55.959159859976694, 70.0], [2.459743290548431, 70.0], [50.424737456242724, 0.0], [0.0, 1.250000000000004]], + 'one': [[28.186697782963847, 70.0], [29.467911318553092, 0.0], [0.0, 15.74999999999999]], + 'two': [[0.0, 70.0], [61.498249708284675, 69.07894736842107], [0.0, 70.0], [42.280046674445714, 37.76315789473684], [51.2485414235706, 26.710526315789476], [52.529754959159845, 11.973684210526297], [40.99883313885647, 1.8421052631578667], [23.061843640606753, 0.0], [8.96849474912483, 3.6842105263157334], [0.0, 9.210526315789416]], + 'three': [[0.0, 65.56962025316454], [23.061843640606867, 70.0], [46.12368728121362, 69.11392405063292], [58.935822637106185, 61.13924050632908], [60.21703617269554, 47.84810126582279], [49.967327887981355, 38.98734177215188], [19.218203033839018, 33.67088607594935], [47.404900816802865, 29.240506329113888], [56.373395565927694, 20.379746835442976], [53.810968494749204, 8.860759493670836], [34.59276546091019, 0.0], [15.374562427071282, 2.658227848101227], [3.843640606767849, 6.202531645569609]], + 'four': [[0.0, 50.74999999999999], [74.31038506417735, 50.74999999999999], [0.0, 50.74999999999999], [55.092182030338336, 0.0], [53.81096849474909, 70.0]], + 'five': [[0.0, 65.5128205128205], [19.218203033839018, 70.0], [42.28004667444577, 68.20512820512823], [53.81096849474909, 60.12820512820512], [58.935822637106185, 49.35897435897434], [52.529754959159845, 36.79487179487181], [33.31155192532094, 30.51282051282054], [10.249708284714188, 33.20512820512819], [12.812135355892678, 0.0], [57.65460910151694, 0.8974358974358841]], + 'six': [[6.406067677946339, 64.54545454545455], [23.061843640606867, 70.0], [44.842473745624375, 69.09090909090911], [55.09218203033845, 58.1818181818182], [55.09218203033845, 43.636363636363626], [48.68611435239211, 31.818181818181824], [32.030338389731696, 29.090909090909058], [15.374562427071282, 34.54545454545451], [2.562427071178604, 43.636363636363626], [6.406067677946339, 64.54545454545455], [0.0, 44.54545454545452], [1.2812135355893588, 25.454545454545475], [10.249708284714188, 10.00000000000001], [29.467911318553092, 0.9090909090908954], [55.09218203033845, 0.0]], + 'seven': [[19.218203033839018, 70.0], [65.34189031505252, 0.0], [0.0, 0.0]], + 'eight': [[1.2812135355892451, 64.61538461538461], [16.655775962660414, 70.0], [37.15519253208868, 69.10256410256412], [53.81096849474909, 61.92307692307696], [55.092182030338336, 48.46153846153846], [43.5612602100349, 39.48717948717946], [10.249708284714075, 27.820512820512807], [3.8436406067677353, 14.358974358974306], [12.812135355892565, 2.6923076923076525], [37.15519253208868, 0.0], [51.24854142357049, 8.076923076923038], [51.24854142357049, 22.435897435897424], [12.812135355892565, 38.58974358974358], [0.0, 47.564102564102576], [1.2812135355892451, 64.61538461538461]], + 'nine': [[3.843640606767849, 70.0], [23.061843640606867, 68.20512820512823], [40.998833138856526, 61.92307692307696], [51.248541423570714, 47.564102564102576], [57.654609101516826, 30.51282051282054], [53.810968494749204, 14.358974358974306], [46.123687281213506, 3.5897435897435366], [25.624270711785357, 0.0], [6.406067677946339, 7.179487179487153], [0.0, 18.846153846153808], [0.0, 32.30769230769231], [16.655775962660528, 40.384615384615344], [37.15519253208868, 39.48717948717946], [57.654609101516826, 30.51282051282054]], + 'zero': [[10.249708284714188, 63.79746835443039], [25.624270711785357, 70.0], [47.404900816802865, 64.68354430379748], [55.09218203033856, 49.62025316455695], [55.09218203033856, 23.924050632911356], [49.967327887981355, 7.974683544303759], [29.467911318553206, 0.0], [10.249708284714188, 5.316455696202532], [0.0, 16.835443037974674], [0.0, 45.189873417721564], [10.249708284714188, 63.79746835443039]], + 'flat': [[1.6569579288025125, 70.0], [0.0, 0.0], [3.3139158576052523, 45.08474576271185], [28.168284789644076, 41.12994350282486], [51.36569579288016, 41.52542372881354], [67.9352750809062, 45.48022598870056], [66.27831715210345, 50.621468926553675], [54.67961165048541, 55.367231638418076], [26.511326860841336, 62.09039548022598], [1.6569579288025125, 70.0]], + 'sharp': [[36.45307443365709, 70.0], [36.45307443365709, 4.605263157894746], [38.110032362459606, 26.249999999999993], [0.0, 28.55263157894738], [119.30097087378658, 21.644736842105274], [86.16181229773474, 23.48684210526315], [87.81877022653725, 0.0], [87.81877022653725, 66.31578947368422], [86.16181229773474, 44.210526315789465], [122.6148867313916, 42.36842105263159], [0.0, 50.19736842105263]] +} diff --git a/src/extensions/scratch3_musiccreation/manifest.js b/src/extensions/scratch3_musiccreation/manifest.js new file mode 100644 index 00000000000..09f9d5ca238 --- /dev/null +++ b/src/extensions/scratch3_musiccreation/manifest.js @@ -0,0 +1,55 @@ +module.exports = { + 'instruments/1-piano/24.mp3': require('!arraybuffer-loader!./assets/instruments/1-piano/24.mp3'), + 'instruments/1-piano/36.mp3': require('!arraybuffer-loader!./assets/instruments/1-piano/36.mp3'), + 'instruments/1-piano/48.mp3': require('!arraybuffer-loader!./assets/instruments/1-piano/48.mp3'), + 'instruments/1-piano/60.mp3': require('!arraybuffer-loader!./assets/instruments/1-piano/60.mp3'), + 'instruments/1-piano/72.mp3': require('!arraybuffer-loader!./assets/instruments/1-piano/72.mp3'), + 'instruments/1-piano/84.mp3': require('!arraybuffer-loader!./assets/instruments/1-piano/84.mp3'), + 'instruments/1-piano/96.mp3': require('!arraybuffer-loader!./assets/instruments/1-piano/96.mp3'), + 'instruments/1-piano/108.mp3': require('!arraybuffer-loader!./assets/instruments/1-piano/108.mp3'), + 'instruments/2-electric-piano/60.mp3': require('!arraybuffer-loader!./assets/instruments/2-electric-piano/60.mp3'), + 'instruments/3-organ/60.mp3': require('!arraybuffer-loader!./assets/instruments/3-organ/60.mp3'), + 'instruments/4-guitar/60.mp3': require('!arraybuffer-loader!./assets/instruments/4-guitar/60.mp3'), + 'instruments/5-electric-guitar/60.mp3': require( + '!arraybuffer-loader!./assets/instruments/5-electric-guitar/60.mp3' + ), + 'instruments/6-bass/36.mp3': require('!arraybuffer-loader!./assets/instruments/6-bass/36.mp3'), + 'instruments/6-bass/48.mp3': require('!arraybuffer-loader!./assets/instruments/6-bass/48.mp3'), + 'instruments/7-pizzicato/60.mp3': require('!arraybuffer-loader!./assets/instruments/7-pizzicato/60.mp3'), + 'instruments/8-cello/36.mp3': require('!arraybuffer-loader!./assets/instruments/8-cello/36.mp3'), + 'instruments/8-cello/48.mp3': require('!arraybuffer-loader!./assets/instruments/8-cello/48.mp3'), + 'instruments/8-cello/60.mp3': require('!arraybuffer-loader!./assets/instruments/8-cello/60.mp3'), + 'instruments/9-trombone/36.mp3': require('!arraybuffer-loader!./assets/instruments/9-trombone/36.mp3'), + 'instruments/9-trombone/48.mp3': require('!arraybuffer-loader!./assets/instruments/9-trombone/48.mp3'), + 'instruments/9-trombone/60.mp3': require('!arraybuffer-loader!./assets/instruments/9-trombone/60.mp3'), + 'instruments/10-clarinet/48.mp3': require('!arraybuffer-loader!./assets/instruments/10-clarinet/48.mp3'), + 'instruments/10-clarinet/60.mp3': require('!arraybuffer-loader!./assets/instruments/10-clarinet/60.mp3'), + 'instruments/11-saxophone/36.mp3': require('!arraybuffer-loader!./assets/instruments/11-saxophone/36.mp3'), + 'instruments/11-saxophone/60.mp3': require('!arraybuffer-loader!./assets/instruments/11-saxophone/60.mp3'), + 'instruments/11-saxophone/84.mp3': require('!arraybuffer-loader!./assets/instruments/11-saxophone/84.mp3'), + 'instruments/12-flute/60.mp3': require('!arraybuffer-loader!./assets/instruments/12-flute/60.mp3'), + 'instruments/12-flute/72.mp3': require('!arraybuffer-loader!./assets/instruments/12-flute/72.mp3'), + 'instruments/13-wooden-flute/60.mp3': require('!arraybuffer-loader!./assets/instruments/13-wooden-flute/60.mp3'), + 'instruments/13-wooden-flute/72.mp3': require('!arraybuffer-loader!./assets/instruments/13-wooden-flute/72.mp3'), + 'instruments/14-bassoon/36.mp3': require('!arraybuffer-loader!./assets/instruments/14-bassoon/36.mp3'), + 'instruments/14-bassoon/48.mp3': require('!arraybuffer-loader!./assets/instruments/14-bassoon/48.mp3'), + 'instruments/14-bassoon/60.mp3': require('!arraybuffer-loader!./assets/instruments/14-bassoon/60.mp3'), + 'instruments/15-choir/48.mp3': require('!arraybuffer-loader!./assets/instruments/15-choir/48.mp3'), + 'instruments/15-choir/60.mp3': require('!arraybuffer-loader!./assets/instruments/15-choir/60.mp3'), + 'instruments/15-choir/72.mp3': require('!arraybuffer-loader!./assets/instruments/15-choir/72.mp3'), + 'instruments/16-vibraphone/60.mp3': require('!arraybuffer-loader!./assets/instruments/16-vibraphone/60.mp3'), + 'instruments/16-vibraphone/72.mp3': require('!arraybuffer-loader!./assets/instruments/16-vibraphone/72.mp3'), + 'instruments/17-music-box/60.mp3': require('!arraybuffer-loader!./assets/instruments/17-music-box/60.mp3'), + 'instruments/18-steel-drum/60.mp3': require('!arraybuffer-loader!./assets/instruments/18-steel-drum/60.mp3'), + 'instruments/19-marimba/60.mp3': require('!arraybuffer-loader!./assets/instruments/19-marimba/60.mp3'), + 'instruments/20-synth-lead/24.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/24.mp3'), + 'instruments/20-synth-lead/36.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/36.mp3'), + 'instruments/20-synth-lead/48.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/48.mp3'), + 'instruments/20-synth-lead/60.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/60.mp3'), + 'instruments/20-synth-lead/72.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/72.mp3'), + 'instruments/20-synth-lead/84.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/84.mp3'), + 'instruments/20-synth-lead/96.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/96.mp3'), + 'instruments/20-synth-lead/108.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/108.mp3'), + 'instruments/20-synth-lead/120.mp3': require('!arraybuffer-loader!./assets/instruments/20-synth-lead/120.mp3'), + 'instruments/21-synth-pad/60.mp3': require('!arraybuffer-loader!./assets/instruments/21-synth-pad/60.mp3') +}; diff --git a/src/extensions/scratch3_musiccreation/musicaccompanimenthelpers.js b/src/extensions/scratch3_musiccreation/musicaccompanimenthelpers.js new file mode 100644 index 00000000000..48c68e7753a --- /dev/null +++ b/src/extensions/scratch3_musiccreation/musicaccompanimenthelpers.js @@ -0,0 +1,108 @@ +const log = require('../../util/log'); +const Cast = require('../../util/cast'); +const hrtime = require('browser-hrtime'); +const mvae = require('@magenta/music/node/music_vae'); +const core = require('@magenta/music/node/core'); +const rnn = require('@magenta/music/node/music_rnn'); +const regeneratorRuntime = require("regenerator-runtime"); + +const symbols = require('./symbols'); +const { time } = require('format-message'); + +var TWINKLE_TWINKLE, music_rnn, music_vae, magentaNotes, notes, rnn_steps, rnn_temperature; + +/** + * The instrument and drum sounds, loaded as static assets. + * @type {object} + */ +let assetData = {}; + +try { + assetData = require('./manifest'); +} catch (e) { + // Non-webpack environment, don't worry about assets. +} + +class MusicAccompanimentHelpers { + constructor(runtime, validNoteDurations, beatsPerSec) { + this.runtime = runtime; + this.validNoteDurations = validNoteDurations; + this.beatsPerSec = beatsPerSec; + TWINKLE_TWINKLE = { + notes: [ + { pitch: 60, startTime: 0.0, endTime: 0.5 }, + { pitch: 60, startTime: 0.5, endTime: 1.0 }, + { pitch: 67, startTime: 1.0, endTime: 1.5 }, + { pitch: 67, startTime: 1.5, endTime: 2.0 }, + { pitch: 69, startTime: 2.0, endTime: 2.5 }, + { pitch: 69, startTime: 2.5, endTime: 3.0 }, + { pitch: 67, startTime: 3.0, endTime: 4.0 }, + { pitch: 65, startTime: 4.0, endTime: 4.5 }, + { pitch: 65, startTime: 4.5, endTime: 5.0 }, + { pitch: 64, startTime: 5.0, endTime: 5.5 }, + { pitch: 64, startTime: 5.5, endTime: 6.0 }, + { pitch: 62, startTime: 6.0, endTime: 6.5 }, + { pitch: 62, startTime: 6.5, endTime: 7.0 }, + { pitch: 60, startTime: 7.0, endTime: 8.0 }, + ], + totalTime: 8 + }; + + this.noteList = []; + + music_rnn = new rnn.MusicRNN('https://storage.googleapis.com/magentadata/js/checkpoints/music_rnn/basic_rnn'); + music_rnn.initialize(); + + music_vae = new mvae.MusicVAE('https://storage.googleapis.com/magentadata/js/checkpoints/music_vae/mel_4bar_small_q2'); + music_vae.initialize(); + + } + + configure(noteList) { + let elapsedTime = 0; + const notes = noteList.map(([pitch, duration]) => { + const startTime = elapsedTime; + elapsedTime = startTime + parseFloat(duration); + return { pitch, startTime, endTime: elapsedTime }; + }); + + return { notes, totalTime: elapsedTime };; + } + + constrainDuration(duration) { + const initial = { delta: Number.MAX_VALUE, index: -1 }; + const { index } = this.validNoteDurations + .map((valid, index) => ({ delta: Math.abs(valid - duration), index })) + .reduce((minimum, query) => (query.delta < minimum.delta) ? query : minimum, initial); + return parseFloat(this.validNoteDurations[index]); + } + + processed(notes) { + return notes.map(note => { + const { quantizedStartStep, quantizedEndStep, pitch } = note; + const duration = (quantizedEndStep - quantizedStartStep) / this.beatsPerSec; + return [pitch, this.constrainDuration(duration), "Piano", 60]; + }); + } + + async testMagentaRNN(noteList, args, utils) { + notes = this.configure(noteList); + rnn_steps = Cast.toNumber(args.STEPS); + rnn_temperature = Cast.toNumber(args.TEMP); + + // The model expects a quantized sequence, and ours was unquantized: + const qns = core.sequences.quantizeNoteSequence(notes, this.beatsPerSec); + const generated = await music_rnn.continueSequence(qns, rnn_steps, rnn_temperature); + magentaNotes = this.processed(generated.notes); + return magentaNotes; + } + + async testMagentaMVAE(utils) { + const vae_temperature = 3; + const generated = await music_vae.sample(1, vae_temperature) + magentaNotes = this.processed(generated[0].notes); + return magentaNotes; + } +} + +module.exports = MusicAccompanimentHelpers; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/musiccreationhelpers.js b/src/extensions/scratch3_musiccreation/musiccreationhelpers.js new file mode 100644 index 00000000000..2ea57f5fdcb --- /dev/null +++ b/src/extensions/scratch3_musiccreation/musiccreationhelpers.js @@ -0,0 +1,768 @@ +const Clone = require('../../util/clone'); +const Cast = require('../../util/cast'); +const formatMessage = require('format-message'); +const MathUtil = require('../../util/math-util'); +const Timer = require('../../util/timer'); +const log = require('../../util/log'); +const { clamp } = require('../../util/math-util'); +const { p } = require('./letters'); +const BlockUtility = require('../../engine/block-utility'); +const VizHelpers = require('./vizhelpers'); + +/** + * The instrument and drum sounds, loaded as static assets. + * @type {object} + */ +let assetData = {}; + +try { + assetData = require('./manifest'); +} catch (e) { + // Non-webpack environment, don't worry about assets. +} + +var globalVolume; + +class MusicCreationHelpers { + constructor(runtime) { + this.runtime = runtime; + this._stopped = false; + + /** + * An array of arrays of sound players. Each instrument has one or more audio players. + * @type {Array[]} + * @private + */ + this._instrumentPlayerArrays = []; + + /** + * An array of arrays of sound players. Each instrument mya have an audio player for each playable note. + * @type {Array[]} + * @private + */ + this._instrumentPlayerNoteArrays = []; + this._loadAllSounds(); + + this.noteList = []; + + this.instrumentNames = this._buildMenu(this.INSTRUMENT_INFO); + + this._onTargetCreated = this._onTargetCreated.bind(this); + this.runtime.on('targetWasCreated', this._onTargetCreated); + + this.volumes = [{ text: "pianissimo", value: 15 }, + { text: "piano", value: 30 }, + { text: "mezzo-piano", value: 45 }, + { text: "mezzo-forte", value: 60 }, + { text: "forte", value: 85 }, + { text: "fortissimo", value: 100 }]; + + globalVolume = "mezzo-forte"; + } + + /** + * The key to load & store a target's music-related state. + * @type {string} + */ + static get STATE_KEY() { + return 'Scratch.musiccreation'; + } + + /** + * The default music-related state, to be used when a target has no existing music state. + * @type {MusicState} + */ + static get DEFAULT_MUSIC_STATE() { + return { + currentInstrument: 0 + }; + } + + /** + * The minimum and maximum MIDI note numbers, for clamping the input to play note. + * @type {{min: number, max: number}} + */ + static get MIDI_NOTE_RANGE() { + return { min: 0, max: 130 }; + } + + /** + * The minimum and maximum beat values, for clamping the duration of play note, play drum and rest. + * 100 beats at the default tempo of 60bpm is 100 seconds. + * @type {{min: number, max: number}} + */ + static get BEAT_RANGE() { + return { min: 0, max: 100 }; + } + + /** + * The maximum number of sounds to allow to play simultaneously. + * @type {number} + */ + static get CONCURRENCY_LIMIT() { + return 30; + } + + /** + * An array of info about each instrument. + * @type {object[]} + * @param {string} name - the translatable name to display in the instruments menu. + * @param {string} dirName - the name of the directory containing audio samples for this instrument. + * @param {number} [releaseTime] - an optional duration for the release portion of each note. + * @param {number[]} samples - an array of numbers representing the MIDI note number for each + * sampled sound used to play this instrument. + */ + get INSTRUMENT_INFO() { + return [ + { + name: formatMessage({ + id: 'musiccreation.instrumentPiano', + default: 'Piano', + description: 'Sound of a piano' + }), + dirName: '1-piano', + releaseTime: 0.5, + samples: [24, 36, 48, 60, 72, 84, 96, 108] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentGuitar', + default: 'Guitar', + description: 'Sound of an accoustic guitar' + }), + dirName: '4-guitar', + releaseTime: 0.5, + samples: [60] + }, { + name: formatMessage({ + id: 'musiccreation.instrumentBass', + default: 'Bass', + description: 'Sound of an accoustic upright bass' + }), + dirName: '6-bass', + releaseTime: 0.25, + samples: [36, 48] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentCello', + default: 'Cello', + description: 'Sound of a cello being played with a bow' + }), + dirName: '8-cello', + releaseTime: 0.1, + samples: [36, 48, 60] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentSaxophone', + default: 'Saxophone', + description: 'Sound of a saxophone being played' + }), + dirName: '11-saxophone', + samples: [36, 60, 84] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentClarinet', + default: 'Clarinet', + description: 'Sound of a clarinet being played' + }), + dirName: '10-clarinet', + samples: [48, 60] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentSynthLead', + default: 'Synth', + description: 'Sound of a "lead" synthesizer being played' + }), + dirName: '20-synth-lead', + releaseTime: 0.1, + samples: [24, 36, 48, 60, 72, 84, 96, 108, 120] + } + ]; + } + + /** + * When a music-playing Target is cloned, clone the music state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated(newTarget, sourceTarget) { + if (sourceTarget) { + const musicState = sourceTarget.getCustomState(MusicCreationHelpers.STATE_KEY); + if (musicState) { + newTarget.setCustomState(MusicCreationHelpers.STATE_KEY, Clone.simple(musicState)); + } + } + } + + /** + * Decode the full set of drum and instrument sounds, and store the audio buffers in arrays. + */ + _loadAllSounds() { + const loadingPromises = []; + this.INSTRUMENT_INFO.forEach((instrumentInfo, instrumentIndex) => { + this._instrumentPlayerArrays[instrumentIndex] = []; + this._instrumentPlayerNoteArrays[instrumentIndex] = []; + instrumentInfo.samples.forEach((sample, noteIndex) => { + const filePath = `instruments/${instrumentInfo.dirName}/${sample}`; + const promise = this._storeSound(filePath, noteIndex, this._instrumentPlayerArrays[instrumentIndex]); + loadingPromises.push(promise); + }); + }); + Promise.all(loadingPromises).then(() => { + // @TODO: Update the extension status indicator. + }); + } + + /** + * Decode a sound and store the player in an array. + * @param {string} filePath - the audio file name. + * @param {number} index - the index at which to store the audio player. + * @param {array} playerArray - the array of players in which to store it. + * @return {Promise} - a promise which will resolve once the sound has been stored. + */ + _storeSound(filePath, index, playerArray) { + const fullPath = `${filePath}.mp3`; + + if (!assetData[fullPath]) return; + + // The sound player has already been downloaded via the manifest file required above. + const soundBuffer = assetData[fullPath]; + + return this._decodeSound(soundBuffer).then(player => { + playerArray[index] = player; + }); + } + + + /** + * Decode a sound and return a promise with the audio buffer. + * @param {ArrayBuffer} soundBuffer - a buffer containing the encoded audio. + * @return {Promise} - a promise which will resolve once the sound has decoded. + */ + _decodeSound(soundBuffer) { + return this.runtime.awaitAudioEngine().then(e => e.decodeSoundPlayer({ data: { buffer: soundBuffer } })); + } + + /** + * Create data for a menu in scratch-blocks format, consisting of an array of objects with text and + * value properties. The text is a translated string, and the value is one-indexed. + * @param {object[]} info - An array of info objects each having a name property. + * @return {array} - An array of objects with text and value properties. + * @private + */ + _buildMenu(info) { + return info.map((entry, index) => { + const obj = {}; + obj.text = entry.name; + obj.value = String(index + 1); + return obj; + }); + } + + /** + * @param {Target} target - collect music state for this target. + * @returns {MusicState} the mutable music state associated with that target. This will be created if necessary. + * @private + */ + _getMusicState(target) { + let musicState = target.getCustomState(MusicCreationHelpers.STATE_KEY); + if (!musicState) { + musicState = Clone.simple(MusicCreationHelpers.DEFAULT_MUSIC_STATE); + target.setCustomState(MusicCreationHelpers.STATE_KEY, musicState); + } + return musicState; + } + + getInstrument(util) { + const stage = this.runtime.getTargetForStage(); + if (stage) { + if (!stage.instrument) { + stage.instrument = "Piano"; + } + return stage.instrument; + } + return 0; + } + + /** + * Internal code to select an instrument for playing notes. If mapMidi is true, set the instrument according to + * the MIDI to Scratch instrument mapping. + * @param {number} instNum - the instrument number. + * @param {object} util - utility object provided by the runtime. + * @param {boolean} mapMidi - whether or not instNum is a MIDI instrument number. + */ + _setInstrument(instNum, util, mapMidi) { + const musicState = this._getMusicState(util.target); + musicState.currentInstrument = this.getInstrumentValue(instNum); + } + + getInstrumentValue(instNum) { + instNum = Cast.toNumber(instNum); + instNum = Math.round(instNum); + const stage = this.runtime.getTargetForStage(); + if (stage) { + stage.instrument = this.findInstrumentForNumber(instNum); + } + instNum -= 1; // instruments are one-indexed + return MathUtil.wrapClamp(instNum, 0, this.INSTRUMENT_INFO.length - 1); + } + + findInstrumentForNumber(number) { + for (var m in this.instrumentNames) { + if (this.instrumentNames[m].value == number) { + return this.instrumentNames[m].text; + } + } + return "Piano"; + } + + findVolumeForNumber(number) { + for (var m in this.volumes) { + if (this.volumes[m].value == number) { + return this.volumes[m].text; + } + } + return "mezzo-forte"; + } + + /** + * Convert volume name to number + * @param {string} volume_name + * @returns {number} the matching numerical volume [0,100] or + * 60 as default if no match is found + */ + findNumberForVolume(volume_name) { + for (var m in this.volumes) { + if (this.volumes[m].text === volume_name) { + return this.volumes[m].value; + } + } + return 60; + } + + /** + * Update the current tempo, clamping it to the min and max allowable range. + * @param {number} tempo - the tempo to set, in beats per minute. + * @private + */ + _updateVolume(volume, util) { + volume = MathUtil.clamp(volume, 0, 100); + util.target.volume = volume; + const stage = this.runtime.getTargetForStage(); + globalVolume = this.findVolumeForNumber(volume); + } + + getVolume(util) { + return globalVolume; + } + + /** + * + * @param {object} noteInfo - contains 'NOTE' and 'SECS' fields + * @param {*} index - the index of this note in + * the sequence of notes to be played + * @returns an object with 'note', 'duration', and 'index' fields + * @private + */ + _clamp(noteInfo, index) { + let note = Cast.toNumber(noteInfo.NOTE); + note = MathUtil.clamp(note, + MusicCreationHelpers.MIDI_NOTE_RANGE.min, MusicCreationHelpers.MIDI_NOTE_RANGE.max); + let beats = Cast.toNumber(noteInfo.SECS); + beats = this._clampBeats(beats); + return { note: note, duration: beats, index: index }; + } + + /** + * Gets the SoundPlayer for this note/instrument combo + * @param {number} inst + * @param {number} note + * @returns {SoundPlayer} object for the player + * + * @see {SoundPlayer} is in the scratch audio node module + */ + _getPlayer(inst, note) { + if (!this._instrumentPlayerNoteArrays[inst][note]) { + this._instrumentPlayerNoteArrays[inst][note] = this._instrumentPlayerArrays[inst][sampleIndex].take(); + } + + const player = this._instrumentPlayerNoteArrays[inst][note]; + + if (player.isPlaying && !player.isStarting) { + // Take the internal player state and create a new player with it. + player.take(); + } + return player; + } + + /** + * Creates a SoundPlayer for the given note and returns it, + * along with an object that contains data about the note + * (including @param dur) + * @param util + * @param {number} note - the frequency of the note to be played + * @param {flot} dur - duration in secs + * @returns an object with 'player' and 'data' fields, or null on error + */ + createPlayer(util, note, dur, inst) { + // Determine which of the audio samples for this instrument to play + const instrumentInfo = this.INSTRUMENT_INFO[inst]; + const sampleArray = instrumentInfo.samples; + const sampleIndex = this._selectSampleIndexForNote(note, sampleArray); + // If the audio sample has not loaded yet, bail out + if (typeof this._instrumentPlayerArrays[inst] === 'undefined' || + typeof this._instrumentPlayerArrays[inst][sampleIndex] === 'undefined') { + console.log('uninitialized instruments'); + return null; + } + + if (!this._instrumentPlayerNoteArrays[inst][note]) { + this._instrumentPlayerNoteArrays[inst][note] = this._instrumentPlayerArrays[inst][sampleIndex].take(); + } + + const player = this._getPlayer(inst, note); + + return { + player: player, + data: + { + instInfo: instrumentInfo, + sampleArray: sampleArray, + sampleIndex: sampleIndex, + note: note, + duration: dur + } + }; + } + + /** + * Plays the note given by @param noteInfo and recursively + * sets up an event chain to play the rest of the notes in @param seq + * @param {object} noteInfo - element of @param seq containing + * 'note', 'index', and 'beats' fields. + * @param {Array[]} seq - array of objects containing information about a note and its duration + * @param {BlockUtility} util + * @param {number} l - length of @param seq + * @param {VizHelpers} vizHelper + * @private + * @augments @param util's stackFrame.duration to be 0 once the last note in @param seq + * has stopped playing. + */ + _playNoteFromSeq(noteInfo, seq, util, l, inst, vol, vizHelper, raw_notes) { + const i = noteInfo['index']; + const last = i === l - 1; + const raw_note = raw_notes[i]; + if (this._concurrencyCounter > this.CONCURRENCY_LIMIT) return; + const playerAndData = this.createPlayer(util, noteInfo['note'], noteInfo['duration'], inst); + if (!playerAndData) { + console.log(`null data for note ${noteInfo}`); + return; + } + const player = playerAndData['player']; + util.sequencer.runtime.once('PROJECT_STOP_ALL', () => { + this._stopped = true; + player.stopImmediately(); + if (util.thread && util.thread.peekStackFrame()) util.stackFrame.duration = 0; + return; + }); + player.once('stop', () => { + if ((last || this._stopped) && util.thread && util.thread.peekStackFrame()) { + util.stackFrame.duration = 0; + } else { + this._playNoteFromSeq(seq[i + 1], seq, util, l, inst, vol, vizHelper, raw_notes); + } + }); + if (!this._stopped) { + vizHelper.requestViz(raw_note, util); + this._activatePlayer(util, playerAndData, vol); + } + } + + /** + * Plays the first note of the given @param seq + * (note that this also sets off an event chain that plays + * the rest of the notes in @param seq) + * @param {BlockUtility} util + * @param {Array[]} seq + * @param {VizHelpers} vizHelper + * @requires - each elem in @param seq has 'note', 'duration' and + * 'index' fields + */ + playFirstNote(util, seq, inst, vol, vizHelper, raw_notes) { + const l = seq.length + if (l === 0) return; + util.sequencer.runtime.setMaxListeners(Infinity); + this._playNoteFromSeq(seq[0], seq, util, l, inst, vol, vizHelper, raw_notes); + } + + /** + * Plays the sequence of notes given by @param args + * @param {object} args - contains raw (magenta) notes and + * cleaned notes with 'mutation', 'NOTE', and 'SECS' fields + * @param args: raw notes --> ['notes'] + * cleaned notes --> ['args'] + * @param {BlockUtility} util + * @param {VizHelpers} vizHelper + */ + playNotes(args, util, inst, vol, vizHelper) { + let clean_notes = args['args']; + let raw_notes = args['notes']; + const l = clean_notes.length; + let seq = []; + for (let i = 0; i < l; i++) { + const noteArg = clean_notes[i]; + seq.push(this._clamp(noteArg, i)); + } + if (l === 0) return; + this._stopped = false; + //begins the chain of events that plays the seq of notes + this.playFirstNote(util, seq, inst, vol, vizHelper, raw_notes); + + //set the duration to MAX. duration is cut off when the last note ends + util.stackFrame.duration = Number.MAX_SAFE_INTEGER; + } + + /** + * plays the given note + * @param {BlockUtility} util + * @param {Array[]} sampleArray - array of samples specific to the instrument + * @param {number} sampleIndex - an index into @param sampleArray + * @param {number} note - number corresponding to freq. of the note + * @param {SoundPlayer} player - sound player specific to this note/inst + * @param {object} instInfo - contains fields specific to the instrument + * @param {number} durationSec - duration, in seconds + * @private + */ + _initNote(util, sampleArray, sampleIndex, note, player, instInfo, durationSec, vol) { + // Set its pitch. + const sampleNote = sampleArray[sampleIndex]; + const notePitchInterval = this._ratioForPitchInterval(note - sampleNote); + + // Fetch the sound player to play the note. + const engine = util.runtime.audioEngine; + + // Create gain nodes for this note's volume and release, and chain them + // to the output. + const context = engine.audioContext; + const volumeGain = context.createGain(); + volumeGain.gain.setValueAtTime(vol / 100, engine.currentTime); + const releaseGain = context.createGain(); + volumeGain.connect(releaseGain); + releaseGain.connect(engine.getInputNode()); + + // Schedule the release of the note, ramping its gain down to zero, + // and then stopping the sound. + const releaseRatio = instInfo.releaseTime ? instInfo.releaseTime : 0.1; + const releaseDuration = durationSec * releaseRatio; + const releaseStart = context.currentTime + durationSec * (1 - releaseRatio); + const releaseEnd = releaseStart + releaseDuration; + releaseGain.gain.setValueAtTime(1, releaseStart); + releaseGain.gain.linearRampToValueAtTime(0.0001, releaseEnd); + + this._concurrencyCounter++; + player.once('stop', () => { + this._concurrencyCounter--; + }); + util.runtime.once('PROJECT_STOP_ALL', () => { + player.stopImmediately(); + if (util.thread && util.thread.peekStackFrame()) util.stackFrame.duration = 0; + }); + + // Start playing the note + player.play(); + // Connect the player to the gain node. + player.connect({ + getInputNode() { + return volumeGain; + } + }); + // Set playback now after play creates the outputNode. + player.outputNode.playbackRate.value = notePitchInterval; + // Schedule playback to stop. + player.outputNode.stop(releaseEnd); + } + + /** + * Activates the player in @param playerAndData to play its + * note, using the data in @param playerAndData to determine + * the instrument and duration + * @param {BlockUtility} util + * @param {object} playerAndData - contains 'player' and 'data' fields + * @private + */ + _activatePlayer(util, playerAndData, vol) { + // If we're playing too many sounds, do not play the note. + if (this._concurrencyCounter > MusicCreationHelpers.CONCURRENCY_LIMIT) { + console.log('concurrency limit reached'); + return; + } + + if (!playerAndData) { + console.log('null data'); + return; + } + + //get note and instrument data + let player = playerAndData['player']; + let data = playerAndData['data']; + let sampleArray = data['sampleArray']; + let sampleIndex = data['sampleIndex']; + let instInfo = data['instInfo']; + let note = data['note']; + let durationSec = data['duration']; + + this._initNote(util, sampleArray, sampleIndex, note, player, instInfo, durationSec, vol); + } + + internalPlayNote(args, util, instrument, vol, start_timer) { + let note = Cast.toNumber(args.NOTE); + note = MathUtil.clamp(note, + MusicCreationHelpers.MIDI_NOTE_RANGE.min, MusicCreationHelpers.MIDI_NOTE_RANGE.max); + let beats = Cast.toNumber(args.SECS); + beats = this._clampBeats(beats); + // If the duration is 0, do not play the note. In Scratch 2.0, "play drum for 0 beats" plays the drum, + // but "play note for 0 beats" is silent. + if (beats === 0) return; + + const durationSec = beats; + if (start_timer) this._startStackTimer(util, durationSec); + this._playNote(util, note, durationSec, instrument, vol); + + // this._startStackTimer(util, durationSec); + const musicState = this._getMusicState(util.target); + const inst = musicState.currentInstrument; + const instrumentInfo = this.INSTRUMENT_INFO[inst] + return [note, beats, instrumentInfo.name]; + } + + playNote(args, util, instrument, vol) { + if (this.stackTimerNeedsInit(util)) { + return this.internalPlayNote(args, util, instrument, vol, true); + } else { + this._checkStackTimer(util); + return []; + } + } + + /** + * Play a note using the current instrument for a duration in seconds. + * This function actually plays the sound, and handles the timing of the sound, including the + * "release" portion of the sound, which continues briefly after the block execution has finished. + * @param {object} util - utility object provided by the runtime. + * @param {number} note - the pitch of the note to play, interpreted as a MIDI note number. + * @param {number} durationSec - the duration in seconds to play the note. + * @private + */ + _playNote(util, note, durationSec, instrument, vol) { + if (util.runtime.audioEngine === null) return; + if (util.target.sprite.soundBank === null) return; + + // If we're playing too many sounds, do not play the note. + if (this._concurrencyCounter > MusicCreationHelpers.CONCURRENCY_LIMIT) { + return; + } + + // Determine which of the audio samples for this instrument to play + const musicState = this._getMusicState(util.target); + const inst = (instrument !== undefined && instrument !== null) ? instrument : musicState.currentInstrument; + const instrumentInfo = this.INSTRUMENT_INFO[inst]; + const sampleArray = instrumentInfo.samples; + const sampleIndex = this._selectSampleIndexForNote(note, sampleArray); + // If the audio sample has not loaded yet, bail out + if (typeof this._instrumentPlayerArrays[inst] === 'undefined') return; + if (typeof this._instrumentPlayerArrays[inst][sampleIndex] === 'undefined') return; + + if (!this._instrumentPlayerNoteArrays[inst][note]) { + this._instrumentPlayerNoteArrays[inst][note] = this._instrumentPlayerArrays[inst][sampleIndex].take(); + } + + const player = this._getPlayer(inst, note); + + this._initNote(util, sampleArray, sampleIndex, note, player, instrumentInfo, + durationSec, vol); + } + + /** + * The samples array for each instrument is the set of pitches of the available audio samples. + * This function selects the best one to use to play a given input note, and returns its index + * in the samples array. + * @param {number} note - the input note to select a sample for. + * @param {number[]} samples - an array of the pitches of the available samples. + * @return {index} the index of the selected sample in the samples array. + * @private + */ + _selectSampleIndexForNote(note, samples) { + // Step backwards through the array of samples, i.e. in descending pitch, in order to find + // the sample that is the closest one below (or matching) the pitch of the input note. + for (let i = samples.length - 1; i >= 0; i--) { + if (note >= samples[i]) { + return i; + } + } + return 0; + } + + /** + * Calcuate the frequency ratio for a given musical interval. + * @param {number} interval - the pitch interval to convert. + * @return {number} a ratio corresponding to the input interval. + * @private + */ + _ratioForPitchInterval(interval) { + return Math.pow(2, (interval / 12)); + } + + /** + * Start the stack timer and the yield the thread if necessary. + * @param {object} util - utility object provided by the runtime. + * @param {number} duration - a duration in seconds to set the timer for. + * @private + */ + _startStackTimer(util, duration) { + util.stackFrame.timer = new Timer(); + util.stackFrame.timer.start(); + util.stackFrame.duration = duration; + util.yield(); + } + + /** + * Check if the stack timer needs initialization. + * @param {object} util - utility object provided by the runtime. + * @return {boolean} - true if the stack timer needs to be initialized. + */ + stackTimerNeedsInit(util) { + return !util.stackFrame.timer; + } + + /** + * Check the stack timer, and if its time is not up yet, yield the thread. + * @param {object} util - utility object provided by the runtime. + * @private + */ + _checkStackTimer(util) { + const timeElapsed = util.stackFrame.timer.timeElapsed(); + if (timeElapsed < util.stackFrame.duration * 1000) { + util.yield(); + } + } + + /** + * Clamp a duration in beats to the allowed min and max duration. + * @param {number} beats - a duration in beats. + * @return {number} - the clamped duration. + * @private + */ + _clampBeats(beats) { + return MathUtil.clamp(beats, MusicCreationHelpers.BEAT_RANGE.min, MusicCreationHelpers.BEAT_RANGE.max); + } + + +} + +module.exports = MusicCreationHelpers; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/musicplayer.js b/src/extensions/scratch3_musiccreation/musicplayer.js new file mode 100644 index 00000000000..c2a2d3635a7 --- /dev/null +++ b/src/extensions/scratch3_musiccreation/musicplayer.js @@ -0,0 +1,552 @@ +const Clone = require('../../util/clone'); +const Cast = require('../../util/cast'); +const formatMessage = require('format-message'); +const MathUtil = require('../../util/math-util'); +const Timer = require('../../util/timer'); +const log = require('../../util/log'); +const regeneratorRuntime = require("regenerator-runtime"); + +var note, beats, durationSec, inst; + + +/** + * The instrument and drum sounds, loaded as static assets. + * @type {object} + */ +let assetData = {}; + + +try { + assetData = require('./manifest'); + console.log("ASSET DATA", assetData); +} catch (e) { + throw new Error("WE CANNOT FIND THE ASSETS"); + // Non-webpack environment, don't worry about assets. +} + +class MusicPlayer { + constructor(runtime) { + this.runtime = runtime; + + /** + * An array of arrays of sound players. Each instrument has one or more audio players. + * @type {Array[]} + * @private + */ + this._instrumentPlayerArrays = []; + + /** + * An array of arrays of sound players. Each instrument mya have an audio player for each playable note. + * @type {Array[]} + * @private + */ + this._instrumentPlayerNoteArrays = []; + this._loadAllSounds(); + + this.noteList = []; + + this.instrumentNames = this._buildMenu(this.INSTRUMENT_INFO); + + this._onTargetCreated = this._onTargetCreated.bind(this); + this.runtime.on('targetWasCreated', this._onTargetCreated); + + this.volumes = [{ text: "pianissimo", value: 15 }, + { text: "piano", value: 30 }, + { text: "mezzo-piano", value: 45 }, + { text: "mezzo-forte", value: 60 }, + { text: "forte", value: 85 }, + { text: "fortissimo", value: 100 }]; + + this.instruments = { + "piano": 0, + "guitar": 1, + "bass": 2, + "cello": 3, + "saxophone": 4, + "clarinet": 5, + "synth": 6 + } + } + + /** + * The key to load & store a target's music-related state. + * @type {string} + */ + static get STATE_KEY() { + return 'Scratch.musiccreation'; + } + + /** + * The default music-related state, to be used when a target has no existing music state. + * @type {MusicState} + */ + static get DEFAULT_MUSIC_STATE() { + return { + currentInstrument: 0 + }; + } + + /** + * The minimum and maximum MIDI note numbers, for clamping the input to play note. + * @type {{min: number, max: number}} + */ + static get MIDI_NOTE_RANGE() { + return { min: 0, max: 130 }; + } + + /** + * The minimum and maximum beat values, for clamping the duration of play note, play drum and rest. + * 100 beats at the default tempo of 60bpm is 100 seconds. + * @type {{min: number, max: number}} + */ + static get BEAT_RANGE() { + return { min: 0, max: 100 }; + } + + /** + * The maximum number of sounds to allow to play simultaneously. + * @type {number} + */ + static get CONCURRENCY_LIMIT() { + return 30; + } + + /** + * An array of info about each instrument. + * @type {object[]} + * @param {string} name - the translatable name to display in the instruments menu. + * @param {string} dirName - the name of the directory containing audio samples for this instrument. + * @param {number} [releaseTime] - an optional duration for the release portion of each note. + * @param {number[]} samples - an array of numbers representing the MIDI note number for each + * sampled sound used to play this instrument. + */ + get INSTRUMENT_INFO() { + return [ + { + name: formatMessage({ + id: 'musiccreation.instrumentPiano', + default: 'Piano', + description: 'Sound of a piano' + }), + dirName: '1-piano', + releaseTime: 0.5, + samples: [24, 36, 48, 60, 72, 84, 96, 108] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentGuitar', + default: 'Guitar', + description: 'Sound of an accoustic guitar' + }), + dirName: '4-guitar', + releaseTime: 0.5, + samples: [60] + }, { + name: formatMessage({ + id: 'musiccreation.instrumentBass', + default: 'Bass', + description: 'Sound of an accoustic upright bass' + }), + dirName: '6-bass', + releaseTime: 0.25, + samples: [36, 48] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentCello', + default: 'Cello', + description: 'Sound of a cello being played with a bow' + }), + dirName: '8-cello', + releaseTime: 0.1, + samples: [36, 48, 60] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentSaxophone', + default: 'Saxophone', + description: 'Sound of a saxophone being played' + }), + dirName: '11-saxophone', + samples: [36, 60, 84] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentClarinet', + default: 'Clarinet', + description: 'Sound of a clarinet being played' + }), + dirName: '10-clarinet', + samples: [48, 60] + }, + { + name: formatMessage({ + id: 'musiccreation.instrumentSynthLead', + default: 'Synth', + description: 'Sound of a "lead" synthesizer being played' + }), + dirName: '20-synth-lead', + releaseTime: 0.1, + samples: [24, 36, 48, 60, 72, 84, 96, 108, 120] + } + ]; + } + + /** + * When a music-playing Target is cloned, clone the music state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated(newTarget, sourceTarget) { + if (sourceTarget) { + const musicState = sourceTarget.getCustomState(MusicPlayer.STATE_KEY); + if (musicState) { + newTarget.setCustomState(MusicPlayer.STATE_KEY, Clone.simple(musicState)); + } + } + } + + /** + * Decode the full set of drum and instrument sounds, and store the audio buffers in arrays. + */ + _loadAllSounds() { + const loadingPromises = []; + this.INSTRUMENT_INFO.forEach((instrumentInfo, instrumentIndex) => { + this._instrumentPlayerArrays[instrumentIndex] = []; + this._instrumentPlayerNoteArrays[instrumentIndex] = []; + instrumentInfo.samples.forEach((sample, noteIndex) => { + const filePath = `instruments/${instrumentInfo.dirName}/${sample}`; + const promise = this._storeSound(filePath, noteIndex, this._instrumentPlayerArrays[instrumentIndex]); + loadingPromises.push(promise); + }); + }); + Promise.all(loadingPromises).then(() => { + // @TODO: Update the extension status indicator. + }); + } + + /** + * Decode a sound and store the player in an array. + * @param {string} filePath - the audio file name. + * @param {number} index - the index at which to store the audio player. + * @param {array} playerArray - the array of players in which to store it. + * @return {Promise} - a promise which will resolve once the sound has been stored. + */ + _storeSound(filePath, index, playerArray) { + const fullPath = `${filePath}.mp3`; + + if (!assetData[fullPath]) return; + + // The sound player has already been downloaded via the manifest file required above. + const soundBuffer = assetData[fullPath]; + + return this._decodeSound(soundBuffer).then(player => { + playerArray[index] = player; + }); + } + + /** + * Decode a sound and return a promise with the audio buffer. + * @param {ArrayBuffer} soundBuffer - a buffer containing the encoded audio. + * @return {Promise} - a promise which will resolve once the sound has decoded. + */ + _decodeSound(soundBuffer) { + return this.runtime.awaitAudioEngine().then(e => e.decodeSoundPlayer({ data: { buffer: soundBuffer } })); + } + + /** + * Create data for a menu in scratch-blocks format, consisting of an array of objects with text and + * value properties. The text is a translated string, and the value is one-indexed. + * @param {object[]} info - An array of info objects each having a name property. + * @return {array} - An array of objects with text and value properties. + * @private + */ + _buildMenu(info) { + return info.map((entry, index) => { + const obj = {}; + obj.text = entry.name; + obj.value = String(index + 1); + return obj; + }); + } + + /** + * @param {Target} target - collect music state for this target. + * @returns {MusicState} the mutable music state associated with that target. This will be created if necessary. + * @private + */ + _getMusicState(target) { + let musicState = target.getCustomState(MusicPlayer.STATE_KEY); + if (!musicState) { + musicState = Clone.simple(MusicPlayer.DEFAULT_MUSIC_STATE); + target.setCustomState(MusicPlayer.STATE_KEY, musicState); + } + return musicState; + } + + getInstrument(util) { + const stage = this.runtime.getTargetForStage(); + if (stage) { + if (!stage.instrument) { + stage.instrument = "Piano"; + } + return stage.instrument; + } + return 0; + } + + /** + * Internal code to select an instrument for playing notes. If mapMidi is true, set the instrument according to + * the MIDI to Scratch instrument mapping. + * @param {number} instNum - the instrument number. + * @param {object} util - utility object provided by the runtime. + * @param {boolean} mapMidi - whether or not instNum is a MIDI instrument number. + */ + _setInstrument(instNum, util, mapMidi) { + const musicState = this._getMusicState(util.target); + instNum = Cast.toNumber(instNum); + instNum = Math.round(instNum); + const stage = this.runtime.getTargetForStage(); + if (stage) { + stage.instrument = this.findInstrumentForNumber(instNum); + } + instNum -= 1; // instruments are one-indexed + instNum = MathUtil.wrapClamp(instNum, 0, this.INSTRUMENT_INFO.length - 1); + musicState.currentInstrument = instNum; + } + + findInstrumentForNumber(number) { + for (var m in this.instrumentNames) { + if (this.instrumentNames[m].value == number) { + return this.instrumentNames[m].text; + } + } + return "Piano"; + } + + findVolumeForNumber(number) { + for (var m in this.volumes) { + if (this.volumes[m].value == number) { + return this.volumes[m].text; + } + } + return "mezzo-forte"; + } + + /** + * Update the current tempo, clamping it to the min and max allowable range. + * @param {number} tempo - the tempo to set, in beats per minute. + * @private + */ + _updateVolume(volume, util) { + volume = MathUtil.clamp(volume, 0, 100); + util.target.volume = volume; + log.log(util.target.volume); + } + + getVolume() { + const stage = this.runtime.getTargetForStage(); + if (stage) { + if (stage.volume == 100) { + return "fortissimo"; + } + return this.findVolumeForNumber(util.target.volume); + } + return "mezzo-forte"; + } + + playNote(args, util) { + if (this._stackTimerNeedsInit(util)) { + let note = Cast.toNumber(args.NOTE); + note = MathUtil.clamp(note, + MusicPlayer.MIDI_NOTE_RANGE.min, MusicPlayer.MIDI_NOTE_RANGE.max); + let beats = Cast.toNumber(args.SECS); + beats = this._clampBeats(beats); + // If the duration is 0, do not play the note. In Scratch 2.0, "play drum for 0 beats" plays the drum, + // but "play note for 0 beats" is silent. + if (beats === 0) return; + + const durationSec = beats; + + this._playNote(util, note, durationSec); + + this._startStackTimer(util, durationSec); + var inst = (instrument == 0) ? musicState.currentInstrument : this.instruments[instrument.toLowerCase()] + log.log("NEW INST"); + return [note, beats, inst]; + } else { + this._checkStackTimer(util); + return []; + } + + } + + /** + * Play a note using the current instrument for a duration in seconds. + * This function actually plays the sound, and handles the timing of the sound, including the + * "release" portion of the sound, which continues briefly after the block execution has finished. + * @param {object} util - utility object provided by the runtime. + * @param {number} note - the pitch of the note to play, interpreted as a MIDI note number. + * @param {number} durationSec - the duration in seconds to play the note. + * @private + */ + _playNote(util, note, durationSec, instrument = 0) { + if (util.runtime.audioEngine === null) return; + if (util.target.sprite.soundBank === null) return; + + // If we're playing too many sounds, do not play the note. + if (this._concurrencyCounter > MusicPlayer.CONCURRENCY_LIMIT) { + return; + } + + // Determine which of the audio samples for this instrument to play + const musicState = this._getMusicState(util.target); + const inst = (instrument == 0) ? musicState.currentInstrument : this.instruments[instrument.toLowerCase()]; + const instrumentInfo = this.INSTRUMENT_INFO[inst]; + const sampleArray = instrumentInfo.samples; + const sampleIndex = this._selectSampleIndexForNote(note, sampleArray); + + // If the audio sample has not loaded yet, bail out + if (typeof this._instrumentPlayerArrays[inst] === 'undefined') return; + if (typeof this._instrumentPlayerArrays[inst][sampleIndex] === 'undefined') return; + + // Fetch the sound player to play the note. + const engine = util.runtime.audioEngine; + + if (!this._instrumentPlayerNoteArrays[inst][note]) { + this._instrumentPlayerNoteArrays[inst][note] = this._instrumentPlayerArrays[inst][sampleIndex].take(); + } + + const player = this._instrumentPlayerNoteArrays[inst][note]; + + if (player.isPlaying && !player.isStarting) { + // Take the internal player state and create a new player with it. + // `.play` does this internally but then instructs the sound to + // stop. + player.take(); + } + + // Set its pitch. + const sampleNote = sampleArray[sampleIndex]; + const notePitchInterval = this._ratioForPitchInterval(note - sampleNote); + + // Create gain nodes for this note's volume and release, and chain them + // to the output. + const context = engine.audioContext; + const volumeGain = context.createGain(); + volumeGain.gain.setValueAtTime(util.target.volume / 100, engine.currentTime); + const releaseGain = context.createGain(); + volumeGain.connect(releaseGain); + releaseGain.connect(engine.getInputNode()); + + // Schedule the release of the note, ramping its gain down to zero, + // and then stopping the sound. + let releaseDuration = this.INSTRUMENT_INFO[inst].releaseTime; + if (typeof releaseDuration === 'undefined') { + releaseDuration = 0.01; + } + const releaseStart = context.currentTime + durationSec; + const releaseEnd = releaseStart + releaseDuration; + releaseGain.gain.setValueAtTime(1, releaseStart); + releaseGain.gain.linearRampToValueAtTime(0.0001, releaseEnd); + + this._concurrencyCounter++; + player.once('stop', () => { + this._concurrencyCounter--; + }); + + // Start playing the note + player.play(); + // Connect the player to the gain node. + player.connect({ + getInputNode() { + return volumeGain; + } + }); + // Set playback now after play creates the outputNode. + player.outputNode.playbackRate.value = notePitchInterval; + // Schedule playback to stop. + player.outputNode.stop(releaseEnd); + } + + /** + * The samples array for each instrument is the set of pitches of the available audio samples. + * This function selects the best one to use to play a given input note, and returns its index + * in the samples array. + * @param {number} note - the input note to select a sample for. + * @param {number[]} samples - an array of the pitches of the available samples. + * @return {index} the index of the selected sample in the samples array. + * @private + */ + _selectSampleIndexForNote(note, samples) { + // Step backwards through the array of samples, i.e. in descending pitch, in order to find + // the sample that is the closest one below (or matching) the pitch of the input note. + for (let i = samples.length - 1; i >= 0; i--) { + if (note >= samples[i]) { + return i; + } + } + return 0; + } + + /** + * Calcuate the frequency ratio for a given musical interval. + * @param {number} interval - the pitch interval to convert. + * @return {number} a ratio corresponding to the input interval. + * @private + */ + _ratioForPitchInterval(interval) { + return Math.pow(2, (interval / 12)); + } + + /** + * Start the stack timer and the yield the thread if necessary. + * @param {object} util - utility object provided by the runtime. + * @param {number} duration - a duration in seconds to set the timer for. + * @private + */ + _startStackTimer(util, duration) { + util.stackFrame.timer = new Timer(); + util.stackFrame.timer.start(); + util.stackFrame.duration = duration; + util.yield(); + } + + /** + * Check if the stack timer needs initialization. + * @param {object} util - utility object provided by the runtime. + * @return {boolean} - true if the stack timer needs to be initialized. + * @private + */ + _stackTimerNeedsInit(util) { + return !util.stackFrame.timer; + } + + /** + * Check the stack timer, and if its time is not up yet, yield the thread. + * @param {object} util - utility object provided by the runtime. + * @private + */ + _checkStackTimer(util) { + const timeElapsed = util.stackFrame.timer.timeElapsed(); + if (timeElapsed < util.stackFrame.duration * 1000) { + util.yield(); + } + } + + /** + * Clamp a duration in beats to the allowed min and max duration. + * @param {number} beats - a duration in beats. + * @return {number} - the clamped duration. + * @private + */ + _clampBeats(beats) { + return MathUtil.clamp(beats, MusicPlayer.BEAT_RANGE.min, MusicPlayer.BEAT_RANGE.max); + } + + +} + +module.exports = MusicPlayer; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/sheetmusic.js b/src/extensions/scratch3_musiccreation/sheetmusic.js new file mode 100644 index 00000000000..7346043e1ed --- /dev/null +++ b/src/extensions/scratch3_musiccreation/sheetmusic.js @@ -0,0 +1,1068 @@ +const Clone = require('../../util/clone'); +const log = require('../../util/log'); +const Cast = require('../../util/cast'); +const Color = require('../../util/color'); +const RenderedTarget = require('../../sprites/rendered-target'); +const StageLayering = require('../../engine/stage-layering'); + +const letters = require('./letters'); +const symbols = require('./symbols'); +const { updateVariableIdentifiers } = require('../../util/variable-util'); + +var pitchToStaff, pitchToStaffBass, sharps, flats, harmonics, drawX, xmid, ymid, up, sym, s, flip, initial, coord, x, y, startX, endX, startY, endY, yStep, xStep, freq, note, duration, symbolX, symbolY, volume, newX, newY, beats, signal, step, theta, rad, dotrad, xrad, yrad, sign, xOffset, scale, restX, restY, offset, newBeats, acc, staff, clef, adjusted, xmidTreble, ymidTreble, ymidBass; + +class SheetMusic { + constructor(runtime) { + this.runtime = runtime; + + /** + * The ID of the renderer Skin corresponding to the pen layer. + * @type {int} + * @private + */ + this._penSkinId = -1; + + /** + * The ID of the renderer Drawable corresponding to the pen layer. + * @type {int} + * @private + */ + this._penDrawableId = -1; + this.black = '0x000000'; + this.purple = '0x800080'; + this.lightpurple = '0xCBC3E3'; + this.lightblue = '0x99ccff'; + + /** + * @type {Array<[number,number,string,number,number]} + * + * noteList[i] is [note frequency, duration, instrument name, volume, id] + */ + this.noteList = []; + + this.axisStartX = -200; + this.axisStartY = -150; + this.xAxisLength = 400; + this.yAxisLength = 300; + + this.staffLength = 411; + this.staffStartX = -200; + this.staffStartY = 115; + this.staffWidth = 10; + + this.spaceBetween = 80; + this.spaceBetweenStaffs = 80; + + this.wavePen = -1; + this.musicPen = 2; + this.FFTPen = 3; + this.spectPen = 4; + + this._onTargetCreated = this._onTargetCreated.bind(this); + this.runtime.on('targetWasCreated', this._onTargetCreated); + + this._onTargetMoved = this._onTargetMoved.bind(this); + + + this._staffLims = { lo_note: 60, hi_note: 85, lo_staff: -2, hi_staff: 12 }; + this._staffBaseLims = { lo_note: 34, hi_note: 34, lo_staff: -5, hi_staff: 9 }; + pitchToStaff = { + 60: -2, + 61: -2, + 62: -1, + 63: 0, + 64: 0, + 65: 1, + 66: 1, + 67: 2, + 68: 2, + 69: 3, + 70: 4, + 71: 4, + 72: 5, + 73: 5, + 74: 6, + 75: 7, + 76: 7, + 77: 8, + 78: 8, + 79: 9, + 80: 9, + 81: 10, + 82: 11, + 83: 11, + 84: 12, + 85: 12 + + } + + this.rests = { + 4: symbols.restfour, + 2: symbols.resttwo, + 1: symbols.restone, + 0.5: symbols.resthalf, + 0.25: symbols.restquarter, + 0.125: symbols.resteighth + } + + this.restOffset = { + 4: 29, + 2: 22, + 1: 35, + 0.5: 26, + 0.25: 26, + 0.125: 33 + } + + this.restScale = { + 4: 8, + 2: 8, + 1: 4, + 0.5: 4, + 0.25: 4, + 0.125: 4 + } + + sharps = [37, 42, 44, 49, 54, 56, 61, 66, 68, 73, 78, 80, 85]; + flats = [39, 46, 51, 58, 63, 70, 75, 82]; + + + pitchToStaffBass = { + 34: -5, + 35: -5, + 36: -4, + 37: -4, + 38: -3, + 39: -2, //F + 40: -2, //G + 41: -1, //A + 42: -1, //DONE + 43: 0, + 44: 0, + 45: 1, + 46: 2, + 47: 2, + 48: 3,//DONE + 49: 3, + 50: 4, + 51: 5, + 52: 5, + 53: 6, + 54: 6, + 55: 7, + 56: 7, + 57: 8, + 58: 9, + 59: 9, + } + + harmonics = { + "Piano": [[1, 1], [2, 0.5]], + "Guitar": [[1, 1], [2, 0.25]], + "Bass": [[1, 1], [3, 0.5]], + "Cello": [[1, 1], [4, 0.5]], + "Saxophone": [[1, 1], [5, 0.5]], + "Clarinet": [[1, 1], [6, 0.5]], + "Synth": [[1, 1]] + } + + this.symbols = { + 15: [symbols.piano, symbols.piano], + 30: [symbols.piano], + 45: [symbols.mezzo, symbols.piano], + 60: [symbols.mezzo, symbols.forte], + 85: [symbols.forte], + 100: [symbols.forte, symbols.forte] + } + + this.spacing = { + 15: [10, 0], + 30: [10, 0], + 45: [5, 0], + 60: [10, 0], + 85: [10, 0], + 100: [10, 0] + } + + this.letters = { + 'a': letters.a, + 'b': letters.b, + 'c': letters.c, + 'd': letters.d, + 'e': letters.e, + 'f': letters.f, + 'g': letters.g, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'k': letters.k, + 'l': letters.l, + 'm': letters.m, + 'n': letters.n, + 'o': letters.o, + 'p': letters.p, + 'q': letters.q, + 'r': letters.r, + 's': letters.s, + 't': letters.t, + 'u': letters.u, + 'v': letters.v, + 'w': letters.w, + 'x': letters.x, + 'y': letters.y, + 'z': letters.z, + '1': letters.one, + '2': letters.two, + '3': letters.three, + '4': letters.four, + '5': letters.five, + '6': letters.six, + '7': letters.seven, + '8': letters.eight, + '9': letters.nine, + '0': letters.zero, + 'F': letters.flat, + 'S': letters.sharp + + } + + this.spacingLetters = { + 'a': 59.03383897316219, + 'b': 35.666277712952166, + 'c': 55.59820426487096, + 'd': 51.65460910151694, + 'e': 33.821470245040814, + 'f': 35.05134189031503, + 'g': 62.10851808634772, + 'h': 51.65460910151691, + 'i': 0.0, + 'j': 27.057176196032685, + 'k': 44.275379229871646, + 'l': 33.20653442240376, + 'm': 76.86697782963824, + 'n': 57.803967327887975, + 'o': 62.108518086347715, + 'p': 35.05134189031503, + 'q': 62.72345390898482, + 'r': 34.305274971941685, + 's': 39.62850729517402, + 't': 51.03967327887982, + 'u': 50.42473745624271, + 'v': 52.88448074679113, + 'w': 88.55075845974329, + 'x': 45.50525087514586, + 'y': 47.350058343057185, + 'z': 55.959159859976694, + '1': 29.467911318553092, + '2': 61.498249708284675, + '3': 60.21703617269554, + '4': 74.31038506417735, + '5': 58.935822637106185, + '6': 55.09218203033845, + '7': 65.34189031505252, + '8': 55.092182030338336, + '9': 57.654609101516826, + '0': 55.09218203033856, + 'F': 67.9352750809062, //flat + 'S': 122.6148867313916 //sharp + } + } + + /** + * The key to load & store a target's music-related state. + * @type {string} + */ + static get VIZ_STATE_KEY() { + return 'Scratch.musicviz'; + } + + static get DEFAULT_PEN_STATE() { + return { + penDown: false, + color: 66.66, + saturation: 100, + brightness: 100, + transparency: 0, + _shade: 50, // Used only for legacy `change shade by` blocks + penAttributes: { + color4f: [0, 0, 1, 1], + diameter: 1 + } + }; + } + + /** + * The minimum and maximum allowed pen size. + * The maximum is twice the diagonal of the stage, so that even an + * off-stage sprite can fill it. + * @type {{min: number, max: number}} + */ + static get PEN_SIZE_RANGE() { + return { min: 1, max: 1200 }; + } + + /** + * When a music-playing Target is cloned, clone the music state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated(newTarget, sourceTarget) { + if (sourceTarget) { + const penState = sourceTarget.getCustomState(SheetMusic.VIZ_STATE_KEY); + if (penState) { + newTarget.setCustomState(SheetMusic.VIZ_STATE_KEY, Clone.simple(penState)); + if (penState.penDown) { + newTarget.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + } + } + + _onTargetMoved(target, oldX, oldY, isForce) { + // Only move the pen if the movement isn't forced (ie. dragged). + if (!isForce) { + let penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + const penState = this._getPenState(target); + this.runtime.renderer.penLine(penSkinId, penState.penAttributes, oldX, oldY, target.x, target.y); + this.runtime.requestRedraw(); + } + } + } + + _getPenLayerID() { + if (this._penSkinId < 0 && this.runtime.renderer) { + this._penSkinId = this.runtime.renderer.createPenSkin(); + this._penDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); + this.runtime.renderer.updateDrawableProperties(this._penDrawableId, { skinId: this._penSkinId }); + } + return this._penSkinId; + } + + _getPenState(target) { + let penState = target.getCustomState(SheetMusic.VIZ_STATE_KEY); + if (!penState) { + penState = Clone.simple(SheetMusic.DEFAULT_PEN_STATE); + target.setCustomState(SheetMusic.VIZ_STATE_KEY, penState); + } + return penState; + } + + testSheetMusicViz(noteList, args, util, vizhelper) { + this.setPenColorToColor(this.black, util); + this.noteList = noteList; + log.log("SHEET MUSIC", this.noteList); + this.clear(); + this.drawStaff(args, util); + this.labelStaff(args, util); + this.drawMusic(args, util, vizhelper); + this.setPenColorToColor(this.black, util); + } + + labelStaff(args, util) { + startX = this.staffStartX; + endX = this.staffStartX + this.staffLength; + var y = this.staffStartY; + yStep = this.staffWidth; + //treble + this.drawString('e', this.staffStartX + this.staffLength + 2, this.staffStartY + 3, 0.5, args, util); + this.drawString('g', this.staffStartX + this.staffLength + 2, this.staffStartY + yStep + 3, 0.5, args, util); + this.drawString('b', this.staffStartX + this.staffLength + 2, this.staffStartY + yStep * 2 + 3, 0.5, args, util); + this.drawString('d', this.staffStartX + this.staffLength + 2, this.staffStartY + yStep * 3 + 3, 0.5, args, util); + this.drawString('f', this.staffStartX + this.staffLength + 2, this.staffStartY + yStep * 4 + 3, 0.5, args, util); + + //bass + this.drawString('g', this.staffStartX + this.staffLength + 2, this.staffStartY - this.spaceBetween + 3, 0.5, args, util); + this.drawString('b', this.staffStartX + this.staffLength + 2, this.staffStartY - this.spaceBetween + yStep + 3, 0.5, args, util); + this.drawString('d', this.staffStartX + this.staffLength + 2, this.staffStartY - this.spaceBetween + yStep * 2 + 3, 0.5, args, util); + this.drawString('f', this.staffStartX + this.staffLength + 2, this.staffStartY - this.spaceBetween + yStep * 3 + 3, 0.5, args, util); + this.drawString('a', this.staffStartX + this.staffLength + 2, this.staffStartY - this.spaceBetween + yStep * 4 + 3, 0.5, args, util); + + //this.drawString('sheet music', this.axisStartX + this.xAxisLength/2 -70, this.axisStartY+this.yAxisLength + 20, 1, args, util); + } + + + drawString(str, xstart, ystart, size, args, util) { + for (var i in str) { + xstart += 5 * size; + if (i >= 1) { + xstart += this.spacingLetters[str[i - 1]] / 5 * size; + } + this.drawLetter(str[i], xstart, ystart, size, args, util); + } + + } + + drawLetter(letter, xstart, ystart, size, args, util) { + letter = this.letters[letter]; + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0] / 5 * size + xstart; + y = -coord[1] / 5 * size + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0] / 5 * size + xstart + 1; + y = -coord[1] / 5 * size + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + } + + drawStaff(args, util) { + const startX = this.staffStartX; + const endX = this.staffStartX + this.staffLength; + var y = this.staffStartY; + const yStep = this.staffWidth; + for (var j = 0; j < 2; j++) { + for (var i = 0; i < 5; i++) { + this.penUp(args, util); + util.target.setXY(startX, y); + this.penDown(args, util); + util.target.setXY(endX, y); + y = y + yStep; + } + y = y - this.spaceBetween - yStep * 5; + for (var i = 0; i < 5; i++) { + this.penUp(args, util); + util.target.setXY(startX, y); + this.penDown(args, util); + util.target.setXY(endX, y); + y = y + yStep; + } + y = y - this.spaceBetween - this.spaceBetweenStaffs; + this.drawTreble(this.staffStartX + 10, this.staffStartY - 12 - j * (this.spaceBetween + yStep * 5 - 12 + this.spaceBetweenStaffs - 8), args, util); + this.drawBass(this.staffStartX, this.staffStartY - 12 - yStep * 7 - j * (this.spaceBetween + yStep * 5 - 12 + this.spaceBetweenStaffs - 8), args, util); + } + this.penUp(args, util); + this.drawTimeSignature(args, util); + + } + + drawTimeSignature(args, util) { + var startX = this.staffStartX; + var y = this.staffStartY; + this.drawString("4", startX + 25, y + 18, 1.2, args, util); + this.drawString("4", startX + 25, y + 38, 1.2, args, util); + + this.drawString("4", startX + 25, y + 18 - this.spaceBetween, 1.2, args, util); + this.drawString("4", startX + 25, y + 38 - this.spaceBetween, 1.2, args, util); + } + + drawSymbol(symbol, args, util, xStart, yStart) { + symbolX = 0; + symbolY = 0; + this.penUp(args, util); + for (var i in symbol) { + coord = symbol[i]; + symbolX = coord[0] / 2 + xStart; + symbolY = -coord[1] / 2 + yStart; + util.target.setXY(symbolX, symbolY); + this.penDown(args, util); + } + this.penUp(args, util); + } + + drawTreble(xstart, ystart, args, util) { + //xstart = this.staffStartX+10; + //ystart = this.staffStartY-12; + const treble = symbols.treble; + this.penUp(args, util); + for (var i in treble) { + const coord = treble[i]; + var x = coord[0] / 5 + xstart; + var y = -coord[1] / 5 + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + for (var i in treble) { + const coord = treble[i]; + x = coord[0] / 5 + xstart + 1; + y = -coord[1] / 5 + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + } + + drawBass(xstart, ystart, args, util) { + //xstart = this.staffStartX+10; + //ystart = this.staffStartY-12; + const bass = symbols.bass; + this.penUp(args, util); + for (var i in bass) { + const coord = bass[i]; + var x = coord[0] / 7 + xstart; + var y = -coord[1] / 7 + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + for (var i in bass) { + const coord = bass[i]; + x = coord[0] / 7 + xstart + 1; + y = -coord[1] / 7 + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + for (var i = 0; i < 2; i++) { + var xmid = xstart + 27; + var ymid = ystart + 27 + i * 10; + var step = Math.PI / 100; + var rad = 2; + for (var theta = 0; theta < 2 * Math.PI; theta += step) { + this.penUp(args, util); + util.target.setXY(xmid, ymid); + var x = xmid + rad * Math.cos(theta); + var y = ymid - rad * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(x, y); + } + } + + + } + + drawMeasure(x, y, args, util) { + this.penUp(args, util); + util.target.setXY(x + 10, y); + this.penDown(args, util); + util.target.setXY(x + 10, y + 40); + this.penUp(args, util); + this.penUp(args, util); + util.target.setXY(x + 11, y); + this.penDown(args, util); + util.target.setXY(x + 11, y + 40); + this.penUp(args, util); + + this.penUp(args, util); + util.target.setXY(x + 10, y - this.spaceBetween); + this.penDown(args, util); + util.target.setXY(x + 10, y + 40 - this.spaceBetween); + this.penUp(args, util); + this.penUp(args, util); + util.target.setXY(x + 11, y - this.spaceBetween); + this.penDown(args, util); + util.target.setXY(x + 11, y + 40 - this.spaceBetween); + this.penUp(args, util); + } + + drawMusic(args, util, vizHelper) { + var xinit = this.staffStartX + 40; + var x = xinit; + var y = this.staffStartY; + var xStep = 45; + var pastVol = 0; + var beats = 0; + var signal = this.convertSignalToMusicList(args, util); + + for (let i in signal) { + log.log(signal[i]); + note = signal[i][0]; + duration = signal[i][1]; + volume = signal[i][2]; + acc = signal[i][4]; + adjusted = signal[i][6]; + beats += duration; + if (note <= 3) { + up = true; + } else { + up = false; + } + x = x + xStep; + if (x > this.staffStartX + this.staffLength) { + x = xinit + xStep; + y = y - this.spaceBetween - 11 * this.staffWidth; + } + + if (beats % 4 == 0 && beats != 0) { + this.setPenColorToColor(this.black, util); + this.drawMeasure(x, y, args, util); + } + ymidTreble = y + note * this.staffWidth / 2; + ymidBass = y + note * this.staffWidth / 2 - this.spaceBetween; + + if (adjusted) { + this.setPenColorToColor(this.purple, util); + } else { + this.setPenColorToColor(this.black, util); + } + + if (signal[i][3] == 'treble') { + ymid = ymidTreble; + xmid = x - 8; + this.addRest(xmid, ymidBass - note * this.staffWidth / 2, duration, args, util); + } else { + xmid = x - 8; + ymid = ymidBass; + this.addRest(xmid, ymidTreble - note * this.staffWidth / 2, duration, args, util); + + } + if (note > 9 || note < -1) { + this.addLedgers(xmid, ymid, note, args, util); + } + + if (acc) { + this.addAccidental(xmid, ymid, note, acc, args, util); + } + + if (signal[i][5] == "tie") { + log.log("tie"); + this.addTie(xmid, ymid, up, xStep, args, util); + } + + + this.drawNote(xmid, ymid, duration, up, args, util); + if ((volume != pastVol)) { + newX = xmid; + newY = y - this.spaceBetween / 4; + if (signal[i][3] == 'bass') { + newY = newY - this.spaceBetween; + } + sym = this.symbols[volume]; + initial = 0; + for (let i in sym) { + s = sym[i]; + this.drawSymbol(s, args, util, newX + initial, newY); + initial += this.spacing[volume][i]; + } + } + pastVol = volume; + } + this.penUp(args, util); + + if (x > 120 && y < 0) { + vizHelper.clearSheetMusicList(); + } + } + + addMultiLineTie(xmid, ymid, up, xstep, args, util) { + var xrad = 8; + var yrad = 4; + if (up) { + var sign = -1; + } else { + sign = 1; + } + var xrad = xrad + xstep / 2 - 8 - xrad / 4; + var yrad = xrad / 2; + var xmid = xmid + xrad; + var ymid = ymid + sign * yrad; + var x = xmid; + var y = ymid + sign * yrad; + var step = Math.PI / 100; + for (var theta = Math.PI / 2; theta < Math.PI; theta += step) { + this.penUp(args, util); + util.target.setXY(x, y); + var x = xmid + xrad * Math.cos(theta); + var y = ymid + sign * yrad * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(x, y); + this.penUp(args, util); + } + + var x = this.staffStartX + xstep + xrad; + var y = ymid - this.spaceBetween - 11 * this.staffWidth; + var xmid = this.staffStartX + xstep; + var ymid = ymid - this.spaceBetween - 11 * this.staffWidth; + for (var theta = 0; theta < Math.PI / 2; theta += step) { + this.penUp(args, util); + util.target.setXY(x, y); + var x = xmid + xrad * Math.cos(theta); + var y = ymid + sign * yrad * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(x, y); + this.penUp(args, util); + } + } + + addTie(xmid, ymid, up, xstep, args, util) { + if (xmid + xstep > this.staffStartX + this.staffLength) { + this.addMultiLineTie(xmid, ymid, up, xstep, args, util); + } else { + var xrad = 8; + var yrad = 4; + if (up) { + var sign = -1; + } else { + sign = 1; + } + var xrad = xrad + xstep / 2 - 8 - xrad / 4; + var yrad = xrad / 2; + var xmid = xmid + xrad; + var ymid = ymid + sign * yrad; + var x = xmid + xrad; + var y = ymid; + var step = Math.PI / 100; + for (var theta = 0; theta < Math.PI; theta += step) { + this.penUp(args, util); + util.target.setXY(x, y); + var x = xmid + xrad * Math.cos(theta); + var y = ymid + sign * yrad * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(x, y); + this.penUp(args, util); + } + } + } + + addRest(xmid, ymid, dur, args, util) { + var symbolDur = dur; + if (dur == 3) { + symbolDur = 2; //add normal half note rest and then dot it + } + var restSymbol = this.rests[symbolDur]; + var restX = xmid; + var restY = ymid; + var offset = this.restOffset[symbolDur]; + if (dur > 1) { + var xOffset = 8; + } else { + var xOffset = 0; + } + var scale = this.restScale[symbolDur]; + this.penUp(args, util); + for (var i in restSymbol) { + coord = restSymbol[i]; + restX = coord[0] / scale + xmid - xOffset; + restY = -coord[1] / scale + ymid + offset; + util.target.setXY(restX, restY); + this.penDown(args, util); + } + this.penUp(args, util); + if (dur == 3) { + var xmid = xmid + 15; + var ymid = ymid + offset; + var step = Math.PI / 100; + var rad = 2; + for (var theta = 0; theta < 2 * Math.PI; theta += step) { + this.penUp(args, util); + util.target.setXY(xmid, ymid); + var restX = xmid + rad * Math.cos(theta); + var restY = ymid - rad * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(restX, restY); + } + } + + } + + addAccidental(xmid, ymid, note, acc, args, util) { + var xrad = 8; + var yrad = 4; + var xmid = xmid; + var ymid = ymid; + if (acc == "sharp") { + this.drawString("S", xmid - xrad * 4, ymid + yrad * 1.5, 0.75, args, util) + } + if (acc == "flat") { + this.drawString("F", xmid - xrad * 3, ymid + yrad * 1.5 + 2, 0.8, args, util); + + } + } + + addLedgers(xmid, ymid, note, args, util) { + var xrad = 8; + var yrad = 4; + if (note > 0) { //treble + if (note % 2 == 0) { + this.penUp(args, util); + util.target.setXY(xmid - xrad - 3, ymid); + this.penDown(args, util); + util.target.setXY(xmid + xrad + 3, ymid); + } + else { + this.penUp(args, util); + util.target.setXY(xmid - xrad - 3, ymid - yrad); + this.penDown(args, util); + util.target.setXY(xmid + xrad + 3, ymid - yrad); + } + for (var i = 0; i < note - 9; i += 2) { + if (i / 2 != 0) { + if (note % 2 == 0) { + this.penUp(args, util); + util.target.setXY(xmid - xrad - 3, ymid - yrad * i); + this.penDown(args, util); + util.target.setXY(xmid + xrad + 3, ymid - yrad * i); + } + else { + this.penUp(args, util); + util.target.setXY(xmid - xrad - 3, ymid - yrad - yrad * i); + this.penDown(args, util); + util.target.setXY(xmid + xrad + 3, ymid - yrad - yrad * i); + } + } + } + } else { //bass + if (note % 2 == 0) { + this.penUp(args, util); + util.target.setXY(xmid - xrad - 3, ymid); + this.penDown(args, util); + util.target.setXY(xmid + xrad + 3, ymid); + } + else { + this.penUp(args, util); + util.target.setXY(xmid - xrad - 3, ymid + yrad); + this.penDown(args, util); + util.target.setXY(xmid + xrad + 3, ymid + yrad); + } + + for (var i = 0; i < -note - 1; i += 2) { + if (i / 2 != 0) { + if (note % 2 == 0) { + this.penUp(args, util); + util.target.setXY(xmid - xrad - 3, ymid + yrad * i); + this.penDown(args, util); + util.target.setXY(xmid + xrad + 3, ymid + yrad * i); + } + else { + this.penUp(args, util); + util.target.setXY(xmid - xrad - 3, ymid + yrad + yrad * i); + this.penDown(args, util); + util.target.setXY(xmid + xrad + 3, ymid + yrad + yrad * i); + } + } + } + + } + } + + drawNote(xmid, ymid, duration, up, args, util) { + var xrad = 8; + var yrad = 4; + if (up) { + flip = 1; + } else { + flip = -1; + } + step = Math.PI / 100; + if (duration <= 1) { //draw solid note for sixteenth, eighth, and quarter notes + for (var theta = 0; theta < 2 * Math.PI; theta += step) { + this.penUp(args, util); + util.target.setXY(xmid, ymid); + var x = xmid + xrad * Math.cos(theta); + var y = ymid - yrad * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(x, y); + } + } else { //draw hollow note for half, dotted half, and whole notes + x = xmid + xrad; + y = ymid; + for (var theta = 0; theta < 2 * Math.PI; theta += step) { + this.penUp(args, util); + util.target.setXY(x, y); + x = xmid + xrad * Math.cos(theta); + y = ymid - yrad * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(x, y); + } + x = xmid + xrad - 1; + y = ymid; + for (var theta = 0; theta < 2 * Math.PI; theta += step) { + this.penUp(args, util); + util.target.setXY(x, y); + x = xmid + (xrad - 1) * Math.cos(theta); + y = ymid - (yrad - 1) * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(x, y); + } + } + if (duration == 3) { //add dot for dotted half note + dotrad = 2; + for (var theta = 0; theta < 2 * Math.PI; theta += step) { + this.penUp(args, util); + util.target.setXY(xmid + 12, ymid); + var x = xmid + 12 + dotrad * Math.cos(theta); + var y = ymid - dotrad * Math.sin(theta); + this.penDown(args, util); + util.target.setXY(x, y); + } + } + if (duration != 4) { //add stem for non-whole notes + this.penUp(args, util); + util.target.setXY(xmid + flip * xrad, ymid); + this.penDown(args, util); + util.target.setXY(xmid + flip * xrad, ymid + flip * 30); + } + if (duration < 1) { //add tails for < quarter notes + if (duration === 0) { + return; + } + offset = 0; + for (var i = 0; i < 1 / (duration * 2); i++) { + this.penUp(args, util); + util.target.setXY(xmid + flip * xrad, ymid + flip * (30 + offset * 6)); + this.penDown(args, util); + util.target.setXY(xmid + flip * xrad + 2, ymid + flip * (30 + offset * 6 - 8)); + util.target.setXY(xmid + flip * xrad + 10, ymid + flip * (30 + offset * 6 - 12)); + this.penUp(args, util); + util.target.setXY(xmid + flip * xrad, ymid + flip * (30 + offset * 6 + 2)); + this.penDown(args, util); + util.target.setXY(xmid + flip * xrad + 2, ymid + flip * (30 + offset * 6 - 8 + 1)); + util.target.setXY(xmid + flip * xrad + 10, ymid + flip * (30 + offset * 6 - 12 + 1)); + offset += 1; + this.penUp(args, util); + } + } + + } + + convertSignalToMusicList(args, util) { + var signal = []; + var beats = 0; + for (var i in this.noteList) { + freq = this.noteList[i][0]; + var acc = ""; + if (sharps.includes(freq)) { + acc = "sharp"; + } + if (flats.includes(freq)) { + acc = "flat"; + } + + let adjusted = false; + + if (freq >= 60) { + if (freq > this._staffLims['hi_note']) { + adjusted = true; + console.log(`adjusting (treble) ${freq} to ${this._staffLims['hi_note']}`); + freq = this._staffLims['hi_note']; + } + var staff = pitchToStaff[freq]; + var dur = this.noteList[i][1] * 4; + var amp = this.noteList[i][3]; + var clef = "treble"; + } else { + if (freq === undefined || freq < this._staffBaseLims['lo_note']) { + adjusted = true; + console.log(`adjusting (bass) ${freq} to ${this._staffBaseLims['lo_note']}`); + freq = this._staffBaseLims['lo_note']; + } + var staff = pitchToStaffBass[freq]; + var dur = this.noteList[i][1] * 4; + var amp = this.noteList[i][3]; + var clef = "bass"; + } + var newBeats = 0; + if (beats + dur == 4) { + newBeats = 0; + signal.push([staff, dur, amp, clef, acc, "", adjusted]); + } else if (beats + dur > 4) { + signal.push([staff, 4 - beats, amp, clef, acc, "tie", adjusted]); + signal.push([staff, dur - (4 - beats), amp, clef, acc, "", adjusted]); + newBeats = dur - (4 - beats); + } else { + newBeats = beats + dur; + signal.push([staff, dur, amp, clef, acc, "", adjusted]); + } + beats = newBeats; + + + } + return signal; + } + + penUp(args, util) { + const penState = this._getPenState(util.target); + if (penState.penDown) { + penState.penDown = false; + util.target.removeListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + + penDown(args, util, penSkinId) { + const penState = this._getPenState(util.target); + if (!penState.penDown) { + penState.penDown = true; + util.target.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + + penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penPoint(penSkinId, penState.penAttributes, util.target.x, util.target.y); + this.runtime.requestRedraw(); + } + } + + /** + * The pen "set pen color to {color}" block sets the pen to a particular RGB color. + * The transparency is reset to 0. + * @param {object} args - the block arguments. + * @property {int} COLOR - the color to set, expressed as a 24-bit RGB value (0xRRGGBB). + * @param {object} util - utility object provided by the runtime. + */ + setPenColorToColor(newColor, util) { + const penState = this._getPenState(util.target); + const rgb = Cast.toRgbColorObject(newColor); + const hsv = Color.rgbToHsv(rgb); + penState.color = (hsv.h / 360) * 100; + penState.saturation = hsv.s * 100; + penState.brightness = hsv.v * 100; + if (rgb.hasOwnProperty('a')) { + penState.transparency = 100 * (1 - (rgb.a / 255.0)); + } else { + penState.transparency = 0; + } + + // Set the legacy "shade" value the same way scratch 2 did. + penState._shade = penState.brightness / 2; + + this._updatePenColor(penState); + } + + /** + * Update the cached color from the color, saturation, brightness and transparency values + * in the provided PenState object. + * @param {PenState} penState - the pen state to update. + * @private + */ + _updatePenColor(penState) { + const rgb = Color.hsvToRgb({ + h: penState.color * 360 / 100, + s: penState.saturation / 100, + v: penState.brightness / 100 + }); + penState.penAttributes.color4f[0] = rgb.r / 255.0; + penState.penAttributes.color4f[1] = rgb.g / 255.0; + penState.penAttributes.color4f[2] = rgb.b / 255.0; + penState.penAttributes.color4f[3] = this._transparencyToAlpha(penState.transparency); + } + + /** + * Convert a pen transparency value to an alpha value. + * Alpha ranges from 0 to 1, where 0 is transparent and 1 is opaque. + * Transparency ranges from 0 to 100, where 0 is opaque and 100 is transparent. + * @param {number} transparency - the input transparency value. + * @returns {number} the alpha value. + * @private + */ + _transparencyToAlpha(transparency) { + return 1.0 - (transparency / 100.0); + } + + /** + * The pen "clear" block clears the pen layer's contents. + */ + clear() { + const penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penClear(penSkinId); + this.runtime.requestRedraw(); + } + } + +} + +module.exports = SheetMusic; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/spectrogram.js b/src/extensions/scratch3_musiccreation/spectrogram.js new file mode 100644 index 00000000000..c3c4f3441a2 --- /dev/null +++ b/src/extensions/scratch3_musiccreation/spectrogram.js @@ -0,0 +1,417 @@ +const Clone = require('../../util/clone'); +const log = require('../../util/log'); +const Cast = require('../../util/cast'); +const Color = require('../../util/color'); +const RenderedTarget = require('../../sprites/rendered-target'); +const StageLayering = require('../../engine/stage-layering'); + +const letters = require('./letters'); +const symbols = require('./symbols'); +const { updateVariableIdentifiers } = require('../../util/variable-util'); + +var midi, inst, dur, harmonic, pitch, k, coeff, hPitch, d, maxDuration, maxFreq, f, start, end, i, coord, x, y; + + +class Spectrogram { + constructor(runtime) { + this.runtime = runtime; + + /** + * The ID of the renderer Skin corresponding to the pen layer. + * @type {int} + * @private + */ + this._penSkinId = -1; + + /** + * The ID of the renderer Drawable corresponding to the pen layer. + * @type {int} + * @private + */ + this._penDrawableId = -1; + this.black = '0x000000'; + this.blue = '0x00008B'; + this.yellow = '0xffff00'; + + this.noteList = []; + + this.axisStartX = -200; + this.axisStartY = -150; + this.xAxisLength = 400; + this.yAxisLength = 300; + + this._onTargetCreated = this._onTargetCreated.bind(this); + this.runtime.on('targetWasCreated', this._onTargetCreated); + + this._onTargetMoved = this._onTargetMoved.bind(this); + + this.harmonics = { + "Piano": [[1, 1], [3, 0.42], [4, 0.22]], //DONE + "Guitar": [[1, 0.55], [2, 0.47], [3, 0.68], [4, 0.24]], + "Bass": [[1, 1], [3, 0.78], [4, 0.22]], + "Cello": [[1, 1], [2, 0.47], [3, 0.24], [4, 0.15]], //DONE + "Saxophone": [[1, 1], [2, 0.38], [3, 0.14], [4, 0.02]], //DONE + "Clarinet": [[1, 0.57], [2, 0.87], [3, 0.23], [4, 0]], //DONE + "Synth": [[1, 1], [2, 0], [3, 0], [4, 0]] //DONE + } + + this.letters = { + 'a': letters.a, + 'b': letters.b, + 'c': letters.c, + 'd': letters.d, + 'e': letters.e, + 'f': letters.f, + 'g': letters.g, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'k': letters.k, + 'l': letters.l, + 'm': letters.m, + 'n': letters.n, + 'o': letters.o, + 'p': letters.p, + 'q': letters.q, + 'r': letters.r, + 's': letters.s, + 't': letters.t, + 'u': letters.u, + 'v': letters.v, + 'w': letters.w, + 'x': letters.x, + 'y': letters.y, + 'z': letters.z + } + + this.spacing = { + 'a': 59.03383897316219, + 'b': 35.666277712952166, + 'c': 55.59820426487096, + 'd': 51.65460910151694, + 'e': 33.821470245040814, + 'f': 35.05134189031503, + 'g': 62.10851808634772, + 'h': 51.65460910151691, + 'i': 0.0, + 'j': 27.057176196032685, + 'k': 44.275379229871646, + 'l': 33.20653442240376, + 'm': 76.86697782963824, + 'n': 57.803967327887975, + 'o': 62.108518086347715, + 'p': 35.05134189031503, + 'q': 62.72345390898482, + 'r': 34.305274971941685, + 's': 39.62850729517402, + 't': 51.03967327887982, + 'u': 50.42473745624271, + 'v': 52.88448074679113, + 'w': 88.55075845974329, + 'x': 45.50525087514586, + 'y': 47.350058343057185, + 'z': 55.959159859976694 + } + } + + /** + * The key to load & store a target's music-related state. + * @type {string} + */ + static get VIZ_STATE_KEY() { + return 'Scratch.musicviz'; + } + + static get DEFAULT_PEN_STATE() { + return { + penDown: false, + color: 66.66, + saturation: 100, + brightness: 100, + transparency: 0, + _shade: 50, // Used only for legacy `change shade by` blocks + penAttributes: { + color4f: [0, 0, 1, 1], + diameter: 1 + } + }; + } + + /** + * The minimum and maximum allowed pen size. + * The maximum is twice the diagonal of the stage, so that even an + * off-stage sprite can fill it. + * @type {{min: number, max: number}} + */ + static get PEN_SIZE_RANGE() { + return { min: 1, max: 1200 }; + } + + /** + * When a music-playing Target is cloned, clone the music state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated(newTarget, sourceTarget) { + if (sourceTarget) { + const penState = sourceTarget.getCustomState(Spectrogram.VIZ_STATE_KEY); + if (penState) { + newTarget.setCustomState(Spectrogram.VIZ_STATE_KEY, Clone.simple(penState)); + if (penState.penDown) { + newTarget.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + } + } + + _onTargetMoved(target, oldX, oldY, isForce) { + // Only move the pen if the movement isn't forced (ie. dragged). + if (!isForce) { + let penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + const penState = this._getPenState(target); + this.runtime.renderer.penLine(penSkinId, penState.penAttributes, oldX, oldY, target.x, target.y); + this.runtime.requestRedraw(); + } + } + } + + _getPenLayerID() { + if (this._penSkinId < 0 && this.runtime.renderer) { + this._penSkinId = this.runtime.renderer.createPenSkin(); + this._penDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); + this.runtime.renderer.updateDrawableProperties(this._penDrawableId, { skinId: this._penSkinId }); + } + return this._penSkinId; + } + + _getPenState(target) { + let penState = target.getCustomState(Spectrogram.VIZ_STATE_KEY); + if (!penState) { + penState = Clone.simple(Spectrogram.DEFAULT_PEN_STATE); + target.setCustomState(Spectrogram.VIZ_STATE_KEY, penState); + } + return penState; + } + + testSpectViz(noteList, args, util) { + this.setPenColorToColor(this.black, util); + this.noteList = noteList; + this.clear(); + this.drawAxes(args, util); + this.drawSpectrogram(args, util); + + } + + labelAxes(args, util) { + this.setPenColorToColor(this.black, util); + this.drawString('time', this.axisStartX + this.xAxisLength - 40, this.axisStartY - 5, 0.8, args, util); + this.drawString('frequencies', this.axisStartX - 30, this.axisStartY + this.yAxisLength + 20, 0.8, args, util); + + this.drawString('spectrogram', this.axisStartX + this.xAxisLength / 2 - 70, this.axisStartY + this.yAxisLength + 20, 1, args, util); + } + + drawSpectrogram(args, util) { + const freqs = []; + const amps = []; + const durs = []; + const coeffs = []; + d = 0; + this.setPenColorToColor(this.yellow, util); + for (let i in this.noteList) { + midi = this.noteList[i][0]; + inst = this.noteList[i][2]; + dur = this.noteList[i][1]; + harmonic = this.harmonics[inst]; + pitch = 2 ** ((midi - 69) / 12) * 440; + for (let i in harmonic) { + k = harmonic[i][0]; + coeff = harmonic[i][1]; + hPitch = pitch * k; + freqs.push(hPitch); + amps.push(coeff); + durs.push([d, d + dur]) + coeffs.push(coeff); + } + d += dur; + } + maxDuration = d; + maxFreq = Math.max(...freqs); + for (let i in freqs) { + f = freqs[i] / (maxFreq + 5); + d = durs[i]; + coeff = coeffs[i]; + start = d[0]; + end = d[1]; + start = start / maxDuration; + end = end / maxDuration; + if (coeff != 0) { + this.penUp(args, util); + util.target.setXY(this.axisStartX + start * this.xAxisLength, this.axisStartY + this.yAxisLength * f); + this.penDown(args, util); + util.target.setXY(this.axisStartX + end * this.xAxisLength, this.axisStartY + this.yAxisLength * f); + this.penUp(args, util); + + this.penUp(args, util); + util.target.setXY(this.axisStartX + start * this.xAxisLength, this.axisStartY + this.yAxisLength * f + 1); + this.penDown(args, util); + util.target.setXY(this.axisStartX + end * this.xAxisLength, this.axisStartY + this.yAxisLength * f + 1); + this.penUp(args, util); + } + + } + } + + drawString(str, xstart, ystart, size, args, util) { + for (var i in str) { + xstart += 5 * size; + if (i >= 1) { + xstart += this.spacing[str[i - 1]] / 5 * size; + } + this.drawLetter(str[i], xstart, ystart, size, args, util); + } + + } + + drawLetter(letter, xstart, ystart, size, args, util) { + letter = letters[letter]; + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0] / 5 * size + xstart; + y = -coord[1] / 5 * size + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0] / 5 * size + xstart + 1; + y = -coord[1] / 5 * size + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + } + + fillInSpec(args, util) { + this.setPenColorToColor(this.blue, util); + for (var i = this.axisStartY + 1; i < this.axisStartY + this.yAxisLength; i++) { + this.penUp(args, util); + util.target.setXY(this.axisStartX + 1, i); + this.penDown(args, util); + util.target.setXY(this.axisStartX + this.xAxisLength, i); + this.penUp(args, util); + } + } + + drawAxes(args, util) { + util.target.setXY(this.axisStartX, this.axisStartY + this.yAxisLength); + this.penDown(args, util); + util.target.setXY(this.axisStartX, this.axisStartY); + this.penUp(args, util); + util.target.setXY(this.axisStartX, this.axisStartY); + this.penDown(args, util); + util.target.setXY(this.axisStartX + this.xAxisLength, this.axisStartY); + this.penUp(args, util); + this.fillInSpec(args, util); + this.labelAxes(args, util); + } + + penUp(args, util) { + const penState = this._getPenState(util.target); + if (penState.penDown) { + penState.penDown = false; + util.target.removeListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + + penDown(args, util, penSkinId) { + const penState = this._getPenState(util.target); + if (!penState.penDown) { + penState.penDown = true; + util.target.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + + penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penPoint(penSkinId, penState.penAttributes, util.target.x, util.target.y); + this.runtime.requestRedraw(); + } + } + + /** + * The pen "set pen color to {color}" block sets the pen to a particular RGB color. + * The transparency is reset to 0. + * @param {object} args - the block arguments. + * @property {int} COLOR - the color to set, expressed as a 24-bit RGB value (0xRRGGBB). + * @param {object} util - utility object provided by the runtime. + */ + setPenColorToColor(newColor, util) { + const penState = this._getPenState(util.target); + const rgb = Cast.toRgbColorObject(newColor); + const hsv = Color.rgbToHsv(rgb); + penState.color = (hsv.h / 360) * 100; + penState.saturation = hsv.s * 100; + penState.brightness = hsv.v * 100; + if (rgb.hasOwnProperty('a')) { + penState.transparency = 100 * (1 - (rgb.a / 255.0)); + } else { + penState.transparency = 0; + } + + // Set the legacy "shade" value the same way scratch 2 did. + penState._shade = penState.brightness / 2; + + this._updatePenColor(penState); + } + + /** + * Update the cached color from the color, saturation, brightness and transparency values + * in the provided PenState object. + * @param {PenState} penState - the pen state to update. + * @private + */ + _updatePenColor(penState) { + const rgb = Color.hsvToRgb({ + h: penState.color * 360 / 100, + s: penState.saturation / 100, + v: penState.brightness / 100 + }); + penState.penAttributes.color4f[0] = rgb.r / 255.0; + penState.penAttributes.color4f[1] = rgb.g / 255.0; + penState.penAttributes.color4f[2] = rgb.b / 255.0; + penState.penAttributes.color4f[3] = this._transparencyToAlpha(penState.transparency); + } + + /** + * Convert a pen transparency value to an alpha value. + * Alpha ranges from 0 to 1, where 0 is transparent and 1 is opaque. + * Transparency ranges from 0 to 100, where 0 is opaque and 100 is transparent. + * @param {number} transparency - the input transparency value. + * @returns {number} the alpha value. + * @private + */ + _transparencyToAlpha(transparency) { + return 1.0 - (transparency / 100.0); + } + + /** + * The pen "clear" block clears the pen layer's contents. + */ + clear() { + const penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penClear(penSkinId); + this.runtime.requestRedraw(); + } + } + +} + +module.exports = Spectrogram; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/symbols.js b/src/extensions/scratch3_musiccreation/symbols.js new file mode 100644 index 00000000000..a59a97a7402 --- /dev/null +++ b/src/extensions/scratch3_musiccreation/symbols.js @@ -0,0 +1,13 @@ +module.exports = { + 'treble': [[0.0, 0.0], [2.0569948186528464, 5.142487046632141], [6.170984455958546, 11.313471502590687], [14.398963730569946, 15.427461139896366], [21.598445595854926, 17.484455958549233], [31.883419689119165, 17.484455958549233], [41.139896373057, 14.39896373056996], [49.3678756476684, 9.25647668393782], [51.42487046632124, -1.0284974093264054], [54.51036269430051, -12.341968911917093], [54.51036269430051, -17.484455958549233], [54.51036269430051, -25.71243523316059], [13.370466321243526, -246.83937823834196], [13.370466321243526, -250.95336787564764], [13.370466321243526, -260.20984455958546], [13.370466321243526, -269.4663212435233], [16.4559585492228, -277.6943005181347], [20.569948186528492, -284.89378238341965], [24.6839378238342, -291.0647668393782], [28.797927461139892, -298.2642487046632], [37.02590673575129, -301.3497409326425], [42.16839378238342, -297.23575129533674], [49.3678756476684, -290.0362694300518], [51.42487046632124, -279.75129533678756], [52.45336787564767, -268.4378238341969], [52.45336787564767, -257.1243523316062], [49.3678756476684, -246.83937823834196], [45.25388601036269, -235.52590673575128], [38.054404145077726, -227.29792746113986], [30.854922279792746, -217.01295336787564], [-12.3419689119171, -172.78756476683935], [-21.59844559585492, -162.50259067357513], [-26.740932642487046, -148.10362694300517], [-30.854922279792746, -129.59067357512953], [-30.854922279792746, -117.24870466321241], [-29.826424870466322, -104.90673575129532], [-24.6839378238342, -94.62176165803106], [-18.512953367875646, -85.36528497409324], [-14.398963730569946, -79.1943005181347], [-4.1139896373057, -71.99481865284972], [8.2279792746114, -63.76683937823833], [22.626943005181346, -61.70984455958549], [33.94041450777202, -60.68134715025906], [48.339378238341965, -62.7383419689119], [58.62435233160622, -70.96632124352331], [67.88082901554404, -81.25129533678756], [71.99481865284974, -97.70725388601034], [70.96632124352331, -107.99222797927459], [68.90932642487047, -115.19170984455957], [61.70984455958549, -123.41968911917098], [54.51036269430051, -129.59067357512953], [41.139896373057, -131.64766839378237], [29.826424870466326, -131.64766839378237], [18.512953367875653, -125.47668393782382], [13.370466321243526, -113.13471502590673], [12.341968911917093, -102.84974093264248], [15.427461139896366, -88.45077720207252], [23.655440414507765, -81.25129533678756]], + 'bass' : [[0.0, 0.0], [82.92880258899677, -54.10598705501616], [120.85355987055016, -95.06472491909383], [137.03478964401293, -124.39320388349515], [147.6537216828479, -159.789644012945], [151.1933656957929, -202.7710355987055], [142.59708737864077, -237.1561488673139], [127.93284789644014, -266.9902912621359], [104.67233009708738, -290.7564724919094], [79.89482200647248, -302.89239482200645], [54.6116504854369, -305.42071197411], [33.879449838187696, -299.3527508090615], [21.743527508090622, -288.2281553398058], [16.18122977346279, -275.58656957928804], [12.641585760517799, -259.40533980582524], [12.641585760517799, -243.22411003236243], [16.6868932038835, -225.02022653721681]], + 'piano': [[0.0, 0.0], [0.0, -1.8770388958594708], [2.8155583437892346, -4.6925972396487055], [6.569636135508176, -4.6925972396487055], [6.569636135508176, -2.815558343789178], [6.569636135508176, 0.9385194479297638], [4.6925972396487055, 5.631116687578412], [3.7540777917189416, 9.385194479297354], [1.8770388958594708, 14.077791718946003], [0.0, 16.893350062735237], [-0.9385194479297354, 20.64742785445418], [-2.815558343789206, 20.64742785445418], [-5.631116687578412, 20.64742785445418], [-4.692597239648677, 20.64742785445418], [-0.9385194479297354, 20.64742785445418], [4.6925972396487055, 20.64742785445418], [7.508155583437883, 21.585947302384], [3.7540777917189416, 20.64742785445418], [2.8155583437892346, 17.831869510664944], [3.7540777917189416, 13.139272271016296], [3.7540777917189416, 9.385194479297354], [5.631116687578412, 4.6925972396487055], [5.631116687578412, 0.9385194479297638], [7.508155583437883, -1.8770388958594708], [10.323713927227118, -2.815558343789178], [12.200752823086589, -5.631116687578412], [15.016311166875767, -5.631116687578412], [18.770388958594708, -4.6925972396487055], [18.770388958594708, -0.938519447929707], [18.770388958594708, 1.8770388958594708], [17.831869510665, 4.6925972396487055], [15.95483061480553, 7.50815558343794], [12.200752823086589, 9.385194479297354], [10.323713927227118, 9.385194479297354], [7.508155583437883, 8.446675031367647]], + 'forte': [[0.0, 0.0], [0.0, -2.815558343789206], [0.0, -4.692597239648677], [-1.8770388958594708, -4.692597239648677], [-2.8155583437892346, -4.692597239648677], [-5.631116687578469, -4.692597239648677], [-7.50815558343794, -2.815558343789206], [-10.323713927227118, 0.9385194479297354], [-11.262233375156882, 3.7540777917189416], [-12.200752823086589, 4.6925972396487055], [-14.07779171894606, 4.6925972396487055], [-15.016311166875823, 4.6925972396487055], [-16.893350062735294, 4.6925972396487055], [-17.831869510665, 4.6925972396487055], [-18.770388958594765, 4.6925972396487055], [-19.708908406524472, 5.631116687578441], [-3.7540777917189416, 5.631116687578441], [-12.200752823086589, 5.631116687578441], [-14.07779171894606, 9.385194479297382], [-14.07779171894606, 12.200752823086589], [-15.95483061480553, 15.95483061480553], [-16.893350062735294, 17.831869510665], [-17.831869510665, 21.58594730238397], [-18.770388958594765, 25.340025094102913], [-19.708908406524472, 27.217063989962384], [-20.647427854454236, 28.15558343789209], [-24.401505646173177, 28.15558343789209], [-26.278544542032648, 28.15558343789209], [-26.278544542032648, 28.15558343789209], [-28.15558343789212, 27.217063989962384], [-29.094102885821854, 24.40150564617315]], + 'mezzo': [[-20.0, 0.0], [-19.061480552070265, -1.8770388958594708], [-18.12296110414053, -4.692597239648649], [-15.307402760351295, -7.508155583437883], [-13.430363864491824, -7.508155583437883], [-11.553324968632353, -6.569636135508119], [-11.553324968632353, -3.7540777917189416], [-12.491844416562088, -0.938519447929707], [-14.36888331242156, 2.8155583437892346], [-14.36888331242156, 5.631116687578469], [-15.307402760351295, 6.569636135508176], [-12.491844416562088, -1.8770388958594708], [-11.553324968632353, -4.692597239648649], [-7.799247176913411, -6.569636135508119], [-4.983688833124205, -6.569636135508119], [-4.04516938519447, -3.7540777917189416], [-4.983688833124205, -0.938519447929707], [-5.9222082810539405, 1.8770388958594708], [-6.860727728983676, 5.631116687578469], [-7.799247176913411, 7.50815558343794], [-4.983688833124205, -1.8770388958594708], [-2.168130489334999, -4.692597239648649], [1.5859473023839428, -5.631116687578412], [5.340025094102884, -5.631116687578412], [4.401505646173177, -2.815558343789178], [3.4629861982434136, 0.0], [1.5859473023839428, 3.7540777917189416], [1.5859473023839428, 7.50815558343794], [2.5244667503137066, 9.385194479297411], [6.278544542032648, 8.446675031367647], [9.094102885821826, 3.7540777917189416]], + 'restfour': [[0.0, 0.0], [0.0, 3.0], [0.0, 6.0], [3.0, 0.0], [3.0, 3.0], [3.0, 6.0], [6.0, 0.0], [6.0, 3.0], [6.0, 6.0], [9.0, 0.0], [9.0, 3.0], [9.0, 6.0], [12.0, 0.0], [12.0, 3.0], [12.0, 6.0], [15.0, 0.0], [15.0, 3.0], [15.0, 6.0], [18.0, 0.0], [18.0, 3.0], [18.0, 6.0], [21.0, 0.0], [21.0, 3.0], [21.0, 6.0], [24.0, 0.0], [24.0, 3.0], [24.0, 6.0], [27.0, 0.0], [27.0, 3.0], [27.0, 6.0], [28.0, 9.0], [28.0, 12.0], [28.0, 15.0], [28.0, 18.0], [28.0, 21.0], [28.0, 24.0], [28.0, 27.0], [28.0, 30.0], [28.0, 33.0], [28.0, 36.0], [28.0, 39.0], [28.0, 41.5], [30.0, 0.0], [30.0, 3.0], [30.0, 6.0], [31.0, 9.0], [31.0, 12.0], [31.0, 15.0], [31.0, 18.0], [31.0, 21.0], [31.0, 24.0], [31.0, 27.0], [31.0, 30.0], [31.0, 33.0], [31.0, 36.0], [31.0, 39.0], [31.0, 41.5], [33.0, 0.0], [33.0, 3.0], [33.0, 6.0], [34.0, 9.0], [34.0, 12.0], [34.0, 15.0], [34.0, 18.0], [34.0, 21.0], [34.0, 24.0], [34.0, 27.0], [34.0, 30.0], [34.0, 33.0], [34.0, 36.0], [34.0, 39.0], [34.0, 41.5], [36.0, 0.0], [36.0, 3.0], [36.0, 6.0], [37.0, 9.0], [37.0, 12.0], [37.0, 15.0], [37.0, 18.0], [37.0, 21.0], [37.0, 24.0], [37.0, 27.0], [37.0, 30.0], [37.0, 33.0], [37.0, 36.0], [37.0, 39.0], [37.0, 41.5], [39.0, 0.0], [39.0, 3.0], [39.0, 6.0], [40.0, 9.0], [40.0, 12.0], [40.0, 15.0], [40.0, 18.0], [40.0, 21.0], [40.0, 24.0], [40.0, 27.0], [40.0, 30.0], [40.0, 33.0], [40.0, 36.0], [40.0, 39.0], [40.0, 41.5], [42.0, 0.0], [42.0, 3.0], [42.0, 6.0], [43.0, 9.0], [43.0, 12.0], [43.0, 15.0], [43.0, 18.0], [43.0, 21.0], [43.0, 24.0], [43.0, 27.0], [43.0, 30.0], [43.0, 33.0], [43.0, 36.0], [43.0, 39.0], [43.0, 41.5], [45.0, 0.0], [45.0, 3.0], [45.0, 6.0], [46.0, 9.0], [46.0, 12.0], [46.0, 15.0], [46.0, 18.0], [46.0, 21.0], [46.0, 24.0], [46.0, 27.0], [46.0, 30.0], [46.0, 33.0], [46.0, 36.0], [46.0, 39.0], [46.0, 41.5], [48.0, 0.0], [48.0, 3.0], [48.0, 6.0], [49.0, 9.0], [49.0, 12.0], [49.0, 15.0], [49.0, 18.0], [49.0, 21.0], [49.0, 24.0], [49.0, 27.0], [49.0, 30.0], [49.0, 33.0], [49.0, 36.0], [49.0, 39.0], [49.0, 41.5], [51.0, 0.0], [51.0, 3.0], [51.0, 6.0], [52.0, 9.0], [52.0, 12.0], [52.0, 15.0], [52.0, 18.0], [52.0, 21.0], [52.0, 24.0], [52.0, 27.0], [52.0, 30.0], [52.0, 33.0], [52.0, 36.0], [52.0, 39.0], [52.0, 41.5], [54.0, 0.0], [54.0, 3.0], [54.0, 6.0], [55.0, 9.0], [55.0, 12.0], [55.0, 15.0], [55.0, 18.0], [55.0, 21.0], [55.0, 24.0], [55.0, 27.0], [55.0, 30.0], [55.0, 33.0], [55.0, 36.0], [55.0, 39.0], [55.0, 41.5], [57.0, 0.0], [57.0, 3.0], [57.0, 6.0], [58.0, 9.0], [58.0, 12.0], [58.0, 15.0], [58.0, 18.0], [58.0, 21.0], [58.0, 24.0], [58.0, 27.0], [58.0, 30.0], [58.0, 33.0], [58.0, 36.0], [58.0, 39.0], [58.0, 41.5], [60.0, 0.0], [60.0, 3.0], [60.0, 6.0], [61.0, 9.0], [61.0, 12.0], [61.0, 15.0], [61.0, 18.0], [61.0, 21.0], [61.0, 24.0], [61.0, 27.0], [61.0, 30.0], [61.0, 33.0], [61.0, 36.0], [61.0, 39.0], [61.0, 41.5], [63.0, 0.0], [63.0, 3.0], [63.0, 6.0], [64.0, 9.0], [64.0, 12.0], [64.0, 15.0], [64.0, 18.0], [64.0, 21.0], [64.0, 24.0], [64.0, 27.0], [64.0, 30.0], [64.0, 33.0], [64.0, 36.0], [64.0, 39.0], [64.0, 41.5], [66.0, 0.0], [66.0, 3.0], [66.0, 6.0], [67.0, 9.0], [67.0, 12.0], [67.0, 15.0], [67.0, 18.0], [67.0, 21.0], [67.0, 24.0], [67.0, 27.0], [67.0, 30.0], [67.0, 33.0], [67.0, 36.0], [67.0, 39.0], [67.0, 41.5], [69.0, 0.0], [69.0, 3.0], [69.0, 6.0], [70.0, 9.0], [70.0, 12.0], [70.0, 15.0], [70.0, 18.0], [70.0, 21.0], [70.0, 24.0], [70.0, 27.0], [70.0, 30.0], [70.0, 33.0], [70.0, 36.0], [70.0, 39.0], [70.0, 41.5], [72.0, 0.0], [72.0, 3.0], [72.0, 6.0], [73.0, 9.0], [73.0, 12.0], [73.0, 15.0], [73.0, 18.0], [73.0, 21.0], [73.0, 24.0], [73.0, 27.0], [73.0, 30.0], [73.0, 33.0], [73.0, 36.0], [73.0, 39.0], [73.0, 41.5], [75.0, 0.0], [75.0, 3.0], [75.0, 6.0], [76.0, 9.0], [76.0, 12.0], [76.0, 15.0], [76.0, 18.0], [76.0, 21.0], [76.0, 24.0], [76.0, 27.0], [76.0, 30.0], [76.0, 33.0], [76.0, 36.0], [76.0, 39.0], [76.0, 41.5], [78.0, 0.0], [78.0, 3.0], [78.0, 6.0], [79.0, 9.0], [79.0, 12.0], [79.0, 15.0], [79.0, 18.0], [79.0, 21.0], [79.0, 24.0], [79.0, 27.0], [79.0, 30.0], [79.0, 33.0], [79.0, 36.0], [79.0, 39.0], [79.0, 41.5], [81.0, 0.0], [81.0, 3.0], [81.0, 6.0], [82.0, 9.0], [82.0, 12.0], [82.0, 15.0], [82.0, 18.0], [82.0, 21.0], [82.0, 24.0], [82.0, 27.0], [82.0, 30.0], [82.0, 33.0], [82.0, 36.0], [82.0, 39.0], [82.0, 41.5], [84.0, 0.0], [84.0, 3.0], [84.0, 6.0], [85.0, 9.0], [85.0, 12.0], [85.0, 15.0], [85.0, 18.0], [85.0, 21.0], [85.0, 24.0], [85.0, 27.0], [85.0, 30.0], [85.0, 33.0], [85.0, 36.0], [85.0, 39.0], [85.0, 41.5], [87.0, 0.0], [87.0, 3.0], [87.0, 6.0], [88.0, 9.0], [88.0, 12.0], [88.0, 15.0], [88.0, 18.0], [88.0, 21.0], [88.0, 24.0], [88.0, 27.0], [88.0, 30.0], [88.0, 33.0], [88.0, 36.0], [88.0, 39.0], [88.0, 41.5], [90.0, 0.0], [90.0, 3.0], [90.0, 6.0], [91.0, 9.0], [91.0, 12.0], [91.0, 15.0], [91.0, 18.0], [91.0, 21.0], [91.0, 24.0], [91.0, 27.0], [91.0, 30.0], [91.0, 33.0], [91.0, 36.0], [91.0, 39.0], [91.0, 41.5], [93.0, 0.0], [93.0, 3.0], [93.0, 6.0], [94.0, 9.0], [94.0, 12.0], [94.0, 15.0], [94.0, 18.0], [94.0, 21.0], [94.0, 24.0], [94.0, 27.0], [94.0, 30.0], [94.0, 33.0], [94.0, 36.0], [94.0, 39.0], [94.0, 41.5], [96.0, 0.0], [96.0, 3.0], [96.0, 6.0], [97.0, 9.0], [97.0, 12.0], [97.0, 15.0], [97.0, 18.0], [97.0, 21.0], [97.0, 24.0], [97.0, 27.0], [97.0, 30.0], [97.0, 33.0], [97.0, 36.0], [97.0, 39.0], [97.0, 41.5], [99.0, 0.0], [99.0, 3.0], [99.0, 6.0], [100.0, 9.0], [100.0, 12.0], [100.0, 15.0], [100.0, 18.0], [100.0, 21.0], [100.0, 24.0], [100.0, 27.0], [100.0, 30.0], [100.0, 33.0], [100.0, 36.0], [100.0, 39.0], [100.0, 41.5], [102.0, 0.0], [102.0, 3.0], [102.0, 6.0], [103.0, 9.0], [103.0, 12.0], [103.0, 15.0], [103.0, 18.0], [103.0, 21.0], [103.0, 24.0], [103.0, 27.0], [103.0, 30.0], [103.0, 33.0], [103.0, 36.0], [103.0, 39.0], [103.0, 41.5], [105.0, 0.0], [105.0, 3.0], [105.0, 6.0], [106.0, 9.0], [106.0, 12.0], [106.0, 15.0], [106.0, 18.0], [106.0, 21.0], [106.0, 24.0], [106.0, 27.0], [106.0, 30.0], [106.0, 33.0], [106.0, 36.0], [106.0, 39.0], [106.0, 41.5], [108.0, 0.0], [108.0, 3.0], [108.0, 6.0], [109.0, 9.0], [109.0, 12.0], [109.0, 15.0], [109.0, 18.0], [109.0, 21.0], [109.0, 24.0], [109.0, 27.0], [109.0, 30.0], [109.0, 33.0], [109.0, 36.0], [109.0, 39.0], [109.0, 41.5], [111.0, 0.0], [111.0, 3.0], [111.0, 6.0], [111.0, 9.0], [111.0, 12.0], [111.0, 15.0], [111.0, 18.0], [111.0, 21.0], [111.0, 24.0], [111.0, 27.0], [111.0, 30.0], [111.0, 33.0], [111.0, 36.0], [111.0, 39.0], [111.0, 41.5], [114.0, 0.0], [114.0, 3.0], [114.0, 6.0], [117.0, 0.0], [117.0, 3.0], [117.0, 6.0], [120.0, 0.0], [120.0, 3.0], [120.0, 6.0], [123.0, 0.0], [123.0, 3.0], [123.0, 6.0], [126.0, 0.0], [126.0, 3.0], [126.0, 6.0], [129.0, 0.0], [129.0, 3.0], [129.0, 6.0], [132.0, 0.0], [132.0, 3.0], [132.0, 6.0], [135.0, 0.0], [135.0, 3.0], [135.0, 6.0], [137.5, 0.0], [137.5, 3.0], [137.5, 6.0]], + 'resttwo': [[0.0, 0.0], [0.0, 12.0], [1.0, 2.8333333333333144], [1.0, 5.833333333333314], [1.0, 8.833333333333314], [3.0, -0.16666666666668561], [3.0, 11.833333333333314], [4.0, 2.8333333333333144], [4.0, 5.833333333333314], [4.0, 8.833333333333314], [6.0, -0.16666666666668561], [6.0, 11.833333333333314], [7.0, 2.8333333333333144], [7.0, 5.833333333333314], [7.0, 8.833333333333314], [9.0, -0.16666666666668561], [9.0, 11.833333333333314], [10.0, 2.8333333333333144], [10.0, 5.833333333333314], [10.0, 8.833333333333314], [12.0, -0.16666666666668561], [12.0, 11.833333333333314], [13.0, 2.8333333333333144], [13.0, 5.833333333333314], [13.0, 8.833333333333314], [15.0, -0.16666666666668561], [15.0, 11.833333333333314], [16.0, 2.8333333333333144], [16.0, 5.833333333333314], [16.0, 8.833333333333314], [18.0, -0.16666666666668561], [18.0, 11.833333333333314], [19.0, 2.8333333333333144], [19.0, 5.833333333333314], [19.0, 8.833333333333314], [21.0, -0.16666666666668561], [21.0, 11.833333333333314], [22.0, 2.8333333333333144], [22.0, 5.833333333333314], [22.0, 8.833333333333314], [24.0, -0.16666666666668561], [24.0, 11.833333333333314], [25.0, 2.8333333333333144], [25.0, 5.833333333333314], [25.0, 8.833333333333314], [27.0, -0.16666666666668561], [27.0, 11.833333333333314], [28.0, 2.8333333333333144], [28.0, 5.833333333333314], [28.0, 8.833333333333314], [30.200000000000045, 0.23333333333329165], [30.200000000000045, 11.833333333333314], [31.0, -31.166666666666686], [31.0, -28.166666666666686], [31.0, -25.166666666666686], [31.0, -22.166666666666686], [31.0, -19.166666666666686], [31.0, -16.166666666666686], [31.0, -13.166666666666686], [31.0, -10.166666666666686], [31.0, -7.166666666666686], [31.0, -4.166666666666686], [31.0, 4.833333333333314], [31.0, 7.833333333333314], [33.0, -1.1666666666666856], [33.0, 1.8333333333333144], [33.0, 11.833333333333314], [34.0, -31.166666666666686], [34.0, -28.166666666666686], [34.0, -25.166666666666686], [34.0, -22.166666666666686], [34.0, -19.166666666666686], [34.0, -16.166666666666686], [34.0, -13.166666666666686], [34.0, -10.166666666666686], [34.0, -7.166666666666686], [34.0, -4.166666666666686], [34.0, 4.833333333333314], [34.0, 7.833333333333314], [36.0, -1.1666666666666856], [36.0, 1.8333333333333144], [36.0, 11.833333333333314], [37.0, -31.166666666666686], [37.0, -28.166666666666686], [37.0, -25.166666666666686], [37.0, -22.166666666666686], [37.0, -19.166666666666686], [37.0, -16.166666666666686], [37.0, -13.166666666666686], [37.0, -10.166666666666686], [37.0, -7.166666666666686], [37.0, -4.166666666666686], [37.0, 4.833333333333314], [37.0, 7.833333333333314], [39.0, -1.1666666666666856], [39.0, 1.8333333333333144], [39.0, 11.833333333333314], [40.0, -31.166666666666686], [40.0, -28.166666666666686], [40.0, -25.166666666666686], [40.0, -22.166666666666686], [40.0, -19.166666666666686], [40.0, -16.166666666666686], [40.0, -13.166666666666686], [40.0, -10.166666666666686], [40.0, -7.166666666666686], [40.0, -4.166666666666686], [40.0, 4.833333333333314], [40.0, 7.833333333333314], [42.0, -1.1666666666666856], [42.0, 1.8333333333333144], [42.0, 11.833333333333314], [43.0, -31.166666666666686], [43.0, -28.166666666666686], [43.0, -25.166666666666686], [43.0, -22.166666666666686], [43.0, -19.166666666666686], [43.0, -16.166666666666686], [43.0, -13.166666666666686], [43.0, -10.166666666666686], [43.0, -7.166666666666686], [43.0, -4.166666666666686], [43.0, 4.833333333333314], [43.0, 7.833333333333314], [45.0, -1.1666666666666856], [45.0, 1.8333333333333144], [45.0, 11.833333333333314], [46.0, -31.166666666666686], [46.0, -28.166666666666686], [46.0, -25.166666666666686], [46.0, -22.166666666666686], [46.0, -19.166666666666686], [46.0, -16.166666666666686], [46.0, -13.166666666666686], [46.0, -10.166666666666686], [46.0, -7.166666666666686], [46.0, -4.166666666666686], [46.0, 4.833333333333314], [46.0, 7.833333333333314], [48.0, -1.1666666666666856], [48.0, 1.8333333333333144], [48.0, 11.833333333333314], [49.0, -31.166666666666686], [49.0, -28.166666666666686], [49.0, -25.166666666666686], [49.0, -22.166666666666686], [49.0, -19.166666666666686], [49.0, -16.166666666666686], [49.0, -13.166666666666686], [49.0, -10.166666666666686], [49.0, -7.166666666666686], [49.0, -4.166666666666686], [49.0, 4.833333333333314], [49.0, 7.833333333333314], [51.0, -1.1666666666666856], [51.0, 1.8333333333333144], [51.0, 11.833333333333314], [52.0, -31.166666666666686], [52.0, -28.166666666666686], [52.0, -25.166666666666686], [52.0, -22.166666666666686], [52.0, -19.166666666666686], [52.0, -16.166666666666686], [52.0, -13.166666666666686], [52.0, -10.166666666666686], [52.0, -7.166666666666686], [52.0, -4.166666666666686], [52.0, 4.833333333333314], [52.0, 7.833333333333314], [54.0, -1.1666666666666856], [54.0, 1.8333333333333144], [54.0, 11.833333333333314], [55.0, -31.166666666666686], [55.0, -28.166666666666686], [55.0, -25.166666666666686], [55.0, -22.166666666666686], [55.0, -19.166666666666686], [55.0, -16.166666666666686], [55.0, -13.166666666666686], [55.0, -10.166666666666686], [55.0, -7.166666666666686], [55.0, -4.166666666666686], [55.0, 4.833333333333314], [55.0, 7.833333333333314], [57.0, -1.1666666666666856], [57.0, 1.8333333333333144], [57.0, 11.833333333333314], [58.0, -31.166666666666686], [58.0, -28.166666666666686], [58.0, -25.166666666666686], [58.0, -22.166666666666686], [58.0, -19.166666666666686], [58.0, -16.166666666666686], [58.0, -13.166666666666686], [58.0, -10.166666666666686], [58.0, -7.166666666666686], [58.0, -4.166666666666686], [58.0, 4.833333333333314], [58.0, 7.833333333333314], [60.0, -1.1666666666666856], [60.0, 1.8333333333333144], [60.0, 11.833333333333314], [61.0, -31.166666666666686], [61.0, -28.166666666666686], [61.0, -25.166666666666686], [61.0, -22.166666666666686], [61.0, -19.166666666666686], [61.0, -16.166666666666686], [61.0, -13.166666666666686], [61.0, -10.166666666666686], [61.0, -7.166666666666686], [61.0, -4.166666666666686], [61.0, 4.833333333333314], [61.0, 7.833333333333314], [63.0, -1.1666666666666856], [63.0, 1.8333333333333144], [63.0, 11.833333333333314], [64.0, -31.166666666666686], [64.0, -28.166666666666686], [64.0, -25.166666666666686], [64.0, -22.166666666666686], [64.0, -19.166666666666686], [64.0, -16.166666666666686], [64.0, -13.166666666666686], [64.0, -10.166666666666686], [64.0, -7.166666666666686], [64.0, -4.166666666666686], [64.0, 4.833333333333314], [64.0, 7.833333333333314], [66.0, -1.1666666666666856], [66.0, 1.8333333333333144], [66.0, 11.833333333333314], [67.0, -31.166666666666686], [67.0, -28.166666666666686], [67.0, -25.166666666666686], [67.0, -22.166666666666686], [67.0, -19.166666666666686], [67.0, -16.166666666666686], [67.0, -13.166666666666686], [67.0, -10.166666666666686], [67.0, -7.166666666666686], [67.0, -4.166666666666686], [67.0, 4.833333333333314], [67.0, 7.833333333333314], [69.0, -1.1666666666666856], [69.0, 1.8333333333333144], [69.0, 11.833333333333314], [70.0, -31.166666666666686], [70.0, -28.166666666666686], [70.0, -25.166666666666686], [70.0, -22.166666666666686], [70.0, -19.166666666666686], [70.0, -16.166666666666686], [70.0, -13.166666666666686], [70.0, -10.166666666666686], [70.0, -7.166666666666686], [70.0, -4.166666666666686], [70.0, 4.833333333333314], [70.0, 7.833333333333314], [72.0, -1.1666666666666856], [72.0, 1.8333333333333144], [72.0, 11.833333333333314], [73.0, -31.166666666666686], [73.0, -28.166666666666686], [73.0, -25.166666666666686], [73.0, -22.166666666666686], [73.0, -19.166666666666686], [73.0, -16.166666666666686], [73.0, -13.166666666666686], [73.0, -10.166666666666686], [73.0, -7.166666666666686], [73.0, -4.166666666666686], [73.0, 4.833333333333314], [73.0, 7.833333333333314], [75.0, -1.1666666666666856], [75.0, 1.8333333333333144], [75.0, 11.833333333333314], [76.0, -31.166666666666686], [76.0, -28.166666666666686], [76.0, -25.166666666666686], [76.0, -22.166666666666686], [76.0, -19.166666666666686], [76.0, -16.166666666666686], [76.0, -13.166666666666686], [76.0, -10.166666666666686], [76.0, -7.166666666666686], [76.0, -4.166666666666686], [76.0, 4.833333333333314], [76.0, 7.833333333333314], [78.0, -1.1666666666666856], [78.0, 1.8333333333333144], [78.0, 11.833333333333314], [79.0, -31.166666666666686], [79.0, -28.166666666666686], [79.0, -25.166666666666686], [79.0, -22.166666666666686], [79.0, -19.166666666666686], [79.0, -16.166666666666686], [79.0, -13.166666666666686], [79.0, -10.166666666666686], [79.0, -7.166666666666686], [79.0, -4.166666666666686], [79.0, 4.833333333333314], [79.0, 7.833333333333314], [81.0, -1.1666666666666856], [81.0, 1.8333333333333144], [81.0, 11.833333333333314], [82.0, -31.166666666666686], [82.0, -28.166666666666686], [82.0, -25.166666666666686], [82.0, -22.166666666666686], [82.0, -19.166666666666686], [82.0, -16.166666666666686], [82.0, -13.166666666666686], [82.0, -10.166666666666686], [82.0, -7.166666666666686], [82.0, -4.166666666666686], [82.0, 4.833333333333314], [82.0, 7.833333333333314], [84.0, -1.1666666666666856], [84.0, 1.8333333333333144], [84.0, 11.833333333333314], [85.0, -31.166666666666686], [85.0, -28.166666666666686], [85.0, -25.166666666666686], [85.0, -22.166666666666686], [85.0, -19.166666666666686], [85.0, -16.166666666666686], [85.0, -13.166666666666686], [85.0, -10.166666666666686], [85.0, -7.166666666666686], [85.0, -4.166666666666686], [85.0, 4.833333333333314], [85.0, 7.833333333333314], [87.0, -1.1666666666666856], [87.0, 1.8333333333333144], [87.0, 11.833333333333314], [88.0, -31.166666666666686], [88.0, -28.166666666666686], [88.0, -25.166666666666686], [88.0, -22.166666666666686], [88.0, -19.166666666666686], [88.0, -16.166666666666686], [88.0, -13.166666666666686], [88.0, -10.166666666666686], [88.0, -7.166666666666686], [88.0, -4.166666666666686], [88.0, 4.833333333333314], [88.0, 7.833333333333314], [90.0, -1.1666666666666856], [90.0, 1.8333333333333144], [90.0, 11.833333333333314], [91.0, -31.166666666666686], [91.0, -28.166666666666686], [91.0, -25.166666666666686], [91.0, -22.166666666666686], [91.0, -19.166666666666686], [91.0, -16.166666666666686], [91.0, -13.166666666666686], [91.0, -10.166666666666686], [91.0, -7.166666666666686], [91.0, -4.166666666666686], [91.0, 4.833333333333314], [91.0, 7.833333333333314], [93.0, -1.1666666666666856], [93.0, 1.8333333333333144], [93.0, 11.833333333333314], [94.0, -31.166666666666686], [94.0, -28.166666666666686], [94.0, -25.166666666666686], [94.0, -22.166666666666686], [94.0, -19.166666666666686], [94.0, -16.166666666666686], [94.0, -13.166666666666686], [94.0, -10.166666666666686], [94.0, -7.166666666666686], [94.0, -4.166666666666686], [94.0, 4.833333333333314], [94.0, 7.833333333333314], [96.0, -1.1666666666666856], [96.0, 1.8333333333333144], [96.0, 11.833333333333314], [97.0, -31.166666666666686], [97.0, -28.166666666666686], [97.0, -25.166666666666686], [97.0, -22.166666666666686], [97.0, -19.166666666666686], [97.0, -16.166666666666686], [97.0, -13.166666666666686], [97.0, -10.166666666666686], [97.0, -7.166666666666686], [97.0, -4.166666666666686], [97.0, 4.833333333333314], [97.0, 7.833333333333314], [99.0, -1.1666666666666856], [99.0, 1.8333333333333144], [99.0, 11.833333333333314], [100.0, -31.166666666666686], [100.0, -28.166666666666686], [100.0, -25.166666666666686], [100.0, -22.166666666666686], [100.0, -19.166666666666686], [100.0, -16.166666666666686], [100.0, -13.166666666666686], [100.0, -10.166666666666686], [100.0, -7.166666666666686], [100.0, -4.166666666666686], [100.0, 4.833333333333314], [100.0, 7.833333333333314], [102.0, -1.1666666666666856], [102.0, 1.8333333333333144], [102.0, 11.833333333333314], [103.0, -31.166666666666686], [103.0, -28.166666666666686], [103.0, -25.166666666666686], [103.0, -22.166666666666686], [103.0, -19.166666666666686], [103.0, -16.166666666666686], [103.0, -13.166666666666686], [103.0, -10.166666666666686], [103.0, -7.166666666666686], [103.0, -4.166666666666686], [103.0, 4.833333333333314], [103.0, 7.833333333333314], [105.0, -1.1666666666666856], [105.0, 1.8333333333333144], [105.0, 11.833333333333314], [106.0, -31.166666666666686], [106.0, -28.166666666666686], [106.0, -25.166666666666686], [106.0, -22.166666666666686], [106.0, -19.166666666666686], [106.0, -16.166666666666686], [106.0, -13.166666666666686], [106.0, -10.166666666666686], [106.0, -7.166666666666686], [106.0, -4.166666666666686], [106.0, 4.833333333333314], [106.0, 7.833333333333314], [108.0, -1.1666666666666856], [108.0, 1.8333333333333144], [108.0, 11.833333333333314], [108.5, -31.166666666666686], [108.5, -28.166666666666686], [108.5, -25.166666666666686], [108.5, -22.166666666666686], [108.5, -19.166666666666686], [108.5, -16.166666666666686], [108.5, -13.166666666666686], [108.5, -10.166666666666686], [108.5, -7.166666666666686], [108.5, -4.166666666666686], [109.25, 4.583333333333314], [109.0, 8.166666666666629], [111.0, -0.16666666666668561], [111.0, 11.833333333333314], [112.0, 2.8333333333333144], [112.0, 5.833333333333314], [112.0, 8.833333333333314], [114.0, -0.16666666666668561], [114.0, 11.833333333333314], [115.0, 2.8333333333333144], [115.0, 5.833333333333314], [115.0, 8.833333333333314], [117.0, -0.16666666666668561], [117.0, 11.833333333333314], [118.0, 2.8333333333333144], [118.0, 5.833333333333314], [118.0, 8.833333333333314], [120.0, -0.16666666666668561], [120.0, 11.833333333333314], [121.0, 2.8333333333333144], [121.0, 5.833333333333314], [121.0, 8.833333333333314], [123.0, -0.16666666666668561], [123.0, 11.833333333333314], [124.0, 2.8333333333333144], [124.0, 5.833333333333314], [124.0, 8.833333333333314], [126.0, -0.16666666666668561], [126.0, 11.833333333333314], [127.0, 2.8333333333333144], [127.0, 5.833333333333314], [127.0, 8.833333333333314], [129.0, -0.16666666666668561], [129.0, 11.833333333333314], [130.0, 2.8333333333333144], [130.0, 5.833333333333314], [130.0, 8.833333333333314], [132.0, -0.16666666666668561], [132.0, 11.833333333333314], [133.0, 2.8333333333333144], [133.0, 5.833333333333314], [133.0, 8.833333333333314], [135.0, -0.16666666666668561], [135.0, 11.833333333333314], [136.0, 2.8333333333333144], [136.0, 5.833333333333314], [136.0, 8.833333333333314], [137.5, -0.16666666666668561], [137.5, 11.833333333333314], [138.0, 2.8333333333333144], [138.0, 5.833333333333314], [138.0, 8.833333333333314]], + 'restone': [[0.0, 0.0], [31.456310679611647, 24.902912621359235], [18.349514563106823, 15.728155339805824], [15.72815533980588, 17.038834951456295], [28.834951456310705, 27.524271844660177], [27.524271844660234, 30.145631067961176], [13.106796116504825, 20.970873786407765], [10.485436893203882, 24.902912621359235], [24.90291262135929, 34.077669902912646], [22.281553398058236, 36.69902912621359], [6.553398058252469, 27.524271844660177], [3.932038834951527, 30.145631067961176], [19.660194174757294, 39.32038834951459], [18.349514563106823, 41.94174757281553], [2.621359223300942, 34.077669902912646], [0.0, 35.38834951456312], [15.72815533980588, 44.56310679611653], [14.41747572815541, 47.18446601941747], [-3.9320388349514133, 36.69902912621359], [-6.553398058252355, 39.32038834951459], [14.41747572815541, 51.11650485436894], [-6.553398058252355, 43.252427184466], [15.72815533980588, 55.04854368932041], [17.03883495145635, 57.66990291262135], [-3.9320388349514133, 45.873786407767], [1.310679611650471, 48.49514563106794], [5.242718446601998, 51.11650485436894], [10.485436893203882, 53.73786407766988], [14.41747572815541, 56.35922330097088], [30.145631067961176, 69.4660194174757], [26.213592233009763, 72.0873786407767], [15.72815533980588, 64.22330097087377], [11.796116504854353, 64.22330097087377], [22.281553398058236, 72.0873786407767], [19.660194174757294, 74.7087378640777], [6.553398058252469, 62.912621359223294], [2.621359223300942, 64.22330097087377], [15.72815533980588, 76.01941747572818], [14.41747572815541, 79.95145631067965], [-1.310679611650471, 65.5339805825243], [-3.9320388349514133, 66.84466019417476], [13.106796116504825, 82.57281553398059], [14.41747572815541, 86.50485436893206], [-5.242718446601884, 70.77669902912623], [-5.242718446601884, 74.7087378640777], [14.41747572815541, 89.126213592233], [14.41747572815541, 93.05825242718447], [-3.9320388349514133, 78.64077669902912], [-2.621359223300942, 81.26213592233012], [13.106796116504825, 82.57281553398059], [14.41747572815541, 85.19417475728159], [0.0, 85.19417475728159], [2.621359223300942, 89.126213592233], [15.72815533980588, 90.43689320388353], [15.72815533980588, 95.67961165048547], [3.932038834951527, 93.05825242718447], [7.86407766990294, 95.67961165048547], [18.349514563106823, 98.30097087378647], [19.660194174757294, 102.23300970873788], [27.524271844660234, 110.09708737864082]], + 'resthalf': [[0.0, 0.0], [-2.621359223300942, -3.932038834951527], [-3.9320388349514133, -7.86407766990294], [-7.86407766990294, -9.174757281553411], [-14.417475728155296, -9.174757281553411], [-15.728155339805767, -3.932038834951527], [-17.03883495145635, 0.0], [-14.417475728155296, 5.242718446601884], [-11.796116504854353, 7.86407766990294], [-7.86407766990294, 7.86407766990294], [0.0, 6.553398058252469], [-3.9320388349514133, 6.553398058252469], [-2.621359223300942, -1.310679611650471], [-7.86407766990294, -3.932038834951527], [-9.174757281553411, -3.932038834951527], [-11.796116504854353, -2.621359223300942], [-11.796116504854353, 1.310679611650471], [-7.86407766990294, 5.242718446601884], [-3.9320388349514133, 2.621359223300942], [-7.86407766990294, 0.0], [-3.9320388349514133, -1.310679611650471], [-14.417475728155296, -6.553398058252469], [0.0, 5.242718446601884], [5.242718446601998, 6.553398058252469], [9.174757281553411, 3.9320388349514133], [13.106796116504825, 0.0], [15.72815533980588, -3.932038834951527], [-5.242718446601884, 55.048543689320354]], + 'restquarter': [[0.0, 0.0], [0.0, -2.621359223301056], [-1.310679611650471, -5.242718446601998], [-3.9320388349514133, -6.553398058252469], [-3.9320388349514133, -7.86407766990294], [-6.553398058252469, -7.86407766990294], [-10.485436893203882, -7.86407766990294], [-13.106796116504825, -6.553398058252469], [-15.72815533980588, -3.932038834951527], [-14.417475728155296, -1.310679611650471], [-11.796116504854353, 1.310679611650471], [-6.553398058252469, 1.310679611650471], [-3.9320388349514133, 1.310679611650471], [-5.242718446601998, -1.310679611650471], [-5.242718446601998, -3.932038834951527], [-11.796116504854353, -3.932038834951527], [-7.86407766990294, -3.932038834951527], [-9.174757281553411, 2.621359223300942], [-9.174757281553411, 0.0], [-11.796116504854353, -2.621359223301056], [1.310679611650471, -2.621359223301056], [-3.9320388349514133, -3.932038834951527], [-2.621359223300942, -1.310679611650471], [1.310679611650471, 0.0], [5.242718446601884, 0.0], [10.485436893203882, -1.310679611650471], [15.728155339805767, -7.86407766990294], [3.9320388349514133, 23.592233009708707], [-1.310679611650471, 27.52427184466012], [-6.553398058252469, 27.52427184466012], [-13.106796116504825, 26.21359223300965], [-13.106796116504825, 24.902912621359178], [-15.72815533980588, 20.970873786407765], [-20.970873786407765, 19.660194174757294], [-24.902912621359178, 19.660194174757294], [-30.145631067961176, 22.281553398058236], [-28.834951456310705, 24.902912621359178], [-26.213592233009763, 28.834951456310705], [-22.281553398058236, 28.834951456310705], [-18.349514563106823, 28.834951456310705], [-15.72815533980588, 26.21359223300965], [-17.03883495145635, 22.281553398058236], [-23.592233009708707, 22.281553398058236], [-24.902912621359178, 23.592233009708707], [-22.281553398058236, 24.902912621359178], [-18.349514563106823, 24.902912621359178], [-19.660194174757294, 22.281553398058236], [-24.902912621359178, 22.281553398058236], [-27.524271844660234, 20.970873786407765], [-23.592233009708707, 19.660194174757294], [-18.349514563106823, 19.660194174757294], [-17.03883495145635, 23.592233009708707], [-17.03883495145635, 28.834951456310705], [-15.72815533980588, 30.145631067961176], [-10.485436893203882, 30.145631067961176], [-6.553398058252469, 28.834951456310705], [-1.310679611650471, 27.52427184466012], [3.9320388349514133, 23.592233009708707], [-11.796116504854353, 65.53398058252424]], + 'resteighth': [[0.0, 0.0], [-2.621359223300942, -2.621359223300942], [-9.174757281553411, -3.9320388349514133], [-13.106796116504825, -3.9320388349514133], [-18.349514563106823, -1.310679611650471], [-23.592233009708707, 0.0], [-23.592233009708707, 3.9320388349514133], [-20.970873786407765, 5.242718446601884], [-18.349514563106823, 7.86407766990294], [-11.796116504854353, 9.174757281553411], [-6.553398058252469, 7.86407766990294], [-1.310679611650471, 9.174757281553411], [1.310679611650471, 6.553398058252469], [-7.86407766990294, 0.0], [-13.106796116504825, 0.0], [-17.03883495145635, 2.621359223300942], [-11.796116504854353, 6.553398058252469], [-1.310679611650471, 5.242718446601884], [-2.621359223300942, 0.0], [-6.553398058252469, 3.9320388349514133], [-14.41747572815541, 3.9320388349514133], [-9.174757281553411, 3.9320388349514133], [-11.796116504854353, 3.9320388349514133], [-15.72815533980588, 7.86407766990294], [-6.553398058252469, 9.174757281553411], [-3.932038834951527, 6.553398058252469], [-3.932038834951527, 3.9320388349514133], [1.310679611650471, 9.174757281553411], [5.242718446601884, 7.86407766990294], [11.796116504854353, 5.242718446601884], [18.349514563106823, -1.310679611650471], [7.86407766990294, 32.76699029126212], [3.9320388349514133, 34.07766990291259], [-7.86407766990294, 36.69902912621353], [-13.106796116504825, 36.69902912621353], [-15.72815533980588, 32.76699029126212], [-15.72815533980588, 27.524271844660234], [-19.660194174757294, 27.524271844660234], [-26.213592233009763, 24.902912621359178], [-30.145631067961176, 27.524271844660234], [-35.388349514563174, 28.834951456310705], [-36.699029126213645, 31.456310679611647], [-36.699029126213645, 35.38834951456306], [-34.07766990291259, 36.69902912621353], [-28.834951456310705, 39.32038834951459], [-23.592233009708707, 39.32038834951459], [-17.03883495145635, 39.32038834951459], [-20.970873786407765, 34.07766990291259], [-20.970873786407765, 31.456310679611647], [-31.456310679611647, 31.456310679611647], [-31.456310679611647, 34.07766990291259], [-28.834951456310705, 34.07766990291259], [-19.660194174757294, 34.07766990291259], [-26.213592233009763, 31.456310679611647], [-26.213592233009763, 31.456310679611647], [-23.592233009708707, 36.69902912621353], [-23.592233009708707, 28.834951456310705], [-26.213592233009763, 30.145631067961176], [-22.281553398058236, 34.07766990291259], [-19.660194174757294, 36.69902912621353], [-7.86407766990294, 36.69902912621353], [3.9320388349514133, 34.07766990291259], [7.86407766990294, 32.76699029126212], [-6.553398058252469, 65.53398058252424], [-13.106796116504825, 65.53398058252424], [-19.660194174757294, 66.84466019417471], [-26.213592233009763, 66.84466019417471], [-28.834951456310705, 62.912621359223294], [-30.145631067961176, 58.98058252427188], [-34.07766990291259, 57.669902912621296], [-40.63106796116506, 56.359223300970825], [-45.87378640776706, 57.669902912621296], [-51.11650485436894, 62.912621359223294], [-45.87378640776706, 66.84466019417471], [-40.63106796116506, 68.15533980582518], [-34.07766990291259, 68.15533980582518], [-28.834951456310705, 68.15533980582518], [-32.76699029126212, 65.53398058252424], [-36.699029126213645, 61.60194174757282], [-44.56310679611647, 61.60194174757282], [-44.56310679611647, 61.60194174757282], [-39.32038834951459, 61.60194174757282], [-39.32038834951459, 65.53398058252424], [-31.456310679611647, 64.22330097087377], [-34.07766990291259, 61.60194174757282], [-45.87378640776706, 58.98058252427188], [-45.87378640776706, 61.60194174757282], [-41.94174757281553, 65.53398058252424], [-36.699029126213645, 65.53398058252424], [-36.699029126213645, 56.359223300970825], [-40.63106796116506, 58.98058252427188], [-43.252427184466, 58.98058252427188], [-48.495145631068, 60.29126213592235], [-39.32038834951459, 66.84466019417471], [-19.660194174757294, 66.84466019417471], [-10.485436893203882, 64.22330097087377], [-6.553398058252469, 61.60194174757282], [-24.90291262135929, 107.47572815533977]] +} \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/textrender.js b/src/extensions/scratch3_musiccreation/textrender.js new file mode 100644 index 00000000000..3e9cd57a343 --- /dev/null +++ b/src/extensions/scratch3_musiccreation/textrender.js @@ -0,0 +1,122 @@ +const Cast = require('../../util/cast'); +const Clone = require('../../util/clone'); +const RenderedTarget = require('../../sprites/rendered-target'); +const uid = require('../../util/uid'); +const StageLayering = require('../../engine/stage-layering'); +const MathUtil = require('../../util/math-util'); +const log = require('../../util/log'); +const letters = require('./letters'); + + +class TextRender { + constructor (runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; + + this.letters = { + 'a': letters.a, + 'b': letters.b, + 'c': letters.c, + 'd': letters.d, + 'e': letters.e, + 'f': letters.f, + 'g': letters.g, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'k': letters.k, + 'l': letters.l, + 'm': letters.m, + 'n': letters.n, + 'o': letters.o, + 'p': letters.p, + 'q': letters.q, + 'r': letters.r, + 's': letters.s, + 't': letters.t, + 'u': letters.u, + 'v': letters.v, + 'w': letters.w, + 'x': letters.x, + 'y': letters.y, + 'z': letters.z + } + + this.spacing = { + 'a': 59.03383897316219, + 'b': 35.666277712952166, + 'c': 55.59820426487096, + 'd': 51.65460910151694, + 'e': 33.821470245040814, + 'f': 35.05134189031503, + 'g': 62.10851808634772, + 'h': 51.65460910151691, + 'i': 0.0, + 'j': 27.057176196032685, + 'k': 44.275379229871646, + 'l': 33.20653442240376, + 'm': 76.86697782963824, + 'n': 57.803967327887975, + 'o': 62.108518086347715, + 'p': 35.05134189031503, + 'q': 62.72345390898482, + 'r': 34.305274971941685, + 's': 39.62850729517402, + 't': 51.03967327887982, + 'u': 50.42473745624271, + 'v': 52.88448074679113, + 'w': 88.55075845974329, + 'x': 45.50525087514586, + 'y': 47.350058343057185, + 'z': 55.959159859976694 + } + + } + + drawString (str, xstart, ystart, args, util) { + var xstart = -200; + var ystart = -150; + for (var i in str) { + log.log(i); + xstart += 5; + if (i >= 1) { + xstart += this.spacing[str[i-1]]/5; + } + this.drawLetter(str[i], xstart, ystart, args, util); + } + + } + + drawLetter(letter, xstart, ystart, args, util) { + letter = letters[letter]; + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0]/5 + xstart; + y = -coord[1]/5 + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0]/5 + xstart+1; + y = -coord[1]/5 + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + } + + + + +} + +module.exports = TextRender; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/vizhelpers.js b/src/extensions/scratch3_musiccreation/vizhelpers.js new file mode 100644 index 00000000000..fc227cc4997 --- /dev/null +++ b/src/extensions/scratch3_musiccreation/vizhelpers.js @@ -0,0 +1,486 @@ +const Clone = require('../../util/clone'); +const log = require('../../util/log'); +const Cast = require('../../util/cast'); +const Color = require('../../util/color'); +const RenderedTarget = require('../../sprites/rendered-target'); +const StageLayering = require('../../engine/stage-layering'); + +const symbols = require('./symbols'); +const SheetMusicHelper = require('./sheetmusic'); +const WaveformHelper = require('./waveform'); +const SpectrogramHelper = require('./spectrogram'); +const FFTHelper = require('./fft'); +const { updateVariableIdentifiers } = require('../../util/variable-util'); +const { e } = require('./letters'); +const BlockUtility = require('../../engine/block-utility'); + +var harmonics; + +class VizHelpers { + constructor(runtime) { + this.runtime = runtime; + + this._count = 0; + this._visState = { status: false, mode: undefined }; + this._noteBuf = { sheet: [], wave: [], freq: [], freqs: [] }; + this._visNames = { 1: 'sheet', 2: 'wave', 3: 'freq', 4: 'freqs' }; + this._visLims = { 'sheet': 50, 'wave': 5, 'freq': 15, 'freqs': 15 }; + this._continuousScroll = { 'sheet': false, 'wave': true, 'freq': false, 'freqs': true }; + + /** + * The ID of the renderer Skin corresponding to the pen layer. + * @type {int} + * @private + */ + this._penSkinId = -1; + + /** + * The ID of the renderer Drawable corresponding to the pen layer. + * @type {int} + * @private + */ + this._penDrawableId = -1; + this.black = '0x000000'; + + this.noteList = []; + + this.axisStartX = -200; + this.axisStartY = -150; + this.xAxisLength = 400; + this.yAxisLength = 300; + + this.staffLength = 400; + this.staffStartX = -200; + this.staffStartY = 130; + this.staffWidth = 8; + + this.spaceBetween = 70; + + this.sheetMusicViz = new SheetMusicHelper(runtime); + this.waveformViz = new WaveformHelper(runtime); + this.spectrogramViz = new SpectrogramHelper(runtime); + this.fftViz = new FFTHelper(runtime); + + this.wavePen = -1; + this.musicPen = 2; + this.FFTPen = 3; + this.spectPen = 4; + + this._onTargetCreated = this._onTargetCreated.bind(this); + this.runtime.on('targetWasCreated', this._onTargetCreated); + + this._onTargetMoved = this._onTargetMoved.bind(this); + + harmonics = { + "Piano": [[1, 1], [2, 0.5]], + "Guitar": [[1, 1], [2, 0.25]], + "Bass": [[1, 1], [3, 0.5]], + "Cello": [[1, 1], [4, 0.5]], + "Saxophone": [[1, 1], [5, 0.5]], + "Clarinet": [[1, 1], [6, 0.5]], + "Synth": [[1, 1]] + } + + this.symbols = { + 15: [symbols.piano, symbols.piano], + 30: [symbols.piano], + 45: [symbols.mezzo, symbols.piano], + 60: [symbols.mezzo, symbols.forte], + 85: [symbols.forte], + 100: [symbols.forte, symbols.forte] + } + + this.spacing = { + 15: [10, 0], + 30: [10, 0], + 45: [5, 0], + 60: [10, 0], + 85: [10, 0], + 100: [10, 0] + } + } + + /** + * The key to load & store a target's music-related state. + * @type {string} + */ + static get VIZ_STATE_KEY() { + return 'Scratch.musicviz'; + } + + static get DEFAULT_PEN_STATE() { + return { + penDown: false, + color: 66.66, + saturation: 100, + brightness: 100, + transparency: 0, + _shade: 50, // Used only for legacy `change shade by` blocks + penAttributes: { + color4f: [0, 0, 1, 1], + diameter: 1 + } + }; + } + + /** + * The minimum and maximum allowed pen size. + * The maximum is twice the diagonal of the stage, so that even an + * off-stage sprite can fill it. + * @type {{min: number, max: number}} + */ + static get PEN_SIZE_RANGE() { + return { min: 1, max: 1200 }; + } + + /** + * When a music-playing Target is cloned, clone the music state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated(newTarget, sourceTarget) { + if (sourceTarget) { + const penState = sourceTarget.getCustomState(VizHelpers.VIZ_STATE_KEY); + if (penState) { + newTarget.setCustomState(VizHelpers.VIZ_STATE_KEY, Clone.simple(penState)); + if (penState.penDown) { + newTarget.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + } + } + + _onTargetMoved(target, oldX, oldY, isForce) { + // Only move the pen if the movement isn't forced (ie. dragged). + if (!isForce) { + let penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + const penState = this._getPenState(target); + this.runtime.renderer.penLine(penSkinId, penState.penAttributes, oldX, oldY, target.x, target.y); + this.runtime.requestRedraw(); + } + } + } + + _getPenLayerID() { + if (this._penSkinId < 0 && this.runtime.renderer) { + this._penSkinId = this.runtime.renderer.createPenSkin(); + this._penDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); + this.runtime.renderer.updateDrawableProperties(this._penDrawableId, { skinId: this._penSkinId }); + } + return this._penSkinId; + } + + _getWavePenLayerID() { + if (this.wavePen < 0 && this.runtime.renderer) { + this.wavePen = this.runtime.renderer.createPenSkin(); + this.wavePenDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); + this.runtime.renderer.updateDrawableProperties(this.wavePenDrawableId, { skinId: this.wavePen }); + } + return this.wavePen; + } + + _getPenState(target) { + let penState = target.getCustomState(VizHelpers.VIZ_STATE_KEY); + if (!penState) { + penState = Clone.simple(VizHelpers.DEFAULT_PEN_STATE); + target.setCustomState(VizHelpers.VIZ_STATE_KEY, penState); + } + return penState; + } + + toggleVisMode(args, util) { + const status = Cast.toNumber(args.STATUS); + const mode = Cast.toNumber(args.FORMAT); + const prev_mode = this._visState.mode; + const prev_status = this._visState.status; + const status_bool = !!status; + this._visState = { mode: mode, status: status_bool }; + if (!status_bool) { + this.clearAllViz(); + } else if (mode !== prev_mode || !prev_status) this.requestViz(null, util); + } + + clearAllViz() { + this.fftViz.clear(); + this.sheetMusicViz.clear(); + this.spectrogramViz.clear(); + this.waveformViz.clear(); + this.clear(); + } + + clearNoteBuffers() { + for (let b in this._noteBuf) { + this._noteBuf[b] = []; + } + } + + + clearSheetMusicList() { + this._noteBuf['sheet'].length = 0; + } + + /** + * + * @param {array} note - [freq, duration, instrument, volume] + */ + requestViz(note, util) { + if (this._visState['status']) { + this.processViz(note, util); + } + } + + + /** + * + * @param {[number,number,string,number] | null} note - if null, this represents the case where we are clearing the canvas + * otherwise, [note,duration,instrument name, volume] + * @param {BlockUtility} util + */ + processViz(note, util) { + const mode = this._visState['mode']; + const name = this._visNames[mode]; + const lim = this._visLims[name]; + const cont = this._continuousScroll[name]; + let buf = this._noteBuf[name]; + if (cont) { + while (buf.length + 1 >= lim) { + buf = buf.splice(1); + } + } else { + if (buf.length + 1 >= lim) buf = []; + } + + try { + note[4] = this._count++; + buf.push(note); + } catch (error) { + buf = []; + } + this._noteBuf[name] = buf; + const [x, y] = this.getXY(util); + switch (name) { + case 'wave': + this.testWaveformViz(buf, null, util); + break; + case 'freq': + this.testFreqViz(buf, null, util); + break; + case 'freqs': + this.testSpectViz(buf, null, util); + break; + default: + this.testSheetMusicViz(buf, null, util); + } + if (util && util.target) { + util.target.setXY(x, y); + } + } + + testWaveformViz(noteList, args, util) { + this.fftViz.clear(); + this.sheetMusicViz.clear(); + this.spectrogramViz.clear(); + this.waveformViz.clear(); + this.waveformViz.testWaveformViz(noteList, args, util); + } + + testSheetMusicViz(noteList, args, util) { + this.clear(); + this.fftViz.clear(); + this.sheetMusicViz.clear(); + this.spectrogramViz.clear(); + this.waveformViz.clear(); + log.log("VIZ", noteList); + this.sheetMusicViz.testSheetMusicViz(noteList, args, util, this); + } + + testFreqViz(noteList, args, util) { + this.fftViz.clear(); + this.sheetMusicViz.clear(); + this.spectrogramViz.clear(); + this.waveformViz.clear(); + this.fftViz.testFreqViz(noteList, args, util); + + } + + testSpectViz(noteList, args, util) { + this.fftViz.clear(); + this.sheetMusicViz.clear(); + this.spectrogramViz.clear(); + this.waveformViz.clear(); + this.spectrogramViz.testSpectViz(noteList, args, util); + + } + + drawFFT(args, util) { + freqs = []; + amps = []; + for (let i in this.noteList) { + midi = this.noteList[i][0]; + inst = this.noteList[i][2]; + harmonic = harmonics[inst]; + pitch = 2 ** ((midi - 69) / 12) * 440; + for (let i in harmonic) { + k = harmonic[i][0]; + coeff = harmonic[i][1]; + hPitch = pitch * k; + exists = false; + for (f in freqs) { + fr = freqs[f]; + if (Math.abs(hPitch - fr) < 10 ** -9) { + amps[f] += coeff; + exists = true; + } + } + if (!exists) { + amp = coeff; + freqs.push(hPitch); + amps.push(amp); + } + + } + } + maxFreq = Math.max(...freqs); + maxAmp = Math.max(...amps); + for (let i in freqs) { + freq = freqs[i]; + amp = amps[i]; + ratio = freq / maxFreq; + ratioAmp = amp / maxAmp; + this.penUp(args, util); + util.target.setXY(this.axisStartX + ratio * this.xAxisLength, this.axisStartY + this.yAxisLength / 2); + this.penDown(args, util); + util.target.setXY(this.axisStartX + ratio * this.xAxisLength, this.axisStartY + this.yAxisLength / 2 + this.yAxisLength / 2 * ratioAmp); + this.penUp(args, util); + } + } + + drawAxes(args, util) { + util.target.setXY(this.axisStartX, this.axisStartY + this.yAxisLength); + this.penDown(args, util); + util.target.setXY(this.axisStartX, this.axisStartY); + this.penUp(args, util); + util.target.setXY(this.axisStartX, this.axisStartY + this.yAxisLength / 2); + this.penDown(args, util); + util.target.setXY(this.axisStartX + this.xAxisLength, this.axisStartY + this.yAxisLength / 2); + this.penUp(args, util); + } + + findCrescDecresc() { + //CHANGE TO MP AND P ETC + up = []; + down = []; + upstart = 0; + downstart = 0; + for (var i in this.noteList) { + log.log(this.noteList[i][3]); + + } + + } + + penUp(args, util) { + const penState = this._getPenState(util.target); + if (penState.penDown) { + penState.penDown = false; + util.target.removeListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + + penDown(args, util, penSkinId) { + const penState = this._getPenState(util.target); + if (!penState.penDown) { + penState.penDown = true; + util.target.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + + penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penPoint(penSkinId, penState.penAttributes, util.target.x, util.target.y); + this.runtime.requestRedraw(); + } + } + + /** + * The pen "set pen color to {color}" block sets the pen to a particular RGB color. + * The transparency is reset to 0. + * @param {object} args - the block arguments. + * @property {int} COLOR - the color to set, expressed as a 24-bit RGB value (0xRRGGBB). + * @param {object} util - utility object provided by the runtime. + */ + setPenColorToColor(newColor, util) { + const penState = this._getPenState(util.target); + const rgb = Cast.toRgbColorObject(newColor); + const hsv = Color.rgbToHsv(rgb); + penState.color = (hsv.h / 360) * 100; + penState.saturation = hsv.s * 100; + penState.brightness = hsv.v * 100; + if (rgb.hasOwnProperty('a')) { + penState.transparency = 100 * (1 - (rgb.a / 255.0)); + } else { + penState.transparency = 0; + } + + // Set the legacy "shade" value the same way scratch 2 did. + penState._shade = penState.brightness / 2; + + this._updatePenColor(penState); + } + + /** + * Update the cached color from the color, saturation, brightness and transparency values + * in the provided PenState object. + * @param {PenState} penState - the pen state to update. + * @private + */ + _updatePenColor(penState) { + const rgb = Color.hsvToRgb({ + h: penState.color * 360 / 100, + s: penState.saturation / 100, + v: penState.brightness / 100 + }); + penState.penAttributes.color4f[0] = rgb.r / 255.0; + penState.penAttributes.color4f[1] = rgb.g / 255.0; + penState.penAttributes.color4f[2] = rgb.b / 255.0; + penState.penAttributes.color4f[3] = this._transparencyToAlpha(penState.transparency); + } + + /** + * Convert a pen transparency value to an alpha value. + * Alpha ranges from 0 to 1, where 0 is transparent and 1 is opaque. + * Transparency ranges from 0 to 100, where 0 is opaque and 100 is transparent. + * @param {number} transparency - the input transparency value. + * @returns {number} the alpha value. + * @private + */ + _transparencyToAlpha(transparency) { + return 1.0 - (transparency / 100.0); + } + + /** + * The pen "clear" block clears the pen layer's contents. + */ + clear() { + const penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penClear(penSkinId); + this.runtime.requestRedraw(); + } + } + + /** + * + * @param {BlockUtility} util + */ + getXY(util) { + if (!util) return [0, 0]; + if (!util.target) return [0, 0]; + const { x, y } = util.target; + return [x ? x : 0, y ? y : 0]; + } +} + +module.exports = VizHelpers; \ No newline at end of file diff --git a/src/extensions/scratch3_musiccreation/waveform.js b/src/extensions/scratch3_musiccreation/waveform.js new file mode 100644 index 00000000000..0908ca9f5bd --- /dev/null +++ b/src/extensions/scratch3_musiccreation/waveform.js @@ -0,0 +1,507 @@ +const Clone = require('../../util/clone'); +const log = require('../../util/log'); +const Cast = require('../../util/cast'); +const Color = require('../../util/color'); +const RenderedTarget = require('../../sprites/rendered-target'); +const StageLayering = require('../../engine/stage-layering'); +const FreqToNote = require('./freqtonote'); + +const letters = require('./letters'); +const textRender = require('./textrender'); +const { updateVariableIdentifiers } = require('../../util/variable-util'); + + +var colorToFreq, note, coord, x, y, colorX, colorY, colors, signal, fs, xStep, heightScaling, st, prevFreq, midi, dur, inst, vol, c, freq, Omega, val, harmonic, coeff, newk, s, color; +class Waveform { + constructor(runtime) { + this.runtime = runtime; + + /** + * The ID of the renderer Skin corresponding to the pen layer. + * @type {int} + * @private + */ + this._penSkinId = -1; + + /** + * The ID of the renderer Drawable corresponding to the pen layer. + * @type {int} + * @private + */ + this._penDrawableId = -1; + this.black = '0x000000'; + this.white = '0xffffff'; + + this.noteList = []; + + this.axisStartX = -200; + this.axisStartY = -150; + this.xAxisLength = 400; + this.yAxisLength = 300; + + this.legendStartX = 150; + this.legendStartY = 80; + this.legendLengthX = 75; + this.legendLengthY = 80; + + this.textRenderer = new textRender(runtime); + + this._onTargetCreated = this._onTargetCreated.bind(this); + this.runtime.on('targetWasCreated', this._onTargetCreated); + + this._onTargetMoved = this._onTargetMoved.bind(this); + + this.letters = { + 'a': letters.a, + 'b': letters.b, + 'c': letters.c, + 'd': letters.d, + 'e': letters.e, + 'f': letters.f, + 'g': letters.g, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'h': letters.h, + 'i': letters.i, + 'j': letters.j, + 'k': letters.k, + 'l': letters.l, + 'm': letters.m, + 'n': letters.n, + 'o': letters.o, + 'p': letters.p, + 'q': letters.q, + 'r': letters.r, + 's': letters.s, + 't': letters.t, + 'u': letters.u, + 'v': letters.v, + 'w': letters.w, + 'x': letters.x, + 'y': letters.y, + 'z': letters.z, + '1': letters.one, + '2': letters.two, + '3': letters.three, + '4': letters.four, + '5': letters.five, + '6': letters.six, + '7': letters.seven, + '8': letters.eight, + '9': letters.nine, + '0': letters.zero, + 'F': letters.flat, + 'S': letters.sharp + + } + + this.spacing = { + 'a': 59.03383897316219, + 'b': 35.666277712952166, + 'c': 55.59820426487096, + 'd': 51.65460910151694, + 'e': 33.821470245040814, + 'f': 35.05134189031503, + 'g': 62.10851808634772, + 'h': 51.65460910151691, + 'i': 0.0, + 'j': 27.057176196032685, + 'k': 44.275379229871646, + 'l': 33.20653442240376, + 'm': 76.86697782963824, + 'n': 57.803967327887975, + 'o': 62.108518086347715, + 'p': 35.05134189031503, + 'q': 62.72345390898482, + 'r': 34.305274971941685, + 's': 39.62850729517402, + 't': 51.03967327887982, + 'u': 50.42473745624271, + 'v': 52.88448074679113, + 'w': 88.55075845974329, + 'x': 45.50525087514586, + 'y': 47.350058343057185, + 'z': 55.959159859976694, + '1': 29.467911318553092, + '2': 61.498249708284675, + '3': 60.21703617269554, + '4': 74.31038506417735, + '5': 58.935822637106185, + '6': 55.09218203033845, + '7': 65.34189031505252, + '8': 55.092182030338336, + '9': 57.654609101516826, + '0': 55.09218203033856, + 'F': 67.9352750809062, + 'S': 122.6148867313916 + } + + this.harmonics = { + "Piano": [[1, 1], [3, 0.42], [4, 0.22]], //DONE + "Guitar": [[1, 0.55], [2, 0.47], [3, 0.68], [4, 0.24]], + "Bass": [[1, 1], [3, 0.78], [4, 0.22]], + "Cello": [[1, 1], [2, 0.47], [3, 0.24], [4, 0.15]], //DONE + "Saxophone": [[1, 1], [2, 0.38], [3, 0.14], [4, 0.02]], //DONE + "Clarinet": [[1, 0.57], [2, 0.87], [3, 0.23], [4, 0]], //DONE + "Synth": [[1, 1], [2, 0], [3, 0], [4, 0]] //DONE + } + + colorToFreq = {}; + } + + /** + * The key to load & store a target's music-related state. + * @type {string} + */ + static get VIZ_STATE_KEY() { + return 'Scratch.musicviz'; + } + + static get DEFAULT_PEN_STATE() { + return { + penDown: false, + color: 66.66, + saturation: 100, + brightness: 100, + transparency: 0, + _shade: 50, // Used only for legacy `change shade by` blocks + penAttributes: { + color4f: [0, 0, 1, 1], + diameter: 1 + } + }; + } + + /** + * The minimum and maximum allowed pen size. + * The maximum is twice the diagonal of the stage, so that even an + * off-stage sprite can fill it. + * @type {{min: number, max: number}} + */ + static get PEN_SIZE_RANGE() { + return { min: 1, max: 1200 }; + } + + /** + * When a music-playing Target is cloned, clone the music state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated(newTarget, sourceTarget) { + if (sourceTarget) { + const penState = sourceTarget.getCustomState(Waveform.VIZ_STATE_KEY); + if (penState) { + newTarget.setCustomState(Waveform.VIZ_STATE_KEY, Clone.simple(penState)); + if (penState.penDown) { + newTarget.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + } + } + + _onTargetMoved(target, oldX, oldY, isForce) { + // Only move the pen if the movement isn't forced (ie. dragged). + if (!isForce) { + let penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + const penState = this._getPenState(target); + this.runtime.renderer.penLine(penSkinId, penState.penAttributes, oldX, oldY, target.x, target.y); + this.runtime.requestRedraw(); + } + } + } + + _getPenLayerID() { + if (this._penSkinId < 0 && this.runtime.renderer) { + this._penSkinId = this.runtime.renderer.createPenSkin(); + this._penDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); + this.runtime.renderer.updateDrawableProperties(this._penDrawableId, { skinId: this._penSkinId }); + } + return this._penSkinId; + } + + _getWavePenLayerID() { + if (this.wavePen < 0 && this.runtime.renderer) { + this.wavePen = this.runtime.renderer.createPenSkin(); + this.wavePenDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); + this.runtime.renderer.updateDrawableProperties(this.wavePenDrawableId, { skinId: this.wavePen }); + } + return this.wavePen; + } + + _getPenState(target) { + let penState = target.getCustomState(Waveform.VIZ_STATE_KEY); + if (!penState) { + penState = Clone.simple(Waveform.DEFAULT_PEN_STATE); + target.setCustomState(Waveform.VIZ_STATE_KEY, penState); + } + return penState; + } + + + testWaveformViz(noteList, args, util) { + this.setPenColorToColor(this.black, util); + this.noteList = noteList; + this.clear(); + this.drawAxes(args, util); + this.drawSignal(args, util); + this.drawLegend(args, util); + this.labelAxes(args, util); + } + + labelAxes(args, util) { + this.drawString('time', this.axisStartX + this.xAxisLength - 40, this.axisStartY + this.yAxisLength / 2 - 5, 0.8, args, util); + this.drawString('signal', this.axisStartX - 30, this.axisStartY + this.yAxisLength + 20, 0.8, args, util); + + this.drawString('waveform', this.axisStartX + this.xAxisLength / 2 - 70, this.axisStartY + this.yAxisLength + 20, 1, args, util); + } + + + drawString(str, xstart, ystart, size, args, util) { + for (var i in str) { + xstart += 5 * size; + if (i >= 1) { + xstart += this.spacing[str[i - 1]] / 5 * size; + } + this.drawLetter(str[i], xstart, ystart, size, args, util); + } + + } + + drawLetter(letter, xstart, ystart, size, args, util) { + letter = this.letters[letter]; + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0] / 5 * size + xstart; + y = -coord[1] / 5 * size + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + for (var i in letter) { + coord = letter[i]; + x = coord[0] / 5 * size + xstart + 1; + y = -coord[1] / 5 * size + ystart; + util.target.setXY(x, y); + this.penDown(args, util); + } + this.penUp(args, util); + } + + drawLegend(args, util) { + //draw Box + this.penUp(args, util); + util.target.setXY(this.legendStartX, this.legendStartY); + this.penDown(args, util); + util.target.setXY(this.legendStartX + this.legendLengthX, this.legendStartY); + this.penDown(args, util); + util.target.setXY(this.legendStartX + this.legendLengthX, this.legendStartY + this.legendLengthY); + this.penDown(args, util); + util.target.setXY(this.legendStartX, this.legendStartY + this.legendLengthY); + this.penDown(args, util); + util.target.setXY(this.legendStartX, this.legendStartY); + this.penUp(args, util); + + for (var i = this.legendStartY + 1; i < this.legendStartY + this.legendLengthY; i++) { + this.setPenColorToColor(this.white, util); + this.penUp(args, util); + util.target.setXY(this.legendStartX + 1, i); + this.penDown(args, util); + util.target.setXY(this.legendStartX + this.legendLengthX - 1, i); + } + + //draw Title + colorX = this.legendStartX + 5; + colorY = this.legendStartY + this.legendLengthY - 20; + this.setPenColorToColor(this.black, util); + this.drawString('legend', colorX, this.legendStartY + this.legendLengthY - 5, 0.7, args, util); + + for (let color in colorToFreq) { + this.setPenColorToColor(color, util); + for (var c = 0; c <= 10; c++) { + this.penUp(args, util); + util.target.setXY(colorX, colorY - c); + this.penDown(args, util); + util.target.setXY(colorX + 15, colorY - c); + } + this.setPenColorToColor(this.black, util); + this.penUp(args, util); + this.drawString(FreqToNote.freqToNote(colorToFreq[color]), colorX + 25, colorY, 0.6, args, util); + colorY -= 15; + } + + this.setPenColorToColor(this.black, util); + this.penUp(args, util); + + } + + drawAxes(args, util) { + util.target.setXY(this.axisStartX, this.axisStartY + this.yAxisLength); + this.penDown(args, util); + util.target.setXY(this.axisStartX, this.axisStartY); + this.penUp(args, util); + util.target.setXY(this.axisStartX, this.axisStartY + this.yAxisLength / 2); + this.penDown(args, util); + util.target.setXY(this.axisStartX + this.xAxisLength, this.axisStartY + this.yAxisLength / 2); + this.penUp(args, util); + //this.drawLabels(args, util); + } + + drawLabels(args, util) { + this.textRenderer.say('here', args, util); + } + + /** + * + * @param {array} note - note[4] contains the ID of this note + * @returns the color associated with this note + */ + getColorFromNote(note) { + colors = ['0xff0000', '0x0000ff', '0x00ff00', '0xffa500']; + return colors[note[4] % colors.length]; + } + + drawSignal(args, util) { + colors = ['0xff0000', '0x0000ff', '0x00ff00', '0xffa500'] + const color_count = colors.length; + colorToFreq = {}; + x = this.axisStartX; + y = this.axisStartY + this.yAxisLength / 2; + signal = this.noteList; + fs = 500; + const totalSamples = fs * signal + .map(v => v[1]) + .reduce((sum, current) => sum + current, 0); + xStep = this.xAxisLength / totalSamples; + heightScaling = 100; + util.target.setXY(x, y); + this.penDown(args, util); + st = 0; + prevFreq = 0; + for (var i in signal) { + note = signal[i]; + midi = note[0]; + dur = note[1]; + inst = note[2]; + vol = note[3]; + c = this.getColorFromNote(note); + colorToFreq[c] = midi; + this.setPenColorToColor(c, util); + freq = 2 ** ((midi - 69) / 12) * 440; + Omega = 2 * Math.PI * freq / 44140; + var st = st * prevFreq / Omega; + prevFreq = Omega; + for (s = st; s < st + dur * fs; s++) { + val = 0 + for (var k in this.harmonics[inst]) { + harmonic = this.harmonics[inst][k]; + coeff = harmonic[1]; + newk = harmonic[0]; + val = val + coeff * (Math.sin(Omega * newk * s * 3)); + } + util.target.setXY(x, y + vol * val); + x = x + xStep; + } + st = st + dur * fs; + } + this.penUp(args, util); + this.setPenColorToColor(this.black, util); + } + + + penUp(args, util) { + const penState = this._getPenState(util.target); + if (penState.penDown) { + penState.penDown = false; + util.target.removeListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + } + + penDown(args, util, penSkinId) { + const penState = this._getPenState(util.target); + if (!penState.penDown) { + penState.penDown = true; + util.target.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); + } + + penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penPoint(penSkinId, penState.penAttributes, util.target.x, util.target.y); + this.runtime.requestRedraw(); + } + } + + /** + * The pen "set pen color to {color}" block sets the pen to a particular RGB color. + * The transparency is reset to 0. + * @param {object} args - the block arguments. + * @property {int} COLOR - the color to set, expressed as a 24-bit RGB value (0xRRGGBB). + * @param {object} util - utility object provided by the runtime. + */ + setPenColorToColor(newColor, util) { + const penState = this._getPenState(util.target); + const rgb = Cast.toRgbColorObject(newColor); + const hsv = Color.rgbToHsv(rgb); + penState.color = (hsv.h / 360) * 100; + penState.saturation = hsv.s * 100; + penState.brightness = hsv.v * 100; + if (rgb.hasOwnProperty('a')) { + penState.transparency = 100 * (1 - (rgb.a / 255.0)); + } else { + penState.transparency = 0; + } + + // Set the legacy "shade" value the same way scratch 2 did. + penState._shade = penState.brightness / 2; + + this._updatePenColor(penState); + } + + /** + * Update the cached color from the color, saturation, brightness and transparency values + * in the provided PenState object. + * @param {PenState} penState - the pen state to update. + * @private + */ + _updatePenColor(penState) { + const rgb = Color.hsvToRgb({ + h: penState.color * 360 / 100, + s: penState.saturation / 100, + v: penState.brightness / 100 + }); + penState.penAttributes.color4f[0] = rgb.r / 255.0; + penState.penAttributes.color4f[1] = rgb.g / 255.0; + penState.penAttributes.color4f[2] = rgb.b / 255.0; + penState.penAttributes.color4f[3] = this._transparencyToAlpha(penState.transparency); + } + + /** + * Convert a pen transparency value to an alpha value. + * Alpha ranges from 0 to 1, where 0 is transparent and 1 is opaque. + * Transparency ranges from 0 to 100, where 0 is opaque and 100 is transparent. + * @param {number} transparency - the input transparency value. + * @returns {number} the alpha value. + * @private + */ + _transparencyToAlpha(transparency) { + return 1.0 - (transparency / 100.0); + } + + /** + * The pen "clear" block clears the pen layer's contents. + */ + clear() { + const penSkinId = this._getPenLayerID(); + if (penSkinId >= 0) { + this.runtime.renderer.penClear(penSkinId); + this.runtime.requestRedraw(); + } + } + +} + +module.exports = Waveform; \ No newline at end of file diff --git a/src/extensions/scratch3_pen/index.js b/src/extensions/scratch3_pen/index.js index f6175f96f66..49c78a0764d 100644 --- a/src/extensions/scratch3_pen/index.js +++ b/src/extensions/scratch3_pen/index.js @@ -43,7 +43,7 @@ const ColorParam = { * @constructor */ class Scratch3PenBlocks { - constructor (runtime) { + constructor(runtime) { /** * The runtime instantiating this block package. * @type {Runtime} @@ -75,7 +75,7 @@ class Scratch3PenBlocks { * The default pen state, to be used when a target has no existing pen state. * @type {PenState} */ - static get DEFAULT_PEN_STATE () { + static get DEFAULT_PEN_STATE() { return { penDown: false, color: 66.66, @@ -97,15 +97,15 @@ class Scratch3PenBlocks { * off-stage sprite can fill it. * @type {{min: number, max: number}} */ - static get PEN_SIZE_RANGE () { - return {min: 1, max: 1200}; + static get PEN_SIZE_RANGE() { + return { min: 1, max: 1200 }; } /** * The key to load & store a target's pen-related state. * @type {string} */ - static get STATE_KEY () { + static get STATE_KEY() { return 'Scratch.pen'; } @@ -115,7 +115,7 @@ class Scratch3PenBlocks { * @returns {number} the clamped size. * @private */ - _clampPenSize (requestedSize) { + _clampPenSize(requestedSize) { return MathUtil.clamp( requestedSize, Scratch3PenBlocks.PEN_SIZE_RANGE.min, @@ -129,7 +129,7 @@ class Scratch3PenBlocks { * @returns {int} the Skin ID of the pen layer, or -1 on failure. * @private */ - _getPenLayerID () { + _getPenLayerID() { if (this._penSkinId < 0 && this.runtime.renderer) { this._penSkinId = this.runtime.renderer.createPenSkin(); this._penDrawableId = this.runtime.renderer.createDrawable(StageLayering.PEN_LAYER); @@ -143,7 +143,7 @@ class Scratch3PenBlocks { * @returns {PenState} the mutable pen state associated with that target. This will be created if necessary. * @private */ - _getPenState (target) { + _getPenState(target) { let penState = target.getCustomState(Scratch3PenBlocks.STATE_KEY); if (!penState) { penState = Clone.simple(Scratch3PenBlocks.DEFAULT_PEN_STATE); @@ -159,7 +159,7 @@ class Scratch3PenBlocks { * @listens Runtime#event:targetWasCreated * @private */ - _onTargetCreated (newTarget, sourceTarget) { + _onTargetCreated(newTarget, sourceTarget) { if (sourceTarget) { const penState = sourceTarget.getCustomState(Scratch3PenBlocks.STATE_KEY); if (penState) { @@ -179,10 +179,10 @@ class Scratch3PenBlocks { * @param {boolean} isForce - whether the movement was forced. * @private */ - _onTargetMoved (target, oldX, oldY, isForce) { + _onTargetMoved(target, oldX, oldY, isForce) { // Only move the pen if the movement isn't forced (ie. dragged). if (!isForce) { - const penSkinId = this._getPenLayerID(); + let penSkinId = this._getPenLayerID(); if (penSkinId >= 0) { const penState = this._getPenState(target); this.runtime.renderer.penLine(penSkinId, penState.penAttributes, oldX, oldY, target.x, target.y); @@ -197,7 +197,7 @@ class Scratch3PenBlocks { * @returns {number} the wrapped value. * @private */ - _wrapColor (value) { + _wrapColor(value) { return MathUtil.wrapClamp(value, 0, 100); } @@ -206,7 +206,7 @@ class Scratch3PenBlocks { * @returns {array} of the localized text and values for each menu element * @private */ - _initColorParam () { + _initColorParam() { return [ { text: formatMessage({ @@ -250,7 +250,7 @@ class Scratch3PenBlocks { * @returns {number} the clamped value. * @private */ - _clampColorParam (value) { + _clampColorParam(value) { return MathUtil.clamp(value, 0, 100); } @@ -262,7 +262,7 @@ class Scratch3PenBlocks { * @returns {number} the transparency value. * @private */ - _alphaToTransparency (alpha) { + _alphaToTransparency(alpha) { return (1.0 - alpha) * 100.0; } @@ -274,14 +274,14 @@ class Scratch3PenBlocks { * @returns {number} the alpha value. * @private */ - _transparencyToAlpha (transparency) { + _transparencyToAlpha(transparency) { return 1.0 - (transparency / 100.0); } /** * @returns {object} metadata for this extension and its blocks. */ - getInfo () { + getInfo() { return { id: 'pen', name: formatMessage({ @@ -497,7 +497,7 @@ class Scratch3PenBlocks { /** * The pen "clear" block clears the pen layer's contents. */ - clear () { + clear() { const penSkinId = this._getPenLayerID(); if (penSkinId >= 0) { this.runtime.renderer.penClear(penSkinId); @@ -510,8 +510,8 @@ class Scratch3PenBlocks { * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. */ - stamp (args, util) { - const penSkinId = this._getPenLayerID(); + stamp(args, util) { + penSkinId = this._getPenLayerID(); if (penSkinId >= 0) { const target = util.target; this.runtime.renderer.penStamp(penSkinId, target.drawableID); @@ -524,7 +524,7 @@ class Scratch3PenBlocks { * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. */ - penDown (args, util) { + penDown(args, util) { const target = util.target; const penState = this._getPenState(target); @@ -533,7 +533,7 @@ class Scratch3PenBlocks { target.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); } - const penSkinId = this._getPenLayerID(); + penSkinId = this._getPenLayerID(); if (penSkinId >= 0) { this.runtime.renderer.penPoint(penSkinId, penState.penAttributes, target.x, target.y); this.runtime.requestRedraw(); @@ -545,7 +545,7 @@ class Scratch3PenBlocks { * @param {object} args - the block arguments. * @param {object} util - utility object provided by the runtime. */ - penUp (args, util) { + penUp(args, util) { const target = util.target; const penState = this._getPenState(target); @@ -562,7 +562,7 @@ class Scratch3PenBlocks { * @property {int} COLOR - the color to set, expressed as a 24-bit RGB value (0xRRGGBB). * @param {object} util - utility object provided by the runtime. */ - setPenColorToColor (args, util) { + setPenColorToColor(args, util) { const penState = this._getPenState(util.target); const rgb = Cast.toRgbColorObject(args.COLOR); const hsv = Color.rgbToHsv(rgb); @@ -587,7 +587,7 @@ class Scratch3PenBlocks { * @param {PenState} penState - the pen state to update. * @private */ - _updatePenColor (penState) { + _updatePenColor(penState) { const rgb = Color.hsvToRgb({ h: penState.color * 360 / 100, s: penState.saturation / 100, @@ -607,22 +607,22 @@ class Scratch3PenBlocks { * @param {boolean} change - if true change param by value, if false set param to value. * @private */ - _setOrChangeColorParam (param, value, penState, change) { + _setOrChangeColorParam(param, value, penState, change) { switch (param) { - case ColorParam.COLOR: - penState.color = this._wrapColor(value + (change ? penState.color : 0)); - break; - case ColorParam.SATURATION: - penState.saturation = this._clampColorParam(value + (change ? penState.saturation : 0)); - break; - case ColorParam.BRIGHTNESS: - penState.brightness = this._clampColorParam(value + (change ? penState.brightness : 0)); - break; - case ColorParam.TRANSPARENCY: - penState.transparency = this._clampColorParam(value + (change ? penState.transparency : 0)); - break; - default: - log.warn(`Tried to set or change unknown color parameter: ${param}`); + case ColorParam.COLOR: + penState.color = this._wrapColor(value + (change ? penState.color : 0)); + break; + case ColorParam.SATURATION: + penState.saturation = this._clampColorParam(value + (change ? penState.saturation : 0)); + break; + case ColorParam.BRIGHTNESS: + penState.brightness = this._clampColorParam(value + (change ? penState.brightness : 0)); + break; + case ColorParam.TRANSPARENCY: + penState.transparency = this._clampColorParam(value + (change ? penState.transparency : 0)); + break; + default: + log.warn(`Tried to set or change unknown color parameter: ${param}`); } this._updatePenColor(penState); } @@ -635,7 +635,7 @@ class Scratch3PenBlocks { * @property {number} VALUE - the amount to change the selected parameter by. * @param {object} util - utility object provided by the runtime. */ - changePenColorParamBy (args, util) { + changePenColorParamBy(args, util) { const penState = this._getPenState(util.target); this._setOrChangeColorParam(args.COLOR_PARAM, Cast.toNumber(args.VALUE), penState, true); } @@ -648,7 +648,7 @@ class Scratch3PenBlocks { * @property {number} VALUE - the amount to set the selected parameter to. * @param {object} util - utility object provided by the runtime. */ - setPenColorParamTo (args, util) { + setPenColorParamTo(args, util) { const penState = this._getPenState(util.target); this._setOrChangeColorParam(args.COLOR_PARAM, Cast.toNumber(args.VALUE), penState, false); } @@ -659,7 +659,7 @@ class Scratch3PenBlocks { * @property {number} SIZE - the amount of desired size change. * @param {object} util - utility object provided by the runtime. */ - changePenSizeBy (args, util) { + changePenSizeBy(args, util) { const penAttributes = this._getPenState(util.target).penAttributes; penAttributes.diameter = this._clampPenSize(penAttributes.diameter + Cast.toNumber(args.SIZE)); } @@ -670,7 +670,7 @@ class Scratch3PenBlocks { * @property {number} SIZE - the amount of desired size change. * @param {object} util - utility object provided by the runtime. */ - setPenSizeTo (args, util) { + setPenSizeTo(args, util) { const penAttributes = this._getPenState(util.target).penAttributes; penAttributes.diameter = this._clampPenSize(Cast.toNumber(args.SIZE)); } @@ -682,7 +682,7 @@ class Scratch3PenBlocks { * @property {number} HUE - the amount to set the hue to. * @param {object} util - utility object provided by the runtime. */ - setPenHueToNumber (args, util) { + setPenHueToNumber(args, util) { const penState = this._getPenState(util.target); const hueValue = Cast.toNumber(args.HUE); const colorValue = hueValue / 2; @@ -697,7 +697,7 @@ class Scratch3PenBlocks { * @property {number} HUE - the amount of desired hue change. * @param {object} util - utility object provided by the runtime. */ - changePenHueBy (args, util) { + changePenHueBy(args, util) { const penState = this._getPenState(util.target); const hueChange = Cast.toNumber(args.HUE); const colorChange = hueChange / 2; @@ -715,7 +715,7 @@ class Scratch3PenBlocks { * @property {number} SHADE - the amount to set the shade to. * @param {object} util - utility object provided by the runtime. */ - setPenShadeToNumber (args, util) { + setPenShadeToNumber(args, util) { const penState = this._getPenState(util.target); let newShade = Cast.toNumber(args.SHADE); @@ -736,10 +736,10 @@ class Scratch3PenBlocks { * @property {number} SHADE - the amount of desired shade change. * @param {object} util - utility object provided by the runtime. */ - changePenShadeBy (args, util) { + changePenShadeBy(args, util) { const penState = this._getPenState(util.target); const shadeChange = Cast.toNumber(args.SHADE); - this.setPenShadeToNumber({SHADE: penState._shade + shadeChange}, util); + this.setPenShadeToNumber({ SHADE: penState._shade + shadeChange }, util); } /** @@ -747,9 +747,9 @@ class Scratch3PenBlocks { * @param {object} penState - update the HSV & RGB values in this pen state from its hue & shade values. * @private */ - _legacyUpdatePenColor (penState) { + _legacyUpdatePenColor(penState) { // Create the new color in RGB using the scratch 2 "shade" model - let rgb = Color.hsvToRgb({h: penState.color * 360 / 100, s: 1, v: 1}); + let rgb = Color.hsvToRgb({ h: penState.color * 360 / 100, s: 1, v: 1 }); const shade = (penState._shade > 100) ? 200 - penState._shade : penState._shade; if (shade < 50) { rgb = Color.mixRgb(Color.RGB_BLACK, rgb, (10 + shade) / 60); diff --git a/src/extensions/scratch3_text_toxicity/index.js b/src/extensions/scratch3_text_toxicity/index.js new file mode 100644 index 00000000000..f56b08dd012 --- /dev/null +++ b/src/extensions/scratch3_text_toxicity/index.js @@ -0,0 +1,530 @@ +require('babel-polyfill'); +const Runtime = require('../../engine/runtime'); + +const ArgumentType = require('../../extension-support/argument-type'); +const BlockType = require('../../extension-support/block-type'); +const Clone = require('../../util/clone'); +const Cast = require('../../util/cast'); +const Video = require('../../io/video'); +const formatMessage = require('format-message'); +const canvas = require('canvas'); +const faceapi = require('face-api.js'); +const { Canvas, Image, ImageData } = canvas + +/** + * Sensor attribute video sensor block should report. + * @readonly + * @enum {string} + */ +const SensingAttribute = { + /** The amount of motion. */ + MOTION: 'motion', + + /** The direction of the motion. */ + DIRECTION: 'direction' +}; + +/** + * Subject video sensor block should report for. + * @readonly + * @enum {string} + */ +const SensingSubject = { + /** The sensor traits of the whole stage. */ + STAGE: 'Stage', + + /** The senosr traits of the area overlapped by this sprite. */ + SPRITE: 'this sprite' +}; + +/** + * States the video sensing activity can be set to. + * @readonly + * @enum {string} + */ +const VideoState = { + /** Video turned off. */ + OFF: 'off', + + /** Video turned on with default y axis mirroring. */ + ON: 'on', + + /** Video turned on without default y axis mirroring. */ + ON_FLIPPED: 'on-flipped' +}; + +let typeArr = [ + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10' +] + +/** + * Class for the motion-related blocks in Scratch 3.0 + * @param {Runtime} runtime - the runtime instantiating this block package. + * @constructor + */ + +class Scratch3Vision { + constructor(runtime) { + this.knn = null + this.trainTypes = typeArr.map(item => { + return 'label' + item + }) + this.faceaipInit() + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; + + /** + * The last millisecond epoch timestamp that the video stream was + * analyzed. + * @type {number} + */ + this._lastUpdate = null; + this.KNN_INTERVAL = 1000 + if (this.runtime.ioDevices) { + // Clear target motion state values when the project starts. + this.runtime.on(Runtime.PROJECT_RUN_START, this.reset.bind(this)); + + // Kick off looping the analysis logic. + // this._loop(); + + // Configure the video device with values from a globally stored + // location. + this.setVideoTransparency({ + TRANSPARENCY: 10 + }); + this.videoToggle({ + VIDEO_STATE: this.globalVideoState + }); + } + + setInterval(async () => { + if (this.globalVideoState === VideoState.ON) { + console.log('knn result:') + } + }, this.KNN_INTERVAL) + } + + /** + * After analyzing a frame the amount of milliseconds until another frame + * is analyzed. + * @type {number} + */ + static get INTERVAL() { + return 33; + } + + /** + * Dimensions the video stream is analyzed at after its rendered to the + * sample canvas. + * @type {Array.} + */ + static get DIMENSIONS() { + return [480, 360]; + } + + /** + * The key to load & store a target's motion-related state. + * @type {string} + */ + static get STATE_KEY() { + return 'Scratch.videoSensing'; + } + + /** + * The default motion-related state, to be used when a target has no existing motion state. + * @type {MotionState} + */ + static get DEFAULT_MOTION_STATE() { + return { + motionFrameNumber: 0, + motionAmount: 0, + motionDirection: 0 + }; + } + + /** + * The transparency setting of the video preview stored in a value + * accessible by any object connected to the virtual machine. + * @type {number} + */ + get globalVideoTransparency() { + const stage = this.runtime.getTargetForStage(); + if (stage) { + return stage.videoTransparency; + } + return 10; + } + + set globalVideoTransparency(transparency) { + const stage = this.runtime.getTargetForStage(); + if (stage) { + stage.videoTransparency = transparency; + } + return transparency; + } + + /** + * The video state of the video preview stored in a value accessible by any + * object connected to the virtual machine. + * @type {number} + */ + get globalVideoState() { + const stage = this.runtime.getTargetForStage(); + if (stage) { + return stage.videoState; + } + return VideoState.ON; + } + + set globalVideoState(state) { + const stage = this.runtime.getTargetForStage(); + if (stage) { + stage.videoState = state; + } + return state; + } + + /** + * Reset the extension's data motion detection data. This will clear out + * for example old frames, so the first analyzed frame will not be compared + * against a frame from before reset was called. + */ + reset() { + const targets = this.runtime.targets; + for (let i = 0; i < targets.length; i++) { + const state = targets[i].getCustomState(Scratch3Vision.STATE_KEY); + if (state) { + state.motionAmount = 0; + state.motionDirection = 0; + } + } + } + + /** + * Occasionally step a loop to sample the video, stamp it to the preview + * skin, and add a TypedArray copy of the canvas's pixel data. + * @private + */ + _loop() { + setTimeout(this._loop.bind(this), Math.max(this.runtime.currentStepTime, Scratch3Vision.INTERVAL)); + + // Add frame to detector + const time = Date.now(); + if (this._lastUpdate === null) { + this._lastUpdate = time; + } + const offset = time - this._lastUpdate; + if (offset > Scratch3Vision.INTERVAL) { + const frame = this.runtime.ioDevices.video.getFrame({ + format: Video.FORMAT_IMAGE_DATA, + dimensions: Scratch3Vision.DIMENSIONS + }); + if (frame) { + this._lastUpdate = time; + } + } + } + + /** + * Create data for a menu in scratch-blocks format, consisting of an array + * of objects with text and value properties. The text is a translated + * string, and the value is one-indexed. + * @param {object[]} info - An array of info objects each having a name + * property. + * @return {array} - An array of objects with text and value properties. + * @private + */ + _buildMenu(info) { + return info.map((entry, index) => { + const obj = {}; + obj.text = entry.name; + obj.value = entry.value || String(index + 1); + return obj; + }); + } + + /** + * @param {Target} target - collect motion state for this target. + * @returns {MotionState} the mutable motion state associated with that + * target. This will be created if necessary. + * @private + */ + _getMotionState(target) { + let motionState = target.getCustomState(Scratch3Vision.STATE_KEY); + if (!motionState) { + motionState = Clone.simple(Scratch3Vision.DEFAULT_MOTION_STATE); + target.setCustomState(Scratch3Vision.STATE_KEY, motionState); + } + return motionState; + } + + static get SensingAttribute() { + return SensingAttribute; + } + + /** + * An array of choices of whether a reporter should return the frame's + * motion amount or direction. + * @type {object[]} an array of objects + * @param {string} name - the translatable name to display in sensor + * attribute menu + * @param {string} value - the serializable value of the attribute + */ + get ATTRIBUTE_INFO() { + return [ + { + name: 'motion', + value: SensingAttribute.MOTION + }, + { + name: 'direction', + value: SensingAttribute.DIRECTION + } + ]; + } + + static get SensingSubject() { + return SensingSubject; + } + + /** + * An array of info about the subject choices. + * @type {object[]} an array of objects + * @param {string} name - the translatable name to display in the subject menu + * @param {string} value - the serializable value of the subject + */ + get SUBJECT_INFO() { + return [ + { + name: 'stage', + value: SensingSubject.STAGE + }, + { + name: 'sprite', + value: SensingSubject.SPRITE + } + ]; + } + + /** + * States the video sensing activity can be set to. + * @readonly + * @enum {string} + */ + static get VideoState() { + return VideoState; + } + + /** + * An array of info on video state options for the "turn video [STATE]" block. + * @type {object[]} an array of objects + * @param {string} name - the translatable name to display in the video state menu + * @param {string} value - the serializable value stored in the block + */ + get VIDEO_STATE_INFO () { + return [ + { + name: formatMessage({ + id: 'videoSensing.off', + default: 'off', + description: 'Option for the "turn video [STATE]" block' + }), + value: VideoState.OFF + }, + { + name: formatMessage({ + id: 'videoSensing.on', + default: 'on', + description: 'Option for the "turn video [STATE]" block' + }), + value: VideoState.ON + }, + { + name: formatMessage({ + id: 'videoSensing.onFlipped', + default: 'on flipped', + description: 'Option for the "turn video [STATE]" block that causes the video to be flipped' + + ' horizontally (reversed as in a mirror)' + }), + value: VideoState.ON_FLIPPED + } + ]; + } + + + /** + * @returns {object} metadata for this extension and its blocks. + */ + getInfo () { + return { + id: 'Vision', + name: 'Vision Blocks', + blocks: [ + { + opcode: 'videoToggle', + text: formatMessage({ + id: 'videoSensing.videoToggle', + default: 'turn video [VIDEO_STATE]', + description: 'Controls display of the video preview layer' + }), + arguments: { + VIDEO_STATE: { + type: ArgumentType.NUMBER, + menu: 'VIDEO_STATE', + defaultValue: VideoState.ON + } + } + }, + { + opcode: 'setVideoTransparency', + text: formatMessage({ + id: 'videoSensing.setVideoTransparency', + default: 'set video transparency to [TRANSPARENCY]', + description: 'Controls transparency of the video preview layer' + }), + arguments: { + TRANSPARENCY: { + type: ArgumentType.NUMBER, + defaultValue: 10 + } + } + }, + { + opcode: 'writeLog', + blockType: BlockType.COMMAND, + text: 'log [TEXT]', + arguments: { + TEXT: { + type: ArgumentType.STRING, + defaultValue: "hello" + } + } + }, + { + opcode: 'faceDetection', + blockType: BlockType.COMMAND, + text: formatMessage({ + id: 'faceapi.faceDetection', + default: 'faceDetection', + description: 'faceDetection is loaded' + }) + } + ], + menus: { + ATTRIBUTE: { + acceptReporters: true, + items: this._buildMenu(this.ATTRIBUTE_INFO) + }, + SUBJECT: { + acceptReporters: true, + items: this._buildMenu(this.SUBJECT_INFO) + }, + VIDEO_STATE: { + acceptReporters: true, + items:this._buildMenu(this.VIDEO_STATE_INFO), + }, + typemenu: { + acceptReporters: true, + items: '_typeArr' + } + } + }; + } + + _typeArr () { + return typeArr.slice(3).map(item => item.toString()) + } + /** + * A scratch command block handle that configures the video state from + * passed arguments. + * @param {object} args - the block arguments + * @param {VideoState} args.VIDEO_STATE - the video state to set the device to + */ + videoToggle(args) { + const state = args.VIDEO_STATE; + this.globalVideoState = state; + if (state === VideoState.OFF) { + this.runtime.ioDevices.video.disableVideo(); + } else { + this.runtime.ioDevices.video.enableVideo().then(() => { + this.video = this.runtime.ioDevices.video.provider.video + console.log('this.video got') + }); + // Mirror if state is ON. Do not mirror if state is ON_FLIPPED. + this.runtime.ioDevices.video.mirror = state === VideoState.ON; + } + } + + /** + * A scratch command block handle that configures the video preview's + * transparency from passed arguments. + * @param {object} args - the block arguments + * @param {number} args.TRANSPARENCY - the transparency to set the video + * preview to + */ + setVideoTransparency(args) { + const transparency = Cast.toNumber(args.TRANSPARENCY); + this.globalVideoTransparency = transparency; + this.runtime.ioDevices.video.setPreviewGhost(transparency); + } + + faceDetection ( ) + { +return new Promise((resolve, reject) => { + + const originCanvas = this.runtime.renderer._gl.canvas + const canvas = faceapi.createCanvasFromMedia(this.video) + + canvas.width = 480 + canvas.height = 360 + + originCanvas.parentElement.style.position = 'relative' + canvas.style.position = 'absolute' + canvas.style.top = '0' + canvas.style.left = '0' + originCanvas.parentElement.append(canvas) + + this.timer = setInterval(async () => { + const results = await faceapi + .detectSingleFace(this.video, new faceapi.TinyFaceDetectorOptions({ inputSize: 224, scoreThreshold: 0.5 })).withFaceLandmarks().withFaceExpressions() + + if (results) { + const displaySize = {width: 480 , height: 360} + const resizedDetections = faceapi.resizeResults(results, displaySize) + canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height) + faceapi.draw.drawDetections(canvas, resizedDetections) + faceapi.draw.drawFaceLandmarks(canvas, resizedDetections) + faceapi.draw.drawFaceExpressions(canvas, resizedDetections) + } + resolve('success') + }, 1000); + }) + } + + writeLog (args) { + const text = Cast.toString(args.TEXT); + log.log(text); + } + + async faceaipInit () { + await faceapi.nets.tinyFaceDetector.loadFromUri('./static/faceapi'), + await faceapi.nets.faceLandmark68Net.loadFromUri('./static/faceapi'), + await faceapi.nets.faceRecognitionNet.loadFromUri('./static/faceapi'), + await faceapi.nets.faceExpressionNet.loadFromUri('./static/faceapi') + console.log(faceapi.nets) + } +} + +module.exports = Scratch3Vision; \ No newline at end of file diff --git a/src/io/video.js b/src/io/video.js index 23dce8b7900..4bb660584ca 100644 --- a/src/io/video.js +++ b/src/io/video.js @@ -1,7 +1,7 @@ const StageLayering = require('../engine/stage-layering'); class Video { - constructor (runtime) { + constructor(runtime) { this.runtime = runtime; /** @@ -41,11 +41,11 @@ class Video { this._forceTransparentPreview = false; } - static get FORMAT_IMAGE_DATA () { + static get FORMAT_IMAGE_DATA() { return 'image-data'; } - static get FORMAT_CANVAS () { + static get FORMAT_CANVAS() { return 'canvas'; } @@ -54,7 +54,7 @@ class Video { * sample canvas. * @type {Array.} */ - static get DIMENSIONS () { + static get DIMENSIONS() { return [480, 360]; } @@ -62,7 +62,7 @@ class Video { * Order preview drawable is inserted at in the renderer. * @type {number} */ - static get ORDER () { + static get ORDER() { return 1; } @@ -71,7 +71,7 @@ class Video { * a video provider can be found in scratch-gui/src/lib/video/video-provider * @param {VideoProvider} provider - Video provider to use */ - setProvider (provider) { + setProvider(provider) { this.provider = provider; } @@ -82,7 +82,7 @@ class Video { * * @return {Promise.