diff --git a/package-lock.json b/package-lock.json index f0aa900f..53c8e790 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,7 +95,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -649,7 +648,6 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -693,7 +691,6 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1469,6 +1466,7 @@ "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -1485,6 +1483,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1507,6 +1506,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1529,6 +1529,7 @@ "os": [ "darwin" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1545,6 +1546,7 @@ "os": [ "darwin" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1561,6 +1563,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1577,6 +1580,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1593,6 +1597,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1609,6 +1614,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1625,6 +1631,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1641,6 +1648,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1657,6 +1665,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -1673,6 +1682,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1695,6 +1705,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1717,6 +1728,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1739,6 +1751,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1761,6 +1774,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1783,6 +1797,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1805,6 +1820,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1824,6 +1840,7 @@ ], "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, + "peer": true, "dependencies": { "@emnapi/runtime": "^1.5.0" }, @@ -1846,6 +1863,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1865,6 +1883,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1884,6 +1903,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -1908,6 +1928,7 @@ "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -1917,6 +1938,7 @@ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "license": "MIT", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -1929,6 +1951,7 @@ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "license": "MIT", + "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -1975,6 +1998,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -2242,7 +2266,8 @@ "version": "16.1.1", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.1.tgz", "integrity": "sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@next/swc-darwin-arm64": { "version": "16.1.1", @@ -2256,6 +2281,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 10" } @@ -2272,6 +2298,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 10" } @@ -2288,6 +2315,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -2304,6 +2332,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -2320,6 +2349,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -2336,6 +2366,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -2352,6 +2383,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10" } @@ -2368,6 +2400,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10" } @@ -2722,6 +2755,7 @@ "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.85.3.tgz", "integrity": "sha512-u9ZiYP23vA2IFtdFQFmetzSmk6SM0xgKIoiOsr1hXNHjHaLhOm+/Ph1ud57wX6+Dbwdzx8coJgnzSKL3W21PCg==", "license": "MIT", + "peer": true, "engines": { "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } @@ -2731,6 +2765,7 @@ "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.85.3.tgz", "integrity": "sha512-/JkS1lGLyzBWP1FbgDwaqEf7qShIC6pUC1M0a/YMAd/v4iqR24MRkQWe7jkYvcBQ2LpEhs5NGE9InhxSv21zCA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.29.0", @@ -2752,6 +2787,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "license": "ISC", + "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -2765,13 +2801,15 @@ "version": "0.33.3", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@react-native/codegen/node_modules/hermes-parser": { "version": "0.33.3", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", "license": "MIT", + "peer": true, "dependencies": { "hermes-estree": "0.33.3" } @@ -2781,6 +2819,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2798,6 +2837,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", + "peer": true, "engines": { "node": ">=10" } @@ -2807,6 +2847,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "license": "MIT", + "peer": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -2825,6 +2866,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -2834,6 +2876,7 @@ "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.85.3.tgz", "integrity": "sha512-fs85dmbIqNmtzEixDb0g+q6R3Vt4H9eAt8/inIZdDKfjN76+sUJA2r1nxODQ76bU23MrIbz8sI7KFBPaWk/zQw==", "license": "MIT", + "peer": true, "dependencies": { "@react-native/dev-middleware": "0.85.3", "debug": "^4.4.0", @@ -2864,6 +2907,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -2876,6 +2920,7 @@ "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.85.3.tgz", "integrity": "sha512-uAu7rM5o/Np1zgp6fi5zM1sP1aB8DcS7DdOLcj/TkSutOAjkMqqd2lWt1/+3S7qXexRHVK5XcP+o3VXo4L/V0A==", "license": "BSD-3-Clause", + "peer": true, "engines": { "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } @@ -2885,6 +2930,7 @@ "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.85.3.tgz", "integrity": "sha512-/jRAaT9boiCttIcEwS02WPwYkUihqsjSaK/TMtHz05vT6uMgac9PaQt5kzBQLIABv5aEIa5gtrMmKVz49MjkjQ==", "license": "MIT", + "peer": true, "dependencies": { "cross-spawn": "^7.0.6", "debug": "^4.4.0", @@ -2899,6 +2945,7 @@ "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.85.3.tgz", "integrity": "sha512-JYzBiT4A8w+KQt+dOD5v+ti+tDrGoPnsSTuApq3Ls4RB5sfWbDlYMyz3dbc8qBIHz9tv0sQ5+eOu6Xwqzr5AQA==", "license": "MIT", + "peer": true, "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.85.3", @@ -2922,6 +2969,7 @@ "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.85.3.tgz", "integrity": "sha512-39dY2j50Q1pntejzwt3XL7vwXtrj8jcIfHq6E+gyu3jzYxZJVvMkMutQ39vSg6zinIQOX36oQDhidXUbCXzgoA==", "license": "MIT", + "peer": true, "engines": { "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } @@ -2931,6 +2979,7 @@ "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.85.3.tgz", "integrity": "sha512-U2+aMshIXf1uFn77tpBb/xhHWB9vkVrMpt7kkucAugF8hJKYTDGB587X7WwelHduK2KBfhl4giSv0rzZGoef9A==", "license": "MIT", + "peer": true, "engines": { "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } @@ -2939,13 +2988,15 @@ "version": "0.85.3", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.85.3.tgz", "integrity": "sha512-hj0PScZEhIbcOvQV5yMKX3ha4XEIOy/SVE1Rrpp0beW0dpNLOgSC7KDxGewmDnIHK9YdQUXGY9eMEfShUMIaZw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@react-native/virtualized-lists": { "version": "0.85.3", "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.85.3.tgz", "integrity": "sha512-dsCjI//OIPEUJMyNHp4l7zNLVjCx7bcaRUceOCkU+IB17hkbtbGWvi7HjGFSzy7FJGmS/MOlcfpb72xXiy1Oig==", "license": "MIT", + "peer": true, "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" @@ -3291,7 +3342,8 @@ "version": "0.27.10", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@solana-mobile/mobile-wallet-adapter-protocol": { "version": "2.2.8", @@ -3373,6 +3425,7 @@ "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", "license": "MIT", + "peer": true, "dependencies": { "buffer": "~6.0.3" }, @@ -3488,7 +3541,6 @@ "resolved": "https://registry.npmjs.org/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.27.tgz", "integrity": "sha512-kXjeNfNFVs/NE9GPmysBRKQ/nf+foSaq3kfVSeMcO/iVgigyRmB551OjU3WyAolLG/1jeEfKLqF9fKwMCRkUqg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@solana/wallet-standard-features": "^1.3.0", "@wallet-standard/base": "^1.1.0", @@ -3669,6 +3721,7 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0" }, @@ -3684,6 +3737,7 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", "license": "MIT", + "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/errors": "2.3.0" @@ -3700,6 +3754,7 @@ "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", "license": "MIT", + "peer": true, "dependencies": { "chalk": "^5.4.1", "commander": "^14.0.0" @@ -3719,6 +3774,7 @@ "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "^5.0.1" } @@ -3728,6 +3784,7 @@ "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", "license": "MIT", + "peer": true, "dependencies": { "base-x": "^3.0.2" } @@ -3737,6 +3794,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "license": "MIT", + "peer": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -3761,6 +3819,7 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.8.0" } @@ -4405,6 +4464,7 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*" } @@ -4490,7 +4550,8 @@ "version": "2.0.46", "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/hast": { "version": "2.3.10", @@ -4505,13 +4566,15 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "license": "MIT", + "peer": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -4521,6 +4584,7 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/istanbul-lib-report": "*" } @@ -4537,6 +4601,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz", "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } @@ -4558,7 +4623,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -4593,7 +4657,8 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@types/unist": { "version": "2.0.11", @@ -4611,13 +4676,15 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*" } @@ -4627,6 +4694,7 @@ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "license": "MIT", + "peer": true, "dependencies": { "@types/yargs-parser": "*" } @@ -4635,7 +4703,8 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@vitejs/plugin-react": { "version": "5.0.1", @@ -4874,6 +4943,7 @@ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", + "peer": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -4899,7 +4969,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4922,6 +4991,7 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", + "peer": true, "engines": { "node": ">= 14" } @@ -4931,6 +5001,7 @@ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", "license": "MIT", + "peer": true, "dependencies": { "humanize-ms": "^1.2.1" }, @@ -4969,7 +5040,8 @@ "version": "1.4.10", "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/ansi-regex": { "version": "5.0.1", @@ -5144,7 +5216,8 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/assertion-error": { "version": "2.0.1", @@ -5222,6 +5295,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.33.3.tgz", "integrity": "sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==", "license": "MIT", + "peer": true, "dependencies": { "hermes-parser": "0.33.3" } @@ -5230,13 +5304,15 @@ "version": "0.33.3", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { "version": "0.33.3", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", "license": "MIT", + "peer": true, "dependencies": { "hermes-estree": "0.33.3" } @@ -5272,13 +5348,15 @@ "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/baseline-browser-mapping": { "version": "2.9.11", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", "license": "Apache-2.0", + "peer": true, "bin": { "baseline-browser-mapping": "dist/cli.js" } @@ -5287,7 +5365,8 @@ "version": "5.2.3", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/body-parser": { "version": "2.2.2", @@ -5330,6 +5409,7 @@ "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "bn.js": "^5.2.0", "bs58": "^4.0.0", @@ -5341,6 +5421,7 @@ "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "^5.0.1" } @@ -5350,6 +5431,7 @@ "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", "license": "MIT", + "peer": true, "dependencies": { "base-x": "^3.0.2" } @@ -5396,7 +5478,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001735", "electron-to-chromium": "^1.5.204", @@ -5415,7 +5496,6 @@ "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", "license": "MIT", - "peer": true, "dependencies": { "base-x": "^5.0.0" } @@ -5425,6 +5505,7 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "node-int64": "^0.4.0" } @@ -5448,6 +5529,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -5457,7 +5539,23 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" + "license": "MIT", + "peer": true + }, + "node_modules/bufferutil": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", + "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } }, "node_modules/bytes": { "version": "3.1.2", @@ -5530,6 +5628,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -5627,6 +5726,7 @@ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", @@ -5645,6 +5745,7 @@ "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.3.0.tgz", "integrity": "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", @@ -5657,13 +5758,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cliui": { "version": "6.0.0", @@ -5747,6 +5850,7 @@ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "license": "MIT", + "peer": true, "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", @@ -5762,6 +5866,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", + "peer": true, "dependencies": { "ms": "2.0.0" } @@ -5770,7 +5875,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/content-disposition": { "version": "1.1.0", @@ -6155,6 +6261,7 @@ "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -6185,6 +6292,7 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -6236,6 +6344,7 @@ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true, "optionalDependencies": { "@types/trusted-types": "^2.0.7" } @@ -6289,6 +6398,7 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -6320,6 +6430,7 @@ "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", "license": "MIT", + "peer": true, "dependencies": { "stackframe": "^1.3.4" } @@ -6519,13 +6630,15 @@ "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "license": "MIT", + "peer": true, "dependencies": { "es6-promise": "^4.0.3" } @@ -6605,7 +6718,6 @@ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6841,6 +6953,7 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -6865,7 +6978,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/express": { "version": "5.2.1", @@ -7046,6 +7160,7 @@ "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "peer": true, "engines": { "node": "> 0.1.90" } @@ -7075,7 +7190,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fault": { "version": "1.0.4", @@ -7095,6 +7211,7 @@ "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", "license": "(MIT OR Apache-2.0)", + "peer": true, "bin": { "dotslash": "bin/dotslash" }, @@ -7107,6 +7224,7 @@ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "bser": "2.1.1" } @@ -7141,6 +7259,7 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "license": "MIT", + "peer": true, "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -7159,6 +7278,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", + "peer": true, "dependencies": { "ms": "2.0.0" } @@ -7167,7 +7287,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/find-root": { "version": "1.1.0", @@ -7217,7 +7338,8 @@ "version": "0.0.6", "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/for-each": { "version": "0.3.5", @@ -7284,6 +7406,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -7649,7 +7772,8 @@ "version": "250829098.0.10", "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.10.tgz", "integrity": "sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/hermes-estree": { "version": "0.25.1", @@ -7726,6 +7850,7 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", + "peer": true, "dependencies": { "agent-base": "^7.1.2", "debug": "4" @@ -7739,6 +7864,7 @@ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.0.0" } @@ -7777,7 +7903,8 @@ "url": "https://feross.org/support" } ], - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/ignore": { "version": "5.3.2", @@ -7794,6 +7921,7 @@ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", "license": "MIT", + "peer": true, "dependencies": { "queue": "6.0.2" }, @@ -7885,6 +8013,7 @@ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.0.0" } @@ -8086,6 +8215,7 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "license": "MIT", + "peer": true, "bin": { "is-docker": "cli.js" }, @@ -8390,6 +8520,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "license": "MIT", + "peer": true, "dependencies": { "is-docker": "^2.0.0" }, @@ -8415,6 +8546,7 @@ "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", "license": "MIT", + "peer": true, "peerDependencies": { "ws": "*" } @@ -8442,6 +8574,7 @@ "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.3.0.tgz", "integrity": "sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/connect": "^3.4.33", "@types/node": "^12.12.54", @@ -8467,19 +8600,22 @@ "version": "12.20.55", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/jayson/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "license": "MIT", + "peer": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -8489,6 +8625,7 @@ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "license": "MIT", + "peer": true, "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -8512,6 +8649,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -8521,6 +8659,7 @@ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "license": "MIT", + "peer": true, "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -8538,6 +8677,7 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -8553,6 +8693,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "license": "MIT", + "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -8610,7 +8751,8 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", - "license": "0BSD" + "license": "0BSD", + "peer": true }, "node_modules/jsesc": { "version": "3.1.0", @@ -8655,7 +8797,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/json5": { "version": "2.2.3", @@ -8707,6 +8850,7 @@ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -8730,6 +8874,7 @@ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", "license": "Apache-2.0", + "peer": true, "dependencies": { "debug": "^2.6.9", "marky": "^1.2.2" @@ -8740,6 +8885,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", + "peer": true, "dependencies": { "ms": "2.0.0" } @@ -8748,7 +8894,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lightningcss": { "version": "1.30.1", @@ -9020,7 +9167,8 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/loose-envify": { "version": "1.4.0", @@ -9080,6 +9228,7 @@ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "tmpl": "1.0.5" } @@ -9089,6 +9238,7 @@ "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", "license": "MIT", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -9100,7 +9250,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/math-intrinsics": { "version": "1.1.0", @@ -9124,7 +9275,8 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/merge-descriptors": { "version": "2.0.0", @@ -9155,13 +9307,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/metro": { "version": "0.84.4", "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.4.tgz", "integrity": "sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/core": "^7.25.2", @@ -9215,6 +9369,7 @@ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.4.tgz", "integrity": "sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", @@ -9230,13 +9385,15 @@ "version": "0.35.0", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/metro-babel-transformer/node_modules/hermes-parser": { "version": "0.35.0", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", "license": "MIT", + "peer": true, "dependencies": { "hermes-estree": "0.35.0" } @@ -9246,6 +9403,7 @@ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.4.tgz", "integrity": "sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==", "license": "MIT", + "peer": true, "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", @@ -9261,6 +9419,7 @@ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.4.tgz", "integrity": "sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==", "license": "MIT", + "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6" }, @@ -9273,6 +9432,7 @@ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.4.tgz", "integrity": "sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==", "license": "MIT", + "peer": true, "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", @@ -9292,6 +9452,7 @@ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.4.tgz", "integrity": "sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==", "license": "MIT", + "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", @@ -9306,6 +9467,7 @@ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.4.tgz", "integrity": "sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==", "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", @@ -9326,6 +9488,7 @@ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.4.tgz", "integrity": "sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==", "license": "MIT", + "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" @@ -9339,6 +9502,7 @@ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.4.tgz", "integrity": "sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==", "license": "MIT", + "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6" }, @@ -9351,6 +9515,7 @@ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.4.tgz", "integrity": "sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" @@ -9364,6 +9529,7 @@ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.4.tgz", "integrity": "sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==", "license": "MIT", + "peer": true, "dependencies": { "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", @@ -9384,6 +9550,7 @@ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.4.tgz", "integrity": "sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==", "license": "MIT", + "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", @@ -9404,6 +9571,7 @@ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.4.tgz", "integrity": "sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.29.1", @@ -9421,6 +9589,7 @@ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.4.tgz", "integrity": "sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.29.1", @@ -9445,6 +9614,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "license": "ISC", + "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -9458,13 +9628,15 @@ "version": "0.35.0", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/metro/node_modules/hermes-parser": { "version": "0.35.0", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", "license": "MIT", + "peer": true, "dependencies": { "hermes-estree": "0.35.0" } @@ -9474,6 +9646,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -9491,6 +9664,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", + "peer": true, "engines": { "node": ">=10" } @@ -9500,6 +9674,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "license": "MIT", + "peer": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9518,6 +9693,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -9540,6 +9716,7 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "license": "MIT", + "peer": true, "bin": { "mime": "cli.js" }, @@ -9611,6 +9788,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "license": "MIT", + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -9698,6 +9876,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-16.1.1.tgz", "integrity": "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "16.1.1", "@swc/helpers": "0.5.15", @@ -9765,6 +9944,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -9785,6 +9965,7 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "license": "MIT", + "peer": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -9806,6 +9987,7 @@ "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "license": "MIT", "optional": true, + "peer": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -9816,7 +9998,8 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/node-releases": { "version": "2.0.19", @@ -9828,13 +10011,15 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/ob1": { "version": "0.84.4", "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.4.tgz", "integrity": "sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==", "license": "MIT", + "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6" }, @@ -9964,6 +10149,7 @@ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "license": "MIT", + "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -9985,6 +10171,7 @@ "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "license": "MIT", + "peer": true, "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" @@ -10277,6 +10464,7 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "license": "MIT", + "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -10291,6 +10479,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -10302,7 +10491,8 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/prismjs": { "version": "1.30.0", @@ -10318,6 +10508,7 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", "license": "MIT", + "peer": true, "dependencies": { "asap": "~2.0.6" } @@ -10415,6 +10606,7 @@ "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", "license": "MIT", + "peer": true, "dependencies": { "inherits": "~2.0.3" } @@ -10448,7 +10640,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -10458,6 +10649,7 @@ "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz", "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==", "license": "MIT", + "peer": true, "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" @@ -10468,7 +10660,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -10480,8 +10671,7 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-native": { "version": "0.85.3", @@ -10548,6 +10738,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "license": "ISC", + "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -10562,6 +10753,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -10571,6 +10763,7 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -10580,6 +10773,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -10592,6 +10786,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -10609,6 +10804,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", + "peer": true, "engines": { "node": ">=10" } @@ -10618,6 +10814,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "license": "MIT", + "peer": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -10636,6 +10833,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -10645,7 +10843,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -10779,8 +10976,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -10842,7 +11038,8 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", @@ -10974,6 +11171,7 @@ "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.9.tgz", "integrity": "sha512-2iQDaTB4g5fDB2ihrTFSJSibCEuxaRi1q7qTW7ZO9/M5/TC+ToHA4D9/ffNLEbAoHNNrcdeP05oATNk44SKZXA==", "license": "LGPL-3.0-only", + "peer": true, "dependencies": { "@swc/helpers": "^0.5.11", "@types/uuid": "^10.0.0", @@ -10997,10 +11195,26 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*" } }, + "node_modules/rpc-websockets/node_modules/utf-8-validate": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.6.tgz", + "integrity": "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/rpc-websockets/node_modules/uuid": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", @@ -11010,6 +11224,7 @@ "https://github.com/sponsors/ctavan" ], "license": "MIT", + "peer": true, "bin": { "uuid": "dist-node/bin/uuid" } @@ -11019,6 +11234,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "license": "MIT", + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -11073,7 +11289,8 @@ "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/safe-push-apply": { "version": "1.0.0", @@ -11136,6 +11353,7 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "license": "MIT", + "peer": true, "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -11160,6 +11378,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", + "peer": true, "dependencies": { "ms": "2.0.0" } @@ -11168,13 +11387,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/send/node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -11184,6 +11405,7 @@ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", + "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -11196,6 +11418,7 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -11205,6 +11428,7 @@ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -11214,6 +11438,7 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "license": "MIT", + "peer": true, "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -11229,6 +11454,7 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -11307,6 +11533,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "optional": true, + "peer": true, "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.0", @@ -11349,6 +11576,7 @@ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -11359,6 +11587,7 @@ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "optional": true, + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -11392,6 +11621,7 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -11501,6 +11731,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", + "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -11511,6 +11742,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -11536,13 +11768,15 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/stacktrace-parser": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", "license": "MIT", + "peer": true, "dependencies": { "type-fest": "^0.7.1" }, @@ -11561,6 +11795,7 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -11589,13 +11824,15 @@ "version": "2.2.5", "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/stream-json": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "stream-chain": "^2.2.5" } @@ -11742,6 +11979,7 @@ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", "license": "MIT", + "peer": true, "dependencies": { "client-only": "0.0.1" }, @@ -11771,6 +12009,7 @@ "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", "license": "MIT", + "peer": true, "engines": { "node": ">=14.0.0" } @@ -11863,6 +12102,7 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz", "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -11880,18 +12120,21 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/text-encoding-utf-8": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", - "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==", + "peer": true }, "node_modules/throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tiny-invariant": { "version": "1.3.3", @@ -11954,7 +12197,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -11976,7 +12218,8 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -12009,7 +12252,8 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tslib": { "version": "2.8.1", @@ -12035,6 +12279,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=8" } @@ -12185,7 +12430,8 @@ "version": "7.24.6", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/unpipe": { "version": "1.0.0", @@ -12250,6 +12496,7 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4.0" } @@ -12353,7 +12600,6 @@ "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -12447,7 +12693,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -12569,13 +12814,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "makeerror": "1.0.12" } @@ -12584,19 +12831,22 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "peer": true }, "node_modules/whatwg-fetch": { "version": "3.6.20", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "license": "MIT", + "peer": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -12807,6 +13057,7 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "license": "ISC", + "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -12932,7 +13183,6 @@ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/App.jsx b/src/App.jsx index f745640e..c84ce11b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -71,6 +71,9 @@ const SlidingWindowVisualizerPage = lazy( const TwoPointerVisualizerPage = lazy( () => import('./components/twoPointer/TwoPointerVisualizer') ) +const GreedyVisualizerPage = lazy( + () => import('./components/greedyAlgo/VisualizerPage') +) const StackVisualizerPage = lazy( () => import('./components/monotonicStack/StackVisualizerPage') ) @@ -261,6 +264,16 @@ const router = createBrowserRouter([ ), }, + { + path: '/greedy', + element: ( + }> + + + + + ), + }, { path: '/challenge', element: ( diff --git a/src/algorithms/greedy/fractionalKnapsackSteps.js b/src/algorithms/greedy/fractionalKnapsackSteps.js new file mode 100644 index 00000000..6a6aa414 --- /dev/null +++ b/src/algorithms/greedy/fractionalKnapsackSteps.js @@ -0,0 +1,267 @@ +const createStep = ({ + lineKey, + type, + items, + knapsackState, + activeItemId = null, + message = '', + variables = {}, + duration = 1000, +}) => ({ + lineKey, + type, + items: structuredClone(items), + knapsackState: structuredClone(knapsackState), + activeItemId, + message, + variables, + duration, +}) + +export function generateFractionalKnapsackSteps(capacity, inputItems) { + const steps = [] + let currentCapacity = Number(capacity) + + if (isNaN(currentCapacity) || currentCapacity <= 0) { + currentCapacity = 50 + } + + // Deep copy the input items + let items = inputItems + .map((item, index) => ({ + id: item.id || `Item ${index + 1}`, + value: Number(item.value), + weight: Number(item.weight), + ratio: 0, + status: 'staged', // staged, ratio-calculated, sorted, active, packed, fractioned, skipped + packedRatio: 0, + packedWeight: 0, + packedValue: 0, + })) + .filter( + (item) => + !isNaN(item.value) && + !isNaN(item.weight) && + item.weight > 0 && + item.value > 0 + ) + + let knapsackState = { + capacityLeft: currentCapacity, + totalCapacity: currentCapacity, + totalValue: 0, + contents: [], // blocks packed inside: { id, weight, value, ratio, color } + } + + // Step 1: Start + steps.push( + createStep({ + lineKey: 'init', + type: 'start', + items, + knapsackState, + message: `Fractional Knapsack Visualizer started. Knapsack capacity: ${currentCapacity} kg.`, + variables: { capacity: currentCapacity, totalItems: items.length }, + duration: 1000, + }) + ) + + // Step 2: Calculate Ratios + items.forEach((item) => { + item.ratio = Number((item.value / item.weight).toFixed(2)) + item.status = 'ratio-calculated' + }) + + steps.push( + createStep({ + lineKey: 'ratio', + type: 'calc-ratios', + items, + knapsackState, + message: + 'Calculated Value-to-Weight ratio (Value / Weight) for each item. Greedy strategy prioritizes higher ratios.', + variables: { capacity: currentCapacity }, + duration: 1200, + }) + ) + + // Step 3: Sort items by ratio descending + items.sort((a, b) => b.ratio - a.ratio || a.weight - b.weight) + items.forEach((item) => { + item.status = 'sorted' + }) + + steps.push( + createStep({ + lineKey: 'sort', + type: 'sort-items', + items, + knapsackState, + message: + 'Sorted all items in descending order of their Value-to-Weight ratio.', + variables: { sorted: true }, + duration: 1200, + }) + ) + + // Step 4: Initialize total value + steps.push( + createStep({ + lineKey: 'total', + type: 'init-total', + items, + knapsackState, + message: 'Initializing total packed value to $0.', + variables: { totalValue: 0, capacityLeft: currentCapacity }, + duration: 800, + }) + ) + + // Step 5: Pack greedily + for (let i = 0; i < items.length; i++) { + const item = items[i] + item.status = 'active' + + steps.push( + createStep({ + lineKey: 'loop', + type: 'process-item', + items, + knapsackState, + activeItemId: item.id, + message: `Inspecting ${item.id} (Weight: ${item.weight} kg, Value: $${item.value}, Ratio: ${item.ratio}).`, + variables: { + activeItem: item.id, + capacityLeft: knapsackState.capacityLeft, + }, + duration: 900, + }) + ) + + steps.push( + createStep({ + lineKey: 'check', + type: 'check-capacity', + items, + knapsackState, + activeItemId: item.id, + message: `Comparing item weight (${item.weight} kg) with remaining capacity (${knapsackState.capacityLeft} kg).`, + variables: { + itemWeight: item.weight, + capacityLeft: knapsackState.capacityLeft, + }, + duration: 900, + }) + ) + + if (knapsackState.capacityLeft >= item.weight) { + // Pack full item + knapsackState.capacityLeft -= item.weight + knapsackState.totalValue += item.value + + item.status = 'packed' + item.packedRatio = 1 + item.packedWeight = item.weight + item.packedValue = item.value + + knapsackState.contents.push({ + id: item.id, + weight: item.weight, + value: item.value, + ratio: item.ratio, + fraction: 1, + }) + + steps.push( + createStep({ + lineKey: 'packFull', + type: 'packed-full', + items, + knapsackState, + activeItemId: item.id, + message: `Remaining capacity is sufficient! Packed 100% of ${item.id}. Remaining Capacity reduces to ${knapsackState.capacityLeft} kg.`, + variables: { + totalValue: knapsackState.totalValue, + capacityLeft: knapsackState.capacityLeft, + }, + duration: 1200, + }) + ) + } else if (knapsackState.capacityLeft > 0) { + // Pack fraction of item + const fraction = knapsackState.capacityLeft / item.weight + const fractionVal = Number((item.value * fraction).toFixed(2)) + const fractionWt = knapsackState.capacityLeft + + knapsackState.totalValue = Number( + (knapsackState.totalValue + fractionVal).toFixed(2) + ) + knapsackState.capacityLeft = 0 + + item.status = 'fractioned' + item.packedRatio = fraction + item.packedWeight = fractionWt + item.packedValue = fractionVal + + knapsackState.contents.push({ + id: item.id, + weight: fractionWt, + value: fractionVal, + ratio: item.ratio, + fraction: fraction, + }) + + steps.push( + createStep({ + lineKey: 'packFraction', + type: 'packed-fraction', + items, + knapsackState, + activeItemId: item.id, + message: `Remaining capacity is ${fractionWt} kg (less than item weight ${item.weight} kg). Took a fraction: ${(fraction * 100).toFixed(1)}% of ${item.id}. Total value increases by $${fractionVal}.`, + variables: { totalValue: knapsackState.totalValue, capacityLeft: 0 }, + duration: 1200, + }) + ) + + // Rest of the items are skipped since knapsack is full + for (let j = i + 1; j < items.length; j++) { + items[j].status = 'skipped' + } + break + } else { + // Capacity is already 0 + item.status = 'skipped' + steps.push( + createStep({ + lineKey: 'loop', + type: 'process-item', + items, + knapsackState, + activeItemId: item.id, + message: `Knapsack is full. Skipping ${item.id}.`, + variables: { totalValue: knapsackState.totalValue, capacityLeft: 0 }, + duration: 800, + }) + ) + } + } + + // Final step + steps.push( + createStep({ + lineKey: 'finish', + type: 'complete', + items, + knapsackState, + message: `Fractional Knapsack complete! Maximized total packed value is $${knapsackState.totalValue}.`, + variables: { + finalValue: knapsackState.totalValue, + capacityUsed: knapsackState.totalCapacity - knapsackState.capacityLeft, + }, + duration: 1500, + }) + ) + + return steps +} diff --git a/src/algorithms/greedy/greedySources.js b/src/algorithms/greedy/greedySources.js new file mode 100644 index 00000000..5a357346 --- /dev/null +++ b/src/algorithms/greedy/greedySources.js @@ -0,0 +1,416 @@ +export const greedySources = { + huffman: { + javascript: { + code: `function buildHuffmanTree(text) { + // Step 1: Calculate character frequencies + const freq = {}; + for (let char of text) { + freq[char] = (freq[char] || 0) + 1; + } + + // Step 2: Initialize priority queue with leaf nodes + const pq = Object.keys(freq).map(char => ({ + char, + freq: freq[char], + left: null, + right: null + })); + + // Step 3: Repeatedly merge two lowest frequency nodes + while (pq.length > 1) { + pq.sort((a, b) => a.freq - b.freq); + const left = pq.shift(); + const right = pq.shift(); + + const parent = { + char: null, + freq: left.freq + right.freq, + left, + right + }; + pq.push(parent); + } + + return pq[0]; // Root node +}`, + lineMap: { + init: 2, + freq: 3, + pq: 8, + loop: 16, + sort: 17, + pick: 18, + merge: 21, + push: 27, + finish: 30, + }, + }, + python: { + code: `import heapq + +def build_huffman_tree(text): + # Step 1: Calculate character frequencies + freq = {} + for char in text: + freq[char] = freq.get(char, 0) + 1 + + # Step 2: Create priority queue + pq = [[f, [c, ""]] for c, f in freq.items()] + heapq.heapify(pq) + + # Step 3: Repeatedly merge nodes + while len(pq) > 1: + left = heapq.heappop(pq) + right = heapq.heappop(pq) + + for pair in left[1:]: + pair[1] = '0' + pair[1] + for pair in right[1:]: + pair[1] = '1' + pair[1] + + merged = [left[0] + right[0]] + left[1:] + right[1:] + heapq.heappush(pq, merged) + + return pq[0]`, + }, + cpp: { + code: `struct Node { + char ch; + int freq; + Node *left, *right; +}; + +struct compare { + bool operator()(Node* l, Node* r) { + return l->freq > r->freq; + } +}; + +Node* buildHuffmanTree(string text) { + unordered_map freq; + for (char ch: text) freq[ch]++; + + priority_queue, compare> pq; + for (auto pair: freq) { + pq.push(new Node{pair.first, pair.second, nullptr, nullptr}); + } + + while (pq.size() > 1) { + Node *left = pq.top(); pq.pop(); + Node *right = pq.top(); pq.pop(); + + int sum = left->freq + right->freq; + pq.push(new Node{'\\0', sum, left, right}); + } + + return pq.top(); +}`, + }, + java: { + code: `class HuffmanNode { + char data; + int frequency; + HuffmanNode left, right; +} + +public static HuffmanNode buildTree(String text) { + Map freq = new HashMap<>(); + for (char c : text.toCharArray()) { + freq.put(c, freq.getOrDefault(c, 0) + 1); + } + + PriorityQueue pq = new PriorityQueue<>((a, b) -> a.frequency - b.frequency); + for (var entry : freq.entrySet()) { + HuffmanNode node = new HuffmanNode(); + node.data = entry.getKey(); + node.frequency = entry.getValue(); + pq.add(node); + } + + while (pq.size() > 1) { + HuffmanNode x = pq.poll(); + HuffmanNode y = pq.poll(); + + HuffmanNode f = new HuffmanNode(); + f.frequency = x.frequency + y.frequency; + f.data = '-'; + f.left = x; + f.right = y; + pq.add(f); + } + + return pq.poll(); +}`, + }, + }, + knapsack: { + javascript: { + code: `function fractionalKnapsack(capacity, items) { + // Step 1: Calculate ratios + items.forEach(item => { + item.ratio = item.value / item.weight; + }); + + // Step 2: Sort items by value/weight ratio descending + items.sort((a, b) => b.ratio - a.ratio); + + let totalValue = 0; + + // Step 3: Greedily pack items + for (let item of items) { + if (capacity >= item.weight) { + capacity -= item.weight; + totalValue += item.value; + } else { + // Pack fraction of item + totalValue += item.ratio * capacity; + capacity = 0; + break; + } + } + + return totalValue; +}`, + lineMap: { + init: 1, + ratio: 3, + sort: 8, + total: 10, + loop: 13, + check: 14, + packFull: 15, + packFraction: 18, + finish: 24, + }, + }, + python: { + code: `def fractional_knapsack(capacity, items): + # Step 1: Calculate value/weight ratio + for item in items: + item['ratio'] = item['value'] / item['weight'] + + # Step 2: Sort items by ratio descending + items.sort(key=lambda x: x['ratio'], reverse=True) + + total_value = 0.0 + + # Step 3: Pack items + for item in items: + if capacity >= item['weight']: + capacity -= item['weight'] + total_value += item['value'] + else: + # Take fraction + fraction = capacity / item['weight'] + total_value += item['value'] * fraction + break + + return total_value`, + }, + cpp: { + code: `struct Item { + int value, weight; +}; + +bool cmp(struct Item a, struct Item b) { + double r1 = (double)a.value / (double)a.weight; + double r2 = (double)b.value / (double)b.weight; + return r1 > r2; +} + +double fractionalKnapsack(int W, struct Item arr[], int N) { + sort(arr, arr + N, cmp); + + double totalValue = 0.0; + + for (int i = 0; i < N; i++) { + if (W >= arr[i].weight) { + W -= arr[i].weight; + totalValue += arr[i].value; + } else { + totalValue += arr[i].value * ((double)W / (double)arr[i].weight); + break; + } + } + return totalValue; +}`, + }, + java: { + code: `class Item { + int value, weight; + Item(int val, int wt) { this.value = val; this.weight = wt; } +} + +public static double getMaxValue(int W, Item[] arr) { + Arrays.sort(arr, (a, b) -> { + double r1 = (double) a.value / (double) a.weight; + double r2 = (double) b.value / (double) b.weight; + return Double.compare(r2, r1); + }); + + double totalValue = 0d; + + for (Item item : arr) { + if (W >= item.weight) { + W -= item.weight; + totalValue += item.value; + } else { + double fraction = ((double) W / item.weight); + totalValue += fraction * item.value; + break; + } + } + + return totalValue; +}`, + }, + }, + jobsequencing: { + javascript: { + code: `function jobSequencing(jobs) { + // Step 1: Sort jobs by profit descending + jobs.sort((a, b) => b.profit - a.profit); + + const n = jobs.length; + // Step 2: Find maximum deadline + let maxDeadline = 0; + for (let i = 0; i < n; i++) { + if (jobs[i].deadline > maxDeadline) { + maxDeadline = jobs[i].deadline; + } + } + + // Step 3: Initialize timeline slots + const slots = new Array(maxDeadline).fill(null); + let totalProfit = 0; + let countJobs = 0; + + // Step 4: Schedule jobs greedily + for (let i = 0; i < n; i++) { + const job = jobs[i]; + // Find free slot from deadline-1 down to 0 + for (let j = job.deadline - 1; j >= 0; j--) { + if (slots[j] === null) { + slots[j] = job.id; + totalProfit += job.profit; + countJobs++; + break; + } + } + } + + return { slots, totalProfit }; +}`, + lineMap: { + init: 2, + sort: 3, + maxDeadline: 7, + initSlots: 15, + loopJobs: 20, + loopSlots: 23, + assignSlot: 24, + finish: 32, + }, + }, + python: { + code: `def job_sequencing(jobs): + # Step 1: Sort jobs by profit descending + jobs.sort(key=lambda x: x['profit'], reverse=True) + + # Step 2: Find max deadline + max_deadline = max(job['deadline'] for job in jobs) + + # Step 3: Initialize slots + slots = [None] * max_deadline + total_profit = 0 + + # Step 4: Schedule jobs + for job in jobs: + # Search backwards from deadline - 1 to 0 + for j in range(job['deadline'] - 1, -1, -1): + if slots[j] is None: + slots[j] = job['id'] + total_profit += job['profit'] + break + + return slots, total_profit`, + }, + cpp: { + code: `struct Job { + char id; + int deadline; + int profit; +}; + +bool comparison(Job a, Job b) { + return (a.profit > b.profit); +} + +void printJobScheduling(Job arr[], int n) { + sort(arr, arr + n, comparison); + + int maxDeadline = 0; + for (int i = 0; i < n; i++) + maxDeadline = max(maxDeadline, arr[i].deadline); + + vector slots(maxDeadline, '0'); + int totalProfit = 0; + + for (int i = 0; i < n; i++) { + for (int j = arr[i].deadline - 1; j >= 0; j--) { + if (slots[j] == '0') { + slots[j] = arr[i].id; + totalProfit += arr[i].profit; + break; + } + } + } +}`, + }, + java: { + code: `class Job { + char id; + int deadline; + int profit; + Job(char id, int deadline, int profit) { + this.id = id; + this.deadline = deadline; + this.profit = profit; + } +} + +public static void solve(Job[] arr) { + Arrays.sort(arr, (a, b) -> b.profit - a.profit); + + int maxDeadline = 0; + for (Job job : arr) { + maxDeadline = Math.max(maxDeadline, job.deadline); + } + + char[] slots = new char[maxDeadline]; + int totalProfit = 0; + + for (Job job : arr) { + for (int j = job.deadline - 1; j >= 0; j--) { + if (slots[j] == '\\0') { + slots[j] = job.id; + totalProfit += job.profit; + break; + } + } + } +}`, + }, + }, +} + +export const getGreedySource = (algo, lang) => { + return greedySources[algo]?.[lang]?.code || '' +} + +export const resolveGreedyLine = (algo, language, lineKey) => { + if (!lineKey) return undefined + const source = + greedySources[algo]?.[language] || greedySources[algo]?.javascript + return source?.lineMap?.[lineKey] +} diff --git a/src/algorithms/greedy/huffmanCodingSteps.js b/src/algorithms/greedy/huffmanCodingSteps.js new file mode 100644 index 00000000..4362b517 --- /dev/null +++ b/src/algorithms/greedy/huffmanCodingSteps.js @@ -0,0 +1,264 @@ +// Helper to create unique IDs for internal nodes +let internalIdCounter = 0 + +const createStep = ({ + lineKey, + type, + forest, + picked = [], + newParentId = null, + freqTable = [], + codes = {}, + message = '', + variables = {}, + duration = 1000, +}) => ({ + lineKey, + type, + forest: structuredClone(forest), + picked, + newParentId, + freqTable, + codes, + message, + variables, + duration, +}) + +// Helper to assign binary codes to leaf nodes by traversing the final tree +function assignCodes(node, currentCode, codesObj) { + if (!node) return + if (node.char !== null) { + node.code = currentCode + codesObj[node.char] = currentCode + return + } + if (node.left) { + node.left.bit = '0' + assignCodes(node.left, currentCode + '0', codesObj) + } + if (node.right) { + node.right.bit = '1' + assignCodes(node.right, currentCode + '1', codesObj) + } +} + +export function generateHuffmanSteps(text) { + const steps = [] + internalIdCounter = 0 + + if (!text || text.trim() === '') { + return [ + createStep({ + lineKey: 'init', + type: 'start', + forest: [], + message: 'Please provide a non-empty string input.', + duration: 800, + }), + ] + } + + // Step 1: Calculate character frequencies + steps.push( + createStep({ + lineKey: 'init', + type: 'start', + forest: [], + message: `Analyzing input text: "${text}". Starting Huffman Coding.`, + variables: { textLength: text.length }, + duration: 1000, + }) + ) + + const freq = {} + for (let char of text) { + freq[char] = (freq[char] || 0) + 1 + } + + const freqTable = Object.keys(freq) + .map((char) => ({ char, freq: freq[char] })) + .sort((a, b) => b.freq - a.freq || a.char.localeCompare(b.char)) + + steps.push( + createStep({ + lineKey: 'freq', + type: 'freq-table', + forest: [], + freqTable, + message: 'Calculated character frequencies from the input text.', + variables: { uniqueChars: freqTable.length }, + duration: 1200, + }) + ) + + // Step 2: Initialize priority queue + let forest = Object.keys(freq).map((char) => ({ + id: `leaf_${char}`, + char, + freq: freq[char], + left: null, + right: null, + bit: '', + })) + + // Sort initially + forest.sort((a, b) => a.freq - b.freq || a.char.localeCompare(b.char)) + + steps.push( + createStep({ + lineKey: 'pq', + type: 'init-nodes', + forest, + freqTable, + message: + 'Created initial leaf nodes. Sorting them in the priority queue.', + variables: { forestSize: forest.length }, + duration: 1200, + }) + ) + + // Special case: Single unique character + if (forest.length === 1) { + const root = forest[0] + const codes = {} + root.bit = '0' + root.code = '0' + codes[root.char] = '0' + + steps.push( + createStep({ + lineKey: 'finish', + type: 'complete', + forest: [root], + freqTable, + codes, + message: 'Only one unique character found. Trivial tree created.', + variables: { forestSize: 1 }, + duration: 1500, + }) + ) + return steps + } + + // Step 3: Repeatedly merge nodes + while (forest.length > 1) { + steps.push( + createStep({ + lineKey: 'loop', + type: 'loop-start', + forest, + freqTable, + message: `Current forest size is ${forest.length}. We need to merge until only 1 root remains.`, + variables: { forestSize: forest.length }, + duration: 800, + }) + ) + + // Sort priority queue + forest.sort((a, b) => { + if (a.freq !== b.freq) return a.freq - b.freq + const valA = a.char || '' + const valB = b.char || '' + return valA.localeCompare(valB) + }) + + steps.push( + createStep({ + lineKey: 'sort', + type: 'sort-pq', + forest, + freqTable, + message: 'Sorted priority queue by frequency ascending.', + variables: { forestSize: forest.length }, + duration: 800, + }) + ) + + // Pick two lowest + const left = forest[0] + const right = forest[1] + + steps.push( + createStep({ + lineKey: 'pick', + type: 'pick-two', + forest, + picked: [left.id, right.id], + freqTable, + message: `Picked two nodes with lowest frequencies: Node "${left.char || 'internal'}" (${left.freq}) and Node "${right.char || 'internal'}" (${right.freq}).`, + variables: { left: left.freq, right: right.freq }, + duration: 1200, + }) + ) + + // Merge them + forest.splice(0, 2) // remove left and right from forest + + const parentId = `internal_${internalIdCounter++}` + left.bit = '0' + right.bit = '1' + + const parent = { + id: parentId, + char: null, + freq: left.freq + right.freq, + left, + right, + bit: '', + } + + forest.push(parent) + + steps.push( + createStep({ + lineKey: 'merge', + type: 'merge-nodes', + forest, + picked: [left.id, right.id], + newParentId: parentId, + freqTable, + message: `Merged nodes into parent with sum frequency = ${parent.freq}. Left child assigned bit 0, right assigned 1.`, + variables: { mergedFreq: parent.freq }, + duration: 1200, + }) + ) + + // Stage re-insertion and sort for loop repeat + forest.sort((a, b) => a.freq - b.freq) + + steps.push( + createStep({ + lineKey: 'push', + type: 're-insert', + forest, + newParentId: parentId, + freqTable, + message: `Inserted merged node back into priority queue.`, + variables: { forestSize: forest.length }, + duration: 1000, + }) + ) + } + + // Tree is complete. Generate final prefix codes + const finalRoot = forest[0] + const codes = {} + assignCodes(finalRoot, '', codes) + + steps.push( + createStep({ + lineKey: 'finish', + type: 'complete', + forest: [finalRoot], + freqTable, + codes, + message: + 'Huffman tree construction complete. Traversed tree to generate optimal binary codes.', + variables: { uniqueCharsCount: Object.keys(codes).length }, + duration: 1800, + }) + ) + + return steps +} diff --git a/src/algorithms/greedy/jobSequencingSteps.js b/src/algorithms/greedy/jobSequencingSteps.js new file mode 100644 index 00000000..ce5e11c6 --- /dev/null +++ b/src/algorithms/greedy/jobSequencingSteps.js @@ -0,0 +1,264 @@ +const createStep = ({ + lineKey, + type, + jobs, + timeline, + activeJobId = null, + activeSlotIndex = null, + message = '', + variables = {}, + duration = 1000, +}) => ({ + lineKey, + type, + jobs: structuredClone(jobs), + timeline: structuredClone(timeline), + activeJobId, + activeSlotIndex, + message, + variables, + duration, +}) + +export function generateJobSequencingSteps(inputJobs) { + const steps = [] + + // Clean and prepare jobs + let jobs = inputJobs + .map((job, index) => ({ + id: job.id || `J${index + 1}`, + profit: Number(job.profit), + deadline: Number(job.deadline), + status: 'staged', // staged, sorting, sorted, active, scheduled, missed + slotAssigned: null, + })) + .filter( + (job) => + !isNaN(job.profit) && + !isNaN(job.deadline) && + job.profit > 0 && + job.deadline > 0 + ) + + if (jobs.length === 0) { + return [ + createStep({ + lineKey: 'init', + type: 'start', + jobs: [], + timeline: [], + message: 'Please add at least one valid job to visualize.', + duration: 1000, + }), + ] + } + + // Find max deadline of input jobs to size the timeline + const maxDeadline = Math.max(...jobs.map((job) => job.deadline)) + + // Timeline: array of slots from 1 to maxDeadline + // slots are 0-indexed in array but represent time [i to i+1] + const timeline = Array.from({ length: maxDeadline }, (_, i) => ({ + slotIndex: i, + label: `${i}-${i + 1}`, + jobId: null, + status: 'empty', // empty, checking, filled + })) + + let totalProfit = 0 + let scheduledCount = 0 + let missedCount = 0 + + // 1. Initial State + steps.push( + createStep({ + lineKey: 'init', + type: 'start', + jobs, + timeline, + message: `Job Sequencing started. Total jobs: ${jobs.length}. Max deadline: ${maxDeadline}.`, + variables: { totalJobs: jobs.length, maxDeadline, totalProfit: 0 }, + duration: 1000, + }) + ) + + // Highlight that we're sorting jobs by profit descending + jobs.forEach((job) => (job.status = 'sorting')) + steps.push( + createStep({ + lineKey: 'sort', + type: 'sorting', + jobs, + timeline, + message: + 'Sorting jobs in descending order of profit to prioritize high-value jobs.', + variables: { sorting: true, totalProfit }, + duration: 1200, + }) + ) + + // Actual sort + jobs.sort((a, b) => b.profit - a.profit || a.deadline - b.deadline) + jobs.forEach((job) => (job.status = 'sorted')) + + steps.push( + createStep({ + lineKey: 'sort', + type: 'sorted', + jobs, + timeline, + message: + 'Jobs sorted by profit descending. We will now consider each job greedily.', + variables: { sorted: true, totalProfit }, + duration: 1200, + }) + ) + + // Initialize timeline slots in code + steps.push( + createStep({ + lineKey: 'initSlots', + type: 'init-timeline', + jobs, + timeline, + message: `Initializing time-slot timeline of size ${maxDeadline} based on the maximum deadline.`, + variables: { maxDeadline, totalProfit }, + duration: 1000, + }) + ) + + // 2. Iterate through sorted jobs + for (let i = 0; i < jobs.length; i++) { + const job = jobs[i] + job.status = 'active' + + steps.push( + createStep({ + lineKey: 'loopJobs', + type: 'process-job', + jobs, + timeline, + activeJobId: job.id, + message: `Inspecting Job ${job.id} (Profit: $${job.profit}, Deadline: ${job.deadline}). Searching for a slot backwards from slot ${job.deadline}.`, + variables: { + activeJob: job.id, + profit: job.profit, + deadline: job.deadline, + totalProfit, + }, + duration: 1200, + }) + ) + + let foundSlot = false + // j starts from deadline - 1 down to 0 + for (let j = job.deadline - 1; j >= 0; j--) { + if (j >= maxDeadline) continue + + // Mark slot as checking + timeline[j].status = 'checking' + + steps.push( + createStep({ + lineKey: 'loopSlots', + type: 'check-slot', + jobs, + timeline, + activeJobId: job.id, + activeSlotIndex: j, + message: `Checking if Slot ${j + 1} (${timeline[j].label}) is available for Job ${job.id}.`, + variables: { activeJob: job.id, checkingSlot: j + 1, totalProfit }, + duration: 1000, + }) + ) + + if (timeline[j].jobId === null) { + // Slot is free! + timeline[j].jobId = job.id + timeline[j].status = 'filled' + + job.status = 'scheduled' + job.slotAssigned = j + 1 + + totalProfit += job.profit + scheduledCount++ + foundSlot = true + + steps.push( + createStep({ + lineKey: 'assignSlot', + type: 'schedule-success', + jobs, + timeline, + activeJobId: job.id, + activeSlotIndex: j, + message: `Slot ${j + 1} is free! Scheduled Job ${job.id} in slot ${timeline[j].label}. Profit increases by $${job.profit}.`, + variables: { + activeJob: job.id, + assignedSlot: j + 1, + totalProfit, + scheduledJobs: `${scheduledCount}/${jobs.length}`, + }, + duration: 1200, + }) + ) + break + } else { + // Slot is occupied, reset status to filled for visual representation + timeline[j].status = 'filled' + + steps.push( + createStep({ + lineKey: 'loopSlots', + type: 'slot-occupied', + jobs, + timeline, + activeJobId: job.id, + activeSlotIndex: j, + message: `Slot ${j + 1} (${timeline[j].label}) is already occupied by Job ${timeline[j].jobId}. Continuing search backwards.`, + variables: { activeJob: job.id, occupiedSlot: j + 1, totalProfit }, + duration: 1000, + }) + ) + } + } + + if (!foundSlot) { + job.status = 'missed' + missedCount++ + + steps.push( + createStep({ + lineKey: 'loopJobs', + type: 'schedule-miss', + jobs, + timeline, + activeJobId: job.id, + message: `No available slots found before deadline ${job.deadline} for Job ${job.id}. This job is missed.`, + variables: { + activeJob: job.id, + status: 'Missed', + totalProfit, + missedCount, + }, + duration: 1200, + }) + ) + } + } + + // 3. Finish + steps.push( + createStep({ + lineKey: 'finish', + type: 'complete', + jobs, + timeline, + message: `Visualization complete! Scheduled ${scheduledCount} jobs for a total profit of $${totalProfit}.`, + variables: { totalProfit, scheduledCount, missedCount, completed: true }, + duration: 1500, + }) + ) + + return steps +} diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index 32407dea..26b704c3 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -135,6 +135,11 @@ const algorithmLinks = [ href: '/two-pointer', difficulty: 'Advanced', }, + { + name: 'Greedy Algorithms', + href: '/greedy', + difficulty: 'Intermediate', + }, { name: 'Monotonic Stack', href: '/monotonic-stack', diff --git a/src/components/SearchBar.jsx b/src/components/SearchBar.jsx index 44918b57..20e258fb 100644 --- a/src/components/SearchBar.jsx +++ b/src/components/SearchBar.jsx @@ -394,6 +394,14 @@ const ALGORITHMS = [ route: '/dynamic-programming', keywords: ['lcs', 'knapsack', 'Coin Change', 'LIS'], }, + //Greedy Algorithms + { + id: 'greedy', + name: 'Greedy Algorithms', + category: 'Greedy Algorithms', + route: '/greedy', + keywords: ['greedy', 'huffman', 'knapsack', 'fractional knapsack', 'job sequencing', 'deadline', 'scheduling'], + }, { id: 'dynamic-prog-journey', name: 'DP Journey', diff --git a/src/components/greedyAlgo/GreedyAlgorithmCard.jsx b/src/components/greedyAlgo/GreedyAlgorithmCard.jsx new file mode 100644 index 00000000..d253d6a5 --- /dev/null +++ b/src/components/greedyAlgo/GreedyAlgorithmCard.jsx @@ -0,0 +1,37 @@ +import React from 'react' +import { motion } from 'framer-motion' + +/** + * GreedyAlgorithmCard – a premium styled card to showcase a greedy algorithm feature. + * Mirrors the visual language of the existing FeatureCard but adds a subtle motion fade‑in. + */ +export default function GreedyAlgorithmCard({ + icon, + title, + description, + gradient, +}) { + return ( + + {/* Background glow */} +
+ {/* Card container */} +
+
+ {icon} +
+

{title}

+

{description}

+
+
+ ) +} diff --git a/src/components/greedyAlgo/GreedyBlock.jsx b/src/components/greedyAlgo/GreedyBlock.jsx new file mode 100644 index 00000000..1cfdbe23 --- /dev/null +++ b/src/components/greedyAlgo/GreedyBlock.jsx @@ -0,0 +1,24 @@ +import React from 'react' +import { motion } from 'framer-motion' + +/** + * GreedyBlock – a premium styled card used by the greedy algorithm visualizers. + * It displays a title and an optional description/content. + * The design mirrors the existing UI (glassmorphism, dark mode, subtle motion). + */ +export default function GreedyBlock({ title, children }) { + return ( + +

+ {title} +

+
{children}
+
+ ) +} diff --git a/src/components/greedyAlgo/HuffmanVisualizer.jsx b/src/components/greedyAlgo/HuffmanVisualizer.jsx new file mode 100644 index 00000000..71a63df8 --- /dev/null +++ b/src/components/greedyAlgo/HuffmanVisualizer.jsx @@ -0,0 +1,390 @@ +import React, { useRef, useState, useEffect, useMemo } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import GreedyBlock from './GreedyBlock' + +const calculatePositions = (node, x, y, dx) => { + if (!node) return + node.x = x + node.y = y + const childDx = Math.max(dx * 0.45, 12) + calculatePositions(node.left, x - dx, y + 55, childDx) + calculatePositions(node.right, x + dx, y + 55, childDx) +} + +export default function HuffmanVisualizer({ currentStep }) { + const containerRef = useRef(null) + const [dimensions, setDimensions] = useState({ width: 800, height: 420 }) + + useEffect(() => { + const updateSize = () => { + if (containerRef.current) { + setDimensions({ + width: containerRef.current.clientWidth, + height: Math.max(containerRef.current.clientHeight, 420), + }) + } + } + updateSize() + window.addEventListener('resize', updateSize) + return () => window.removeEventListener('resize', updateSize) + }, []) + + const { nodes, edges, roots } = useMemo(() => { + if ( + !currentStep || + !currentStep.forest || + currentStep.forest.length === 0 + ) { + return { nodes: [], edges: [], roots: [] } + } + + const rootsCopy = JSON.parse(JSON.stringify(currentStep.forest)) + const width = dimensions.width + const allNodes = [] + const allEdges = [] + + rootsCopy.forEach((root, index) => { + const colWidth = width / rootsCopy.length + const centerX = index * colWidth + colWidth / 2 + const initialDx = Math.max(colWidth / 4.2, 25) + + calculatePositions(root, centerX, 45, initialDx) + + const traverse = (node, parent) => { + if (!node) return + allNodes.push(node) + if (parent) { + allEdges.push({ + id: `${parent.id}-${node.id}`, + x1: parent.x, + y1: parent.y, + x2: node.x, + y2: node.y, + bit: node.bit, + }) + } + traverse(node.left, node) + traverse(node.right, node) + } + + traverse(root, null) + }) + + return { nodes: allNodes, edges: allEdges, roots: rootsCopy } + }, [currentStep, dimensions.width]) + + const pickedIds = currentStep?.picked || [] + const newParentId = currentStep?.newParentId || null + const isComplete = currentStep?.type === 'complete' + const codes = currentStep?.codes || {} + const freqTable = currentStep?.freqTable || [] + + return ( +
+ {/* Forest Tree Canvas */} +
+

+ Priority Queue Forest (Subtrees) +

+ +
+ {roots.length === 0 ? ( +
+ Start searching to build the Huffman tree forest... +
+ ) : ( + <> + {/* SVG Edges */} + + + {edges.map((edge) => { + const isNewEdge = + newParentId && edge.id.includes(newParentId) + + return ( + + + {/* Edge Label (0 or 1) */} + + {edge.bit} + + + ) + })} + + + + {/* Render Nodes */} + + {nodes.map((node) => { + const isLeaf = node.char !== null + const isPicked = pickedIds.includes(node.id) + const isNewParent = newParentId === node.id + + let borderClass = 'border-slate-600 bg-slate-800' + let textClass = 'text-slate-200' + + if (isLeaf) { + borderClass = + 'border-emerald-500/80 bg-emerald-500/10 hover:bg-emerald-500/25' + textClass = 'text-emerald-300' + } else { + borderClass = 'border-indigo-500/80 bg-indigo-500/10' + textClass = 'text-indigo-300' + } + + if (isPicked) { + borderClass = + 'border-yellow-400 bg-yellow-400/20 scale-115 shadow-[0_0_12px_rgba(250,204,21,0.5)]' + textClass = 'text-yellow-200 font-bold' + } + + if (isNewParent) { + borderClass = + 'border-pink-500 bg-pink-500/20 scale-115 shadow-[0_0_12px_rgba(236,72,153,0.5)]' + textClass = 'text-pink-300 font-bold' + } + + return ( + + + {isLeaf ? (node.char === ' ' ? '␣' : node.char) : 'āˆ‘'} + + + {node.freq} + + + ) + })} + + + )} +
+
+ + {/* Priority Queue (Forest State List) */} +
+

+ Priority Queue / Forest List +

+
+ {roots.map((root) => { + const isPicked = pickedIds.includes(root.id) + const isNewParent = newParentId === root.id + + let cardStyle = 'border-slate-800 bg-slate-950/60 text-slate-400' + if (root.char !== null) { + cardStyle = + 'border-emerald-950 bg-emerald-950/20 text-emerald-300' + } else { + cardStyle = 'border-indigo-950 bg-indigo-950/20 text-indigo-300' + } + + if (isPicked) { + cardStyle = + 'border-yellow-500 bg-yellow-500/10 text-yellow-300 shadow-[0_0_8px_rgba(250,204,21,0.2)]' + } + if (isNewParent) { + cardStyle = + 'border-pink-500 bg-pink-500/10 text-pink-300 shadow-[0_0_8px_rgba(236,72,153,0.2)]' + } + + return ( +
+ + {root.char !== null + ? root.char === ' ' + ? 'Space' + : `'${root.char}'` + : 'Merge'} + + + {root.freq} +
+ ) + })} + {roots.length === 0 && ( +
+ Priority queue is empty. +
+ )} +
+
+ + This visualizer demonstrates a greedy approach for building Huffman + trees. + + + {/* Results details (Code Table and compression details) */} + {isComplete && Object.keys(codes).length > 0 && ( + + {/* Code Table */} +
+

+ Huffman Codewords Table +

+
+ + + + + + + + + + {freqTable.map((item) => ( + + + + + + ))} + +
CharFreqCodeword
+ {item.char === ' ' ? 'Space' : `'${item.char}'`} + {item.freq} + {codes[item.char] || '—'} +
+
+
+ + {/* Compression Efficiency */} +
+
+

+ Compression Performance +

+ +
+
+
+

+ ASCII Encoding +

+

+ {freqTable.reduce((acc, curr) => acc + curr.freq, 0) * 8}{' '} + bits +

+ + (8 bits per char) + +
+ +
+

+ Huffman Coding +

+

+ {freqTable.reduce( + (acc, curr) => + acc + curr.freq * (codes[curr.char] || '').length, + 0 + )}{' '} + bits +

+ + (Variable length) + +
+
+ + {/* Efficiency calculation */} + {(() => { + const asciiBits = + freqTable.reduce((acc, curr) => acc + curr.freq, 0) * 8 + const huffmanBits = freqTable.reduce( + (acc, curr) => + acc + curr.freq * (codes[curr.char] || '').length, + 0 + ) + const saving = ( + ((asciiBits - huffmanBits) / asciiBits) * + 100 + ).toFixed(1) + return ( +
+
+

+ Space Saved +

+

+ {saving}% +

+
+
+ Requires fewer bits for higher frequency characters! +
+
+ ) + })()} +
+
+
+
+ )} + {/* Greedy Summary Block */} +
+ + This visualizer demonstrates a greedy approach for building Huffman + trees. + +
+
+ ) +} diff --git a/src/components/greedyAlgo/JobSequencingVisualizer.jsx b/src/components/greedyAlgo/JobSequencingVisualizer.jsx new file mode 100644 index 00000000..a9564565 --- /dev/null +++ b/src/components/greedyAlgo/JobSequencingVisualizer.jsx @@ -0,0 +1,282 @@ +import React from 'react' +import { motion } from 'framer-motion' + +const JOB_COLORS = [ + { + bg: 'from-cyan-500 to-blue-600', + border: 'border-cyan-400 border-2', + text: 'text-cyan-300', + light: 'bg-cyan-500/10', + }, + { + bg: 'from-emerald-500 to-teal-600', + border: 'border-emerald-400 border-2', + text: 'text-emerald-300', + light: 'bg-emerald-500/10', + }, + { + bg: 'from-purple-500 to-indigo-600', + border: 'border-purple-400 border-2', + text: 'text-purple-300', + light: 'bg-purple-500/10', + }, + { + bg: 'from-amber-500 to-orange-600', + border: 'border-amber-400 border-2', + text: 'text-amber-300', + light: 'bg-amber-500/10', + }, + { + bg: 'from-rose-500 to-red-600', + border: 'border-rose-400 border-2', + text: 'text-rose-300', + light: 'bg-rose-500/10', + }, + { + bg: 'from-fuchsia-500 to-pink-600', + border: 'border-fuchsia-400 border-2', + text: 'text-fuchsia-300', + light: 'bg-fuchsia-500/10', + }, + { + bg: 'from-teal-500 to-emerald-600', + border: 'border-teal-400 border-2', + text: 'text-teal-300', + light: 'bg-teal-500/10', + }, + { + bg: 'from-sky-500 to-blue-600', + border: 'border-sky-400 border-2', + text: 'text-sky-300', + light: 'bg-sky-500/10', + }, +] + +export default function JobSequencingVisualizer({ currentStep }) { + const jobs = React.useMemo(() => currentStep?.jobs || [], [currentStep?.jobs]) + const timeline = React.useMemo( + () => currentStep?.timeline || [], + [currentStep?.timeline] + ) + const activeJobId = currentStep?.activeJobId || null + const activeSlotIndex = currentStep?.activeSlotIndex ?? null + + const jobColorMap = React.useMemo(() => { + const map = {} + jobs.forEach((job, idx) => { + map[job.id] = JOB_COLORS[idx % JOB_COLORS.length] + }) + return map + }, [jobs]) + + const totalProfit = currentStep?.variables?.totalProfit ?? 0 + const scheduledCount = jobs.filter((j) => j.status === 'scheduled').length + const missedCount = jobs.filter((j) => j.status === 'missed').length + + return ( +
+ {/* Live Metrics Panel */} +
+ {/* Total Profit Card */} +
+
+

+ Total Profit +

+

+ ${totalProfit} +

+
+
šŸ’°
+
+ + {/* Scheduled Jobs Card */} +
+
+
+

+ Jobs Scheduled +

+

+ {scheduledCount} / {jobs.length} +

+
+
āœ…
+
+
+ +
+
+ + {/* Missed Jobs Card */} +
+
+

+ Jobs Missed +

+

+ {missedCount} +

+
+
āŒ
+
+
+ + {/* Gantt Chart Time-Slot Grid */} +
+

+ Gantt Chart Time-Slot Grid (Timeline) +

+ + {timeline.length === 0 ? ( +
+ No timeline initialized yet. Start visualizer to see available + slots. +
+ ) : ( +
+ {timeline.map((slot, index) => { + const assignedJobId = slot.jobId + const jobColor = assignedJobId ? jobColorMap[assignedJobId] : null + const isChecking = activeSlotIndex === index && slot.status === 'checking' + + let slotClass = + 'border-dashed border-2 border-slate-800 bg-slate-950/20 text-slate-500' + + if (isChecking) { + slotClass = + 'border-yellow-500 bg-yellow-500/5 animate-pulse shadow-[0_0_10px_rgba(234,179,8,0.3)] text-yellow-400 font-bold' + } else if (assignedJobId) { + slotClass = `border-solid border border-emerald-500/30 bg-gradient-to-br ${jobColor?.bg || 'from-emerald-500 to-teal-600'} text-white shadow-[0_0_12px_rgba(16,185,129,0.15)]` + } + + return ( + +
+ Slot {index + 1} + + {slot.label} + +
+ +
+ {assignedJobId ? ( + <> + + {assignedJobId} + + + Profit: $ + {jobs.find((j) => j.id === assignedJobId)?.profit || + 0} + + + ) : isChecking ? ( + + Checking... + + ) : ( + + Empty + + )} +
+
+ ) + })} +
+ )} +
+ + {/* Jobs Directory Cards */} +
+

+ Jobs Directory +

+ +
+ {jobs.map((job) => { + const colors = jobColorMap[job.id] || JOB_COLORS[0] + + let statusBadge = 'bg-slate-800 border-slate-700 text-slate-400' + let cardBorder = 'border-slate-800 bg-slate-950/40 opacity-70' + + if (job.status === 'sorting') { + statusBadge = + 'bg-yellow-500/10 border-yellow-500/20 text-yellow-400 animate-pulse' + cardBorder = 'border-yellow-500/30 bg-slate-950/50' + } else if (job.status === 'sorted') { + statusBadge = 'bg-cyan-500/10 border-cyan-500/20 text-cyan-300' + cardBorder = 'border-slate-700/80 bg-slate-950/60' + } else if (job.status === 'active') { + statusBadge = + 'bg-yellow-500/20 border-yellow-500/30 text-yellow-300' + cardBorder = + 'border-yellow-500 bg-yellow-500/5 scale-102 shadow-[0_0_12px_rgba(234,179,8,0.25)]' + } else if (job.status === 'scheduled') { + statusBadge = + 'bg-emerald-500/20 border-emerald-500/30 text-emerald-300' + cardBorder = `border-emerald-500/30 ${colors.light}` + } else if (job.status === 'missed') { + statusBadge = 'bg-rose-500/10 border-rose-500/20 text-rose-400' + cardBorder = 'border-slate-800 bg-slate-950/20 opacity-40' + } + + return ( + +
+
+ + {job.id} + + + {job.status} + +
+
+
+ Profit:{' '} + + ${job.profit} + +
+
+ Deadline:{' '} + + {job.deadline} + +
+
+
+ + {job.slotAssigned && ( +
+ Assigned Slot: + Slot {job.slotAssigned} +
+ )} +
+ ) + })} +
+
+
+ ) +} diff --git a/src/components/greedyAlgo/KnapsackVisualizer.jsx b/src/components/greedyAlgo/KnapsackVisualizer.jsx new file mode 100644 index 00000000..8f4b1aa6 --- /dev/null +++ b/src/components/greedyAlgo/KnapsackVisualizer.jsx @@ -0,0 +1,308 @@ +import React from 'react' +import GreedyBlock from './GreedyBlock' +import { motion } from 'framer-motion' + +const ITEM_COLORS = [ + { + bg: 'from-cyan-500 to-blue-600', + border: 'border-cyan-400', + text: 'text-cyan-300', + light: 'bg-cyan-500/10', + }, + { + bg: 'from-emerald-500 to-teal-600', + border: 'border-emerald-400', + text: 'text-emerald-300', + light: 'bg-emerald-500/10', + }, + { + bg: 'from-purple-500 to-indigo-600', + border: 'border-purple-400', + text: 'text-purple-300', + light: 'bg-purple-500/10', + }, + { + bg: 'from-amber-500 to-orange-600', + border: 'border-amber-400', + text: 'text-amber-300', + light: 'bg-amber-500/10', + }, + { + bg: 'from-rose-500 to-red-600', + border: 'border-rose-400', + text: 'text-rose-300', + light: 'bg-rose-500/10', + }, + { + bg: 'from-fuchsia-500 to-pink-600', + border: 'border-fuchsia-400', + text: 'text-fuchsia-300', + light: 'bg-fuchsia-500/10', + }, +] + +export default function KnapsackVisualizer({ currentStep }) { + const items = React.useMemo( + () => currentStep?.items || [], + [currentStep?.items] + ) + const knapsackState = currentStep?.knapsackState || { + capacityLeft: 50, + totalCapacity: 50, + totalValue: 0, + contents: [], + } + + // Map each item ID to its color index so color is stable + const itemColorMap = React.useMemo(() => { + const map = {} + items.forEach((item, idx) => { + map[item.id] = ITEM_COLORS[idx % ITEM_COLORS.length] + }) + return map + }, [items]) + + const totalCapacity = knapsackState.totalCapacity + const capacityLeft = knapsackState.capacityLeft + const capacityUsed = totalCapacity - capacityLeft + const totalValue = knapsackState.totalValue + + return ( +
+
+ {/* Item List and Status */} +
+
+

+ Items Directory +

+ +
+ {items.map((item) => { + const colors = itemColorMap[item.id] || ITEM_COLORS[0] + + let statusBadge = 'bg-slate-800 border-slate-700 text-slate-400' + let cardBorder = 'border-slate-800 bg-slate-950/40 opacity-70' + + if (item.status === 'ratio-calculated') { + statusBadge = 'bg-slate-800 border-slate-700 text-slate-300' + cardBorder = 'border-slate-700 bg-slate-950/50 opacity-90' + } else if (item.status === 'sorted') { + statusBadge = + 'bg-cyan-500/10 border-cyan-500/20 text-cyan-300' + cardBorder = 'border-slate-700/80 bg-slate-950/60' + } else if (item.status === 'active') { + statusBadge = + 'bg-yellow-500/20 border-yellow-500/30 text-yellow-300' + cardBorder = + 'border-yellow-500 bg-yellow-500/5 scale-102 shadow-[0_0_12px_rgba(234,179,8,0.25)]' + } else if (item.status === 'packed') { + statusBadge = + 'bg-emerald-500/20 border-emerald-500/30 text-emerald-300' + cardBorder = `border-emerald-500/30 ${colors.light}` + } else if (item.status === 'fractioned') { + statusBadge = + 'bg-indigo-500/20 border-indigo-500/30 text-indigo-300' + cardBorder = `border-indigo-500/30 ${colors.light}` + } else if (item.status === 'skipped') { + statusBadge = + 'bg-rose-500/10 border-rose-500/20 text-rose-400' + cardBorder = 'border-slate-800 bg-slate-950/20 opacity-40' + } + + return ( + +
+
+ + {item.id} + + + {item.status.replace('-', ' ')} + +
+
+
+ Value:{' '} + + ${item.value} + +
+
+ Weight:{' '} + + {item.weight} kg + +
+
+
+ +
+
+

+ Ratio (V/W) +

+

+ ${item.ratio} +

+
+ + {(item.status === 'packed' || + item.status === 'fractioned') && ( +
+

+ Packed +

+

+ {(item.packedRatio * 100).toFixed(0)}% ( + {item.packedWeight} kg) +

+
+ )} +
+
+ ) + })} +
+
+ + {/* Legend and tips */} +
+

Greedy Choice Rule:

+

+ Pick items with the maximum Value-to-Weight ratio ($ per kg) + first. If a full item does not fit, slice it fractionally to fill + the remaining capacity. +

+
+
+ + {/* Visual Knapsack Packing */} +
+

+ Knapsack Cargo Box +

+ + {/* Knapsack visual stack */} +
+
+ {/* Backgrid capacity indicators */} +
+ {[100, 75, 50, 25, 0].map((percent) => ( +
+ + {percent}% + +
+
+ ))} +
+ + {/* Stack items */} +
+ {knapsackState.contents.map((block, idx) => { + const colors = itemColorMap[block.id] || ITEM_COLORS[0] + const heightPercent = (block.weight / totalCapacity) * 100 + const isFraction = block.fraction < 1 + + return ( + + {/* Fractional slice stripe overlay */} + {isFraction && ( +
+ )} + + + {block.id} + + + {isFraction + ? `Slice (${(block.fraction * 100).toFixed(0)}%)` + : 'Full'} + + + {block.weight} kg | ${block.value} + +
+ ) + })} + + {knapsackState.contents.length === 0 && ( +
+ Knapsack is empty. Start visualization to pack items. +
+ )} +
+
+
+ + {/* Knapsack capacity display and total value bar */} +
+
+
+ Weight Capacity Used + + {capacityUsed} / {totalCapacity} kg + +
+
+ +
+
+ +
+
+

+ Knapsack Value +

+

+ ${totalValue} +

+
+ +
+

+ Capacity Left +

+

+ {capacityLeft} kg +

+
+
+
+
+
+ + + This visualizer demonstrates the greedy fractional knapsack approach. + +
+ ) +} diff --git a/src/components/greedyAlgo/README.md b/src/components/greedyAlgo/README.md new file mode 100644 index 00000000..ea8b34ab --- /dev/null +++ b/src/components/greedyAlgo/README.md @@ -0,0 +1,40 @@ +# Greedy Algorithms Visualizer + +This directory contains the components and layout for the interactive visualizers of **Greedy Algorithms** in AlgoScope. + +The visualizers allow users to explore step-by-step greedy strategy animations, modify input datasets, inspect variables in real time, and view code execution mappings in Java, C++, Python, and JavaScript. + +## Algorithms Covered + +1. **Huffman Coding** (Data Compression): + - Visualizes how character frequencies are calculated and leaf nodes are merged into a binary tree forest. + - Outputs the constructed tree with edges labeled with bits (`0` or `1`) and final generated character codes. + - Controlled via custom text inputs. + +2. **Fractional Knapsack** (Resource Optimization): + - Visualizes calculating value-to-weight ratios, sorting items by ratio, and packing items (full or fractions) into the knapsack. + - Outputs an interactive knapsack container grid reflecting packed volumes. + - Configured via cargo items and knapsack weight capacity. + +3. **Job Sequencing with Deadlines** (Timeline Optimization): + - Visualizes sorting jobs by profit in descending order and scheduling each job in the latest available time slot before its deadline. + - Outputs a Gantt chart time-slot timeline showing backwards searches and filled slots alongside a Live Metrics dashboard (Total Profit, Scheduled, and Missed Jobs). + - Configured via a directory of up to 8 jobs with variable profits and deadlines. + +## Component Architecture + +- `VisualizerPage.jsx`: The main controller page, handling algorithm selection, inputs, and layout synchronization. It imports code execution snippets and step playback state management. +- `HuffmanVisualizer.jsx`: Renders the binary tree structure of the Huffman forest using custom node position mapping and SVG lines. +- `KnapsackVisualizer.jsx`: Renders the cargo inventory and visual packaging stack representing current capacity utilization. +- `JobSequencingVisualizer.jsx`: Renders the Gantt time-slot grid, real-time metrics cards, and status-coded job deck. +- `GreedyBlock.jsx`: Styled container card block using uniform glassmorphic elements. +- `GreedyAlgorithmCard.jsx`: Feature overview card. + +## Step Generation & Playback + +Algorithm logic is separated into standalone generators that produce step states consumed by the `useStepPlayback` hook: +- `src/algorithms/greedy/huffmanCodingSteps.js` +- `src/algorithms/greedy/fractionalKnapsackSteps.js` +- `src/algorithms/greedy/jobSequencingSteps.js` + +To avoid dependency bundling overhead, steps are cloned using native browser `structuredClone()`. diff --git a/src/components/greedyAlgo/VisualizerPage.jsx b/src/components/greedyAlgo/VisualizerPage.jsx new file mode 100644 index 00000000..ede1542b --- /dev/null +++ b/src/components/greedyAlgo/VisualizerPage.jsx @@ -0,0 +1,755 @@ +import React, { useState, useMemo, useEffect } from 'react' +import { useSearchParams } from 'react-router-dom' +import SpeedSlider from '../SpeedSlider.jsx' +import CodePanel from '../visualizer/CodePanel' +import { useStepPlayback } from '../visualizer/useStepPlayback' +import ComplexityCard from '../ComplexityCard' +import Tooltip from '../Tooltip' +import { useKeyboardShortcuts } from '../visualizer/useKeyboardShortcuts' +import LearningPathSuggestions from '../LearningPathSuggestions' + +import HuffmanVisualizer from './HuffmanVisualizer' +import KnapsackVisualizer from './KnapsackVisualizer' +import JobSequencingVisualizer from './JobSequencingVisualizer' + +import { generateHuffmanSteps } from '../../algorithms/greedy/huffmanCodingSteps' +import { generateFractionalKnapsackSteps } from '../../algorithms/greedy/fractionalKnapsackSteps' +import { generateJobSequencingSteps } from '../../algorithms/greedy/jobSequencingSteps' +import { + getGreedySource, + resolveGreedyLine, +} from '../../algorithms/greedy/greedySources' + +const DEFAULT_KNAPSACK_ITEMS = [ + { id: 'Item A', value: 60, weight: 10 }, + { id: 'Item B', value: 100, weight: 20 }, + { id: 'Item C', value: 120, weight: 30 }, +] + +const DEFAULT_JOBS = [ + { id: 'Job A', profit: 100, deadline: 2 }, + { id: 'Job B', profit: 19, deadline: 1 }, + { id: 'Job C', profit: 27, deadline: 2 }, + { id: 'Job D', profit: 25, deadline: 1 }, + { id: 'Job E', profit: 15, deadline: 3 }, +] + +export default function VisualizerPage() { + const [searchParams, setSearchParams] = useSearchParams() + const [algorithm, setAlgorithm] = useState( + () => searchParams.get('algo') || 'huffman' + ) + const [language, setLanguage] = useState( + () => searchParams.get('lang') || 'javascript' + ) + const [speed, setSpeed] = useState(1) + const [showShortcuts, setShowShortcuts] = useState(false) + const [isStepMode, setIsStepMode] = useState(false) + + // Huffman Inputs + const [huffmanText, setHuffmanText] = useState('BEEP BOOP BEER') + + // Knapsack Inputs + const [knapsackCapacity, setKnapsackCapacity] = useState(50) + const [knapsackItems, setKnapsackItems] = useState(DEFAULT_KNAPSACK_ITEMS) + const [newItemValue, setNewItemValue] = useState('') + const [newItemWeight, setNewItemWeight] = useState('') + + // Job Sequencing Inputs + const [jobs, setJobs] = useState(DEFAULT_JOBS) + const [newJobProfit, setNewJobProfit] = useState('') + const [newJobDeadline, setNewJobDeadline] = useState('') + + useEffect(() => { + const params = { algo: algorithm, lang: language } + setSearchParams(params, { replace: true }) + }, [algorithm, language, setSearchParams]) + + const { + currentStep, + currentStepIndex, + steps, + hasSteps, + isComplete, + isPlaying, + loadSteps, + clear: clearPlayback, + pause: pausePlayback, + play: playPlayback, + replay: replayPlayback, + stepForward, + stepBackward, + } = useStepPlayback({ speed }) + + const handleVisualize = () => { + clearPlayback() + if (algorithm === 'huffman') { + const huffmanSteps = generateHuffmanSteps(huffmanText) + loadSteps(huffmanSteps, { autoPlay: !isStepMode }) + } else if (algorithm === 'knapsack') { + const knapsackSteps = generateFractionalKnapsackSteps( + knapsackCapacity, + knapsackItems + ) + loadSteps(knapsackSteps, { autoPlay: !isStepMode }) + } else if (algorithm === 'jobsequencing') { + const jobSteps = generateJobSequencingSteps(jobs) + loadSteps(jobSteps, { autoPlay: !isStepMode }) + } + } + + const handleReset = () => { + clearPlayback() + if (algorithm === 'huffman') { + setHuffmanText('BEEP BOOP BEER') + } else if (algorithm === 'knapsack') { + setKnapsackCapacity(50) + setKnapsackItems(DEFAULT_KNAPSACK_ITEMS) + } else if (algorithm === 'jobsequencing') { + setJobs(DEFAULT_JOBS) + } + } + + useKeyboardShortcuts({ + onPlayPause: () => { + if (isPlaying) pausePlayback() + else if (hasSteps && !isComplete) playPlayback() + }, + onStepForward: () => { + if (!isPlaying && !isComplete && hasSteps) stepForward() + }, + onStepBackward: () => { + if (!isPlaying && currentStepIndex > 0) stepBackward() + }, + onReset: handleReset, + onSpeedUp: () => setSpeed((s) => Math.min(3, +(s + 0.25).toFixed(2))), + onSlowDown: () => setSpeed((s) => Math.max(0.25, +(s - 0.25).toFixed(2))), + onHelp: () => setShowShortcuts((v) => !v), + }) + + const handleAddKnapsackItem = () => { + const val = Number(newItemValue) + const wt = Number(newItemWeight) + if (isNaN(val) || isNaN(wt) || val <= 0 || wt <= 0) return + + const nextLetter = String.fromCharCode(65 + knapsackItems.length) // Item A, B, C, D... + const newItem = { + id: `Item ${nextLetter}`, + value: val, + weight: wt, + } + + setKnapsackItems([...knapsackItems, newItem]) + setNewItemValue('') + setNewItemWeight('') + clearPlayback() + } + + const handleRemoveKnapsackItem = (id) => { + setKnapsackItems(knapsackItems.filter((item) => item.id !== id)) + clearPlayback() + } + + const handleAddJob = () => { + const profit = Number(newJobProfit) + const deadline = Number(newJobDeadline) + if (isNaN(profit) || isNaN(deadline) || profit <= 0 || deadline <= 0) return + + const nextLetter = String.fromCharCode(65 + jobs.length) + const newJob = { + id: `Job ${nextLetter}`, + profit, + deadline: Math.min(9, deadline), // clamp max deadline to 9 to prevent UI overflow + } + + setJobs([...jobs, newJob]) + setNewJobProfit('') + setNewJobDeadline('') + clearPlayback() + } + + const handleRemoveJob = (id) => { + setJobs(jobs.filter((job) => job.id !== id)) + clearPlayback() + } + + const currentSource = useMemo(() => { + return getGreedySource(algorithm, language) + }, [algorithm, language]) + + const activeLine = useMemo(() => { + if (!currentStep?.lineKey) return undefined + return resolveGreedyLine(algorithm, language, currentStep.lineKey) + }, [algorithm, currentStep, language]) + + const handleAlgorithmChange = (e) => { + setAlgorithm(e.target.value) + clearPlayback() + } + + return ( +
+
+
+
+ {/* Visualizer and code display */} +
+ {showShortcuts && ( +
+
+

+ Keyboard Shortcuts +

+ +
+ + + {[ + ['Space', 'Play / Pause'], + ['→ Right Arrow', 'Next Step'], + ['← Left Arrow', 'Previous Step'], + ['R', 'Reset Settings'], + ['+', 'Increase Speed'], + ['-', 'Decrease Speed'], + ['?', 'Toggle Shortcuts'], + ].map(([key, action]) => ( + + + + + ))} + +
+ + {key} + + {action}
+
+ )} + + + + {/* Main Canvas Component */} +
+ {algorithm === 'huffman' ? ( + + ) : algorithm === 'knapsack' ? ( + + ) : ( + + )} +
+ + {/* Complexity Analysis */} + + + {/* Code Panel and Step Insight */} +
+ {/* Step Insight */} +
+

+ Step Insight +

+

+ {currentStep?.message || + 'Start the visualization to see greedy step progression.'} +

+ +
+
+

+ Variables Dashboard +

+
+ {currentStep?.variables && + Object.keys(currentStep.variables).length > 0 ? ( + Object.entries(currentStep.variables).map( + ([key, value]) => ( +
+ {key}: + + {typeof value === 'boolean' + ? String(value) + : value} + +
+ ) + ) + ) : ( + + No active variables + + )} +
+
+ +
+

+ Status +

+

+ {isComplete + ? 'Visualization Complete' + : isPlaying + ? 'Running...' + : hasSteps + ? 'Paused' + : 'Ready'} +

+
+
+
+ + {/* Code Panel */} +
+ +
+
+
+ + {/* Sidebar Controls Panel */} +
+ {/* How to use */} +
+

+ How to use +

+ {[ + { step: '1', label: 'Select Greedy Algorithm' }, + { + step: '2', + label: + algorithm === 'huffman' + ? 'Modify text string' + : algorithm === 'knapsack' + ? 'Modify cargo items list' + : 'Modify jobs and deadlines', + }, + { step: '3', label: 'Run greedy visualization' }, + ].map(({ step, label }) => { + const done = + (step === '1' && algorithm) || + (step === '2' && + (algorithm === 'huffman' + ? huffmanText + : algorithm === 'knapsack' + ? knapsackItems.length > 0 + : jobs.length > 0)) || + (step === '3' && hasSteps) + return ( +
+ + {done ? 'āœ“' : step} + + + {label} + +
+ ) + })} +
+ + {/* Controls */} +
+ {/* Algorithm Selector */} +
+

+ Target Algorithm +

+ + + +
+ + {/* Huffman Specific Controls */} + {algorithm === 'huffman' && ( +
+

+ Input text string +

+ + { + setHuffmanText(e.target.value) + clearPlayback() + }} + disabled={isPlaying} + maxLength={25} + className="w-full bg-slate-900/80 text-white text-sm border border-slate-700 rounded-xl px-4 py-3 focus:outline-none focus:border-cyan-500 transition disabled:opacity-50 font-mono" + placeholder="Text to encode" + /> + + + Maximum 25 characters for layout spacing. + +
+ )} + + {/* Knapsack Specific Controls */} + {algorithm === 'knapsack' && ( +
+ {/* Capacity input */} +
+

+ Knapsack Capacity (kg) +

+ { + setKnapsackCapacity( + Math.max(1, Number(e.target.value)) + ) + clearPlayback() + }} + disabled={isPlaying} + className="w-full bg-slate-900/80 text-white text-sm border border-slate-700 rounded-xl px-4 py-3 focus:outline-none focus:border-cyan-500 transition disabled:opacity-50" + placeholder="Capacity" + /> +
+ + {/* Item editor list */} +
+

+ Cargo Items list +

+ +
+ {knapsackItems.map((item) => ( +
+ + {item.id} + + + ${item.value} | {item.weight} kg |{' '} + {(item.value / item.weight || 0).toFixed(1)}/kg + + +
+ ))} +
+ + {/* Add new item */} +
+

+ Add Custom Cargo +

+
+ setNewItemValue(e.target.value)} + disabled={isPlaying || knapsackItems.length >= 6} + placeholder="Val ($)" + className="bg-slate-900 text-white text-xs border border-slate-700 rounded-xl px-3 py-2 focus:outline-none focus:border-cyan-500 transition disabled:opacity-50" + /> + setNewItemWeight(e.target.value)} + disabled={isPlaying || knapsackItems.length >= 6} + placeholder="Wt (kg)" + className="bg-slate-900 text-white text-xs border border-slate-700 rounded-xl px-3 py-2 focus:outline-none focus:border-cyan-500 transition disabled:opacity-50" + /> +
+ + {knapsackItems.length >= 6 && ( + + Maximum 6 items allowed. + + )} +
+
+
+ )} + + {/* Job Sequencing Specific Controls */} + {algorithm === 'jobsequencing' && ( +
+
+

+ Jobs Directory Editor +

+ +
+ {jobs.map((job) => ( +
+ + {job.id} + + + Profit: ${job.profit} | Deadline: {job.deadline} + + +
+ ))} +
+ + {/* Add new job */} +
+

+ Add Custom Job +

+
+ setNewJobProfit(e.target.value)} + disabled={isPlaying || jobs.length >= 8} + placeholder="Profit ($)" + className="bg-slate-900 text-white text-xs border border-slate-700 rounded-xl px-3 py-2 focus:outline-none focus:border-cyan-500 transition disabled:opacity-50" + /> + setNewJobDeadline(e.target.value)} + disabled={isPlaying || jobs.length >= 8} + placeholder="Deadline" + className="bg-slate-900 text-white text-xs border border-slate-700 rounded-xl px-3 py-2 focus:outline-none focus:border-cyan-500 transition disabled:opacity-50" + /> +
+ + {jobs.length >= 8 && ( + + Maximum 8 jobs allowed. + + )} +
+
+
+ )} + + {/* Speed Slider */} +
+ setSpeed(v)} + min={0.25} + max={3} + step={0.05} + /> +
+ + {/* Stepper Modes */} +
+ + +
+ + {/* Play Action Triggers */} +
+ + +
+
+ + {/* Playback step-by-step panel */} + {hasSteps && ( +
+
+
+

+ Playback Stepper +

+

+ Step {currentStepIndex + 1} of {steps.length} +

+
+
+ {isPlaying + ? 'Running' + : isComplete + ? 'Completed' + : 'Paused'} +
+
+
+ + + + +
+
+ )} + + +
+
+
+
+
+ ) +} diff --git a/src/data/complexityMap.js b/src/data/complexityMap.js index 381ec11f..9b5e6da2 100644 --- a/src/data/complexityMap.js +++ b/src/data/complexityMap.js @@ -211,4 +211,22 @@ export const complexityMap = { worst: 'O(R * C)', space: 'O(C)', }, + huffman: { + best: 'O(N log N)', + average: 'O(N log N)', + worst: 'O(N log N)', + space: 'O(N)', + }, + knapsack: { + best: 'O(N log N)', + average: 'O(N log N)', + worst: 'O(N log N)', + space: 'O(N)', + }, + jobsequencing: { + best: 'O(N log N)', + average: 'O(N²)', + worst: 'O(N²)', + space: 'O(N)', + }, } diff --git a/src/data/visualizerData.js b/src/data/visualizerData.js index b22bfbf9..cf1c0d0c 100644 --- a/src/data/visualizerData.js +++ b/src/data/visualizerData.js @@ -130,6 +130,15 @@ export const ALGORITHMS = [ link: '/two-pointer', difficulty: 'Intermediate', }, + { + id: 'greedy', + title: 'Greedy Algorithms', + description: + 'Explore Huffman Coding, Fractional Knapsack, and Job Sequencing with Deadlines.', + color: 'theme-card border-cyan-500/30 hover:border-cyan-400', + link: '/greedy', + difficulty: 'Intermediate', + }, ] export const OPERATING_SYSTEMS = [