diff --git a/src/problem_1/sum_to_n.js b/src/problem_1/sum_to_n.js new file mode 100644 index 000000000..757c70e13 --- /dev/null +++ b/src/problem_1/sum_to_n.js @@ -0,0 +1,31 @@ + +var sum_to_n_a = function(n) { + let sum = 0; + for (let i = 1; i <= n; i++) { + sum += i; + } + return sum; +}; + +var sum_to_n_b = function(n) { + if (n <= 0) { + return 0; + } + if (n === 1) { + return 1; + } + return n + sum_to_n_b(n - 1); +}; + +var sum_to_n_c = function(n) { + return (n * (n + 1)) / 2; +}; + +console.log("Testing sum_to_n_a:"); +console.log("sum_to_n_a(5) =", sum_to_n_a(5)); // Expected: 15 + +console.log("\nTesting sum_to_n_b:"); +console.log("sum_to_n_b(5) =", sum_to_n_b(5)); // Expected: 15 + +console.log("\nTesting sum_to_n_c:"); +console.log("sum_to_n_c(5) =", sum_to_n_c(5)); // Expected: 15 diff --git a/src/problem_2/.gitignore b/src/problem_2/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/src/problem_2/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/src/problem_2/README.md b/src/problem_2/README.md new file mode 100644 index 000000000..b1d25f695 --- /dev/null +++ b/src/problem_2/README.md @@ -0,0 +1,69 @@ +# Currency Swap Form + +A modern, interactive currency swap form built with React and Vite. + +## Features + +- 🎨 Beautiful, modern UI with gradient design +- 💱 Real-time exchange rate calculation +- 🔄 Token swap functionality +- ✅ Input validation and error handling +- 📱 Responsive design +- 🖼️ Token icons from Switcheo token-icons repository +- 💰 Live price data from Switcheo API + +## Project Structure + +``` +problem_2/ +├── src/ +│ ├── components/ +│ │ ├── CurrencySwapForm.jsx +│ │ └── CurrencySwapForm.css +│ ├── lib/ +│ │ ├── api.js # API utilities for fetching prices +│ │ └── validation.js # Input validation utilities +│ ├── App.jsx +│ ├── App.css +│ └── main.jsx +├── package.json +├── vite.config.js +└── index.html +``` + +## Getting Started + +1. Install dependencies: +```bash +npm install +``` + +2. Start the development server: +```bash +npm run dev +``` + +3. Build for production: +```bash +npm run build +``` + +## API Integration + +- **Token Prices**: Fetched from `https://interview.switcheo.com/prices.json` +- **Token Icons**: Loaded from `https://raw.githubusercontent.com/Switcheo/token-icons/main/tokens/{TOKEN}.svg` + +## Usage + +1. Select a "From" token from the dropdown +2. Select a "To" token from the dropdown +3. Enter the amount you want to swap +4. The output amount is automatically calculated based on current exchange rates +5. Click the swap button (↕️) to swap the tokens +6. Click "Swap" to execute the transaction + +## Technologies Used + +- React 18 +- Vite +- CSS3 (with modern features like gradients and animations) diff --git a/src/problem_2/index.html b/src/problem_2/index.html new file mode 100644 index 000000000..577534db6 --- /dev/null +++ b/src/problem_2/index.html @@ -0,0 +1,13 @@ + + + + + + + Currency Swap + + +
+ + + diff --git a/src/problem_2/jsconfig.json b/src/problem_2/jsconfig.json new file mode 100644 index 000000000..774631159 --- /dev/null +++ b/src/problem_2/jsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "jsx": "react-jsx", + "moduleResolution": "bundler", + "allowImportingTsExtensions": false, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "strict": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/src/problem_2/package-lock.json b/src/problem_2/package-lock.json new file mode 100644 index 000000000..e56f163bb --- /dev/null +++ b/src/problem_2/package-lock.json @@ -0,0 +1,1828 @@ +{ + "name": "problem_2", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "problem_2", + "version": "0.0.0", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@vitejs/plugin-react": "^4.2.1", + "vite": "^7.2.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001767", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", + "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/src/problem_2/package.json b/src/problem_2/package.json new file mode 100644 index 000000000..62509e200 --- /dev/null +++ b/src/problem_2/package.json @@ -0,0 +1,21 @@ +{ + "name": "problem_2", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@vitejs/plugin-react": "^4.2.1", + "vite": "^7.2.4" + } +} diff --git a/src/problem_2/public/vite.svg b/src/problem_2/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/src/problem_2/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/problem_2/src/App.css b/src/problem_2/src/App.css new file mode 100644 index 000000000..123249fcb --- /dev/null +++ b/src/problem_2/src/App.css @@ -0,0 +1,18 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +#root { + width: 100%; + min-height: 100vh; +} diff --git a/src/problem_2/src/App.jsx b/src/problem_2/src/App.jsx new file mode 100644 index 000000000..a6ae7180b --- /dev/null +++ b/src/problem_2/src/App.jsx @@ -0,0 +1,8 @@ +import CurrencySwapForm from './components/CurrencySwapForm'; +import './App.css'; + +function App() { + return ; +} + +export default App; diff --git a/src/problem_2/src/components/CurrencySwapForm.css b/src/problem_2/src/components/CurrencySwapForm.css new file mode 100644 index 000000000..fa8e83d3c --- /dev/null +++ b/src/problem_2/src/components/CurrencySwapForm.css @@ -0,0 +1,722 @@ +.currency-swap-container { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%); + position: relative; + overflow: hidden; +} + +.currency-swap-container::before { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle, rgba(255,255,255,0.15) 1px, transparent 1px); + background-size: 50px 50px; + animation: moveBackground 20s linear infinite; + pointer-events: none; +} + +@keyframes moveBackground { + 0% { transform: translate(0, 0); } + 100% { transform: translate(50px, 50px); } +} + +.currency-swap-card { + background: rgba(255, 255, 255, 0.98); + backdrop-filter: blur(20px); + border-radius: 32px; + padding: 40px; + box-shadow: 0 25px 80px rgba(102, 126, 234, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.3); + width: min(90vw, 500px); + max-width: 500px; + min-width: 320px; + animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); + position: relative; + z-index: 1; + border: 2px solid rgba(255, 255, 255, 0.5); + box-sizing: border-box; + overflow: hidden; + flex-shrink: 0; +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(40px) scale(0.95); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +.card-header { + margin-bottom: 32px; +} + +.title { + font-size: 36px; + font-weight: 800; + background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + margin: 0; + text-align: center; + letter-spacing: -0.5px; +} + +.swap-form { + display: flex; + flex-direction: column; + gap: 20px; + width: 100%; + box-sizing: border-box; +} + +.token-section { + display: flex; + flex-direction: column; + gap: 10px; +} + +.section-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 6px; +} + +.section-label { + font-size: 14px; + font-weight: 700; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-transform: uppercase; + letter-spacing: 1px; +} + +.balance { + font-size: 13px; + color: #8b5cf6; + font-weight: 600; +} + +.token-input-container { + display: flex; + flex-direction: column; + gap: 10px; +} + +.token-select-container { + position: relative; +} + +.token-select-button { + width: 100%; + display: flex; + align-items: center; + gap: 14px; + padding: 18px 20px; + background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%); + border: 2px solid #e0e7ff; + border-radius: 20px; + cursor: pointer; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + font-size: 17px; + font-weight: 700; + color: #4c1d95; +} + +.token-select-button:hover { + border-color: #8b5cf6; + background: linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%); + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(139, 92, 246, 0.2); +} + +.token-select-button:active { + transform: translateY(0) scale(0.98); +} + +.token-icon { + width: 36px; + height: 36px; + border-radius: 50%; + object-fit: cover; + flex-shrink: 0; + border: 2px solid rgba(139, 92, 246, 0.2); +} + +.token-symbol { + flex: 1; + text-align: left; + color: #4c1d95; +} + +.select-token-text { + flex: 1; + text-align: left; + color: #a78bfa; + font-weight: 600; +} + +.dropdown-arrow { + flex-shrink: 0; + color: #8b5cf6; + transition: transform 0.3s; +} + +.token-select-button:hover .dropdown-arrow { + transform: rotate(180deg); + color: #7c3aed; +} + +.token-dropdown { + position: absolute; + top: calc(100% + 10px); + left: 0; + right: 0; + background: white; + border: 2px solid #e0e7ff; + border-radius: 20px; + box-shadow: 0 15px 50px rgba(139, 92, 246, 0.25); + z-index: 1000; + max-height: 320px; + overflow: hidden; + animation: dropdownSlide 0.2s cubic-bezier(0.4, 0, 0.2, 1); +} + +@keyframes dropdownSlide { + from { + opacity: 0; + transform: translateY(-15px) scale(0.95); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +.dropdown-search { + padding: 16px; + border-bottom: 2px solid #f3f4f6; + background: linear-gradient(135deg, #fafbff 0%, #f8f9ff 100%); +} + +.search-input { + width: 100%; + padding: 12px 16px; + border: 2px solid #e0e7ff; + border-radius: 12px; + font-size: 15px; + outline: none; + transition: all 0.3s; + background: white; + color: #4c1d95; + font-weight: 600; +} + +.search-input:focus { + border-color: #8b5cf6; + box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.15); + transform: scale(1.02); +} + +.token-list { + max-height: 260px; + overflow-y: auto; + padding: 8px; +} + +.token-option { + width: 100%; + display: flex; + align-items: center; + gap: 14px; + padding: 14px 16px; + border: none; + background: transparent; + border-radius: 14px; + cursor: pointer; + transition: all 0.2s; + text-align: left; +} + +.token-option:hover { + background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%); + transform: translateX(4px); +} + +.token-option.selected { + background: linear-gradient(135deg, #ede9fe 0%, #ddd6fe 100%); + border: 2px solid #8b5cf6; +} + +.token-option-icon { + width: 32px; + height: 32px; + border-radius: 50%; + object-fit: cover; + flex-shrink: 0; + border: 2px solid rgba(139, 92, 246, 0.2); +} + +.token-option-symbol { + flex: 1; + font-weight: 700; + color: #4c1d95; + font-size: 15px; +} + +.token-option-price { + font-size: 13px; + color: #8b5cf6; + font-weight: 600; +} + +.no-tokens { + padding: 30px; + text-align: center; + color: #a78bfa; + font-size: 15px; + font-weight: 600; +} + +.amount-container { + display: flex; + align-items: center; + gap: 10px; + position: relative; + width: 100%; +} + +.amount-input { + flex: 1; + padding: 16px 18px; + font-size: 24px; + font-weight: 700; + border: 2px solid #e0e7ff; + border-radius: 16px; + outline: none; + transition: all 0.3s; + background: linear-gradient(135deg, #ffffff 0%, #fafbff 100%); + color: #4c1d95; + min-width: 0; +} + +.amount-input:focus { + border-color: #8b5cf6; + box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.15); + transform: scale(1.02); +} + +.amount-input.error { + border-color: #ef4444; + background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%); +} + +.amount-input:read-only { + background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%); + cursor: not-allowed; + color: #6d28d9; +} + +.amount-display { + display: flex; + align-items: center; + min-height: 56px; + padding: 16px 18px; + font-size: 24px; + font-weight: 700; + border: 2px solid #e0e7ff; + border-radius: 16px; + background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%); + color: #4c1d95; + flex: 1; + width: 100%; +} + +.placeholder-text { + color: #a78bfa; + font-weight: 600; +} + +.animated-number { + display: inline-block; + color: #4c1d95; + font-weight: 700; + transition: all 0.3s ease; +} + +.animated-number.animating { + animation: numberSlide 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +@keyframes numberSlide { + 0% { + opacity: 0.5; + transform: translateY(10px) scale(0.95); + color: #8b5cf6; + } + 50% { + opacity: 1; + transform: translateY(-2px) scale(1.02); + color: #7c3aed; + } + 100% { + opacity: 1; + transform: translateY(0) scale(1); + color: #4c1d95; + } +} + +.max-button { + padding: 12px 20px; + background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); + border: none; + border-radius: 12px; + font-size: 12px; + font-weight: 700; + color: white; + cursor: pointer; + transition: all 0.3s; + text-transform: uppercase; + letter-spacing: 1px; + box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3); + white-space: nowrap; + flex-shrink: 0; + height: fit-content; + line-height: 1.2; +} + +.max-button:hover:not(:disabled) { + background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%); + transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(139, 92, 246, 0.4); +} + +.max-button:active:not(:disabled) { + transform: translateY(0); +} + +.max-button:disabled { + opacity: 0.5; + cursor: not-allowed; + background: #e0e7ff; + color: #a78bfa; +} + +.error-message { + font-size: 13px; + color: #ef4444; + margin-top: -4px; + padding-left: 6px; + font-weight: 600; +} + +.amount-usd { + font-size: 13px; + color: #8b5cf6; + padding-left: 6px; + font-weight: 700; +} + +.swap-button-container { + display: flex; + justify-content: center; + margin: 8px 0; +} + +.swap-button { + width: 56px; + height: 56px; + border-radius: 50%; + border: 3px solid #e0e7ff; + background: linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%); + color: #8b5cf6; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 4px 16px rgba(139, 92, 246, 0.2); +} + +.swap-button:hover:not(:disabled) { + background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); + color: white; + border-color: #8b5cf6; + transform: rotate(180deg) scale(1.15); + box-shadow: 0 8px 24px rgba(139, 92, 246, 0.4); +} + +.swap-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.exchange-rate-info { + padding: 16px 20px; + background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%); + border-radius: 16px; + margin-top: 6px; + border: 2px solid #e0e7ff; +} + +.rate-row { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; +} + +.rate-row > span:first-child { + color: #8b5cf6; + font-weight: 700; +} + +.rate-value { + font-weight: 800; + color: #4c1d95; +} + +.submit-button { + width: 100%; + padding: 18px; + font-size: 18px; + font-weight: 800; + color: white; + background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 50%, #6d28d9 100%); + border: none; + border-radius: 20px; + cursor: pointer; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 6px 20px rgba(139, 92, 246, 0.4); + margin-top: 10px; + text-transform: uppercase; + letter-spacing: 1.5px; + position: relative; + overflow: hidden; +} + +.submit-button::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); + transition: left 0.5s; +} + +.submit-button:hover:not(:disabled)::before { + left: 100%; +} + +.submit-button:hover:not(:disabled) { + transform: translateY(-3px); + box-shadow: 0 10px 30px rgba(139, 92, 246, 0.5); + background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 50%, #5b21b6 100%); +} + +.submit-button:active:not(:disabled) { + transform: translateY(-1px); +} + +.submit-button:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; + background: linear-gradient(135deg, #c4b5fd 0%, #a78bfa 100%); +} + +.submit-button.swapping { + background: linear-gradient(135deg, #a78bfa 0%, #8b5cf6 100%); + pointer-events: none; +} + +.swap-spinner { + display: inline-block; + width: 18px; + height: 18px; + border: 3px solid rgba(255, 255, 255, 0.3); + border-top-color: white; + border-radius: 50%; + animation: spin 0.6s linear infinite; + margin-right: 10px; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +.loading-spinner { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; + color: white; +} + +.spinner { + width: 56px; + height: 56px; + border: 5px solid rgba(255, 255, 255, 0.3); + border-top-color: white; + border-radius: 50%; + animation: spin 0.7s linear infinite; +} + +.loading-spinner p { + font-size: 18px; + font-weight: 700; + text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); +} + +.error-card { + background: white; + border-radius: 32px; + padding: 48px; + text-align: center; + max-width: 420px; + box-shadow: 0 25px 80px rgba(239, 68, 68, 0.3); + border: 2px solid #fee2e2; +} + +.error-icon { + font-size: 64px; + margin-bottom: 20px; +} + +.error-card h2 { + font-size: 28px; + color: #4c1d95; + margin: 0 0 16px 0; + font-weight: 800; +} + +.error-card p { + color: #8b5cf6; + margin: 0 0 28px 0; + font-weight: 600; +} + +.retry-button { + padding: 14px 28px; + background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); + color: white; + border: none; + border-radius: 16px; + font-weight: 700; + cursor: pointer; + transition: all 0.3s; + text-transform: uppercase; + letter-spacing: 1px; + box-shadow: 0 4px 16px rgba(139, 92, 246, 0.3); +} + +.retry-button:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(139, 92, 246, 0.4); +} + +/* Custom scrollbar for token list */ +.token-list::-webkit-scrollbar { + width: 8px; +} + +.token-list::-webkit-scrollbar-track { + background: #f8f9ff; + border-radius: 4px; +} + +.token-list::-webkit-scrollbar-thumb { + background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); + border-radius: 4px; +} + +.token-list::-webkit-scrollbar-thumb:hover { + background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%); +} + +/* Responsive design */ +@media (max-width: 768px) { + .currency-swap-card { + width: min(92vw, 480px); + max-width: 480px; + padding: 32px; + border-radius: 28px; + } + + .title { + font-size: 30px; + } +} + +@media (max-width: 640px) { + .currency-swap-card { + width: min(95vw, 420px); + max-width: 420px; + padding: 28px; + border-radius: 24px; + min-width: 300px; + } + + .title { + font-size: 28px; + } + + .amount-input { + font-size: 22px; + padding: 14px 16px; + } + + .amount-display { + font-size: 22px; + min-height: 52px; + padding: 14px 16px; + } + + .max-button { + padding: 10px 16px; + font-size: 11px; + } + + .token-select-button { + padding: 16px 18px; + } +} + +@media (max-width: 480px) { + .currency-swap-card { + width: min(98vw, 380px); + max-width: 380px; + padding: 24px; + min-width: 280px; + } + + .title { + font-size: 24px; + } + + .amount-input { + font-size: 24px; + padding: 16px; + } + + .amount-display { + font-size: 24px; + min-height: 60px; + padding: 16px; + } +} diff --git a/src/problem_2/src/components/CurrencySwapForm.jsx b/src/problem_2/src/components/CurrencySwapForm.jsx new file mode 100644 index 000000000..c2c94c566 --- /dev/null +++ b/src/problem_2/src/components/CurrencySwapForm.jsx @@ -0,0 +1,510 @@ +import { useState, useEffect, useRef } from 'react'; +import { fetchTokenPrices, getTokenIconUrl, calculateExchangeRate, calculateOutputAmount } from '../lib/api'; +import { isValidPositiveNumber, formatNumber } from '../lib/validation'; +import './CurrencySwapForm.css'; + +// Animated number component with smooth, elegant animation +function AnimatedNumber({ value, className = '' }) { + const [displayValue, setDisplayValue] = useState(value); + const [isAnimating, setIsAnimating] = useState(false); + const [animationKey, setAnimationKey] = useState(0); + const prevValueRef = useRef(value); + + useEffect(() => { + if (prevValueRef.current !== value && value && value !== '') { + setIsAnimating(true); + setAnimationKey(prev => prev + 1); + + const startValue = parseFloat(prevValueRef.current) || 0; + const endValue = parseFloat(value) || 0; + const duration = 300; // 300ms fast animation + const startTime = Date.now(); + + const animate = () => { + const now = Date.now(); + const elapsed = now - startTime; + const progress = Math.min(elapsed / duration, 1); + + // Smooth ease-out-quart for elegant feel + const easeOut = 1 - Math.pow(1 - progress, 4); + const currentValue = startValue + (endValue - startValue) * easeOut; + + setDisplayValue(formatNumber(currentValue)); + + if (progress < 1) { + requestAnimationFrame(animate); + } else { + setDisplayValue(value); + setIsAnimating(false); + } + }; + + requestAnimationFrame(animate); + prevValueRef.current = value; + } else { + setDisplayValue(value); + } + }, [value]); + + return ( + + {displayValue} + + ); +} + +export default function CurrencySwapForm() { + const [tokenPrices, setTokenPrices] = useState({}); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + const [fromToken, setFromToken] = useState(''); + const [toToken, setToToken] = useState(''); + const [fromAmount, setFromAmount] = useState(''); + const [toAmount, setToAmount] = useState(''); + + const [fromAmountError, setFromAmountError] = useState(''); + const [exchangeRate, setExchangeRate] = useState(0); + const [showFromDropdown, setShowFromDropdown] = useState(false); + const [showToDropdown, setShowToDropdown] = useState(false); + const [searchFrom, setSearchFrom] = useState(''); + const [searchTo, setSearchTo] = useState(''); + const [isSwapping, setIsSwapping] = useState(false); + + const fromDropdownRef = useRef(null); + const toDropdownRef = useRef(null); + + // Fetch token prices on component mount + useEffect(() => { + async function loadPrices() { + try { + setLoading(true); + setError(null); + const prices = await fetchTokenPrices(); + setTokenPrices(prices); + + // Set default tokens if available + const tokens = Object.keys(prices); + if (tokens.length > 0) { + setFromToken(tokens[0]); + if (tokens.length > 1) { + setToToken(tokens[1]); + } + } + } catch (err) { + setError('Failed to load token prices. Please try again later.'); + console.error(err); + } finally { + setLoading(false); + } + } + loadPrices(); + }, []); + + // Close dropdowns when clicking outside + useEffect(() => { + function handleClickOutside(event) { + if (fromDropdownRef.current && !fromDropdownRef.current.contains(event.target)) { + setShowFromDropdown(false); + } + if (toDropdownRef.current && !toDropdownRef.current.contains(event.target)) { + setShowToDropdown(false); + } + } + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + // Calculate exchange rate and output amount when inputs change + useEffect(() => { + if (fromToken && toToken && tokenPrices[fromToken] && tokenPrices[toToken]) { + const rate = calculateExchangeRate(tokenPrices[fromToken], tokenPrices[toToken]); + setExchangeRate(rate); + + if (fromAmount && isValidPositiveNumber(fromAmount)) { + const output = calculateOutputAmount(parseFloat(fromAmount), rate); + setToAmount(formatNumber(output)); + } else { + setToAmount(''); + } + } else { + setExchangeRate(0); + setToAmount(''); + } + }, [fromToken, toToken, fromAmount, tokenPrices]); + + // Handle from amount input change + const handleFromAmountChange = (e) => { + const value = e.target.value; + setFromAmount(value); + + if (value === '') { + setFromAmountError(''); + setToAmount(''); + return; + } + + if (!isValidPositiveNumber(value)) { + setFromAmountError('Please enter a valid positive number'); + setToAmount(''); + } else { + setFromAmountError(''); + } + }; + + // Handle max button click + const handleMaxClick = () => { + // In a real app, this would use actual balance + // For now, we'll use a placeholder + const mockBalance = '1000'; + setFromAmount(mockBalance); + setFromAmountError(''); + }; + + // Handle swap tokens + const handleSwapTokens = () => { + if (!fromToken || !toToken) return; + + const tempToken = fromToken; + setFromToken(toToken); + setToToken(tempToken); + + // Swap amounts + const tempAmount = fromAmount; + setFromAmount(toAmount); + setToAmount(tempAmount); + }; + + // Handle swap button click with animation + const handleSwapClick = () => { + if (!fromToken || !toToken || !fromAmount || fromAmountError || !isValidPositiveNumber(fromAmount)) { + return; + } + + setIsSwapping(true); + + // Trigger animation effect + setTimeout(() => { + setIsSwapping(false); + }, 1000); + }; + + // Get available tokens (only those with prices) + const availableTokens = Object.keys(tokenPrices).sort(); + + // Filter tokens based on search + const filteredFromTokens = availableTokens.filter(token => + token.toLowerCase().includes(searchFrom.toLowerCase()) + ); + const filteredToTokens = availableTokens.filter(token => + token.toLowerCase().includes(searchTo.toLowerCase()) && token !== fromToken + ); + + // Handle token selection + const handleSelectFromToken = (token) => { + setFromToken(token); + setShowFromDropdown(false); + setSearchFrom(''); + if (token === toToken) { + setToToken(''); + } + }; + + const handleSelectToToken = (token) => { + setToToken(token); + setShowToDropdown(false); + setSearchTo(''); + }; + + if (loading) { + return ( +
+
+
+

Loading token prices...

+
+
+ ); + } + + if (error) { + return ( +
+
+
⚠️
+

Error

+

{error}

+ +
+
+ ); + } + + return ( +
+
+
+

Swap

+
+ +
+ {/* From Token Section */} +
+
+ From + {fromToken && ( + Balance: {formatNumber(1000, 2)} + )} +
+
+
+ + + {showFromDropdown && ( +
+
+ setSearchFrom(e.target.value)} + className="search-input" + autoFocus + /> +
+
+ {filteredFromTokens.length > 0 ? ( + filteredFromTokens.map(token => ( + + )) + ) : ( +
No tokens found
+ )} +
+
+ )} +
+ +
+ + +
+ {fromAmountError && ( + {fromAmountError} + )} + {fromToken && tokenPrices[fromToken] && fromAmount && isValidPositiveNumber(fromAmount) && ( +
+ ≈ $ USD +
+ )} +
+
+ + {/* Swap Button */} +
+ +
+ + {/* To Token Section */} +
+
+ To + {toToken && ( + Balance: {formatNumber(500, 2)} + )} +
+
+
+ + + {showToDropdown && ( +
+
+ setSearchTo(e.target.value)} + className="search-input" + autoFocus + /> +
+
+ {filteredToTokens.length > 0 ? ( + filteredToTokens.map(token => ( + + )) + ) : ( +
No tokens found
+ )} +
+
+ )} +
+ +
+
+ {toAmount ? ( + + ) : ( + 0.00 + )} +
+
+ {toToken && tokenPrices[toToken] && toAmount && ( +
+ ≈ USD +
+ )} +
+
+ + {/* Exchange Rate Display */} + {fromToken && toToken && exchangeRate > 0 && ( +
+
+ Rate + + 1 {fromToken} = {toToken} + +
+
+ )} + + {/* Swap Button */} + +
+
+
+ ); +} diff --git a/src/problem_2/src/lib/api.js b/src/problem_2/src/lib/api.js new file mode 100644 index 000000000..b67f04c2b --- /dev/null +++ b/src/problem_2/src/lib/api.js @@ -0,0 +1,89 @@ +/** + * API utilities for fetching token prices + */ + +const PRICES_API_URL = 'https://interview.switcheo.com/prices.json'; +const TOKEN_ICON_BASE_URL = 'https://raw.githubusercontent.com/Switcheo/token-icons/main/tokens'; + +/** + * Fetch token prices from the API + * @returns {Promise} Object with token symbols as keys and prices as values + */ +export async function fetchTokenPrices() { + try { + const response = await fetch(PRICES_API_URL); + if (!response.ok) { + throw new Error('Failed to fetch token prices'); + } + const data = await response.json(); + + // The API returns an array of objects: [{currency, date, price}, ...] + // Convert to object format: { "BLUR": 0.208, "ETH": 1645.93, ... } + // If a currency appears multiple times, use the latest one (by date) + const pricesMap = {}; + + data.forEach(item => { + const currency = item.currency; + const price = item.price; + const date = new Date(item.date); + + // If currency doesn't exist or this entry is newer, update it + if (!pricesMap[currency] || new Date(pricesMap[currency].date) < date) { + pricesMap[currency] = { + price: price, + date: date + }; + } + }); + + // Convert to simple object with just prices + const prices = {}; + Object.keys(pricesMap).forEach(currency => { + prices[currency] = pricesMap[currency].price; + }); + + return prices; + } catch (error) { + console.error('Error fetching token prices:', error); + throw error; + } +} + +/** + * Get token icon URL + * @param {string} tokenSymbol - Token symbol (e.g., 'SWTH', 'BTC') + * @returns {string} URL to the token icon SVG + */ +export function getTokenIconUrl(tokenSymbol) { + return `${TOKEN_ICON_BASE_URL}/${tokenSymbol}.svg`; +} + +/** + * Calculate exchange rate between two tokens + * @param {number|string} fromPrice - Price of the source token + * @param {number|string} toPrice - Price of the destination token + * @returns {number} Exchange rate + */ +export function calculateExchangeRate(fromPrice, toPrice) { + // Convert to numbers if they're strings + const from = typeof fromPrice === 'string' ? parseFloat(fromPrice) : Number(fromPrice); + const to = typeof toPrice === 'string' ? parseFloat(toPrice) : Number(toPrice); + + if (!from || !to || isNaN(from) || isNaN(to) || to === 0) { + return 0; + } + return from / to; +} + +/** + * Calculate the output amount based on input amount and exchange rate + * @param {number} inputAmount - Amount to swap + * @param {number} exchangeRate - Exchange rate between tokens + * @returns {number} Output amount + */ +export function calculateOutputAmount(inputAmount, exchangeRate) { + if (!inputAmount || inputAmount <= 0 || !exchangeRate) { + return 0; + } + return inputAmount * exchangeRate; +} diff --git a/src/problem_2/src/lib/validation.js b/src/problem_2/src/lib/validation.js new file mode 100644 index 000000000..b88159b14 --- /dev/null +++ b/src/problem_2/src/lib/validation.js @@ -0,0 +1,63 @@ +/** + * Validation utilities for form inputs + */ + +/** + * Validate if a value is a positive number + * @param {string|number} value - Value to validate + * @returns {boolean} True if valid positive number + */ +export function isValidPositiveNumber(value) { + if (value === '' || value === null || value === undefined) { + return false; + } + const num = typeof value === 'string' ? parseFloat(value) : value; + return !isNaN(num) && num > 0 && isFinite(num); +} + +/** + * Validate if a value is a non-negative number + * @param {string|number} value - Value to validate + * @returns {boolean} True if valid non-negative number + */ +export function isValidNonNegativeNumber(value) { + if (value === '' || value === null || value === undefined) { + return false; + } + const num = typeof value === 'string' ? parseFloat(value) : value; + return !isNaN(num) && num >= 0 && isFinite(num); +} + +/** + * Format number to display with appropriate decimal places + * @param {number|string} value - Number to format + * @param {number} decimals - Number of decimal places (default: 6) + * @returns {string} Formatted number string + */ +export function formatNumber(value, decimals = 6) { + // Handle null, undefined, empty string, or invalid values + if (value === null || value === undefined || value === '') { + return '0'; + } + + // Convert to number if it's a string + const num = typeof value === 'string' ? parseFloat(value) : Number(value); + + // Check if conversion resulted in a valid number + if (isNaN(num) || !isFinite(num)) { + return '0'; + } + + // Handle zero + if (num === 0) { + return '0'; + } + + // Handle very small numbers + if (Math.abs(num) < 0.000001) { + return num.toExponential(2); + } + + // Format the number + return parseFloat(num.toFixed(decimals)).toString(); +} diff --git a/src/problem_2/src/main.jsx b/src/problem_2/src/main.jsx new file mode 100644 index 000000000..185ca91d1 --- /dev/null +++ b/src/problem_2/src/main.jsx @@ -0,0 +1,9 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import App from './App.jsx' + +createRoot(document.getElementById('app')).render( + + + , +) diff --git a/src/problem_2/tsconfig.json b/src/problem_2/tsconfig.json new file mode 100644 index 000000000..0777a1a62 --- /dev/null +++ b/src/problem_2/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": false, + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/src/problem_2/vite.config.js b/src/problem_2/vite.config.js new file mode 100644 index 000000000..1145aa7d3 --- /dev/null +++ b/src/problem_2/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], + server: { + host: '0.0.0.0', // Listen on all network interfaces + port: 5173, + strictPort: false, // Try next available port if 5173 is taken + }, +}) diff --git a/src/problem_3/README.md b/src/problem_3/README.md new file mode 100644 index 000000000..d3a2ce84b --- /dev/null +++ b/src/problem_3/README.md @@ -0,0 +1,44 @@ +# Problem 3: React TypeScript Code Analysis + +## Computational Inefficiencies and Anti-patterns Found + +### 1. **Critical Logic Error** +- **Line 22**: `lhsPriority` is undefined but should be `balancePriority` +- **Line 23**: Filter logic is inverted - returns balances with amount ≤ 0, which are typically unwanted + +### 2. **Missing Dependencies in useMemo** +- `getPriority` function is not memoized but used inside `useMemo` +- This causes the dependency array to be incomplete, potentially causing stale closures + +### 3. **Inefficient Data Processing** +- `formattedBalances` is computed but never used +- `rows` processes `sortedBalances` instead of `formattedBalances`, missing the formatted data +- Type mismatch: `sortedBalances` contains `WalletBalance` but `rows` expects `FormattedWalletBalance` + +### 4. **Performance Issues** +- `getPriority` function recreated on every render +- Missing `prices` dependency usage in the filter/sort logic +- Inefficient array operations (filter + sort + map could be optimized) + +### 5. **Type Safety Issues** +- `blockchain` parameter typed as `any` instead of proper string union +- Missing `blockchain` property in `WalletBalance` interface +- Empty `Props` interface extending `BoxProps` + +### 6. **Anti-patterns** +- Using array index as React key instead of unique identifier +- Unused `children` destructuring +- Missing error handling for undefined prices + +## Key Improvements Made + +1. **Fixed logic errors** and undefined variable references +2. **Memoized `getPriority`** with `useCallback` to prevent unnecessary re-renders +3. **Proper dependency arrays** in `useMemo` hooks +4. **Combined operations** into single efficient chain +5. **Added type safety** with proper interfaces and null checks +6. **Used meaningful keys** instead of array indices +7. **Eliminated unused computations** and variables +8. **Added error handling** for missing price data + +These changes significantly improve performance, maintainability, and correctness of the component. \ No newline at end of file diff --git a/src/problem_3/index.tsx b/src/problem_3/index.tsx new file mode 100644 index 000000000..d73e5f3e4 --- /dev/null +++ b/src/problem_3/index.tsx @@ -0,0 +1,64 @@ +interface WalletBalance { + currency: string; + amount: number; + blockchain: string; +} + +interface FormattedWalletBalance extends WalletBalance { + formatted: string; +} + +interface Props extends BoxProps {} + +const WalletPage: React.FC = (props) => { + const { children, ...rest } = props; + const balances = useWalletBalances(); + const prices = usePrices(); + + const getPriority = useCallback((blockchain: string): number => { + const priorities: Record = { + 'Osmosis': 100, + 'Ethereum': 50, + 'Arbitrum': 30, + 'Zilliqa': 20, + 'Neo': 20 + }; + return priorities[blockchain] ?? -99; + }, []); + + const formattedBalances = useMemo(() => { + return balances + .filter((balance: WalletBalance) => { + const balancePriority = getPriority(balance.blockchain); + return balancePriority > -99 && balance.amount > 0; + }) + .sort((lhs: WalletBalance, rhs: WalletBalance) => { + return getPriority(rhs.blockchain) - getPriority(lhs.blockchain); + }) + .map((balance: WalletBalance): FormattedWalletBalance => ({ + ...balance, + formatted: balance.amount.toFixed() + })); + }, [balances, getPriority]); + + const rows = useMemo(() => { + return formattedBalances.map((balance: FormattedWalletBalance) => { + const usdValue = (prices[balance.currency] ?? 0) * balance.amount; + return ( + + ); + }); + }, [formattedBalances, prices]); + + return ( +
+ {rows} +
+ ); +};