diff --git a/Dockerfile.cn b/Dockerfile.cn index 19ce3cc..26b2f61 100644 --- a/Dockerfile.cn +++ b/Dockerfile.cn @@ -2,7 +2,7 @@ # 升级到 Node.js v20 或更高版本,以解决 `ReferenceError: File is not defined` 问题 # 参考链接:https://github.com/vercel/next.js/discussions/56032 -FROM dockerp.com/node:22-alpine AS base +FROM docker.1ms.run/node:22-alpine AS base # 仅在需要时安装依赖 FROM base AS deps diff --git a/bun.lock b/bun.lock index 2071c9d..4b2cc51 100644 --- a/bun.lock +++ b/bun.lock @@ -4,6 +4,7 @@ "": { "name": "monaco-editor-lsp-next", "dependencies": { + "@ai-sdk/deepseek": "^0.2.14", "@ai-sdk/openai": "^1.3.0", "@ai-sdk/react": "^1.2.0", "@auth/prisma-adapter": "^2.8.0", @@ -32,13 +33,14 @@ "@tanstack/react-table": "^8.21.2", "@types/vscode": "^1.97.0", "ai": "^4.2.0", - "bcrypt": "^5.1.1", + "bcryptjs": "^3.0.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", "devicons-react": "^1.4.0", "dockerode": "^4.0.4", "dockview": "^4.2.1", + "flexlayout-react": "^0.7.15", "framer-motion": "^12.7.3", "github-markdown-css": "^5.8.1", "lucide-react": "^0.482.0", @@ -73,7 +75,6 @@ "devDependencies": { "@eslint/eslintrc": "^3", "@shikijs/monaco": "^3.2.1", - "@types/bcrypt": "^5.0.2", "@types/dockerode": "^3.3.35", "@types/node": "^20", "@types/react": "^19", @@ -96,8 +97,12 @@ }, }, "packages": { + "@ai-sdk/deepseek": ["@ai-sdk/deepseek@0.2.14", "https://registry.npmmirror.com/@ai-sdk/deepseek/-/deepseek-0.2.14.tgz", { "dependencies": { "@ai-sdk/openai-compatible": "0.2.14", "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-TISD1FzBWuQkHEHoVustoJILV33ZNgfYxeTkq1xU2vHEZuWTGZV7/IlXixyFsfqDCdVgrbLeIABk5FuCw7niLg=="], + "@ai-sdk/openai": ["@ai-sdk/openai@1.3.22", "https://registry.npmmirror.com/@ai-sdk/openai/-/openai-1.3.22.tgz", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-QwA+2EkG0QyjVR+7h6FE7iOu2ivNqAVMm9UJZkVxxTk5OIq5fFJDTEI/zICEMuHImTTXR2JjsL6EirJ28Jc4cw=="], + "@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@0.2.14", "https://registry.npmmirror.com/@ai-sdk/openai-compatible/-/openai-compatible-0.2.14.tgz", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-icjObfMCHKSIbywijaoLdZ1nSnuRnWgMEMLgwoxPJgxsUHMx0aVORnsLUid4SPtdhHI3X2masrt6iaEQLvOSFw=="], + "@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-1.1.3.tgz", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="], "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="], @@ -278,8 +283,6 @@ "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "https://registry.npmmirror.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], - "@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@1.0.11", "https://registry.npmmirror.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", { "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", "make-dir": "^3.1.0", "node-fetch": "^2.6.7", "nopt": "^5.0.0", "npmlog": "^5.0.1", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.11" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ=="], - "@mdx-js/mdx": ["@mdx-js/mdx@3.1.0", "https://registry.npmmirror.com/@mdx-js/mdx/-/mdx-3.1.0.tgz", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw=="], "@mdx-js/react": ["@mdx-js/react@3.1.0", "https://registry.npmmirror.com/@mdx-js/react/-/react-3.1.0.tgz", { "dependencies": { "@types/mdx": "^2.0.0" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ=="], @@ -486,8 +489,6 @@ "@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], - "@types/bcrypt": ["@types/bcrypt@5.0.2", "https://registry.npmmirror.com/@types/bcrypt/-/bcrypt-5.0.2.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ=="], - "@types/debug": ["@types/debug@4.1.12", "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], "@types/diff-match-patch": ["@types/diff-match-patch@1.0.36", "https://registry.npmmirror.com/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", {}, "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg=="], @@ -580,16 +581,12 @@ "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.7.2", "https://registry.npmmirror.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.2.tgz", { "os": "win32", "cpu": "x64" }, "sha512-friS8NEQfHaDbkThxopGk+LuE5v3iY0StruifjQEt7SLbA46OnfgMO15sOTkbpJkol6RB+1l1TYPXh0sCddpvA=="], - "abbrev": ["abbrev@1.1.1", "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz", {}, "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="], - "accepts": ["accepts@2.0.0", "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "acorn": ["acorn@8.14.1", "https://registry.npmmirror.com/acorn/-/acorn-8.14.1.tgz", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], "acorn-jsx": ["acorn-jsx@5.3.2", "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - "agent-base": ["agent-base@6.0.2", "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], - "ai": ["ai@4.3.15", "https://registry.npmmirror.com/ai/-/ai-4.3.15.tgz", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@ai-sdk/react": "1.2.12", "@ai-sdk/ui-utils": "1.2.11", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["react"] }, "sha512-TYKRzbWg6mx/pmTadlAEIhuQtzfHUV0BbLY72+zkovXwq/9xhcH24IlQmkyBpElK6/4ArS0dHdOOtR1jOPVwtg=="], "ajv": ["ajv@6.12.6", "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], @@ -602,10 +599,6 @@ "anymatch": ["anymatch@3.1.3", "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "aproba": ["aproba@2.0.0", "https://registry.npmmirror.com/aproba/-/aproba-2.0.0.tgz", {}, "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="], - - "are-we-there-yet": ["are-we-there-yet@2.0.0", "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" } }, "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw=="], - "arg": ["arg@5.0.2", "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], "argparse": ["argparse@2.0.1", "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], @@ -656,10 +649,10 @@ "base64-js": ["base64-js@1.5.1", "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "bcrypt": ["bcrypt@5.1.1", "https://registry.npmmirror.com/bcrypt/-/bcrypt-5.1.1.tgz", { "dependencies": { "@mapbox/node-pre-gyp": "^1.0.11", "node-addon-api": "^5.0.0" } }, "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww=="], - "bcrypt-pbkdf": ["bcrypt-pbkdf@1.0.2", "https://registry.npmmirror.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", { "dependencies": { "tweetnacl": "^0.14.3" } }, "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w=="], + "bcryptjs": ["bcryptjs@3.0.2", "https://registry.npmmirror.com/bcryptjs/-/bcryptjs-3.0.2.tgz", { "bin": { "bcrypt": "bin/bcrypt" } }, "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog=="], + "binary-extensions": ["binary-extensions@2.3.0", "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], "bl": ["bl@4.1.0", "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], @@ -724,8 +717,6 @@ "color-string": ["color-string@1.9.1", "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], - "color-support": ["color-support@1.1.3", "https://registry.npmmirror.com/color-support/-/color-support-1.1.3.tgz", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="], - "colorette": ["colorette@2.0.20", "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "https://registry.npmmirror.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], @@ -734,8 +725,6 @@ "concat-map": ["concat-map@0.0.1", "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - "console-control-strings": ["console-control-strings@1.1.0", "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz", {}, "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="], - "content-disposition": ["content-disposition@1.0.0", "https://registry.npmmirror.com/content-disposition/-/content-disposition-1.0.0.tgz", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="], "content-type": ["content-type@1.0.5", "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], @@ -778,8 +767,6 @@ "define-properties": ["define-properties@1.2.1", "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], - "delegates": ["delegates@1.0.0", "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="], - "depd": ["depd@2.0.0", "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], "dequal": ["dequal@2.0.3", "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], @@ -942,6 +929,8 @@ "flatted": ["flatted@3.3.3", "https://registry.npmmirror.com/flatted/-/flatted-3.3.3.tgz", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + "flexlayout-react": ["flexlayout-react@0.7.15", "https://registry.npmmirror.com/flexlayout-react/-/flexlayout-react-0.7.15.tgz", { "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" } }, "sha512-ydTMdEoQO5BniylxVkSxa59rEY0+96lqqRII+QK+yq6028eHywPuxZawt4g45y5pMb9ptP4N9HPAQXAFsxwowQ=="], + "for-each": ["for-each@0.3.5", "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], "foreground-child": ["foreground-child@3.3.1", "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], @@ -954,10 +943,6 @@ "fs-constants": ["fs-constants@1.0.0", "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], - "fs-minipass": ["fs-minipass@2.1.0", "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-2.1.0.tgz", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], - - "fs.realpath": ["fs.realpath@1.0.0", "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], - "fsevents": ["fsevents@2.3.3", "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], @@ -966,8 +951,6 @@ "functions-have-names": ["functions-have-names@1.2.3", "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], - "gauge": ["gauge@3.0.2", "https://registry.npmmirror.com/gauge/-/gauge-3.0.2.tgz", { "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.1", "object-assign": "^4.1.1", "signal-exit": "^3.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.2" } }, "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q=="], - "get-caller-file": ["get-caller-file@2.0.5", "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], "get-intrinsic": ["get-intrinsic@1.3.0", "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], @@ -1008,8 +991,6 @@ "has-tostringtag": ["has-tostringtag@1.0.2", "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], - "has-unicode": ["has-unicode@2.0.1", "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz", {}, "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="], - "hasown": ["hasown@2.0.2", "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], "hast-util-from-dom": ["hast-util-from-dom@5.0.1", "https://registry.npmmirror.com/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", { "dependencies": { "@types/hast": "^3.0.0", "hastscript": "^9.0.0", "web-namespaces": "^2.0.0" } }, "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q=="], @@ -1046,8 +1027,6 @@ "http-errors": ["http-errors@2.0.0", "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], - "https-proxy-agent": ["https-proxy-agent@5.0.1", "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], - "iconv-lite": ["iconv-lite@0.6.3", "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "ieee754": ["ieee754@1.2.1", "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], @@ -1058,8 +1037,6 @@ "imurmurhash": ["imurmurhash@0.1.4", "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - "inflight": ["inflight@1.0.6", "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], - "inherits": ["inherits@2.0.4", "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "inline-style-parser": ["inline-style-parser@0.2.4", "https://registry.npmmirror.com/inline-style-parser/-/inline-style-parser-0.2.4.tgz", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], @@ -1200,8 +1177,6 @@ "lucide-react": ["lucide-react@0.482.0", "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.482.0.tgz", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-XM8PzHzSrg8ATmmO+fzf+JyYlVVdQnJjuyLDj2p4V2zEtcKeBNAqAoJIGFv1x2HSBa7kT8gpYUxwdQ0g7nypfw=="], - "make-dir": ["make-dir@3.1.0", "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], - "markdown-extensions": ["markdown-extensions@2.0.0", "https://registry.npmmirror.com/markdown-extensions/-/markdown-extensions-2.0.0.tgz", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], "markdown-table": ["markdown-table@3.0.4", "https://registry.npmmirror.com/markdown-table/-/markdown-table-3.0.4.tgz", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], @@ -1332,10 +1307,6 @@ "minipass": ["minipass@7.1.2", "https://registry.npmmirror.com/minipass/-/minipass-7.1.2.tgz", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], - "minizlib": ["minizlib@2.1.2", "https://registry.npmmirror.com/minizlib/-/minizlib-2.1.2.tgz", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], - - "mkdirp": ["mkdirp@1.0.4", "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], - "mkdirp-classic": ["mkdirp-classic@0.5.3", "https://registry.npmmirror.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], "monaco-editor": ["monaco-editor@0.36.1", "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.36.1.tgz", {}, "sha512-/CaclMHKQ3A6rnzBzOADfwdSJ25BFoFT0Emxsc4zYVyav5SkK9iA6lEtIeuN/oRYbwPgviJT+t3l+sjFa28jYg=="], @@ -1370,18 +1341,10 @@ "next-themes": ["next-themes@0.4.6", "https://registry.npmmirror.com/next-themes/-/next-themes-0.4.6.tgz", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], - "node-addon-api": ["node-addon-api@5.1.0", "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-5.1.0.tgz", {}, "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="], - - "node-fetch": ["node-fetch@2.7.0", "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - - "nopt": ["nopt@5.0.0", "https://registry.npmmirror.com/nopt/-/nopt-5.0.0.tgz", { "dependencies": { "abbrev": "1" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ=="], - "normalize-path": ["normalize-path@3.0.0", "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], "normalize-url": ["normalize-url@8.0.1", "https://registry.npmmirror.com/normalize-url/-/normalize-url-8.0.1.tgz", {}, "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w=="], - "npmlog": ["npmlog@5.0.1", "https://registry.npmmirror.com/npmlog/-/npmlog-5.0.1.tgz", { "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", "gauge": "^3.0.0", "set-blocking": "^2.0.0" } }, "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw=="], - "oauth4webapi": ["oauth4webapi@3.5.1", "https://registry.npmmirror.com/oauth4webapi/-/oauth4webapi-3.5.1.tgz", {}, "sha512-txg/jZQwcbaF7PMJgY7aoxc9QuCxHVFMiEkDIJ60DwDz3PbtXPQnrzo+3X4IRYGChIwWLabRBRpf1k9hO9+xrQ=="], "object-assign": ["object-assign@4.1.1", "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], @@ -1434,8 +1397,6 @@ "path-exists": ["path-exists@4.0.0", "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - "path-is-absolute": ["path-is-absolute@1.0.1", "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], - "path-key": ["path-key@3.1.1", "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "path-parse": ["path-parse@1.0.7", "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], @@ -1590,8 +1551,6 @@ "reusify": ["reusify@1.1.0", "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - "rimraf": ["rimraf@3.0.2", "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "router": ["router@2.2.0", "https://registry.npmmirror.com/router/-/router-2.2.0.tgz", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], "run-parallel": ["run-parallel@1.2.0", "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], @@ -1620,8 +1579,6 @@ "server-only": ["server-only@0.0.1", "https://registry.npmmirror.com/server-only/-/server-only-0.0.1.tgz", {}, "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="], - "set-blocking": ["set-blocking@2.0.0", "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], - "set-function-length": ["set-function-length@1.2.2", "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], "set-function-name": ["set-function-name@2.0.2", "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], @@ -1724,8 +1681,6 @@ "tailwindcss-animate": ["tailwindcss-animate@1.0.7", "https://registry.npmmirror.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="], - "tar": ["tar@6.2.1", "https://registry.npmmirror.com/tar/-/tar-6.2.1.tgz", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], - "tar-fs": ["tar-fs@2.1.2", "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.2.tgz", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA=="], "tar-stream": ["tar-stream@3.1.7", "https://registry.npmmirror.com/tar-stream/-/tar-stream-3.1.7.tgz", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], @@ -1746,8 +1701,6 @@ "toidentifier": ["toidentifier@1.0.1", "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], - "tr46": ["tr46@0.0.3", "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - "trim-lines": ["trim-lines@3.0.1", "https://registry.npmmirror.com/trim-lines/-/trim-lines-3.0.1.tgz", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], "trough": ["trough@2.2.0", "https://registry.npmmirror.com/trough/-/trough-2.2.0.tgz", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], @@ -1848,10 +1801,6 @@ "web-namespaces": ["web-namespaces@2.0.1", "https://registry.npmmirror.com/web-namespaces/-/web-namespaces-2.0.1.tgz", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], - "webidl-conversions": ["webidl-conversions@3.0.1", "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], - - "whatwg-url": ["whatwg-url@5.0.0", "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], - "which": ["which@2.0.2", "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], @@ -1862,8 +1811,6 @@ "which-typed-array": ["which-typed-array@1.1.19", "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.19.tgz", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], - "wide-align": ["wide-align@1.1.5", "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="], - "word-wrap": ["word-wrap@1.2.5", "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], "wrap-ansi": ["wrap-ansi@7.0.0", "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], @@ -1874,8 +1821,6 @@ "y18n": ["y18n@5.0.8", "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yallist": ["yallist@4.0.0", "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], - "yaml": ["yaml@2.7.1", "https://registry.npmmirror.com/yaml/-/yaml-2.7.1.tgz", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="], "yargs": ["yargs@17.7.2", "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], @@ -1928,38 +1873,24 @@ "fast-glob/glob-parent": ["glob-parent@5.1.2", "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "fs-minipass/minipass": ["minipass@3.3.6", "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - - "gauge/signal-exit": ["signal-exit@3.0.7", "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - "glob/minimatch": ["minimatch@9.0.5", "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "jsondiffpatch/chalk": ["chalk@5.4.1", "https://registry.npmmirror.com/chalk/-/chalk-5.4.1.tgz", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], "katex/commander": ["commander@8.3.0", "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], - "make-dir/semver": ["semver@6.3.1", "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], - "minizlib/minipass": ["minipass@3.3.6", "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "monaco-languageclient/vscode-languageclient": ["vscode-languageclient@8.1.0", "https://registry.npmmirror.com/vscode-languageclient/-/vscode-languageclient-8.1.0.tgz", { "dependencies": { "minimatch": "^5.1.0", "semver": "^7.3.7", "vscode-languageserver-protocol": "3.17.3" } }, "sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing=="], "next/postcss": ["postcss@8.4.31", "https://registry.npmmirror.com/postcss/-/postcss-8.4.31.tgz", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "parse-entities/@types/unist": ["@types/unist@2.0.11", "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], - "rimraf/glob": ["glob@7.2.3", "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "string-width/emoji-regex": ["emoji-regex@8.0.0", "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - "tar/chownr": ["chownr@2.0.0", "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], - - "tar/minipass": ["minipass@5.0.0", "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], - "tar-fs/tar-stream": ["tar-stream@2.2.0", "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], "tinyglobby/picomatch": ["picomatch@4.0.2", "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], diff --git a/messages/en.json b/messages/en.json index d1c0755..e9c625d 100644 --- a/messages/en.json +++ b/messages/en.json @@ -49,7 +49,7 @@ "DetailsPage": { "BackButton": "All Submissions", "Time": "Submitted on", - "Input": "Input", + "Input": "Last Executed Input", "ExpectedOutput": "Expected Output", "ActualOutput": "Acutal Output", "Code": "Code" @@ -127,7 +127,8 @@ "description": "Enter your email below to sign up to your account", "or": "Or", "haveAccount": "Already have an account?", - "signIn": "Sign in" + "signIn": "Sign in", + "oauth": "Sign in with {provider}" }, "StatusMessage": { "PD": "Pending", @@ -150,12 +151,25 @@ "Time": "Time", "Memory": "Memory" }, + "Testcase": { + "Table": { + "Case": "Case" + } + }, "WorkspaceEditorHeader": { "LspStatusButton": { "TooltipContent": "Language Server" }, + "AnalyzeButton": { + "TooltipContent": "Analyze", + "ComplexityAnalysis": "Complexity Analysis", + "TimeComplexity": "Time Complexity:", + "SpaceComplexity": "Space Complexity", + "Error": "Error occurred while analyzing complexity, please try again later.", + "Analyzing": "Analyzing..." + }, "ResetButton": { - "TooltipContent": "Reset Code" + "TooltipContent": "Reset" }, "UndoButton": { "TooltipContent": "Undo" @@ -215,5 +229,13 @@ "answer4": "Editor uses @shikijs/monaco themes, documentation rendered with github-markdown-css" } } + }, + "LoginPromptCard": { + "title": "Join Judge4c to Code!", + "description": "View your Submission records here", + "loginButton": "Log In" + }, + "Video": { + "unsupportedBrowser": "Your browser does not support HTML5 video." } } diff --git a/messages/zh.json b/messages/zh.json index 9758d5b..245f0e6 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -17,13 +17,13 @@ }, "BackButton": "返回", "Bot": { - "title": "询问AI助手", - "description": "由Vercel Ai SDK驱动", - "placeholder": "AI助手将自动获取您当前的代码" + "title": "询问 AI 助手", + "description": "由 Vercel Ai SDK 驱动", + "placeholder": "AI 助手将自动获取您当前的代码" }, "BotVisibilityToggle": { - "open": "打开AI助手", - "close": "关闭AI助手" + "open": "打开 AI 助手", + "close": "关闭 AI 助手" }, "CredentialsSignInForm": { "email": "邮箱", @@ -49,7 +49,7 @@ "DetailsPage": { "BackButton": "所有提交记录", "Time": "提交于", - "Input": "输入", + "Input": "最后执行的输入", "ExpectedOutput": "期望输出", "ActualOutput": "实际输出", "Code": "代码" @@ -127,7 +127,8 @@ "description": "请输入你的邮箱以注册账户", "or": "或者", "haveAccount": "已经有账户了?", - "signIn": "登录" + "signIn": "登录", + "oauth": "使用 {provider} 登录" }, "StatusMessage": { "PD": "待处理", @@ -150,12 +151,25 @@ "Time": "执行用时", "Memory": "消耗内存" }, + "Testcase": { + "Table": { + "Case": "样例" + } + }, "WorkspaceEditorHeader": { "LspStatusButton": { "TooltipContent": "语言服务" }, + "AnalyzeButton": { + "TooltipContent": "分析", + "ComplexityAnalysis": "复杂度分析", + "TimeComplexity": "时间复杂度:", + "SpaceComplexity": "空间复杂度:", + "Error": "解析复杂度时出错,请稍后重试。", + "Analyzing": "分析中..." + }, "ResetButton": { - "TooltipContent": "重置代码" + "TooltipContent": "重置" }, "UndoButton": { "TooltipContent": "撤销" @@ -215,5 +229,13 @@ "answer4": "编辑器采用 @shikijs/monaco, 文档采用 github-markdown-css 样式" } } + }, + "LoginPromptCard": { + "title": "加入 Judge4c 开始编程!", + "description": "在此查看您的提交记录", + "loginButton": "登录" + }, + "Video": { + "unsupportedBrowser": "您的浏览器不支持 HTML5 视频。" } } diff --git a/package.json b/package.json index 1ccafd4..2f0ec87 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "seed": "tsx prisma/seed.ts" }, "dependencies": { + "@ai-sdk/deepseek": "^0.2.14", "@ai-sdk/openai": "^1.3.0", "@ai-sdk/react": "^1.2.0", "@auth/prisma-adapter": "^2.8.0", @@ -41,13 +42,14 @@ "@tanstack/react-table": "^8.21.2", "@types/vscode": "^1.97.0", "ai": "^4.2.0", - "bcrypt": "^5.1.1", + "bcryptjs": "^3.0.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", "devicons-react": "^1.4.0", "dockerode": "^4.0.4", "dockview": "^4.2.1", + "flexlayout-react": "^0.7.15", "framer-motion": "^12.7.3", "github-markdown-css": "^5.8.1", "lucide-react": "^0.482.0", @@ -82,7 +84,6 @@ "devDependencies": { "@eslint/eslintrc": "^3", "@shikijs/monaco": "^3.2.1", - "@types/bcrypt": "^5.0.2", "@types/dockerode": "^3.3.35", "@types/node": "^20", "@types/react": "^19", diff --git a/prisma/migrations/20250516195446_add_password_for_user/migration.sql b/prisma/migrations/20250516195446_add_password_for_user/migration.sql new file mode 100644 index 0000000..2f77ec7 --- /dev/null +++ b/prisma/migrations/20250516195446_add_password_for_user/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "password" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5daae16..e56f09e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -59,6 +59,7 @@ model User { id String @id @default(cuid()) name String? email String @unique + password String? emailVerified DateTime? image String? role Role @default(GUEST) diff --git a/prisma/seed.ts b/prisma/seed.ts index 87a72d8..02f360a 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,75 +1,67 @@ -import { PrismaClient, Prisma, EditorLanguage, LanguageServerProtocol } from "@/generated/client"; +import { PrismaClient, Prisma } from "@/generated/client"; const prisma = new PrismaClient(); -const editorLanguageConfigData: Prisma.EditorLanguageConfigCreateInput[] = [ +const dockerConfigData: Prisma.DockerConfigCreateInput[] = [ { - language: EditorLanguage.c, - label: "C", - fileName: "main", - fileExtension: ".c", - languageServerConfig: { - create: { - protocol: LanguageServerProtocol.ws, - hostname: "localhost", - port: 4594, - path: "/clangd", - }, - }, - dockerConfig: { - create: { - image: "gcc", - tag: "latest", - workingDir: "/src", - compileOutputLimit: 1 * 1024 * 1024, - runOutputLimit: 1 * 1024 * 1024, - }, - }, + language: "c", + image: "gcc", + tag: "latest", + workingDir: "/src", + compileOutputLimit: 1 * 1024 * 1024, + runOutputLimit: 1 * 1024 * 1024, }, { - language: EditorLanguage.cpp, - label: "C++", - fileName: "main", - fileExtension: ".cpp", - languageServerConfig: { - create: { - protocol: LanguageServerProtocol.ws, - hostname: "localhost", - port: 4595, - path: "/clangd", - }, - }, - dockerConfig: { - create: { - image: "gcc", - tag: "latest", - workingDir: "/src", - compileOutputLimit: 1 * 1024 * 1024, - runOutputLimit: 1 * 1024 * 1024, - }, - }, + language: "cpp", + image: "gcc", + tag: "latest", + workingDir: "/src", + compileOutputLimit: 1 * 1024 * 1024, + runOutputLimit: 1 * 1024 * 1024, }, ]; -const userData: Prisma.UserCreateInput[] = [ +const languageServerConfigData: Prisma.LanguageServerConfigCreateInput[] = [ { - name: "cfngc4594", - email: "cfngc4594@gmail.com", - password: "$2b$10$edWXpq2TOiiGQkPOXWKGlO4EKnp2YyV7OoS2qqk/W0E6GyiVQIC66", - role: "ADMIN", - problems: { + language: "c", + protocol: "wss", + hostname: "lsp-c.litchi.icu", + path: "/clangd", + }, + { + language: "cpp", + protocol: "wss", + hostname: "lsp-cpp.litchi.icu", + path: "/clangd", + }, +]; + +const problemData: Prisma.ProblemCreateInput[] = [ + { + displayId: 1000, + difficulty: "EASY", + isPublished: true, + localizations: { create: [ { - displayId: 1000, - title: "Two Sum", - description: `Given an array of integers \`nums\` and an integer \`target\`, return indices of the two numbers such that they add up to \`target\`. + locale: "en", + type: "TITLE", + content: "Two Sum", + }, + { + locale: "zh", + type: "TITLE", + content: "两数之和", + }, + { + locale: "en", + type: "DESCRIPTION", + content: `Given an array of integers \`nums\` and an integer \`target\`, return indices of the two numbers such that they add up to \`target\`. You may assume that each input would have **exactly one solution**, and you may not use the same element twice. You can return the answer in any order. - - ## Examples ### Example 1 @@ -127,7 +119,78 @@ So, if we fix one of the numbers, say \`x\`, we have to scan the entire array to The second train of thought is, without changing the array, can we use additional space somehow? Like maybe a hash map to speed up the search? `, - solution: ` + }, + { + locale: "zh", + type: "DESCRIPTION", + content: `给定一个整数数组\`nums\` 一个整数\`target\`, 返回数组中两个数的下标,使得它们的和等于 \`target\`. + +你可以假设每个输入恰好有一个解,并且你不能重复使用同一个元素。 + +答案可以按任意顺序返回。 + +## 示例 + +### 示例 1 + +\`\`\`shell +输入: nums = [2,7,11,15], target = 9 +输出: [0,1] +解释: Because nums[0] + nums[1] == 9, we return [0, 1]. +\`\`\` + +### 示例 2 + +\`\`\`shell +输入: nums = [3,2,4], target = 6 +输出: [1,2] +\`\`\` + +### 示例 3 + +\`\`\`shell +输入: nums = [3,3], target = 6 +输出: [0,1] +\`\`\` + +## 约束 + +\`\`\`math +2 <= nums.length <= 10^4 +\`\`\` + +\`\`\`math +-10^9 <= nums[i] <= 10^9 +\`\`\` + +\`\`\`math +-10^9 <= target <= 10^9 +\`\`\` + +
+只存在一个有效的答案。 +
+ +**进阶问题:** 你能否设计一个时间复杂度低于 $O(n^2)$ 的算法来解决这个问题?? + +--- + + +一种真正的暴力方法是遍历所有可能的数字对,但这种方法太慢了。不过,为了完整性,尝试暴力解法仍然是有意义的。正是从这些暴力解法中,你才能找到优化的思路。 + + + +所以,如果我们固定其中一个数字,例如 \`x\`, 我们就必须遍历整个数组来找到另一个数字 \`y\`,而 \`y\`等于 \`value - x\` (这里的 value 是输入的参数)。我们能否以某种方式对数组进行处理,从而让这种查找变得更快呢? + + + +第二种思路是,在不改变数组的前提下,我们能否借助额外的空间呢?比如,是否可以用哈希表来加快查找速度? +`, + }, + { + locale: "en", + type: "SOLUTION", + content: `![Example](https://assets.leetcode.com/uploads/2020/10/02/addtwonumber1.jpg) ## Approach 1: Brute Force @@ -137,7 +200,7 @@ The brute force approach is simple. Loop through each element $x$ and find if th ### Implementation -\`\`\`c showLineNumbers +\`\`\`c showLineNumbers {2-3,6-7,15} int* twoSum(int* nums, int numsSize, int target, int* returnSize) { for (int i = 0; i < numsSize; i++) { for (int j = i + 1; j < numsSize; j++) { @@ -166,6 +229,8 @@ int* twoSum(int* nums, int numsSize, int target, int* returnSize) { The space required does not depend on the size of the input array, so only constant space is used. + + --- ## Approach 2: Two-pass Hash Table @@ -291,13 +356,184 @@ int* twoSum(int* nums, int numsSize, int target, int* returnSize) { | Brute Force | $O(n^2)$ | $O(1)$ | | Two-pass Hash Table | $O(n)$ | $O(n)$ | | One-pass Hash Table | $O(n)$ | $O(n)$ |`, - difficulty: "EASY", - published: true, - templates: { - create: [ - { - language: "c", - template: `#include + }, + { + locale: "zh", + type: "SOLUTION", + content: `![示例](https://assets.leetcode.com/uploads/2020/10/02/addtwonumber1.jpg) + +## 方法一:暴力枚举 + +### 算法思路 + +暴力枚举法的思路很简单:遍历数组中的每个元素 x,并查找是否存在另一个元素的值等于 $target - x$. + +### 代码实现 + +\`\`\`c showLineNumbers {2-3,6-7,15} +int* twoSum(int* nums, int numsSize, int target, int* returnSize) { + for (int i = 0; i < numsSize; i++) { + for (int j = i + 1; j < numsSize; j++) { + if (nums[j] == target - nums[i]) { + int* result = malloc(sizeof(int) * 2); + result[0] = i; + result[1] = j; + *returnSize = 2; + return result; + } + } + } + // 如果未找到解,返回一个空数组 + *returnSize = 0; + return malloc(sizeof(int) * 0); +} +\`\`\` + +### 复杂度分析 + +- **时间复杂度:** $O(n^2)$. + + 对于数组中的每个元素,我们都要通过遍历数组的剩余部分来查找它的补数,这需要 $O(n)$ 的时间。因此,总的时间复杂度是 $O(n^2)$. + +- **空间复杂度:\(O(1)\)** $O(1)$. + + 所需的空间并不依赖于输入数组的大小,所以只使用了常数级别的空间。 + + + +--- + +## 方法 2: 两遍哈希表 + +### 思路 + +为了提高运行时的时间复杂度,我们需要一种更高效的方法来检查数组中是否存在某个元素的补数。如果补数存在,我们还需要获取它的索引。维护数组中每个元素与其索引之间的映射的最佳方法是什么呢?答案是哈希表。 + +我们可以通过用空间换取时间的方式,将查找时间从 $O(n)$ 降低到 $O(1)$ 。哈希表非常适合这个目的,因为它支持在近似常数时间内进行快速查找。我之所以说 “近似”,是因为如果发生了哈希冲突,查找时间可能会退化为 $O(n)$ 。不过,只要精心选择哈希函数,哈希表的查找时间平均为 $O(1)$ 。 + +### 算法 + +一种简单的实现方式是使用两次迭代。在第一次迭代中,我们将每个元素的值作为键,其索引作为值添加到哈希表中。然后,在第二次迭代中,我们检查每个元素的补数 ($target - nums[i]$) 是否存在于哈希表中。如果存在,我们就返回当前元素的索引和它补数的索引。需要注意的是,补数不能是元素本身 $nums[i]$ ! + +### 代码实现 + +\`\`\`c showLineNumbers +int* twoSum(int* nums, int numsSize, int target, int* returnSize) { + struct hashTable { + int key; + int value; + UT_hash_handle hh; + } *hashTable = NULL, *item, *tmpItem; + + for (int i = 0; i < numsSize; i++) { + HASH_FIND_INT(hashTable, &nums[i], item); + if (item) { + int* result = malloc(sizeof(int) * 2); + result[0] = item->value; + result[1] = i; + *returnSize = 2; + HASH_ITER(hh, hashTable, item, tmpItem) { + HASH_DEL(hashTable, item); + free(item); + } + return result; + } + item = malloc(sizeof(struct hashTable)); + item->key = target - nums[i]; + item->value = i; + HASH_ADD_INT(hashTable, key, item); + } + + HASH_ITER(hh, hashTable, item, tmpItem) { + HASH_DEL(hashTable, item); + free(item); + } + + *returnSize = 0; + // 如果没有找到有效的数对,则返回一个空数组 + return malloc(sizeof(int) * 0); +} +\`\`\` + +### 复杂度分析 + +- **时间复杂度:** $O(n)$. + + 我们精确地遍历包含 n 个元素的列表两次。由于哈希表将查找时间减少到 $O(1)$,所以总的时间复杂度为 $O(n)$。 + +- **空间复杂度:** $O(n)$. + + 所需的额外空间取决于存储在哈希表中的元素数量,而哈希表中恰好存储了 $n$ 个元素。 + +--- + +## 方法三:一遍哈希表 + +### 算法 + +事实证明,我们可以通过一遍遍历实现。在我们遍历并将元素插入哈希表的同时,我们还要检查当前元素的补数是否已经存在于哈希表中。如果存在,我们就找到了一个解决方案,并立即返回索引。 + +### 代码实现 + +\`\`\`c showLineNumbers +int* twoSum(int* nums, int numsSize, int target, int* returnSize) { + struct hashTable { + int key; + int value; + UT_hash_handle hh; + } *hashTable = NULL, *item; + + for (int i = 0; i < numsSize; i++) { + int complement = target - nums[i]; + HASH_FIND_INT(hashTable, &complement, item); + if (item) { + int* result = malloc(sizeof(int) * 2); + result[0] = item->value; + result[1] = i; + *returnSize = 2; + HASH_CLEAR(hh, hashTable); // 释放哈希表内存 + return result; + } + item = malloc(sizeof(struct hashTable)); + item->key = nums[i]; + item->value = i; + HASH_ADD_INT(hashTable, key, item); + } + + *returnSize = 0; + HASH_CLEAR(hh, hashTable); // 释放哈希表内存 + // 若未找到解,返回一个空数组 + return malloc(0); // 分配0字节内存(即空数组) +} +\`\`\` + +### 复杂度分析 + +- **时间复杂度:** $O(n)$. + + 我们仅遍历包含 n 个元素的列表一次。表中每次查找仅需 $O(1)$ 时间。 + +- **空间复杂度:** $O(n)$. + + 所需的额外空间取决于哈希表中存储的元素数量,该哈希表最多存储 $n$ 个元素。 + +--- + +## 方法总结 + +| 方法 | 时间复杂度 | 空间复杂度 | +| ------------------- | :-------------: | :--------------: | +| 暴力枚举 | $O(n^2)$ | $O(1)$ | +| 两遍哈希表 | $O(n)$ | $O(n)$ | +| 一遍哈希表 | $O(n)$ | $O(n)$ |`, + }, + ], + }, + templates: { + create: [ + { + language: "c", + content: `#include #include #include @@ -371,10 +607,10 @@ int main() { } return 0; }`, - }, - { - language: "cpp", - template: `#include + }, + { + language: "cpp", + content: `#include #include #include #include @@ -435,45 +671,85 @@ int main() { return 0; }`, - }, - ], - }, - testcases: { + }, + ], + }, + testcases: { + create: [ + { + inputs: { create: [ { - data: { - create: [ - { label: "nums", value: "[2,7,11,15]", index: 0 }, - { label: "target", value: "9", index: 1 }, - ], - }, - expectedOutput: "[0,1]", + index: 0, + name: "nums", + value: "[2,7,11,15]", }, { - data: { - create: [ - { label: "nums", value: "[3,2,4]", index: 0 }, - { label: "target", value: "6", index: 1 }, - ], - }, - expectedOutput: "[1,2]", - }, - { - data: { - create: [ - { label: "nums", value: "[3,3]", index: 0 }, - { label: "target", value: "6", index: 1 }, - ], - }, - expectedOutput: "[0,1]", + index: 1, + name: "target", + value: "9", }, ], }, + expectedOutput: "[0,1]", }, { - displayId: 1001, - title: "Add Two Numbers", - description: `You are given two **non-empty** linked lists representing two non-negative integers. The digits are stored in **reverse order**, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list. + inputs: { + create: [ + { + index: 0, + name: "nums", + value: "[3,2,4]", + }, + { + index: 1, + name: "target", + value: "6", + }, + ], + }, + expectedOutput: "[1,2]", + }, + { + inputs: { + create: [ + { + index: 0, + name: "nums", + value: "[3,3]", + }, + { + index: 1, + name: "target", + value: "6", + }, + ], + }, + expectedOutput: "[0,1]", + }, + ], + }, + }, + { + displayId: 1001, + difficulty: "MEDIUM", + isPublished: true, + localizations: { + create: [ + { + locale: "en", + type: "TITLE", + content: "Add Two Numbers", + }, + { + locale: "zh", + type: "TITLE", + content: "两数相加", + }, + { + locale: "en", + type: "DESCRIPTION", + content: `You are given two **non-empty** linked lists representing two non-negative integers. The digits are stored in **reverse order**, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. @@ -516,7 +792,58 @@ The number of nodes in each linked list is in the range $[1, 100]$.
It is guaranteed that the list represents a number that does not have leading zeros.
`, - solution: `## Approach 1: Elementary Math + }, + { + locale: "zh", + type: "DESCRIPTION", + content: `给定两个**非空**链表,它们表示两个非负整数。这些数字以**逆序**存储,并且每个节点包含一个数字。将这两个数字相加,并以链表形式返回它们的和。 + +你可以假设这两个数字除了数字 0 本身外,不包含任何前导零。 + +## 示例 + +### 示例1 + +![示例1](https://assets.leetcode.com/uploads/2020/10/02/addtwonumber1.jpg) + +\`\`\`shell +输入: l1 = [2,4,3], l2 = [5,6,4] +输出: [7,0,8] +解释: 342 + 465 = 807. +\`\`\` + +### 示例2 + +\`\`\`shell +输入: l1 = [0], l2 = [0] +输出: [0] +\`\`\` + +### 示例3 + +\`\`\`shell +输入: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] +输出: [8,9,9,9,0,0,0,1] +\`\`\` + +## 约束条件 + +
+每个链表中的节点数范围是 e $[1, 100]$. +
+ +\`\`\`math +0 <= 节点值 <= 9 +\`\`\` + +
+保证链表表示的数字无前导零。 +
`, + }, + { + locale: "en", + type: "SOLUTION", + content: `## Approach 1: Elementary Math ### Intuition @@ -610,13 +937,112 @@ struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) { What if the the digits in the linked list are stored in non-reversed order? For example: $(3 → 4 → 2) + (4 → 6 → 5) = 8 → 0 → 7$`, - difficulty: "MEDIUM", - published: true, - templates: { - create: [ - { - language: "c", - template: `#include + }, + { + locale: "zh", + type: "SOLUTION", + content: `## 方法 1:基础数学方法 + +### 思路 + +使用一个变量跟踪进位,并从链表头部(存储最低有效位)开始逐位模拟数字相加。 + +![Figure 1](https://leetcode.com/problems/add-two-numbers/Figures/2_add_two_numbers.svg) + +*图 1. 两数相加的可视化过程: $342 + 465 = 807$.* + +*每个节点包含一个数字,且数字按逆序存储* + +### 算法 + +就像在纸上计算两数相加一样,我们从最低有效位(即 $l1$ 和 $l2$ 的头部)开始逐位相加。由于每个数字在 $0…9$ 范围内,两数相加可能会产生 “进位”。例如 $5 + 7 = 12$,此时当前位设为 $2$ ,并将进位 $carry = 1$ 带入下一次计算。进位 $carry$ 只能是 $0$ 或 $1$ ,因为两个数字(含进位)的最大和为 $9 + 9 + 1 = 19$. + +伪代码如下: + +- 初始化当前节点为返回链表的哑结点(dummy head)。 + +- 初始化进位 carry 为 $0$. + +- 遍历链表 $l1$ 和 $l2$ ,直到两链表均遍历完毕且进位为 $0$. + + - 设 $x$ 为 $l1$ 当前节点的值,若 $l1$ 已遍历结束则设为 $0$. + + - 设 $y$ 为 $l2$ 当前节点的值,若 $l2$ 已遍历结束则设为 $0$. + + - 计算总和 $sum = x + y + carry$. + + - 更新进位 $carry = sum/10$. + + - 创建新节点,值为 $sum$ $mod$ $10$ ,连接到当前节点的下一个位置,并将当前节点后移。 + + - 同时后移 $l1$ 和 $l2$ 指针(若未遍历结束)。 + +- 返回哑结点的下一个节点(即实际链表的头节点)。 + +说明:使用哑结点可简化代码逻辑。若无哑结点,需额外处理头节点的初始化条件。 + +需特别注意以下测试用例: + +| 测试用例 | 说明 | +| ----------------------- | ----------------------------------------------------------------------------- | +| l1=[0,1]
l2=[0,1,2] | 其中一个链表较长的情况。 | +| l1=[]
l2=[0,1] | 链表为空的情况(等价于数字0)。 | +| l1=[9,9]
l2=[1] | 末尾相加后仍有进位的情况(易遗漏最终进位)。 | + +### 实现 + +\`\`\`c showLineNumbers +struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) { + struct ListNode* dummyHead = malloc(sizeof(struct ListNode)); + dummyHead->val = 0; + dummyHead->next = NULL; + struct ListNode* curr = dummyHead; + int carry = 0; + + while (l1 != NULL || l2 != NULL || carry != 0) { + int x = (l1 != NULL) ? l1->val : 0; + int y = (l2 != NULL) ? l2->val : 0; + int sum = carry + x + y; + carry = sum / 10; + + curr->next = malloc(sizeof(struct ListNode)); + curr->next->val = sum % 10; + curr->next->next = NULL; + curr = curr->next; + + if (l1 != NULL) l1 = l1->next; + if (l2 != NULL) l2 = l2->next; + } + + struct ListNode* result = dummyHead->next; + free(dummyHead); // 释放为哑结点(dummyHead)分配的内存。 + return result; +} +\`\`\` + +### 复杂度分析 + +- **时间复杂度:** $O(max(m,n))$ + + 假设 $m$ 和 $n$ 分别表示链表 $l1$ 和 $l2$ 的长度,上述算法最多迭代 $max(m,n)$ 次。 + +- **空间复杂度:** $O(1)$ + + 新链表的长度最多为 $max(m,n) + 1$ ,但我们通常不将结果链表计入空间复杂度分析。 + +### 后续问题 + +如果链表中的数字以非逆序(正序)存储,该如何处理?例如: + +$(3 → 4 → 2) + (4 → 6 → 5) = 8 → 0 → 7$`, + }, + ], + }, + templates: { + create: [ + { + language: "c", + content: `#include #include #include @@ -688,10 +1114,10 @@ int main() { } return 0; }`, - }, - { - language: "cpp", - template: `#include + }, + { + language: "cpp", + content: `#include #include #include #include @@ -772,55 +1198,85 @@ int main() { } return 0; }`, - }, - ], - }, - testcases: { + }, + ], + }, + testcases: { + create: [ + { + inputs: { create: [ { - data: { - create: [ - { label: "l1", value: "[2,4,3]", index: 0 }, - { label: "l2", value: "[5,6,4]", index: 1 }, - ], - }, - expectedOutput: "[7,0,8]", + index: 0, + name: "l1", + value: "[2,4,3]", }, { - data: { - create: [ - { label: "l1", value: "[0]", index: 0 }, - { label: "l2", value: "[0]", index: 1 }, - ], - }, - expectedOutput: "[0]", - }, - { - data: { - create: [ - { label: "l1", value: "[9,9,9,9,9,9,9]", index: 0 }, - { label: "l2", value: "[9,9,9,9]", index: 1 }, - ], - }, - expectedOutput: "[8,9,9,9,0,0,0,1]", + index: 1, + name: "l2", + value: "[5,6,4]", }, ], }, + expectedOutput: "[7,0,8]", + }, + { + inputs: { + create: [ + { + index: 0, + name: "l1", + value: "[0]", + }, + { + index: 1, + name: "l2", + value: "[0]", + }, + ], + }, + expectedOutput: "[0]", + }, + { + inputs: { + create: [ + { + index: 0, + name: "l1", + value: "[9,9,9,9,9,9,9]", + }, + { + index: 1, + name: "l2", + value: "[9,9,9,9]", + }, + ], + }, + expectedOutput: "[8,9,9,9,0,0,0,1]", }, ], }, }, { - name: "fly6516", - email: "fly6516@outlook.com", - password: "$2b$10$SD1T/dYvKTArGdTmf8ERxuBKIONxY01/wSboRNaNsHnKZzDhps/0u", - role: "ADMIN", - problems: { + displayId: 1002, + difficulty: "HARD", + isPublished: true, + localizations: { create: [ { - displayId: 1002, - title: "Median of Two Sorted Arrays", - description: `Given two sorted arrays \`nums1\` and \`nums2\` of size \`m\` and \`n\` respectively, return **the median** of the two sorted arrays. + locale: "en", + type: "TITLE", + content: "Median of Two Sorted Arrays", + }, + { + locale: "zh", + type: "TITLE", + content: "寻找两个正序数组的中位数", + }, + { + locale: "en", + type: "DESCRIPTION", + content: `Given two sorted arrays \`nums1\` and \`nums2\` of size \`m\` and \`n\` respectively, return **the median** of the two sorted arrays. The overall run time complexity should be $O(log(m+n))$. @@ -867,7 +1323,62 @@ nums_2.length == n \`\`\`math -10^6 <= nums_1[i], nums_2[i] <= 10^6 \`\`\``, - solution: `## Approach 1: Merge Sort + }, + { + locale: "zh", + type: "DESCRIPTION", + content: `给定两个大小分别为 \`nums1\` 和 \`nums2\` 的有序数组 \`m\` 和 \`n\` ,请返回这两个有序数组的**中位数**。 + +要求整体时间复杂度为 $O(log(m+n))$. + +## 示例 + +### 示例 1 + +\`\`\`shell +Input: nums1 = [1,3], nums2 = [2] +Output: 2.00000 +Explanation: merged array = [1,2,3] and median is 2. +\`\`\` + +### 示例 2 + +\`\`\`shell +Input: nums1 = [1,2], nums2 = [3,4] +Output: 2.50000 +Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5. +\`\`\` + +## 约束条件 + +\`\`\`math +nums_1.length == m +\`\`\` + +\`\`\`math +nums_2.length == n +\`\`\` + +\`\`\`math +0 <= m <= 1000 +\`\`\` + +\`\`\`math +0 <= n <= 1000 +\`\`\` + +\`\`\`math +1 <= m + n <= 2000 +\`\`\` + +\`\`\`math +-10^6 <= nums_1[i], nums_2[i] <= 10^6 +\`\`\``, + }, + { + locale: "en", + type: "SOLUTION", + content: `## Approach 1: Merge Sort ### Intuition @@ -957,13 +1468,107 @@ Let $m$ be the size of array \`nums1\` and $n$ be the size of array \`nums2\`. - **Space complexity:** $O(1)$ - We only need to maintain two pointers \`p1\` and \`p2\`.`, - difficulty: "HARD", - published: true, - templates: { - create: [ - { - language: "c", - template: `#include + }, + { + locale: "zh", + type: "SOLUTION", + content: `## 方法 1: 归并排序思路 + +### 思路 + +我们从最直接的方法开始思考。如果将两个数组合并成一个数组 \`A\` 并排序,假设合并后数组的长度为 \`n\`,那么中位数为: + +- 当 n 为奇数时,中位数是 \`A[n / 2]\`。 + +- 当 n 为偶数时,中位数是 \`A[n / 2]\` 和 \`A[n / 2 + 1]\` 的平均值。 + +不过,我们实际上不需要真正合并和排序数组。注意到两个数组已经是有序的,因此最小的元素一定是 \`nums1\` 或 \`nums2\`。 因此,我们可以设置两个指针 \`p1\` 和 \`p2\` 分别指向两个数组的起始位置,通过比较 \`nums1[p1]\` 和 \`nums2[p2]\`的值来逐步获取合并后的有序元素。 + +以下面的示例流程为例(可参考对应图示): + +### 算法 + +1. 计算两个数组的总长度 \`m + n\` + + - 若 \`m + n\` 为奇数,我们需要找到第 \`(m + n) / 2\` 个元素(从 0 开始计数)。 + + - 若 \`m + n\` 为偶数,我们需要找到第 \`(m + n) / 2\` 个和第 \`(m + n) / 2 + 1\` 个元素的平均值。 + +2. 初始化指针 \`p1\` = 0(指向 \`nums1\` 起始)和 \`p2\` = 0(指向 \`nums2\` 起始)。 + +3. 如果 \`p1\` 和 \`p2\` 都在数组的有效范围内(即未越界),则比较 \`p1\` 和 \`p2\`所指位置的值: + + - 如果 \`nums1[p1]\` 小于 \`nums2[p2]\`,则将 \`p1\` 向右移动一位。 + + - 否则,将 \`p2\` 向右移动一位。 + + 如果 \`p1\` 超出 \`nums1\`的范围,则直接将 \`p2\` 向右移动一位。 + + 如果 \`p2\` 超出 \`nums2\`的范围,则直接将 \`p1\` 向右移动一位。 + +4. 获取目标元素并计算中位数: + + - 若 \`m + n\` 为奇数,重复步骤 \`3 (m + n + 1) / 2\` 次(每次移动指针对应获取一个元素),最后一次步骤中得到的元素即为中位数。 + - 若 \`m + n\` 为偶数,重复步骤 \`3 (m + n) / 2 + 1\` 次,取最后两次步骤中得到的元素,计算它们的平均值作为中位数。 + +### 实现 + +\`\`\`c showLineNumbers +double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) { + int m = nums1Size, n = nums2Size; + int p1 = 0, p2 = 0; + + int getMin() { + if (p1 < m && p2 < n) { + return nums1[p1] < nums2[p2] ? nums1[p1++] : nums2[p2++]; + } else if (p1 < m) { + return nums1[p1++]; + } else if (p2 < n) { + return nums2[p2++]; + } + return -1; + } + + double median; + if ((m + n) % 2 == 0) { + for (int i = 0; i < ((m + n) / 2) - 1; ++i) { + int temp = getMin(); + } + median = (getMin() + getMin()) / 2.0; + } else { + for (int i = 0; i < (m + n) / 2; ++i) { + int temp = getMin(); + } + median = getMin(); + } + + return median; +} +\`\`\` + +### 复杂度分析 + +设数组 \`nums1\` 的长度为 $m$ ,数组 \`nums2\` 的长度为 $n$ 。 + +- **时间复杂度:** $O(m + n)$ + + - 我们通过比较 \`p1\` 和 \`p2\`指向的两个元素来获取当前最小元素,每次比较和移动指针的时间为 $O(1)$ 。 + + - 在找到中位数元素(或元素对)之前,需要遍历两个数组中最多一半的元素。 + + - 综上,总时间复杂度为 $O(m + n)$. + +- **空间复杂度:** $O(1)$ + + - 仅需维护两个指针 \`p1\` 和 \`p2\` ,无需额外线性空间。`, + }, + ], + }, + templates: { + create: [ + { + language: "c", + content: `#include #include #include @@ -1014,10 +1619,10 @@ int main() { return 0; }`, - }, - { - language: "cpp", - template: `#include + }, + { + language: "cpp", + content: `#include #include #include #include @@ -1061,31 +1666,44 @@ int main() { } return 0; }`, - }, - ], - }, - testcases: { + }, + ], + }, + testcases: { + create: [ + { + inputs: { create: [ { - data: { - create: [ - { label: "nums1", value: "[1,3]", index: 0 }, - { label: "nums2", value: "[2]", index: 1 }, - ], - }, - expectedOutput: "2.00000", + index: 0, + name: "nums1", + value: "[1,3]", }, { - data: { - create: [ - { label: "nums1", value: "[1,2]", index: 0 }, - { label: "nums2", value: "[3,4]", index: 1 }, - ], - }, - expectedOutput: "2.50000", + index: 1, + name: "nums2", + value: "[2]", }, ], }, + expectedOutput: "2.00000", + }, + { + inputs: { + create: [ + { + index: 0, + name: "nums1", + value: "[1,2]", + }, + { + index: 1, + name: "nums2", + value: "[3,4]", + }, + ], + }, + expectedOutput: "2.50000", }, ], }, @@ -1093,12 +1711,22 @@ int main() { ]; export async function main() { - for (const e of editorLanguageConfigData) { - await prisma.editorLanguageConfig.create({ data: e }); + for (const dockerConfig of dockerConfigData) { + await prisma.dockerConfig.create({ + data: dockerConfig, + }); } - for (const u of userData) { - await prisma.user.create({ data: u }); + for (const languageServerConfig of languageServerConfigData) { + await prisma.languageServerConfig.create({ + data: languageServerConfig, + }); + } + + for (const problem of problemData) { + await prisma.problem.create({ + data: problem, + }); } } diff --git a/public/sign-in.mp4 b/public/sign-in.mp4 new file mode 100644 index 0000000..82867cf Binary files /dev/null and b/public/sign-in.mp4 differ diff --git a/src/actions/judge.ts b/src/actions/judge.ts deleted file mode 100644 index 103ebf0..0000000 --- a/src/actions/judge.ts +++ /dev/null @@ -1,544 +0,0 @@ -"use server"; - -import fs from "fs"; -import tar from "tar-stream"; -import Docker from "dockerode"; -import prisma from "@/lib/prisma"; -import { auth } from "@/lib/auth"; -import { redirect } from "next/navigation"; -import { Readable, Writable } from "stream"; -import { Status } from "@/generated/client"; -import { revalidatePath } from "next/cache"; -import type { ProblemWithTestcases, TestcaseWithDetails } from "@/types/prisma"; -import type { EditorLanguage, Submission, TestcaseResult } from "@/generated/client"; - -const isRemote = process.env.DOCKER_HOST_MODE === "remote"; - -// Docker client initialization -const docker = isRemote - ? new Docker({ - protocol: process.env.DOCKER_REMOTE_PROTOCOL as "https" | "http" | "ssh" | undefined, - host: process.env.DOCKER_REMOTE_HOST, - port: process.env.DOCKER_REMOTE_PORT, - ca: fs.readFileSync(process.env.DOCKER_REMOTE_CA_PATH || "/certs/ca.pem"), - cert: fs.readFileSync(process.env.DOCKER_REMOTE_CERT_PATH || "/certs/cert.pem"), - key: fs.readFileSync(process.env.DOCKER_REMOTE_KEY_PATH || "/certs/key.pem"), - }) - : new Docker({ socketPath: "/var/run/docker.sock" }); - -// Prepare Docker image environment -async function prepareEnvironment(image: string, tag: string): Promise { - try { - const reference = `${image}:${tag}`; - const filters = { reference: [reference] }; - const images = await docker.listImages({ filters }); - return images.length !== 0; - } catch (error) { - console.error("Error checking Docker images:", error); - return false; - } -} - -// Create Docker container with keep-alive -async function createContainer( - image: string, - tag: string, - workingDir: string, - memoryLimit?: number -) { - const container = await docker.createContainer({ - Image: `${image}:${tag}`, - Cmd: ["tail", "-f", "/dev/null"], // Keep container alive - WorkingDir: workingDir, - HostConfig: { - Memory: memoryLimit ? memoryLimit * 1024 * 1024 : undefined, - MemorySwap: memoryLimit ? memoryLimit * 1024 * 1024 : undefined, - }, - NetworkDisabled: true, - }); - - await container.start(); - return container; -} - -// Create tar stream for code submission -function createTarStream(file: string, value: string) { - const pack = tar.pack(); - pack.entry({ name: file }, value); - pack.finalize(); - return Readable.from(pack); -} - -export async function judge( - language: EditorLanguage, - code: string, - problemId: string, -): Promise { - const session = await auth(); - if (!session?.user?.id) redirect("/sign-in"); - - const userId = session.user.id; - let container: Docker.Container | null = null; - let submission: Submission | null = null; - - try { - const problem = await prisma.problem.findUnique({ - where: { id: problemId }, - include: { - testcases: { - include: { - data: true, - }, - }, - }, - }) as ProblemWithTestcases | null; - - if (!problem) { - submission = await prisma.submission.create({ - data: { - language, - code, - status: Status.SE, - userId, - problemId, - message: "Problem not found", - }, - }); - return submission; - } - - const config = await prisma.editorLanguageConfig.findUnique({ - where: { language }, - include: { - dockerConfig: true, - }, - }); - - if (!config?.dockerConfig) { - submission = await prisma.submission.create({ - data: { - language, - code, - status: Status.SE, - userId, - problemId, - message: " Missing editor or docker configuration", - }, - }); - return submission; - } - - const testcases = problem.testcases; - - if (!testcases || testcases.length === 0) { - submission = await prisma.submission.create({ - data: { - language, - code, - status: Status.SE, - userId, - problemId, - message: "Testcases not found", - }, - }); - return submission; - } - - const { - image, - tag, - workingDir, - compileOutputLimit, - runOutputLimit, - } = config.dockerConfig; - const { fileName, fileExtension } = config; - const file = `${fileName}.${fileExtension}`; - - // Prepare the environment and create a container - if (await prepareEnvironment(image, tag)) { - container = await createContainer(image, tag, workingDir, problem.memoryLimit); - } else { - console.error("Docker image not found:", image, ":", tag); - submission = await prisma.submission.create({ - data: { - language, - code, - status: Status.SE, - userId, - problemId, - message: "The docker environment is not ready", - }, - }); - return submission; - } - - submission = await prisma.submission.create({ - data: { - language, - code, - status: Status.PD, - userId, - problemId, - message: "", - }, - }); - - // Upload code to the container - const tarStream = createTarStream(file, code); - await container.putArchive(tarStream, { path: workingDir }); - - // Compile the code - const compileResult = await compile(container, file, fileName, compileOutputLimit, submission.id, language); - if (compileResult.status === Status.CE) { - return compileResult; - } - - // Run the code - const runResult = await run(container, fileName, problem.timeLimit, runOutputLimit, submission.id, testcases); - return runResult; - } catch (error) { - console.error(error); - if (submission) { - const updatedSubmission = await prisma.submission.update({ - where: { id: submission.id }, - data: { - status: Status.SE, - message: "System Error", - } - }) - return updatedSubmission; - } else { - submission = await prisma.submission.create({ - data: { - language, - code, - status: Status.PD, - userId, - problemId, - message: "", - }, - }) - return submission; - } - } finally { - revalidatePath(`/problems/${problemId}`); - if (container) { - try { - await container.kill(); - await container.remove(); - } catch (error) { - console.error("Container cleanup failed:", error); - } - } - } -} - -async function compile( - container: Docker.Container, - file: string, - fileName: string, - compileOutputLimit: number = 1 * 1024 * 1024, - submissionId: string, - language: EditorLanguage, -): Promise { - const compileCmd = - language === "c" - ? ["gcc", "-O2", file, "-o", fileName] - : language === "cpp" - ? ["g++", "-O2", file, "-o", fileName] - : null; - - if (!compileCmd) { - return prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.SE, - message: "Unsupported language", - }, - }); - } - - const compileExec = await container.exec({ - Cmd: compileCmd, - AttachStdout: true, - AttachStderr: true, - }); - - return new Promise((resolve, reject) => { - compileExec.start({}, (error, stream) => { - if (error || !stream) { - return reject({ message: "System Error", Status: Status.SE }); - } - - const stdoutChunks: string[] = []; - let stdoutLength = 0; - const stdoutStream = new Writable({ - write(chunk, _encoding, callback) { - let text = chunk.toString(); - if (stdoutLength + text.length > compileOutputLimit) { - text = text.substring(0, compileOutputLimit - stdoutLength); - stdoutChunks.push(text); - stdoutLength = compileOutputLimit; - callback(); - return; - } - stdoutChunks.push(text); - stdoutLength += text.length; - callback(); - }, - }); - - const stderrChunks: string[] = []; - let stderrLength = 0; - const stderrStream = new Writable({ - write(chunk, _encoding, callback) { - let text = chunk.toString(); - if (stderrLength + text.length > compileOutputLimit) { - text = text.substring(0, compileOutputLimit - stderrLength); - stderrChunks.push(text); - stderrLength = compileOutputLimit; - callback(); - return; - } - stderrChunks.push(text); - stderrLength += text.length; - callback(); - }, - }); - - docker.modem.demuxStream(stream, stdoutStream, stderrStream); - - stream.on("end", async () => { - const stdout = stdoutChunks.join(""); - const stderr = stderrChunks.join(""); - const exitCode = (await compileExec.inspect()).ExitCode; - - let updatedSubmission: Submission; - - if (exitCode !== 0 || stderr) { - updatedSubmission = await prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.CE, - message: stderr || "Compilation Error", - }, - }); - } else { - updatedSubmission = await prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.CS, - message: stdout, - }, - }); - } - - resolve(updatedSubmission); - }); - - stream.on("error", () => { - reject({ message: "System Error", Status: Status.SE }); - }); - }); - }); -} - -// Run code and implement timeout -async function run( - container: Docker.Container, - fileName: string, - timeLimit: number = 1000, - maxOutput: number = 1 * 1024 * 1024, - submissionId: string, - testcases: TestcaseWithDetails, -): Promise { - let finalSubmission: Submission | null = null; - let maxExecutionTime = 0; - - for (const testcase of testcases) { - const sortedData = testcase.data.sort((a, b) => a.index - b.index); - const inputData = sortedData.map(d => d.value).join("\n"); - - const runExec = await container.exec({ - Cmd: [`./${fileName}`], - AttachStdout: true, - AttachStderr: true, - AttachStdin: true, - }); - - const result = await new Promise((resolve, reject) => { - // Start the exec stream - runExec.start({ hijack: true }, async (error, stream) => { - if (error || !stream) { - const submission = await prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.SE, - message: "System Error", - } - }) - return resolve(submission); - } - - stream.write(inputData); - stream.end(); - - const stdoutChunks: string[] = []; - const stderrChunks: string[] = []; - let stdoutLength = 0; - let stderrLength = 0; - - const stdoutStream = new Writable({ - write: (chunk, _, callback) => { - const text = chunk.toString(); - if (stdoutLength + text.length > maxOutput) { - stdoutChunks.push(text.substring(0, maxOutput - stdoutLength)); - stdoutLength = maxOutput; - } else { - stdoutChunks.push(text); - stdoutLength += text.length; - } - callback(); - } - }); - - const stderrStream = new Writable({ - write: (chunk, _, callback) => { - const text = chunk.toString(); - if (stderrLength + text.length > maxOutput) { - stderrChunks.push(text.substring(0, maxOutput - stderrLength)); - stderrLength = maxOutput; - } else { - stderrChunks.push(text); - stderrLength += text.length; - } - callback(); - } - }); - - docker.modem.demuxStream(stream, stdoutStream, stderrStream); - - const startTime = Date.now(); - - // Timeout mechanism - const timeoutId = setTimeout(async () => { - stream.destroy(); // Destroy the stream to stop execution - await prisma.testcaseResult.create({ - data: { - isCorrect: false, - output: "", - submissionId, - testcaseId: testcase.id, - } - }) - const updatedSubmission = await prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.TLE, - message: "Time Limit Exceeded", - } - }) - resolve(updatedSubmission); - }, timeLimit); - - stream.on("end", async () => { - clearTimeout(timeoutId); // Clear the timeout if the program finishes before the time limit - const stdout = stdoutChunks.join(""); - const stderr = stderrChunks.join(""); - const exitCode = (await runExec.inspect()).ExitCode; - const executionTime = Date.now() - startTime; - - // Exit code 0 means successful execution - if (exitCode === 0) { - const expectedOutput = testcase.expectedOutput; - const testcaseResult = await prisma.testcaseResult.create({ - data: { - isCorrect: stdout.trim() === expectedOutput.trim(), - output: stdout, - executionTime, - submissionId, - testcaseId: testcase.id, - } - }) - resolve(testcaseResult); - } else if (exitCode === 137) { - await prisma.testcaseResult.create({ - data: { - isCorrect: false, - output: stdout, - executionTime, - submissionId, - testcaseId: testcase.id, - } - }) - const updatedSubmission = await prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.MLE, - message: stderr || "Memory Limit Exceeded", - } - }) - resolve(updatedSubmission); - } else { - await prisma.testcaseResult.create({ - data: { - isCorrect: false, - output: stdout, - executionTime, - submissionId, - testcaseId: testcase.id, - } - }) - const updatedSubmission = await prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.RE, - message: stderr || "Runtime Error", - } - }) - resolve(updatedSubmission); - } - }); - - stream.on("error", () => { - clearTimeout(timeoutId); // Clear timeout in case of error - reject({ message: "System Error", Status: Status.SE }); - }); - }); - }); - - if ('status' in result) { - return result; - } else { - if (!result.isCorrect) { - finalSubmission = await prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.WA, - message: "Wrong Answer", - }, - include: { - testcaseResults: true, - } - }); - return finalSubmission; - } else { - maxExecutionTime = Math.max(maxExecutionTime, result.executionTime ?? 0); - } - } - } - const maxMemoryUsage = (await container.stats({ stream: false, "one-shot": true })).memory_stats.max_usage; - finalSubmission = await prisma.submission.update({ - where: { id: submissionId }, - data: { - status: Status.AC, - message: "All testcases passed", - executionTime: maxExecutionTime, - memoryUsage: maxMemoryUsage / 1024 / 1024, - }, - include: { - testcaseResults: true, - } - }); - return finalSubmission; -} diff --git a/src/actions/language-server.ts b/src/actions/language-server.ts deleted file mode 100644 index cd823e2..0000000 --- a/src/actions/language-server.ts +++ /dev/null @@ -1,29 +0,0 @@ -"use server"; - -import prisma from "@/lib/prisma"; -import { EditorLanguage } from "@/generated/client"; -import { SettingsLanguageServerFormValues } from "@/app/(app)/dashboard/@admin/settings/language-server/form"; - -export const getLanguageServerConfig = async (language: EditorLanguage) => { - return await prisma.languageServerConfig.findUnique({ - where: { language }, - }); -}; - -export const handleLanguageServerConfigSubmit = async ( - language: EditorLanguage, - data: SettingsLanguageServerFormValues -) => { - const existing = await getLanguageServerConfig(language); - - if (existing) { - await prisma.languageServerConfig.update({ - where: { language }, - data, - }); - } else { - await prisma.languageServerConfig.create({ - data: { ...data, language }, - }); - } -}; diff --git a/src/app/(app)/dashboard/@admin/layout.tsx b/src/app/(app)/dashboard/@admin/layout.tsx deleted file mode 100644 index 3b711bd..0000000 --- a/src/app/(app)/dashboard/@admin/layout.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { - SidebarInset, - SidebarProvider, - SidebarTrigger, -} from "@/components/ui/sidebar"; -import { auth } from "@/lib/auth"; -import { User } from "@/generated/client"; -import { redirect } from "next/navigation"; -import { Navbar } from "@/components/navbar"; -import { AppSidebar } from "@/components/app-sidebar"; -import { Separator } from "@/components/ui/separator"; -import { type NavUserProps } from "@/components/nav-user"; - -interface AdminDashboardLayoutProps { - children: React.ReactNode; -} - -export default async function AdminDashboardLayout({ - children, -}: AdminDashboardLayoutProps) { - const session = await auth(); - - if (!session?.user) { - redirect("/sign-in"); - } - - const user: NavUserProps["user"] = (({ name, email, image }) => ({ - name: name ?? "", - email: email ?? "", - avatar: image ?? "", - }))(session.user as User); - - return ( - - - -
-
- - - -
-
-
- {children} -
-
-
- ); -} diff --git a/src/app/(app)/dashboard/@admin/page.tsx b/src/app/(app)/dashboard/@admin/page.tsx deleted file mode 100644 index e1d7c98..0000000 --- a/src/app/(app)/dashboard/@admin/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function DashboardAdmin() { - return
Dashboard Admin
; -} diff --git a/src/app/(app)/dashboard/@admin/problemset/new/description/page.tsx b/src/app/(app)/dashboard/@admin/problemset/new/description/page.tsx deleted file mode 100644 index 2779fc6..0000000 --- a/src/app/(app)/dashboard/@admin/problemset/new/description/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import NewProblemDescriptionForm from "@/components/features/dashboard/admin/problemset/new/components/description-form"; - -export default function NewProblemDescriptionPage() { - return ; -} diff --git a/src/app/(app)/dashboard/@admin/problemset/new/metadata/page.tsx b/src/app/(app)/dashboard/@admin/problemset/new/metadata/page.tsx deleted file mode 100644 index 9a57c4f..0000000 --- a/src/app/(app)/dashboard/@admin/problemset/new/metadata/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import NewProblemMetadataForm from "@/components/features/dashboard/admin/problemset/new/components/metadata-form"; - -export default function NewProblemMetadataPage() { - return ; -} diff --git a/src/app/(app)/dashboard/@admin/problemset/new/page.tsx b/src/app/(app)/dashboard/@admin/problemset/new/page.tsx deleted file mode 100644 index 9e28de4..0000000 --- a/src/app/(app)/dashboard/@admin/problemset/new/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { redirect } from "next/navigation"; - -export default function NewProblemPage() { - redirect("/dashboard/problemset/new/metadata"); -} diff --git a/src/app/(app)/dashboard/@admin/problemset/new/solution/page.tsx b/src/app/(app)/dashboard/@admin/problemset/new/solution/page.tsx deleted file mode 100644 index 2b68fdf..0000000 --- a/src/app/(app)/dashboard/@admin/problemset/new/solution/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import NewProblemSolutionForm from "@/components/features/dashboard/admin/problemset/new/components/solution-form"; - -export default function NewProblemSolutionPage() { - return ; -} diff --git a/src/app/(app)/dashboard/@admin/problemset/new/store.ts b/src/app/(app)/dashboard/@admin/problemset/new/store.ts deleted file mode 100644 index 030d92b..0000000 --- a/src/app/(app)/dashboard/@admin/problemset/new/store.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { create } from "zustand"; -import { createJSONStorage, persist } from "zustand/middleware"; -import { ProblemSchema } from "@/components/features/dashboard/admin/problemset/new/schema"; - -interface NewProblemActions { - setHydrated: (value: boolean) => void; - setData: (data: Partial) => void; -} - -type NewProblemState = Partial & { - hydrated: boolean; -} & NewProblemActions; - -export const useNewProblemStore = create()( - persist( - (set) => ({ - hydrated: false, - setHydrated: (value) => set({ hydrated: value }), - setData: (data) => set(data), - }), - { - name: "zustand:new-problem", - storage: createJSONStorage(() => localStorage), - // eslint-disable-next-line @typescript-eslint/no-unused-vars - partialize: ({ hydrated, ...rest }) => rest, - onRehydrateStorage: () => (state, error) => { - if (error) { - console.error("An error happened during hydration", error); - } else if (state) { - state.setHydrated(true); - } - }, - } - ) -); diff --git a/src/app/(app)/dashboard/@admin/problemset/page.tsx b/src/app/(app)/dashboard/@admin/problemset/page.tsx deleted file mode 100644 index 20a8f12..0000000 --- a/src/app/(app)/dashboard/@admin/problemset/page.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import prisma from "@/lib/prisma"; -import { ProblemsetTable } from "@/components/features/dashboard/admin/problemset/table"; - -export default async function AdminDashboardProblemsetPage() { - const problems = await prisma.problem.findMany({ - select: { - id: true, - displayId: true, - title: true, - difficulty: true, - }, - }); - - return ( -
- -
- ); -} diff --git a/src/app/(app)/dashboard/@admin/settings/language-server/accordion.tsx b/src/app/(app)/dashboard/@admin/settings/language-server/accordion.tsx deleted file mode 100644 index 34f4828..0000000 --- a/src/app/(app)/dashboard/@admin/settings/language-server/accordion.tsx +++ /dev/null @@ -1,77 +0,0 @@ -"use client"; - -import { - Accordion, - AccordionContent, - AccordionItem, - AccordionTrigger, -} from "@/components/ui/accordion"; -import { Loading } from "@/components/loading"; -import { useAdminSettingsStore } from "@/stores/useAdminSettingsStore"; -import { EditorLanguage, LanguageServerConfig } from "@/generated/client"; -import { SettingsLanguageServerForm } from "@/app/(app)/dashboard/@admin/settings/language-server/form"; - -interface LanguageServerAccordionProps { - configs: { - language: EditorLanguage; - config: LanguageServerConfig | null; - }[]; -} - -export function LanguageServerAccordion({ - configs, -}: LanguageServerAccordionProps) { - const { hydrated, activeLanguageServerSetting, setActiveLanguageServerSetting } = - useAdminSettingsStore(); - - if (!hydrated) { - return ( -
- - -
- ); - } - - return ( - - {configs.map(({ language, config }) => ( - - - {language.toUpperCase()} - - -
- -
-
-
- ))} -
- ); -} diff --git a/src/app/(app)/dashboard/@admin/settings/language-server/form.tsx b/src/app/(app)/dashboard/@admin/settings/language-server/form.tsx deleted file mode 100644 index 55e9548..0000000 --- a/src/app/(app)/dashboard/@admin/settings/language-server/form.tsx +++ /dev/null @@ -1,181 +0,0 @@ -"use client"; - -import { z } from "zod"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { useForm } from "react-hook-form"; -import { Input } from "@/components/ui/input"; -import { Button } from "@/components/ui/button"; -import { Separator } from "@/components/ui/separator"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { EditorLanguage, LanguageServerProtocol } from "@/generated/client"; -import { handleLanguageServerConfigSubmit } from "@/actions/language-server"; - -const settingsLanguageServerFormSchema = z.object({ - protocol: z.nativeEnum(LanguageServerProtocol), - hostname: z.string(), - port: z - .number() - .nullable() - .transform((val) => (val === undefined ? null : val)), - path: z - .string() - .nullable() - .transform((val) => (val === "" || val === undefined ? null : val)), -}); - -export type SettingsLanguageServerFormValues = z.infer; - -interface SettingsLanguageServerFormProps { - defaultValues: Partial; - language: EditorLanguage; -} - -export function SettingsLanguageServerForm({ - defaultValues, - language, -}: SettingsLanguageServerFormProps) { - const form = useForm({ - resolver: zodResolver(settingsLanguageServerFormSchema), - defaultValues, - mode: "onChange", - }); - - const onSubmit = async (data: SettingsLanguageServerFormValues) => { - await handleLanguageServerConfigSubmit(language, data); - }; - - return ( -
- - ( - -
- Protocol - - This is the protocol of the language server. - -
-
- - -
-
- )} - /> - - ( - -
- Hostname - - This is the hostname of the language server. - -
-
- - - - -
-
- )} - /> - - ( - -
- Port - - This is the port of the language server. - -
-
- - { - const value = e.target.value; - field.onChange(value === "" ? null : Number(value)); - }} - className="w-full" - /> - - -
-
- )} - /> - - ( - -
- Path - - This is the path of the language server. - -
-
- - - - -
-
- )} - /> -
- -
- - - ); -} diff --git a/src/app/(app)/dashboard/@admin/settings/language-server/layout.tsx b/src/app/(app)/dashboard/@admin/settings/language-server/layout.tsx deleted file mode 100644 index 35e5724..0000000 --- a/src/app/(app)/dashboard/@admin/settings/language-server/layout.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Suspense } from "react"; -import { Loading } from "@/components/loading"; -import { Separator } from "@/components/ui/separator"; - -interface SettingsLanguageServerLayoutProps { - children: React.ReactNode; -} - -export default function SettingsLanguageServerLayout({ - children, -}: SettingsLanguageServerLayoutProps) { - return ( -
-
-

Language Server Settings

-

- Configure the language server connection settings. -

-
- - }> - {children} - -
- ); -} diff --git a/src/app/(app)/dashboard/@admin/settings/language-server/page.tsx b/src/app/(app)/dashboard/@admin/settings/language-server/page.tsx deleted file mode 100644 index 5cc6bff..0000000 --- a/src/app/(app)/dashboard/@admin/settings/language-server/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { EditorLanguage } from "@/generated/client"; -import { getLanguageServerConfig } from "@/actions/language-server"; -import { LanguageServerAccordion } from "@/app/(app)/dashboard/@admin/settings/language-server/accordion"; - -export default async function SettingsLanguageServerPage() { - const languages = Object.values(EditorLanguage); - - const configPromises = languages.map(async (language) => ({ - language, - config: await getLanguageServerConfig(language), - })); - - const configs = await Promise.all(configPromises); - - return ; -} diff --git a/src/app/(app)/dashboard/layout.tsx b/src/app/(app)/dashboard/layout.tsx deleted file mode 100644 index 02898c7..0000000 --- a/src/app/(app)/dashboard/layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { auth } from "@/lib/auth"; -import { User } from "@/generated/client"; -import { notFound, redirect } from "next/navigation"; - -interface DashboardLayoutProps { - admin: React.ReactNode; -} - -export default async function DashboardLayout({ - admin, -}: DashboardLayoutProps) { - const session = await auth(); - if (!session?.user) { - redirect("/sign-in"); - } - - const user = session.user as User; - - return user.role === "ADMIN" ? admin : notFound(); -} diff --git a/src/app/(app)/problems/[id]/@Bot/layout.tsx b/src/app/(app)/problems/[id]/@Bot/layout.tsx deleted file mode 100644 index 4de618b..0000000 --- a/src/app/(app)/problems/[id]/@Bot/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Suspense } from "react"; -import { Loading } from "@/components/loading"; - -interface BotLayoutProps { - children: React.ReactNode; -} - -export default function BotLayout({ children }: BotLayoutProps) { - return ( -
- }> - {children} - -
- ); -} diff --git a/src/app/(app)/problems/[id]/@Bot/page.tsx b/src/app/(app)/problems/[id]/@Bot/page.tsx deleted file mode 100644 index e21d9f2..0000000 --- a/src/app/(app)/problems/[id]/@Bot/page.tsx +++ /dev/null @@ -1,127 +0,0 @@ -"use client"; - -import { toast } from "sonner"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { useCallback } from "react"; -import { useChat } from "@ai-sdk/react"; -import { useTranslations } from "next-intl"; -import { Button } from "@/components/ui/button"; -import { useProblem } from "@/hooks/use-problem"; -import MdxPreview from "@/components/mdx-preview"; -import { Textarea } from "@/components/ui/textarea"; -import { BotIcon, SendHorizonal } from "lucide-react"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { ChatMessageList } from "@/components/ui/chat/chat-message-list"; -import { ChatBubble, ChatBubbleMessage } from "@/components/ui/chat/chat-bubble"; - -export default function Bot() { - const t = useTranslations("Bot"); - const { problemId, problem, currentLang, currentValue } = useProblem(); - - const { messages, input, handleInputChange, setMessages, handleSubmit } = useChat({ - initialMessages: [ - { - id: problemId, - role: "system", - content: `Problem description:\n${problem.description}`, - }, - ], - }); - - const handleFormSubmit = useCallback( - (e: React.FormEvent) => { - e.preventDefault(); - - if (!input.trim()) { - toast.error("Input cannot be empty"); - return; - } - - const currentCodeMessage = { - id: problemId, - role: "system" as const, - content: `Current code:\n\`\`\`${currentLang}\n${currentValue}\n\`\`\``, - }; - - setMessages((prev) => [...prev, currentCodeMessage]); - handleSubmit(); - }, - [currentLang, currentValue, handleSubmit, input, problemId, setMessages] - ); - - return ( - <> -
- {!messages.some( - (message) => message.role === "user" || message.role === "assistant" - ) && ( -
- - {t("title")} - {t("description")} -
- )} - -
- - - {messages - .filter( - (message) => message.role === "user" || message.role === "assistant" - ) - .map((message) => ( - - - - - - ))} - - -
-
- -