diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7594035 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,70 @@ +# Node.js 相关 +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# 源代码和开发文件(精简版不需要) +src +scripts +public +package*.json +vite.config.js +eslint.config.js +index.html + +# 构建相关 +dist +.vite + +# 环境文件 +.env* + +# IDE/Editor files +.vscode +.idea +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Git +.git +.gitignore + +# Docker 相关(保留 Dockerfile) +docker-compose.yml + +# 脚本文件(精简版不需要) +docker-entrypoint.sh + +# 文档 +README*.md +LICENSE + +# 日志 +logs +*.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# ESLint cache +.eslintcache \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f3ca0cb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,50 @@ +# 极简静态资源镜像 +FROM nginx:alpine + +# 安装 wget 用于健康检查 +RUN apk add --no-cache wget + +# 极简静态资源镜像 +FROM nginx:alpine + +# 安装 wget 用于健康检查 +RUN apk add --no-cache wget + +# 创建自定义 nginx 配置,禁用缓存并确保正确读取挂载目录 +RUN printf 'server {\n\ + listen 80;\n\ + server_name localhost;\n\ + root /usr/share/nginx/html;\n\ + index index.html index.htm;\n\ + \n\ + # 禁用缓存\n\ + add_header Cache-Control "no-cache, no-store, must-revalidate";\n\ + add_header Pragma "no-cache";\n\ + add_header Expires "0";\n\ + \n\ + location / {\n\ + try_files $uri $uri/ /index.html;\n\ + # 确保每次都读取最新文件\n\ + sendfile off;\n\ + tcp_nodelay on;\n\ + tcp_nopush off;\n\ + }\n\ + \n\ + # 禁用所有静态文件缓存\n\ + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {\n\ + add_header Cache-Control "no-cache, no-store, must-revalidate";\n\ + add_header Pragma "no-cache";\n\ + add_header Expires "0";\n\ + }\n\ +}\n' > /etc/nginx/conf.d/default.conf + +# 确保挂载目录存在但为空(避免与外部挂载冲突) +RUN mkdir -p /usr/share/nginx/html && \ + rm -rf /usr/share/nginx/html/* && \ + echo "Waiting for external mount..." > /usr/share/nginx/html/.placeholder + +# 暴露静态服务端口 +EXPOSE 80 + +# 启动 nginx 前台运行 +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 0e46c11..0000000 --- a/README.en.md +++ /dev/null @@ -1,159 +0,0 @@ -# Markdown To Web - -> Turn a local Markdown notes folder into a deployable static React site. - -This project scans all `.md` files inside `public/mengyanote/`, generates JSON datasets (directory tree, file contents, stats) at build time, and renders them client‑side with React + `react-markdown`. The output is a **pure static site** (no server / no DB) suitable for GitHub Pages, Netlify, Vercel, or any static hosting. - -Chinese documentation: see `README.md`. - -## ✨ Features - -- 🚀 One‑command data generation (recursive scan → JSON assets) -- 📦 Fully static deployment (no runtime backend needed) -- 🧭 Expandable directory tree with stable IDs / paths -- 📝 Rich Markdown: GFM (tables, task lists, strikethrough), soft line breaks, math (KaTeX), code highlighting -- 🧮 Math via `remark-math` + `rehype-katex` -- 💡 Enhanced code blocks: language label + copy button -- 📚 Breadcrumb navigation derived from file path -- 🔌 Pluggable remark / rehype pipeline (easy to remove / replace) -- 🕶 Dark theme (fully customizable via CSS) -- 🔍 Multi-path fallback when fetching generated JSON (`/data` → `/src/data` → `./data`) -- 🧯 Ignore mechanism via `ignore.json` -- 📊 Basic statistics (file count, folder count, timestamp) - -## 🛠 Tech Stack - -- React 19 + Hooks + Context -- Vite -- `react-markdown` + remark / rehype plugins: - - `remark-gfm`, `remark-math`, `remark-breaks` - - `rehype-raw`, `rehype-katex`, `rehype-highlight` -- Highlight.js theme (replaceable) -- KaTeX (optional) - -## ⚡ Quick Start - -```bash -npm install -npm run dev # generate data + start dev server -npm run build # generate data + build static site (dist/) -npm run preview # preview production build -npm run generate-data # only regenerate JSON -npm run lint -``` - -## 📂 Key Structure - -``` -public/ - mengyanote/ # Source Markdown tree (add your .md here) - data/ # Public copy of generated JSON -scripts/ - generateData.js # Node script: scans + emits JSON -src/ - data/ # Generated JSON (consumed in dev/build) - components/ # UI (MarkdownRenderer, Sidebar, ...) - context/ # AppContext (state + actions) - utils/fileUtils.js # Fetch + helpers + breadcrumbs -``` - -## 🧬 How It Works - -1. `generateData.js` walks `public/mengyanote/` (applying `ignore.json` rules) -2. Builds: - - `directoryTree.json` (hierarchical tree) - - `fileContents.json` (path → raw markdown text) - - `stats.json` (counts + timestamp) -3. Writes duplicates to `src/data/` (for imports / dev) and `public/data/` (for runtime fetch in final build) -4. Frontend loads JSON (tries `/data` → `/src/data` → `./data`) and renders selected file - -``` -Markdown(.md) --> generateData.js --> JSON (tree, contents, stats) --> React (render) -``` - -## 🧯 Ignore Rules - -Default ignored: `.obsidian`, `.trash`, `.git`, `node_modules`, any dot‑prefixed file/dir. - -Custom ignore: create `public/mengyanote/ignore.json`: - -```json -{ "ignore": ["Drafts", "private", "Scratch.md"] } -``` - -## 🎨 Customization Cheatsheet - -| Goal | Where | Action | -|------|-------|--------| -| Remove math | `MarkdownRenderer.jsx` | Drop `remark-math` + `rehype-katex` + CSS import | -| Remove code highlighting | `MarkdownRenderer.jsx` | Remove `rehype-highlight` and theme CSS | -| New highlight theme | Add dependency | Replace imported highlight style | -| Inline code as plain text | Already done | Custom plugin strips inline code styling | -| Change image layout | `MarkdownRenderer.css` | Adjust `.markdown-image img` | -| Change breadcrumb format | `fileUtils.generateBreadcrumbs` | Modify join logic | - -## 🚢 Deployment - -Build output: `dist/` (fully static). - -Platforms: - -| Platform | Notes | -|----------|-------| -| GitHub Pages | Push `dist/` to `gh-pages` or use an Action | -| Netlify | Build: `npm run build`, Publish: `dist` | -| Vercel | Auto-detect Vite | -| Any static host / Nginx | Upload `dist/` | - -Example Nginx: - -``` -server { - listen 80; - server_name example.com; - root /var/www/markdown-to-web/dist; - location / { try_files $uri /index.html; } - add_header Cache-Control "public, max-age=31536000"; -} -``` - -## FAQ - -**New file not appearing?** Regenerate data: `npm run generate-data` (or rerun dev/build). - -**Ignore not working?** Ensure `ignore.json` sits directly in `public/mengyanote/` and key is exactly `ignore`. - -**Large number of files causes slow load?** Consider splitting `fileContents.json` into per‑file JSON (enhancement idea). - -**Search support?** Not yet. You can integrate `minisearch` or `lunr` during build. - -**Can I support frontmatter?** Extend the generator to parse YAML frontmatter and attach metadata to each node. - -## Roadmap (Open for Contributions) - -- [ ] Full‑text search -- [ ] Per‑file lazy loading -- [ ] Recent updates panel / changelog -- [ ] Frontmatter tags + filters -- [ ] RSS / JSON feed generation -- [ ] PDF / print friendly mode -- [ ] Service Worker caching -- [ ] GitHub Actions deploy workflow example - -## Contributing & License - -Issues / PRs welcome. Please open an issue before large feature work; attach screenshots for UI changes. License: see `LICENSE`. - -## Contact - -Open an issue describing: - -- Desired visual style (links / screenshots) -- Needed deployment pipeline (e.g., GitHub Pages Action) -- Theming or performance concerns - -I can suggest patches or configuration examples. - ---- - -Happy publishing! If you build cool themes (minimal / book‑like / image‑first), consider sharing them back. 🙌 diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..0971ad9 --- /dev/null +++ b/build.bat @@ -0,0 +1,31 @@ +@echo off +setlocal enabledelayedexpansion + +echo ============== 开始执行构建 ============== +:: 关键:添加 call 确保 npm 执行完后继续执行后续命令 +call npm run build + +:: 检查构建是否成功 +if %errorlevel% neq 0 ( + echo 【错误】构建失败!请查看上面的错误信息 + pause + exit /b 1 +) + +echo ============== 构建成功,准备启动服务器 ============== +echo 正在进入 dist 目录... +cd dist || ( + echo 【错误】找不到 dist 目录!构建可能未生成该目录 + echo 当前目录:%cd% (请确认该目录下是否有 dist 文件夹) + pause + exit /b 1 +) + +echo ============== 服务器启动中(端口 8080) ============== +echo 提示:服务器启动后会一直运行,访问 http://localhost:8080 查看 +echo 若要停止服务器,请按 Ctrl + C,然后按 Y 确认 +python -m http.server 8080 + +:: 服务器停止后执行 +echo ============== 服务器已停止 ============== +pause \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..fca6c2e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.8' + +services: + web: + build: . + container_name: markdown-to-web + ports: + - "5173:80" + volumes: + - /shumengya/docker/storage/markdown2web/dist:/usr/share/nginx/html + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:80"] + interval: 30s + timeout: 10s + retries: 3 diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..7f96a49 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +# 该脚本在简化后的 Docker 流程中不再使用,保留占位避免误调用。 +echo "docker-entrypoint.sh 已弃用:当前镜像仅用于静态文件托管。" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 022ff41..73c6dd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.4.0", + "http-server": "^14.1.1", "vite": "^7.1.7" } }, @@ -62,6 +63,7 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -1437,6 +1439,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.15.tgz", "integrity": "sha512-+kLxJpaJzXybyDyFXYADyP1cznTO8HSuBpenGlnKOAkH4hyNINiywvXS/tGJhsrGGP/gM185RA3xpjY0Yg4erA==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1490,6 +1493,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1547,6 +1551,13 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -1574,6 +1585,19 @@ "baseline-browser-mapping": "dist/cli.js" } }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1605,6 +1629,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001741", @@ -1619,6 +1644,37 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1779,6 +1835,16 @@ "node": ">=18" } }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1859,6 +1925,21 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.227", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.227.tgz", @@ -1878,6 +1959,39 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.10", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", @@ -1949,6 +2063,7 @@ "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -2131,6 +2246,13 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2227,6 +2349,27 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2242,6 +2385,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2252,6 +2405,45 @@ "node": ">=6.9.0" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2278,6 +2470,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2288,6 +2493,32 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hast-util-from-dom": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", @@ -2510,6 +2741,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/highlight.js": { "version": "11.11.1", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", @@ -2519,6 +2760,19 @@ "node": ">=12.0.0" } }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/html-url-attributes": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", @@ -2539,6 +2793,62 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-server": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", + "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.6", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "bin": { + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2843,6 +3153,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", @@ -3740,6 +4060,19 @@ ], "license": "MIT" }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3753,6 +4086,16 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3792,6 +4135,29 @@ "dev": true, "license": "MIT" }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -3925,6 +4291,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3932,6 +4299,20 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/portfinder": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", + "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.6", + "debug": "^4.3.6" + }, + "engines": { + "node": ">= 10.12" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -3991,11 +4372,28 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/react": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -4005,6 +4403,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -4235,6 +4634,13 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -4287,12 +4693,33 @@ "fsevents": "~2.3.2" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", "license": "MIT" }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", + "dev": true, + "license": "MIT" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -4332,6 +4759,82 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -4479,6 +4982,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/unist-util-find-after": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", @@ -4616,6 +5131,13 @@ "punycode": "^2.1.0" } }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true, + "license": "MIT" + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -4664,6 +5186,7 @@ "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -4743,6 +5266,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 325c5fb..0f61f7a 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.4.0", + "http-server": "^14.1.1", "vite": "^7.1.7" } } diff --git a/public/data/directoryTree.json b/public/data/directoryTree.json index 0e5b08d..026d768 100644 --- a/public/data/directoryTree.json +++ b/public/data/directoryTree.json @@ -5,6 +5,64 @@ "type": "folder", "path": "编程语言", "children": [ + { + "id": "编程语言/前端", + "name": "前端", + "type": "folder", + "path": "编程语言/前端", + "children": [ + { + "id": "编程语言/前端/JavaScript趣味题", + "name": "JavaScript趣味题", + "type": "folder", + "path": "编程语言/前端/JavaScript趣味题", + "children": [ + { + "id": "编程语言/前端/JavaScript趣味题/JavaScript趣味题_128.md", + "name": "JavaScript趣味题_128.md", + "type": "file", + "path": "编程语言/前端/JavaScript趣味题/JavaScript趣味题_128.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/前端/JavaScript趣味题/JavaScript趣味题_18.md", + "name": "JavaScript趣味题_18.md", + "type": "file", + "path": "编程语言/前端/JavaScript趣味题/JavaScript趣味题_18.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/前端/JavaScript趣味题/JavaScript趣味题_28.md", + "name": "JavaScript趣味题_28.md", + "type": "file", + "path": "编程语言/前端/JavaScript趣味题/JavaScript趣味题_28.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/前端/纯静态网页的强大功能与应用.md", + "name": "纯静态网页的强大功能与应用.md", + "type": "file", + "path": "编程语言/前端/纯静态网页的强大功能与应用.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/前端/css注入代码合集.md", + "name": "css注入代码合集.md", + "type": "file", + "path": "编程语言/前端/css注入代码合集.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, { "id": "编程语言/Android", "name": "Android", @@ -335,6 +393,30 @@ "type": "folder", "path": "计算机科普", "children": [ + { + "id": "计算机科普/编程语言科普.md", + "name": "编程语言科普.md", + "type": "file", + "path": "计算机科普/编程语言科普.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/编程语言之间的划分.md", + "name": "编程语言之间的划分.md", + "type": "file", + "path": "计算机科普/编程语言之间的划分.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/操作系统科普.md", + "name": "操作系统科普.md", + "type": "file", + "path": "计算机科普/操作系统科普.md", + "children": [], + "isExpanded": false + }, { "id": "计算机科普/多模态大模型识别图片,视频,音频原理.md", "name": "多模态大模型识别图片,视频,音频原理.md", @@ -343,14 +425,6 @@ "children": [], "isExpanded": false }, - { - "id": "计算机科普/光纤和网线的特点和区别.md", - "name": "光纤和网线的特点和区别.md", - "type": "file", - "path": "计算机科普/光纤和网线的特点和区别.md", - "children": [], - "isExpanded": false - }, { "id": "计算机科普/科普-Nagle 算法.md", "name": "科普-Nagle 算法.md", @@ -359,6 +433,14 @@ "children": [], "isExpanded": false }, + { + "id": "计算机科普/术语解释-DMZ.md", + "name": "术语解释-DMZ.md", + "type": "file", + "path": "计算机科普/术语解释-DMZ.md", + "children": [], + "isExpanded": false + }, { "id": "计算机科普/术语科普-CVM.md", "name": "术语科普-CVM.md", @@ -383,6 +465,22 @@ "children": [], "isExpanded": false }, + { + "id": "计算机科普/术语科普-MQ.md", + "name": "术语科普-MQ.md", + "type": "file", + "path": "计算机科普/术语科普-MQ.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/术语科普-POI.md", + "name": "术语科普-POI.md", + "type": "file", + "path": "计算机科普/术语科普-POI.md", + "children": [], + "isExpanded": false + }, { "id": "计算机科普/术语科普-pwn.md", "name": "术语科普-pwn.md", @@ -391,6 +489,46 @@ "children": [], "isExpanded": false }, + { + "id": "计算机科普/术语科普-QPS.md", + "name": "术语科普-QPS.md", + "type": "file", + "path": "计算机科普/术语科普-QPS.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/网络协议科普.md", + "name": "网络协议科普.md", + "type": "file", + "path": "计算机科普/网络协议科普.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/游戏行业简单科普.md", + "name": "游戏行业简单科普.md", + "type": "file", + "path": "计算机科普/游戏行业简单科普.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/游戏引擎科普.md", + "name": "游戏引擎科普.md", + "type": "file", + "path": "计算机科普/游戏引擎科普.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/C,C++,CSharp,Objective-c的差异与特点.md", + "name": "C,C++,CSharp,Objective-c的差异与特点.md", + "type": "file", + "path": "计算机科普/C,C++,CSharp,Objective-c的差异与特点.md", + "children": [], + "isExpanded": false + }, { "id": "计算机科普/clash机场三种代理模式科普.md", "name": "clash机场三种代理模式科普.md", @@ -407,6 +545,14 @@ "children": [], "isExpanded": false }, + { + "id": "计算机科普/IDE,编辑器,编译器区别和特点.md", + "name": "IDE,编辑器,编译器区别和特点.md", + "type": "file", + "path": "计算机科普/IDE,编辑器,编译器区别和特点.md", + "children": [], + "isExpanded": false + }, { "id": "计算机科普/IDEA专业版和社区版的区别和特点.md", "name": "IDEA专业版和社区版的区别和特点.md", @@ -465,10 +611,26 @@ "isExpanded": false }, { - "id": "计算机网络/TCP的三次握手四次握手.md", - "name": "TCP的三次握手四次握手.md", + "id": "计算机网络/HTTP版本协议对比区别.md", + "name": "HTTP版本协议对比区别.md", "type": "file", - "path": "计算机网络/TCP的三次握手四次握手.md", + "path": "计算机网络/HTTP版本协议对比区别.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机网络/HTTP常见状态码.md", + "name": "HTTP常见状态码.md", + "type": "file", + "path": "计算机网络/HTTP常见状态码.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机网络/TCP的三次握手四次握手总结.md", + "name": "TCP的三次握手四次握手总结.md", + "type": "file", + "path": "计算机网络/TCP的三次握手四次握手总结.md", "children": [], "isExpanded": false } @@ -476,24 +638,48 @@ "isExpanded": false }, { - "id": "面试八股", - "name": "面试八股", + "id": "内网穿透", + "name": "内网穿透", "type": "folder", - "path": "面试八股", + "path": "内网穿透", "children": [ { - "id": "面试八股/计算机面试经典八股.md", - "name": "计算机面试经典八股.md", + "id": "内网穿透/搭建derp和headscale避坑与指南.md", + "name": "搭建derp和headscale避坑与指南.md", "type": "file", - "path": "面试八股/计算机面试经典八股.md", + "path": "内网穿透/搭建derp和headscale避坑与指南.md", "children": [], "isExpanded": false }, { - "id": "面试八股/Nacos功能与应用场景详解.md", - "name": "Nacos功能与应用场景详解.md", + "id": "内网穿透/内网穿透方案.md", + "name": "内网穿透方案.md", "type": "file", - "path": "面试八股/Nacos功能与应用场景详解.md", + "path": "内网穿透/内网穿透方案.md", + "children": [], + "isExpanded": false + }, + { + "id": "内网穿透/Frp的kcp和quic的区别和特点.md", + "name": "Frp的kcp和quic的区别和特点.md", + "type": "file", + "path": "内网穿透/Frp的kcp和quic的区别和特点.md", + "children": [], + "isExpanded": false + }, + { + "id": "内网穿透/frp服务端配置.md", + "name": "frp服务端配置.md", + "type": "file", + "path": "内网穿透/frp服务端配置.md", + "children": [], + "isExpanded": false + }, + { + "id": "内网穿透/frp客户端配置.md", + "name": "frp客户端配置.md", + "type": "file", + "path": "内网穿透/frp客户端配置.md", "children": [], "isExpanded": false } @@ -506,6 +692,14 @@ "type": "folder", "path": "嵌入式", "children": [ + { + "id": "嵌入式/光纤和网线的特点和区别.md", + "name": "光纤和网线的特点和区别.md", + "type": "file", + "path": "嵌入式/光纤和网线的特点和区别.md", + "children": [], + "isExpanded": false + }, { "id": "嵌入式/USB拓展坞接口数量决定因素.md", "name": "USB拓展坞接口数量决定因素.md", @@ -575,6 +769,81 @@ ], "isExpanded": false }, + { + "id": "实习求职", + "name": "实习求职", + "type": "folder", + "path": "实习求职", + "children": [ + { + "id": "实习求职/面试八股", + "name": "面试八股", + "type": "folder", + "path": "实习求职/面试八股", + "children": [ + { + "id": "实习求职/面试八股/HTTP 与HTTPS", + "name": "HTTP 与HTTPS", + "type": "folder", + "path": "实习求职/面试八股/HTTP 与HTTPS", + "children": [ + { + "id": "实习求职/面试八股/HTTP 与HTTPS/从「敲下一个 URL」到「页面出现在屏幕」整条链路全景.md", + "name": "从「敲下一个 URL」到「页面出现在屏幕」整条链路全景.md", + "type": "file", + "path": "实习求职/面试八股/HTTP 与HTTPS/从「敲下一个 URL」到「页面出现在屏幕」整条链路全景.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "实习求职/面试八股/计算机面试经典八股.md", + "name": "计算机面试经典八股.md", + "type": "file", + "path": "实习求职/面试八股/计算机面试经典八股.md", + "children": [], + "isExpanded": false + }, + { + "id": "实习求职/面试八股/Nacos功能与应用场景详解.md", + "name": "Nacos功能与应用场景详解.md", + "type": "file", + "path": "实习求职/面试八股/Nacos功能与应用场景详解.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "实习求职/27双非本一腾讯IEG游戏安全后台实习面经.md", + "name": "27双非本一腾讯IEG游戏安全后台实习面经.md", + "type": "file", + "path": "实习求职/27双非本一腾讯IEG游戏安全后台实习面经.md", + "children": [], + "isExpanded": false + }, + { + "id": "实习求职/术语科普-HC.md", + "name": "术语科普-HC.md", + "type": "file", + "path": "实习求职/术语科普-HC.md", + "children": [], + "isExpanded": false + }, + { + "id": "实习求职/术语科普-PM.md", + "name": "术语科普-PM.md", + "type": "file", + "path": "实习求职/术语科普-PM.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, { "id": "数据结构与算法", "name": "数据结构与算法", @@ -973,6 +1242,14 @@ "children": [], "isExpanded": false }, + { + "id": "AI/AI大模型应用拆解.md", + "name": "AI大模型应用拆解.md", + "type": "file", + "path": "AI/AI大模型应用拆解.md", + "children": [], + "isExpanded": false + }, { "id": "AI/Qwen-Code官方文档使用教程.md", "name": "Qwen-Code官方文档使用教程.md", @@ -1004,6 +1281,14 @@ "type": "folder", "path": "Docker/优秀好用的Docker镜像", "children": [ + { + "id": "Docker/优秀好用的Docker镜像/模板.md", + "name": "模板.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/模板.md", + "children": [], + "isExpanded": false + }, { "id": "Docker/优秀好用的Docker镜像/FileCodeBox-文件快递柜.md", "name": "FileCodeBox-文件快递柜.md", @@ -1012,6 +1297,14 @@ "children": [], "isExpanded": false }, + { + "id": "Docker/优秀好用的Docker镜像/frp-内网穿透神器.md", + "name": "frp-内网穿透神器.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/frp-内网穿透神器.md", + "children": [], + "isExpanded": false + }, { "id": "Docker/优秀好用的Docker镜像/Gitea-私有化仓库部署.md", "name": "Gitea-私有化仓库部署.md", @@ -1067,6 +1360,22 @@ "path": "Docker/优秀好用的Docker镜像/Redis-内存数据库.md", "children": [], "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/SurveyKing-强大的问卷调查服务.md", + "name": "SurveyKing-强大的问卷调查服务.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/SurveyKing-强大的问卷调查服务.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/tailscale-ip-derp.md", + "name": "tailscale-ip-derp.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/tailscale-ip-derp.md", + "children": [], + "isExpanded": false } ], "isExpanded": false diff --git a/public/data/fileContents.json b/public/data/fileContents.json index 01e1469..670e471 100644 --- a/public/data/fileContents.json +++ b/public/data/fileContents.json @@ -1,4 +1,5 @@ { + "AI/AI大模型应用拆解.md": "> 此笔记记录一些AI工具的应用原理,给自己制作此类工具提供一点思路\n\nAI老师阅卷批改:\nOCR文字识别->大语言模型文本处理\n\nAI视频总结(bilinote):\n下载视频->提取音频->音频转文字->大语言模型文本处理", "AI/AI提示词工程/AI绘画提示词.md": "*by 树萌芽*\n\n**图片风格为2D像素像素化风格,比例 「1:1」 画一个游戏道具,背景是纯黑色,纯黑色** \n**不带任何文字,没有任何文字,现在我要你画 一个闪闪发光的金黄色金币卡**\n\n\n**图片风格为2D像素风格,比例 「1:1」 画一个游戏元素,风格为2.5D 就是上帝视角,就是正交斜视角那种有立体感,背景是纯黑色,纯黑色 不带任何文字,现在我要你画一个** \n**一丛茂密的灌木丛 记住一定要3d立体感 只要 灌木丛 只要 灌木丛!**\n\n\n比例 「1:1」图片风格为2D像素风格, 画一个游戏装饰元素,风格为2.5D 就是上帝视角,就是正交斜视角那种有立体感,背景是纯黑色,纯黑色 不带任何文字,现在我要你画一个 占卜测运算命台 相关的装饰可以多一点 记住一定要3d立体感 ", "AI/AI提示词工程/开发前后端分离网站提示词.md": "1.取消CORS跨域限制,允许任何链接\n2.前端使用React框架,后端使用python的Flask框架\n3.前端修改在frontend文件夹,后端修改在backend文件夹", "AI/Qwen-Code命令行安装使用教程.md": "**Qwen Code** 是一个 CLI 工具,修改自 **Gemini CLI**,针对 Qwen3‑Coder系列的模型增强了解析器和工具支持。\n\n确保已安装 Node.js 20 及以上版本,可以通过以下命令安装:\n\n```bash\ncurl -qL https://www.npmjs.com/install.sh | sh\n```\n\n然后通过 npm 管理器安装 Qwen Code:\n\n```bash\nnpm i -g @qwen-code/qwen-code\n```\n\n> 另一种方式是从源码安装:\n> \n> ```bash\n> git clone https://github.com/QwenLM/qwen-code.git\n> cd qwen-code && npm install && npm install -g\n> ```\n\nQwen Code 支持 OpenAI SDK 调用 LLM,你可以导出以下环境变量,或者简单地将其放在 `.envfile` 中。\n\n```bash\nexport OPENAI_API_KEY=\"your_api_key_here\"\nexport OPENAI_BASE_URL=\"https://dashscope.aliyuncs.com/compatible-mode/v1\"\nexport OPENAI_MODEL=\"qwen3-coder-plus\"\n```\n\n现在,你可以通过简单地输入 **`qwen`** 来享受 Qwen-Code 和 Qwen 带来的编程体验。\n\n### Claude Code\n\n除了 Qwen Code 之外,现在还可以将 Qwen3‑Coder 与 Claude Code 搭配使用。只需在[阿里云百炼](https://bailian.console.aliyun.com/)平台申请 API Key,并安装 Claude Code,即可开始畅享编码体验。\n\n```bash\nnpm install -g @anthropic-ai/claude-code\n```\n\n我们提供了两种接入方式,帮助你无缝地用 Qwen3‑Coder 进行编码。\n\n#### 使用dashscope提供的代理  API\n\n只需要将Anthropic的base url替换成dashscope上提供的endpoint即可。\n\n```bash\nexport ANTHROPIC_BASE_URL=https://dashscope.aliyuncs.com/api/v2/apps/claude-code-proxy\nexport ANTHROPIC_AUTH_TOKEN=your-dashscope-apikey\n```\n\n可选方案 2:使用 claude-code-config 自定义路由\n\n#### Optional 2: 使用 claude-code-config 自定义路由\n\nclaude-code-router 是一个第三方的路由工具,用于为 Claude Code 灵活地切换不同的后端 API。dashScope平台提供了一个简单的扩展包 claude-code-config,可为 claude-code-router 生成包含 dashScope 支持的默认配置。\n\n```bash\nnpm install -g @musistudio/claude-code-router\nnpm install -g @dashscope-js/claude-code-config\n```\n\n生成配置文件和插件目录:\n\n```bash\nccr-dashscope\n```\n\n该命令会自动生成 ccr 所需的配置文件和插件目录。你也可以手动调整 ~/.claude-code-router/config.json 和 ~/.claude-code-router/plugins/ 中的配置。\n\n最后,通过 ccr 开始使用 Claude Code:\n\n```bash\nccr code\n```\n\n至此,你即可通过 ccr 使用 Claude Code 畅享 Qwen3‑Coder 的强大编码能力。祝开发顺利!\n\n### Cline\n\n配置 Qwen3-Coder-480B-A35B-instruct 以使用 cline ‒ 进入 cline 的配置设置 ‒ 选择“OpenAI Compatible”模式 ‒ 在 OpenAI Compatible API tokens处,输入从 Dashscope 获取的密钥 ‒ 勾选“使用自定义基础 URL”,并输入:`https://dashscope.aliyuncs.com/compatible-mode/v1` ‒ 输入模型名称:`qwen3-coder-plus`", @@ -10,13 +11,17 @@ "Docker/Docker命令集合.md": "\ndocker-compose up -d\n\ndocker-compose down\n\ndocker-compose restart\n\ndocker-compose logs -f\n\ndocker-compose ps \n\ndocker-compose build --no-cache\n\n\n**Docker容器一键更新到最新版镜像(以60s API举例)**\n```bash\n#拉取最新镜像\ndocker pull vikiboss/60s:latest \ndocker pull mlikiowa/napcat-docker:latest\ndocker pull couchdb:latest #Obsidian同步的数据库\ndocker pull aceberg/watchyourlan #扫描局域网的工具\n\ndocker pull dpanel/dpanel:latest\n\n\n#停止并删除旧容器\ndocker stop 60s\ndocker rm 60s\ndocker stop napcat\ndocker rm napcat\n\n#兰空图床免费版\ndocker run -d \\\n --name lsky-pro \\\n -p 8089:80 \\\n -v /shumengya/docker/storage/lsky:/var/www/html \\\n --restart=always \\\n halcyonazure/lsky-pro:latest\n\n\n\n\n\n\n\n\n#可视化Docker面板\ndocker run -d \\\n --name dpanel \\\n -p 8800:8080 \\\n -v /var/run/docker.sock:/var/run/docker.sock \\\n -v /shumengya/docker/storage/dpanel:/dpanel/data \\\n --restart=always \\\n dpanel/dpanel:latest\n\n\n\n#扫描局域网的工具\ndocker run -d \\\n --name watch-your-lan \\\n --restart unless-stopped \\\n --net=host \\\n -e TZ=Asia/Shanghai \\\n -v /shumengya/docker/storage/watchyourlan:/data \\\n aceberg/watchyourlan\n\n#Obsidian 同步数据库\ndocker run -d \\\n --name obsidian-couchdb \\\n -e COUCHDB_USER=shumengya \\\n -e COUCHDB_PASSWORD='tyh@19900420' \\\n -p 5984:5984 \\\n couchdb:latest\n\n#60s api后端\ndocker run -d \\\n --restart always \\\n --name 60s \\\n -p 4399:4399 \\\n vikiboss/60s:latest\n \n#napcat QQ机器人\ndocker run -d \\\n --name napcat \\\n --restart=always \\\n -e NAPCAT_GID=$(id -g) \\\n -e NAPCAT_UID=$(id -u) \\\n -p 4080:3000 \\\n -p 4070:3001 \\\n -p 4060:6099 \\\n -v /shumengya/docker/storage/napcat/qq:/app/.config/QQ \\\n -v /shumengya/docker/storage/napcat/config:/app/napcat/config \\\n mlikiowa/napcat-docker:latest\n\n\n\n\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", "Docker/Docker镜像快速迁移.md": "\n---\n\n## ✅ 方法一:直接导出容器(container → tar)\n\n如果你运行的是一个 **容器**(而不是镜像),可以直接打包它:\n\n```bash\n# 导出容器\ndocker export <容器ID或名字> -o container.tar\n\n# 在另一台Linux机器上导入\ndocker import container.tar new-image:latest\n```\n\n特点:\n\n- 容器的运行时文件系统会被打包(包含你安装的软件和修改),**但不会包含容器的历史层和环境变量**。\n \n- 类似于“快照”迁移。\n \n\n---\n\n## ✅ 方法二:保存镜像(image → tar)\n\n如果你已经把容器做成了一个镜像,建议用 **save/load**:\n\n```bash\n# 在源主机上保存镜像\ndocker save -o myimage.tar myimage:latest\ndocker save -o frpc-1panel.tar snowdreamtech/frpc:0.63.0\n\n# 拷贝到目标主机(比如用 scp)\nscp myimage.tar user@remote:/path/\n\n# 在目标主机导入\ndocker load -i myimage.tar\n```\n\n特点:\n\n- 保留镜像层和构建历史。\n \n- 推荐这种方式。\n \n\n---\n\n", "Docker/优秀好用的Docker镜像/FileCodeBox-文件快递柜.md": "\n```bash\ndocker run -d \\\n --name filecodebox \\\n --restart=always \\\n -p 12345:12345 \\\n -v /shumengya/docker/storage/filecodebox:/app/data \\\n lanol/filecodebox:beta\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull lanol/filecodebox:beta\n```\n\n```\ndocker stop lanol/filecodebox:beta\ndocker rm lanol/filecodebox:beta\n```", + "Docker/优秀好用的Docker镜像/frp-内网穿透神器.md": "\n```bash\n#启动最新版frp客户端\ndocker run -d \\\n --name frpc \\\n --restart=always \\\n --network host \\\n -v /shumengya/docker/storage/frpc:/etc/frp \\\n -e TZ=Asia/Shanghai \\\n natfrp/frpc:latest \\\n -c /etc/frp/frpc.toml\n\n#启动最新版frp服务端\ndocker run -d \\\n --name frps \\\n --restart=always \\\n --network host \\\n -e TZ=Asia/Tokyo \\\n -v /shumengya/docker/storage/frps:/etc/frp \\\n snowdreamtech/frps:latest \\\n -c /etc/frp/frps.toml\n\n\n```\n\n```bash\n\n```\n\n```\n\n```", "Docker/优秀好用的Docker镜像/Gitea-私有化仓库部署.md": "\n```bash\n#github/gitlab的本地轻量化部署代替-gitea\ndocker run -d \\\n --name gitea \\\n -p 8989:3000 \\\n -p 8022:22 \\\n -e USER_UID=1000 \\\n -e USER_GID=1000 \\\n -v /shumengya/docker/storage/gitea:/data \\\n --restart=always \\\n gitea/gitea:latest\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull gitea/gitea:latest\n```\n\n```\ndocker stop gitea/gitea:latest\ndocker rm gitea/gitea:latest\n```", "Docker/优秀好用的Docker镜像/MongoDB-数据库.md": "\n```bash\n#MongoDB数据库\ndocker run -d --name mongodb \\\n -e MONGO_INITDB_ROOT_USERNAME=shumengya \\\n -e MONGO_INITDB_ROOT_PASSWORD=shumengya520 \\\n -v /shumengya/docker/storage/mongodb:/data/db \\\n -p 27017:27017 \\\n mongo\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull mongo \n```", - "Docker/优秀好用的Docker镜像/MySQL-数据库.md": "\n```bash\ndocker run -d \\\n --name mysql \\\n -e MYSQL_ROOT_PASSWORD=shumengya520 \\\n -e MYSQL_DATABASE=shumengyadb \\\n -e MYSQL_USER=shumengya \\\n -e MYSQL_PASSWORD=shumengya520 \\\n -v /shumengya/docker/storage/mysql:/var/lib/mysql \\\n -p 3306:3306 \\\n --restart=always \\\n mysql:latest\n \n \ndocker run -d \\\n --name mysql \\\n -e MYSQL_ROOT_PASSWORD=shumengya520 \\\n -e MYSQL_DATABASE=shumengyadb \\\n -e MYSQL_USER=shumengya \\\n -e MYSQL_PASSWORD=shumengya520 \\\n -v /shumengya/docker/storage/mysql:/var/lib/mysql \\\n -p 3306:3306 \\\n --restart=always \\\n mysql:5.7.44\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull mysql:5.7.44\n```\n\n```\ndocker stop mysql\ndocker rm mysql\n```", + "Docker/优秀好用的Docker镜像/MySQL-数据库.md": "\n```bash\ndocker run -d \\\n--name mysql_latest \\\n-p 3306:3306 \\\n-v /shumengya/docker/storage/mysql:/var/lib/mysql \\\n-e MYSQL_ROOT_PASSWORD=shumengya520 \\\n--memory=4g \\\n--cpus=4 \\\nmysql:latest\n\n\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull mysql:latest\n```\n\n```\ndocker stop mysql\ndocker rm mysql\n```", "Docker/优秀好用的Docker镜像/NapCat-QQ机器人框架.md": "\n```bash\ndocker run -d \\\n --name filecodebox \\\n --restart=always \\\n -p 12345:12345 \\\n -v /shumengya/docker/storage/filecodebox:/app/data \\\n lanol/filecodebox:beta\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull lanol/filecodebox:beta\n```\n\n```\ndocker stop lanol/filecodebox:beta\ndocker rm lanol/filecodebox:beta\n```", "Docker/优秀好用的Docker镜像/Ntfy-萌芽通知.md": "\n```bash\ndocker run -d \\\n --name ntfy \\\n --restart=always \\\n -e TZ=\"Asia/Shanghai\" \\\n -e NTFY_BASE_URL=\"https://ntfy.shumengya.top\" \\\n -e NTFY_CACHE_FILE=\"/var/cache/ntfy/cache.db\" \\\n -e NTFY_AUTH_FILE=\"/var/lib/ntfy/auth.db\" \\\n -e NTFY_AUTH_DEFAULT_ACCESS=\"deny-all\" \\\n -e NTFY_BEHIND_PROXY=\"true\" \\\n -e NTFY_ATTACHMENT_CACHE_DIR=\"/var/lib/ntfy/attachments\" \\\n -e NTFY_ENABLE_LOGIN=\"true\" \\\n -v /shumengya/docker/storage/ntfy/cache:/var/cache/ntfy \\\n -v /shumengya/docker/storage/ntfy/etc:/etc/ntfy \\\n -v /shumengya/docker/storage/ntfy/lib:/var/lib/ntfy \\\n -p 82:80 \\\n binwiederhier/ntfy:latest \\\n serve\n\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull binwiederhier/ntfy:latest\n```\n\n```\ndocker stop binwiederhier/ntfy:latest\ndocker rm binwiederhier/ntfy:latest\n```", "Docker/优秀好用的Docker镜像/Postgres-数据库.md": "\n```bash\n#postgres数据库\ndocker run -d \\\n --name postgres \\\n -e POSTGRES_PASSWORD=shumengya520 \\\n -e POSTGRES_USER=shumengya \\\n -e POSTGRES_DB=shumengyadb \\\n -v /shumengya/docker/storage/postgres:/data \\\n -e PGDATA=/data/pgdata \\\n -p 5432:5432 \\\n --restart=always \\\n postgres:latest\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull postgres:latest\n```\n\n```\ndocker stop postgres:latest\ndocker rm postgres:latest\n```", - "Docker/优秀好用的Docker镜像/Redis-内存数据库.md": "\n```bash\n#MongoDB数据库\ndocker run -d --name mongodb \\\n -e MONGO_INITDB_ROOT_USERNAME=shumengya \\\n -e MONGO_INITDB_ROOT_PASSWORD=shumengya520 \\\n -v /shumengya/docker/storage/mongodb:/data/db \\\n -p 27017:27017 \\\n mongo\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull mongo \n```", + "Docker/优秀好用的Docker镜像/Redis-内存数据库.md": "\n```bash\n#Redis数据库\ndocker run -d --name redis-server \\\n -p 6379:6379 \\\n redis:latest \\\n redis-server --requirepass \"shumengya520\"\n\n```\n\n```bash\n\ndocker pull redis\n```", + "Docker/优秀好用的Docker镜像/SurveyKing-强大的问卷调查服务.md": "\n```bash\ndocker run -d \\\n -p 1991:1991 \\\n --memory=4g \\\n --cpus=4 \\\n surveyking/surveyking\n\n\n```\n\n```bash\n\n```\n\n```\n\n```", + "Docker/优秀好用的Docker镜像/tailscale-ip-derp.md": "\n```bash\ndocker run -d \\\n--name derper \\\n-p 33445:13477/tcp \\\n-p 3478:3478/udp \\\n-v /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock \\\n-e DERP_ADDR=\":33445\" \\\n-e DERP_VERIFY_CLIENTS=true \\\nghcr.io/yangchuansheng/ip_derper:latest\n\n\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull lanol/filecodebox:beta\n```\n\n```\ndocker stop lanol/filecodebox:beta\ndocker rm lanol/filecodebox:beta\n```", + "Docker/优秀好用的Docker镜像/模板.md": "\n```bash\n\n\n\n```\n\n```bash\n\n```\n\n```\n\n```", "Github/Github仓库公共API总结.md": "\n---\n\n## Releases(发行版本)相关接口\n\n- **获取最新发布版本(Latest Release)** \n `GET /repos/{owner}/{repo}/releases/latest` \n 返回最新非预发布、非草稿版的发布详情,包括版本号、发布时间、说明等。([GitHub Docs](https://docs.github.com/en/rest/releases?utm_source=chatgpt.com \"REST API endpoints for releases and release assets\"))\n \n- **列出所有发布版本(List Releases)** \n `GET /repos/{owner}/{repo}/releases` \n 返回该仓库所有发布版本的列表,不包含未关联发布的普通 Git 标签。([GitHub Docs](https://docs.github.com/en/rest/releases/releases?utm_source=chatgpt.com \"REST API endpoints for releases\"))\n \n- **通过 Tag 获取指定发布版本(Get a Release by Tag)** \n `GET /repos/{owner}/{repo}/releases/tags/{tag}` \n 根据具体 tag 名称获取对应发布版本的信息。([GitHub Docs](https://docs.github.com/en/rest/releases?utm_source=chatgpt.com \"REST API endpoints for releases and release assets\"))\n \n- **创建、更新、删除发布版本(Create / Update / Delete Release)**\n \n - `POST /repos/{owner}/{repo}/releases` — 创建新的发布版本\n \n - `PATCH /repos/{owner}/{repo}/releases/{release_id}` — 更新发布版本\n \n - `DELETE /repos/{owner}/{repo}/releases/{release_id}` — 删除发布版本 \n (这些操作通常需要认证权限。)([GitHub Docs](https://docs.github.com/en/rest/releases?utm_source=chatgpt.com \"REST API endpoints for releases and release assets\"))\n \n\n---\n\n## Git Tags(标签)相关接口\n\n- **列出仓库的 Git 标签** \n `GET /repos/{owner}/{repo}/tags` \n 返回该仓库所有标签(包括 lightweight 和 annotated)。([Stack Overflow](https://stackoverflow.com/questions/18384873/how-to-list-the-releases-of-a-repository?utm_source=chatgpt.com \"github - How to list the releases of a repository?\"), [GitHub Docs](https://docs.github.com/en/rest/repos/tags?utm_source=chatgpt.com \"REST API endpoints for repository tags\"))\n \n- **获取标签引用(Tag Reference)** \n `GET /repos/{owner}/{repo}/git/refs/tags/{tag_name}` \n 可获取该标签所对应的对象(TAG_SHA),用于进一步查询。([Stack Overflow](https://stackoverflow.com/questions/72429056/how-to-get-single-tag-information-using-github-api?utm_source=chatgpt.com \"How to get Single tag Information using GitHub Api?\"))\n \n- **获取 Annotated Tag 对象详情** \n `GET /repos/{owner}/{repo}/git/tags/{tag_sha}` \n 获取标签对象的完整信息,包括 `object.sha` 即对应的 commit SHA、tagger、message 等。([Stack Overflow](https://stackoverflow.com/questions/72429056/how-to-get-single-tag-information-using-github-api?utm_source=chatgpt.com \"How to get Single tag Information using GitHub Api?\"))\n \n\n---\n\n## Commits(提交)相关接口\n\n- **列出提交记录(List Commits)** \n `GET /repos/{owner}/{repo}/commits` \n 返回最新的提交列表,第一个通常为最新提交。响应中包含 SHA、作者、提交信息、签名验证信息等。([GitHub Docs](https://docs.github.com/en/rest/commits/commits?utm_source=chatgpt.com \"REST API endpoints for commits\"))\n \n- **获取单个提交详情(Get a Commit)** \n `GET /repos/{owner}/{repo}/commits/{commit_sha}` \n 获取指定提交的详细信息。([GitHub Docs](https://docs.github.com/en/rest/commits?utm_source=chatgpt.com \"REST API endpoints for commits\"))\n \n- **比较两个提交(Compare Commits)** \n `GET /repos/{owner}/{repo}/compare/{base}...{head}` \n 用于比较两个 commit 或两个 tag 之间的差异。([Stack Overflow](https://stackoverflow.com/questions/61359461/get-all-commits-in-a-git-tag-through-github-api-return-only-the-first-commit?utm_source=chatgpt.com \"get all commits in a Git tag through GitHub API return only ...\"))\n \n\n---\n\n## 综合流程示例\n\n下面是一个常见逻辑,例如想获取最新发布对应的 commit SHA:\n\n1. 调用 `GET /repos/{owner}/{repo}/releases/latest` 获取最新 release 的 `tag_name`。\n \n2. 调用 `GET /repos/{owner}/{repo}/git/refs/tags/{tag_name}` 获取 TAG_SHA。\n \n3. 调用 `GET /repos/{owner}/{repo}/git/tags/{tag_sha}` 获取该标签对象的 commit SHA(object.sha)。\n \n\n这套流程常用于从发布版本跳转到对应的 Git 提交。([Stack Overflow](https://stackoverflow.com/questions/67040794/how-can-i-get-the-commit-hash-of-the-latest-release-from-github-api?utm_source=chatgpt.com \"How can I get the commit hash of the latest release from ...\"))\n\n---\n\n## 表格总结\n\n|功能需求|接口路径 / 方法|\n|---|---|\n|最新发布版本信息|`GET /repos/{owner}/{repo}/releases/latest`|\n|列出所有发布版本|`GET /repos/{owner}/{repo}/releases`|\n|通过 tag 查询发布|`GET /repos/{owner}/{repo}/releases/tags/{tag}`|\n|获取标签列表|`GET /repos/{owner}/{repo}/tags`|\n|获取标签引用(TAG_SHA)|`GET /repos/{owner}/{repo}/git/refs/tags/{tag_name}`|\n|获取标签对象详情|`GET /repos/{owner}/{repo}/git/tags/{tag_sha}`|\n|列出提交|`GET /repos/{owner}/{repo}/commits`|\n|获取指定 commit 信息|`GET /repos/{owner}/{repo}/commits/{commit_sha}`|\n|比较两个 commit/tag|`GET /repos/{owner}/{repo}/compare/{base}...{head}`|\n\n---\n\n如果你还希望了解更多,如 API 速率限制、认证方式(匿名 vs token)、分页处理(per_page、page 参数)、使用 GraphQL API 实现同类功能,或具体的 JavaScript `fetch` 调用示例,都可以随时继续讨论!", "Github/Github获取仓库密钥.md": "这个地方要注意:\n\n你输入 `git push` 时出现\n\n```\nUsername for 'https://github.com': shumengya\nPassword for 'https://shumengya@github.com':\n```\n\n这里的 **Password** 已经不是 GitHub 登录密码了。\n从 2021 年 8 月开始,GitHub **禁用了账户密码推送**,必须用 **Personal Access Token (PAT)** 或 **SSH Key** 来认证。\n\n---\n\n### ✅ 方案一:生成 Personal Access Token(HTTPS 推荐)\n\n1. 登录 GitHub → 右上角头像 → **Settings**\n2. 左侧栏 → **Developer settings** → **Personal access tokens** → **Tokens (classic)**\n3. 点击 **Generate new token (classic)**\n\n * 勾选 **repo**(访问和推送仓库必须要有)\n * 设置有效期(比如 90 天或无期限)\n * 点击生成\n4. 复制生成的 Token(只会显示一次)\n\n之后推送时:\n\n* **Username**:填 GitHub 用户名(`shumengya`)\n* **Password**:填刚生成的 Token\n\n---\n\n### ✅ 方案二:改用 SSH Key(更方便)\n\n1. 本地生成 SSH Key:\n\n ```bash\n ssh-keygen -t ed25519 -C \"你的邮箱\"\n ```\n\n 按回车保存,默认会在 `~/.ssh/id_ed25519` 和 `~/.ssh/id_ed25519.pub`。\n2. 查看公钥:\n\n ```bash\n cat ~/.ssh/id_ed25519.pub\n ```\n3. 复制内容 → GitHub → **Settings → SSH and GPG keys → New SSH key** → 粘贴保存。\n4. 修改仓库地址为 SSH:\n\n ```bash\n git remote set-url origin git@github.com:shumengya/你的仓库名.git\n ```\n5. 之后直接 `git push` 就不用输密码了。\n\n---\n\n👉 建议你选 **SSH Key**,因为用一次就永久生效,不会过期。\n\n要不要我给你写一份 **完整 SSH Key 配置和测试流程**(从生成到验证)?\n\n", "Github/Linux下使用git探索.md": "**修改全局代理为http1**\n```\ngit config --global http.version HTTP/1.1\n```\n\n**相当于 git fetch + git merge,会把远程最新提交合并到你当前分支。**\n```\ngit pull\n```\n\n**这会把你的本地提交临时“挪开”,先更新远程提交,然后再把你的提交放回去,避免多余的合并记录。**\n```\ngit pull --rebase\n```\n\n**如果只想下载最新提交但不合并**\n```\ngit fetch\n```\n\n**树萌芽GitHub仓库提交代码通用密钥:**\n```\n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\n```\n\n### 1. 添加所有改动\n```\ngit add .\n```\n### 2. 提交,写上提交说明\n```\ngit commit -m \"更新说明\"\n```\n### 3. 推送到远程仓库(假设分支是 main)\n```\ngit push origin main\n```\n\n\n**压缩成一条命令实现:**\n```\ngit add . && git commit -m \"update\" && git push origin main\n```\n\n**或者设置命令别名,比如写进 ~/.bashrc 或 ~/.zshrc:**\n```\nalias gopush='git add . && git commit -m \"update\" && git push origin main'\n```\n\n\n注意:校园网可能会屏蔽梯子,必要时开热点提交\n\n", @@ -72,7 +77,19 @@ "Linux/飞牛os切换root.md": "1.打开飞牛ssh\r\n2.ssh软件连接上飞牛(飞牛账号)\r\n3.给root新建密码:sudo passwd root 回车\r\n再次输入飞牛密码\r\n再输入密码(root密码)两次(不回显,每次输完回车)\r\n4.配置权限文件:sudo nano /etc/ssh/sshd_config 回车\r\n5.光标移动到:permitrootlogin no 把no 改为yes \r\n6.ctrl+o(写入文本)回车 ctrl+x(退出) 重启服务器:sudo reboot\r\n7.重启ssh服务:sudo service sshd restart\r\n8.用命令切换root账号:su -(或者sudo su -)还要输入一次目前飞牛密码回车就切换root了。", "Minecraft/Minecraft常用命令.md": "***/kill @e[type=mutant:mskeleton_bones]*** \n清除掉突变骷髅模组的骷髅骨头实体\n\n***/kill @e[type=item]*** \n清除所有掉落物\n\n***/gamerule mobGriefing true*** \n设置生物破坏开启或者禁用 (禁用后村民不会繁殖,雪傀儡不会产雪)", "Obsidion/Obsidion美化.md": "```json\n{\n \"Appearance-light@@theme-light-style-select\": \"theme-light-background-adapt\",\n \"Appearance-light@@mod-left-split-background-select-light\": \"mod-left-split-background-CSS-light\",\n \"Appearance-light@@background-mod-left-CSS-light\": \"radial-gradient(100% 50% at 100% 50%, rgba(90, 109, 237, 0.1) 0%, rgba(255, 255, 255, 0) 100%)\",\n \"Appearance-light@@background-mod-left-CSS-backdrop-filter-light\": \"blur(0px)\",\n \"Appearance-light@@mod-right-split-background-select-light\": \"mod-right-split-background-CSS-light\",\n \"Appearance-light@@background-mod-right-CSS-light\": \"radial-gradient(100% 50% at 0% 50%, rgba(90, 109, 237, 0.1) 0%, rgba(255, 255, 255, 0) 100%)\",\n \"Appearance-light@@background-mod-right-CSS-backdrop-filter-light\": \"blur(0px)\",\n \"Appearance-light@@mod-root-split-background-select-light\": \"mod-root-split-background-CSS-light\",\n \"Appearance-light@@background-mod-root-CSS-light\": \"transparent\",\n \"Appearance-light@@background-mod-root-CSS-backdrop-filter-light\": \"blur(0px)\",\n \"Appearance-light@@background-underlying-select-light\": \"background-underlying-CSS-light\",\n \"Appearance-light@@background-underlying-CSS-light\": \"linear-gradient(168.44deg, #D7DAEA 1.62%, #F2F2F8 95.72%)\",\n \"Appearance-light@@background-underlying-CSS-blend-mode-light\": \"normal\",\n \"Appearance-light@@card-border-radius-light\": \"0px\",\n \"Appearance-light@@card-shadow-light\": \"none\",\n \"Appearance-light@@background-activated-tab-header-light\": \"radial-gradient(50% 150% at 50% 150%, #F8F9FF 0%, rgba(97, 54, 144, 0) 100%)\",\n \"Appearance-light@@shadow-activated-tab-header-light\": \"none\",\n \"Appearance-light@@indicator-remove-light\": true,\n \"Appearance-light@@Active-states-file-explorer-select-light\": \"activated-file-tab-style-light\",\n \"Appearance-light@@workspace-divider-transparent-light\": true,\n \"Components@@CTA-BTN-enable\": true,\n \"Components@@file-names-untrim\": true,\n \"Components@@folder-font-bold\": true,\n \"Components@@colorful-folder\": true,\n \"Components@@file-icon-remove\": false,\n \"Components@@outline-enhanced\": true,\n \"Components@@new-tab-btn-select\": \"new-tab-btn-default\",\n \"Components@@immersive-canvas\": true,\n \"Components@@scrollbar-hide\": true,\n \"Appearance-light@@card-layout-open-light\": true,\n \"Appearance-light@@accent-color-override-light\": false,\n \"Appearance-light@@card-highlight-light\": true,\n \"Editor@@line-hover-indicator\": true,\n \"Editor@@focus-indicator-codeblock-line-number\": true,\n \"Editor@@focus-indicator-list-level\": true,\n \"Editor@@editor-grid-background-pattren\": true,\n \"Editor@@inline-title-divider-remove\": true,\n \"Editor@@h1-divider-on\": true,\n \"Editor@@h2-divider-on\": true,\n \"Editor@@h3-divider-on\": true,\n \"Editor@@h4-divider-on\": true,\n \"Editor@@h5-divider-on\": true,\n \"Editor@@h6-divider-on\": true,\n \"Editor@@text-align-justify\": true,\n \"Editor@@bold-color@@light\": \"#4781EC\",\n \"Editor@@italic-color@@light\": \"#FF4BFE\",\n \"Editor@@img-center-align\": true,\n \"Mobile@@drawer-phone-full-width\": true,\n \"Mobile@@card-layout-pad-open\": true,\n \"Plugin@@colorful-checkbox\": true\n}\n```", + "内网穿透/frp客户端配置.md": "\n```toml\n#=============================================================================\n#===================================基础设置===================================\n#=============================================================================\n\nserverAddr = \"47.108.90.0\"\nserverPort = 7000\n\nauth.method = \"token\"\nauth.token = \"smy\"\n\nwebServer.addr = \"0.0.0.0\"\nwebServer.port = 7400\nwebServer.user = \"shumengya\"\nwebServer.password = \"tyh@19900420\"\nwebServer.pprofEnable = false\n\n#下面两个二选一\ntransport.protocol = \"kcp\"\n#transport.protocol = \"quic\"\n\n# 日志配置\nlog.to = \"console\"\nlog.level = \"info\"\n\n\n#=============================================================================\n#===================================Http服务===================================\n#=============================================================================\n\n# 萌芽盘-openlist\n[[proxies]]\nname = \"openlist\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 5244\ncustomDomains = [\"openlist.shumengya.top\",\"pan.shumengya.top\"] \n\n\n#大萌芽1panel面板-1panel\n[[proxies]]\nname = \"1panel\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 19132\ncustomDomains = [\"1panel.shumengya.top\"] \n\n\n#Obsidian笔记同步-couchdb\n[[proxies]]\nname = \"couchdb\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 5984\ncustomDomains = [\"note.shumengya.top\"] \n\n#大萌芽frp客户端-frpc\n[[proxies]]\nname = \"frpc\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 7400\ncustomDomains = [\"frpc.shumengya.top\"] \n\n#萌芽文件快传-filecodebox\n[[proxies]]\nname = \"filecodebox\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 12345\ncustomDomains = [\"file.shumengya.top\",\"send.shumengya.top\"] \n\n#萌芽图床-lsky-pro\n[[proxies]]\nname = \"lsky-pro\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 8089\ncustomDomains = [\"image.shumengya.top\",\"img.shumengya.top\"] \n\n#在线代码编辑器-codeserver\n[[proxies]]\nname = \"codeserver\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 8888\ncustomDomains = [\"code.shumengya.top\"] \n\n#60sAPI接口集合-60sapi\n[[proxies]]\nname = \"60s-API\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 4399\ncustomDomains = [\"60s.api.shumengya.top\"] \n\n#社交媒体视频ai总结-bilinote\n[[proxies]]\nname = \"bilinote\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 3015\ncustomDomains = [\"bilinote.shumengya.top\"] \n\n#萌芽git仓库-gitea\n[[proxies]]\nname = \"gitea\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 8989\ncustomDomains = [\"repo.shumengya.top\"] \n\n#Docker可视化面板-DPanel\n[[proxies]]\nname = \"dpanel\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 8800\ncustomDomains = [\"dpanel.shumengya.top\"] \n\n#萌芽通知-ntfy\n[[proxies]]\nname = \"ntfy\"\ntype = \"http\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 82\ncustomDomains = [\"ntfy.shumengya.top\"] \n\n#萌芽大内网管理后台-openwrt\n[[proxies]]\nname = \"openwrt\"\ntype = \"http\"\nlocalIP = \"192.168.1.1\"\nlocalPort = 80\ncustomDomains = [\"openwrt.shumengya.top\"] \n\n#=========================================================================\n#===================================TCP服务=================================\n#=========================================================================\n\n#萌芽农场远程控制台\n[[proxies]]\nname = \"mengyafarm-config\"\ntype = \"tcp\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 7071\nremotePort = 6060\n\n#mysql数据库\n[[proxies]]\nname = \"mysql\"\ntype = \"tcp\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 3306\nremotePort = 3307 # frps 上的映射端口\n\n#MongoDB数据库\n[[proxies]]\nname = \"mongodb\"\ntype = \"tcp\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 27017\nremotePort = 27018\n\n#Postgres数据库\n[[proxies]]\nname = \"postgres\"\ntype = \"tcp\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 5432\nremotePort = 5433\n\n#大萌芽-Debian11 SSH连接\n[[proxies]]\nname = \"bigmengya-ssh\"\ntype = \"tcp\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 22\nremotePort = 9022\n\n#Redis数据库\n[[proxies]]\nname = \"redis\"\ntype = \"tcp\"\nlocalIP = \"127.0.0.1\"\nlocalPort = 6379\nremotePort = 6380\n\n\n#=========================================================================\n#===================================UDP服务=================================\n#=========================================================================\n\n```\n", + "内网穿透/frp服务端配置.md": "\n```toml\n# frp服务端配置 - 作为nginx后端服务\n# 与nginx配合使用,提供HTTPS支持\n\nbindAddr = \"0.0.0.0\"\nbindPort = 7000\n\n#下面两个二选一\nkcpBindPort = 7000 # KCP 监听的 UDP 端口(可与 bindPort 相同)\n#quicBindPort = 7000 # QUIC 使用的 UDP 端口(与 bindPort 可相同)\n\n[auth]\nauth.method = \"token\" \nauth.token = \"smy\" \n\n# HTTP配置 - 作为后端服务(nginx代理)\nvhostHTTPPort = 8080 # nginx代理到此端口\n\n# 日志配置\nlog.to = \"console\"\nlog.level = \"info\"\n\n# 管理界面\n[webServer]\nwebServer.addr = \"0.0.0.0\"\nwebServer.port = 7500\nwebServer.user = \"shumengya\"\nwebServer.password = \"tyh@19900420\" \n\n[transport]\ntcpMux = true # 如要关闭 tcp 多路复用(默认启用)\nmaxPoolCount = 10 # 服务端允许的最大连接池数量\ntls.force = false # 不强制客户端必须 TLS(除非你要强制安全)\n```\n\n", + "内网穿透/Frp的kcp和quic的区别和特点.md": "\n---\n\n## 基础:QUIC 与 KCP 本身的区别(协议层面)\n\n要理解 FRP 下这两种模式的差别,首先必须认识 QUIC 与 KCP 两种协议在 UDP 之上的设计差异。下面从几个维度来对比。\n\n|维度|KCP|QUIC|\n|---|---|---|\n|协议定位 / 设计目标|一个可靠的 UDP 层协议(“可靠 UDP + ARQ + 拥塞控制 + 重传策略”),强调低延迟、对弱网络适应性较好。 ([腾讯云](https://cloud.tencent.com/developer/article/1964393?utm_source=chatgpt.com \"KCP协议:从TCP到UDP家族QUIC/KCP/ENET-腾讯云开发 ...\"))|更现代的传输层协议,最初由 Google 设计,后来演化成为 HTTP/3 的底层传输(即:QUIC + TLS + 多路复用)的一部分。它在 UDP 之上集成了连接管理、多路复用、拥塞控制、0-RTT、TLS 加密等机制。 ([CSDN博客](https://blog.csdn.net/qq_36541069/article/details/132143729?utm_source=chatgpt.com \"所得杂记:KCP,QUIC,MQTT - CSDN博客\"))|\n|连接建立 / 握手延迟|KCP 在使用上一般是比较“轻”的握手(因为只是建立会话 ID 等),延迟比较低|QUIC 支持 0-RTT、较快握手(因为集成 TLS)等机制,从连接建立角度更有优势|\n|多路复用 / 多流支持|传统 KCP 是面向“单流”(一个会话对应一个流式数据)。要实现真正的多路复用,需要在上层自己设计;否则每条独立连接就是一个 KCP 实例|QUIC 原生支持多流(multiple streams)和流内优先级,能在一个连接上同时承载多个逻辑数据流,减少队头阻塞(Head-of-line blocking)的问题|\n|拥塞控制 / 拥塞算法|KCP 自己有拥塞控制与窗口机制,也可以调节参数去“弱化”拥塞控制以换取低延迟。 ([腾讯云](https://cloud.tencent.com/developer/article/1964393?utm_source=chatgpt.com \"KCP协议:从TCP到UDP家族QUIC/KCP/ENET-腾讯云开发 ...\"))|QUIC 的拥塞控制受到现代研究和 TCP 的启发,有较为成熟的拥塞控制与流量控制算法;它也能动态适应网络变化|\n|丢包 / 重传机制|KCP 使用选择性重传 (Selective Retransmission)、快速重传、延迟 ACK 调节等策略来减少重传滞后和延迟惩罚。 ([腾讯云](https://cloud.tencent.com/developer/article/1964393?utm_source=chatgpt.com \"KCP协议:从TCP到UDP家族QUIC/KCP/ENET-腾讯云开发 ...\"))|QUIC 也具备细粒度的 ACK / 重传机制,有更复杂的 ACK / 确认策略,集成了更现代的重传算法|\n|加密 / 安全|KCP 本身通常是“裸协议”或可选加密(上层或 FRP 在其上做加密)|QUIC 本身设计是**加密为默认**(TLS 集成在协议里),所有控制面与数据面都加密,更能防止中间人干扰、流量识别等问题|\n|开销 / 资源占用|相对轻量;因为协议栈简单,控制开销、头部开销较低|更复杂,协议处理开销更大(比如加密、握手、流管理、ACK 处理等)|\n|在极端场景 / 性能瓶颈下表现|在高延迟 + 大包 / 大数据量 + 丢包环境下,KCP 性能可能下降。比如有测试指出在**高延迟 + 发送超过 MTU 的数据**时,KCP 的延迟会显著恶化。 ([GitHub](https://github.com/xtaci/kcp-go/issues/204?utm_source=chatgpt.com \"对比TCP/QUIC/KCP的测试结果 · Issue #204 · xtaci/kcp-go - GitHub\"))|在这些情况下,QUIC 的设计通常更稳健一些,更能处理大流量、多个流、多并发场景|\n\n从这些对比来看,QUIC 在协议设计上更“现代”、更全面、更关注安全性与多路复用,而 KCP 更加轻量、灵活,适合对实时性、低延迟要求比较高的场景。\n\n不过,协议设计优劣并不是绝对的,具体在 FRP 的应用场景下,还要考虑实现、参数调优、网络环境等因素。\n\n---\n\n## 在 FRP 中:QUIC 模式 vs KCP 模式的区别与表现\n\nFRP 支持将底层通信协议从默认的 TCP / HTTPTransport 切换成 KCP 或 QUIC(即 `transport.protocol = \"kcp\"` 或 `\"quic\"`)模式。官方文档里对此有说明。 ([gofrp.org](https://gofrp.org/en/docs/features/common/network/network/?utm_source=chatgpt.com \"Communication Security and Optimization | frp\"))\n\n下面是两种模式在 FRP 中常见的差别、优缺点、使用注意。\n\n### 优点 / 劣势对比\n\n|特性 / 维度|FRP + KCP 模式|FRP + QUIC 模式|\n|---|---|---|\n|延迟表现 / 实时响应|通常优于 TCP,尤其在丢包 / 抖动较大、网络不稳定的环境下。很多用户用 KCP 模式来加速远程桌面、SSH 等。 ([CSDN博客](https://blog.csdn.net/MENGHUANBEIKE/article/details/100793876?utm_source=chatgpt.com \"利用frp内网穿透kcp模式做跳板,加速流畅访问远程桌面3389\"))|在连接建立、短连接场景以及多流场景中,QUIC 有优势;也能在某些网络被封、被干扰的情况下更抗阻断性(因为包头更难识别)|\n|抗网络干扰 / 被封锁风险|KCP 尽管在 UDP 上传输,但协议本身特征可能比较容易被识别;在被运营商主动干扰 UDP 流量的环境中可能被限速或封锁|QUIC 本身带加密和混淆特性,更难被中间设备识别,某些用户用 QUIC 模式来规避“被运营商阻断 FRP TCP 连接”的情况。比如有一篇博客指出,TCP 模式在某些校园网或被 ISP 限制时连接失败,而改用 QUIC 协议就能恢复连接。 ([ZRHan's Blog](https://blog.zrhan.top/2024/07/14/%E7%94%A8quic%E5%8D%8F%E8%AE%AE%E8%A7%A3%E5%86%B3frp%E8%A2%AB%E8%BF%90%E8%90%A5%E5%95%86%E9%98%BB%E6%96%AD%E7%9A%84%E9%97%AE%E9%A2%98/?utm_source=chatgpt.com \"用quic协议解决frp被运营商阻断的问题 - ZRHan's Blog\"))|\n|带宽开销 / 效率|KCP 为了追求低延迟,会在一定程度上牺牲一些带宽效率(可能会有额外重传、冗余、控制包开销等) ([gofrp.org](https://gofrp.org/en/docs/features/common/network/network/?utm_source=chatgpt.com \"Communication Security and Optimization \\| frp\"))|QUIC 在设计上对带宽利用率考虑较多,控制与重传机制更复杂,会在多流、大连接场景下更高效|\n|多代理 / 多连接 / 并发|KCP 模式下,如果你在一个 FRP 实例下跑很多代理 / 多条连接,每条连接都是一条 KCP,会有一定管理开销|QUIC 的多流 / 多路复用设计可以在一个连接上承载多个代理或多个数据流,更理想地减少连接数和开销|\n|实现稳定性 / Bug 风险|KCP 在 FRP 中被使用较久、成熟度较高,用户社区案例较多,参数调优经验丰富|QUIC 是相对较新、更复杂的模式,在 FRP 中可能还存在一些 bug 或限制;例如,有 issue 提到 “无法单独运行在 QUIC 模式” 的问题——无论是否配置 bind_port 字段,frps 总会监听 TCP 端口(这个 issue 在 FRP 的 issue 列表里被关闭为“不计划修复”)([GitHub](https://github.com/fatedier/frp/issues/3225?utm_source=chatgpt.com \"无法单独运行在quic模式 · Issue #3225 · fatedier/frp · GitHub\"))|\n|参数调优空间 / 灵活性|KCP 的很多参数(MTU、窗口、nodelay、重传策略等)都可以调,灵活性高;但需要手动调优以适应网络环境|QUIC 的很多机制是在协议内部做的(如流控、拥塞控制、加密层),对用户的参数调控空间可能较少(或复杂)|\n|适用场景|需要低延迟或在弱网络环境里工作的服务(如 SSH、RDP、交互式服务)|多流服务、HTTP(s) 代理、长连接传输、多代理复用、抗干扰场合等可能更适合|\n\n综合来看:如果你现在主要是用 FRP 来做一些 SSH、远程桌面、交互性强的服务,或者网络环境不稳定/丢包率高,KCP 模式可能是更稳定、可控的选择。而如果你需要让 FRP 在更复杂的网络环境下更具抗封锁性、更现代化、更高效,QUIC 模式是一个很有吸引力的选项。\n\n### 在 FRP 上使用时的注意与限制\n\n- 要让 QUIC / KCP 模式生效,你需要在 frps 和 frpc 两边都正确配置对应的端口(`quicBindPort` / `kcpBindPort` 等)与 `transport.protocol = \"quic\"` 或 `\"kcp\"`。否则默认仍用 TCP。 ([格态随记](https://blog.gotab.cn/archives/RvdYvu2g?utm_source=chatgpt.com \"Frp:服务端 frps.toml 和 frpc.toml 客户端配置文件详解\"))\n \n- 防火墙 / UDP 端口必须开放 — 因为 KCP / QUIC 都是在 UDP 上运行的,无法简单依赖 TCP。\n \n- 参数调优很关键:KCP 有很多参数(如 `nodelay`、`interval`、窗口大小、重传策略等)需要根据网络环境调整,否则可能效果不好或发生延迟爆炸。\n \n- QUIC 模式在 FRP 中可能还不够成熟 / 存在一些边界 bug。例如前面提到的 “无法单独运行在 QUIC 模式” 问题就是一个。 ([GitHub](https://github.com/fatedier/frp/issues/3225?utm_source=chatgpt.com \"无法单独运行在quic模式 · Issue #3225 · fatedier/frp · GitHub\"))\n \n- 在高带宽 / 长距离 /大流量场景下,KCP 模式可能表现不如预期,因为协议本身在大包 / 高延迟 + 数据量大时延迟会膨胀。实测中有用户发现,在延迟较高 + 发送大于 MTU 的数据场景下,QUIC 表现优于 KCP。 ([GitHub](https://github.com/xtaci/kcp-go/issues/204?utm_source=chatgpt.com \"对比TCP/QUIC/KCP的测试结果 · Issue #204 · xtaci/kcp-go - GitHub\"))\n \n- 加密开销:如果你还在 FRP 上启用 TLS / 加密,QUIC 本身就有加密,叠加可能有额外开销;KCP 则通常是裸或可选加密,开销可能较低。\n \n\n---\n\n## 总结 & 建议\n\n- **优势倾向** \n  - 若你更注重“稳定 + 可控 + 低延迟 + 在弱网环境下表现好”,KCP 是一个比较稳妥的选择(尤其已有成熟经验) \n  - 若你更希望未来扩展性强、支持多流、抗干扰 / 抗封锁能力更好、连接更现代化,QUIC 是更有前景的选择\n \n- **实用建议** \n  1. 在你的网络环境下做对比测试:部署一个用 KCP,一个用 QUIC,测一下延迟、丢包率、吞吐量、稳定性,哪一个更符合你的场景就用哪个。 \n  2. 若你目前已有稳定的 KCP 环境且能满足需求,不必急于切换;只有在遇到 TCP 被封锁 / 性能瓶颈 / 抗干扰需求时,再考虑 QUIC。 \n  3. 在启用 QUIC(或 KCP)模式时,务必留一个“回退”方案(例如保留 TCP 模式),以防 QUIC 模式在某些网络环境下连接失败 / 不稳定。 \n  4. 多关注 FRP 的版本更新、issue 列表,特别是关于 QUIC 模式的 bug 或兼容性问题。\n \n", + "内网穿透/内网穿透方案.md": "\n---\n\n## 一、开源替代方案 /工具清单\n\n下面是目前社区里比较流行 /有实用性的开源方案:\n\n|名称|语言 / 技术栈|支持协议 /功能|特点 /亮点|可能缺点 /注意|\n|---|---|---|---|---|\n|**rathole**|Rust|TCP / HTTP /TLS|轻量、高性能,内存占用低,支持热重载、服务令牌认证等。被设计为 FRP / ngrok 的替代品。 ([GitHub](https://github.com/rathole-org/rathole?utm_source=chatgpt.com \"GitHub - rathole-org/rathole: A lightweight and high-performance ...\"))|文档 /社区可能不如 FRP 那么成熟;一些边缘功能可能欠缺|\n|**NSmartProxy**|.NET Core / C#|TCP / HTTP 反向代理 /穿透|跨平台支持好,用异步 I/O 架构驱动穿透代理。 ([GitHub](https://github.com/tmoonlight/NSmartProxy?utm_source=chatgpt.com \"GitHub - tmoonlight/NSmartProxy: NSmartProxy是一款开源的内网穿透工具。采用.NET CORE ...\"))|在 Linux /非 .NET 平台上的稳定性 /优化要测试;社区规模可能偏小|\n|**Tunnelmole**|Node.js / TypeScript|HTTP / HTTPS 隧道|100% 开源、可自托管、方便给本地 Web 服务生成公开 URL。 ([tunnelmole.com](https://tunnelmole.com/?utm_source=chatgpt.com \"Tunnelmole - A free and open source tunneling tool\"))|主要面向 HTTP/HTTPS,游戏 /通用 TCP 服务可能支持不够好;对于高并发 /大流量性能需要评估|\n|**Reverse Proxy Tool(基于 Netty 的)**|Java / Netty|支持任意 TCP 上层协议和 HTTP|支持 HTTP 升级、SSL 验证、协议透传等功能。 ([Gitee](https://gitee.com/codebanks/reverse-proxy-tool?utm_source=chatgpt.com \"Reverse Proxy Tool: Reverse Proxy Tool : 基于Netty实现的 ...\"))|Java 程序可能资源占用较高;配置可能稍复杂;性能需要根据 JVM 优化|\n|**nps / NPS** / **lanproxy** / **holer**|Go /其他|TCP / HTTP /UDP 穿透、反向代理|在「开源内网穿透工具」合集 /对比文章里经常被提及。 ([laoliang.net](https://www.laoliang.net/jsjh/technology/14975.html?utm_source=chatgpt.com \"归纳几种免费开源的内网穿透工具(frp、holer、nps、lanproxy)\"))|各工具在稳定性、协议支持深度、社区维护度上有差别;需要逐个评估|\n|**reverse-tunnel(snsi nfu 的项目)**|(未知 /社区项目)|公网 → 私网 隧道 /映射|提供反向隧道映射能力,据社区介绍可以做安全隧道。 ([CSDN.blog](https://blog.csdn.net/gitblog_01080/article/details/141481391?utm_source=chatgpt.com \"反向隧道工具 reverse-tunnel 使用指南-CSDN博客\"))|项目可能成熟度不高,文档 /示例可能不足;功能边界需自己测试|\n|**tiny-frpc**|Go / 精简 FRP 客户端|frp 协议子集|体积小、适合资源紧张的嵌入式 /小设备使用。 ([博客园](https://www.cnblogs.com/tang863/p/18274521?utm_source=chatgpt.com \"tiny-frpc: frp 反向代理精简版客户端 - AmbiaCode - 博客园\"))|只是 frpc 的子集,用于客户端,不是完整替代;功能限制较多|\n\n---\n\n", + "内网穿透/搭建derp和headscale避坑与指南.md": "derp(Docker安装):\n\n```bash\n#Docker容器一键化启动\n#默认开启tcp端口33445 udp端口3478\ndocker run --restart always \\\n --name derper1 \\\n -p 33445:33445 \\\n -p 3478:3478/udp \\\n -v /shumengya/ssl/derp1/:/app/certs \\\n -e DERP_CERT_MODE=manual \\\n -e DERP_ADDR=:33445 \\\n -e DERP_DOMAIN=derp1.shumengya.top \\\n -e DERP_CERT_FILE=/app/certs/derp1.shumengya.top.crt \\\n -e DERP_KEY_FILE=/app/certs/derp1.shumengya.top.key \\\n -d ghcr.io/yangchuansheng/derper:latest\n \n docker run --restart always \\\n --name derper2 \\\n -p 33445:33445 \\\n -p 3478:3478/udp \\\n -v /shumengya/ssl/derp2/:/app/certs \\\n -e DERP_CERT_MODE=manual \\\n -e DERP_ADDR=:33445 \\\n -e DERP_DOMAIN=derp2.shumengya.top \\\n -e DERP_CERT_FILE=/app/certs/derp2.shumengya.top.crt \\\n -e DERP_KEY_FILE=/app/certs/derp2.shumengya.top.key \\\n -d ghcr.io/yangchuansheng/derper:latest\n \ndocker run --restart always \\\n --name derper3 \\\n -p 33445:33445 \\\n -p 3478:3478/udp \\\n -v /shumengya/ssl/derp3/:/app/certs \\\n -e DERP_CERT_MODE=manual \\\n -e DERP_ADDR=:33445 \\\n -e DERP_DOMAIN=derp3.shumengya.top \\\n -e DERP_CERT_FILE=/app/certs/derp3.shumengya.top.crt \\\n -e DERP_KEY_FILE=/app/certs/derp3.shumengya.top.key \\\n -d ghcr.io/yangchuansheng/derper:latest\n\n```\n\n```bash\n#默认使用Let's Encrypt签发ssl证书\n#默认需要关闭nginx占用80端口来签发证书\ncurl -s https://get.acme.sh | sh\n\nsource ~/.bashrc\n\nacme.sh --issue --standalone -d 你的域名\n#安装依赖\napt update && apt install -y socat\nyum install -y socat\ndnf install -y socat\n\nacme.sh --register-account -m 你的邮箱地址\n```\n\n\nheadscale(直接部署systemctl运行):\n\nheadscale默认放行:9090~9092 和50443\n\n配置一个域名:\nheadscale.shumengya.top\n下载headscale:[https://github.com/juanfont/headscale](headscale)\n下载headscale-ui:[https://github.com/juanfont/headscale](headscale-ui)\n\n新建文件夹(用来放相关文件):\nmkdir -p shumengya/headscale\n\n安装headscale:\ndpkg -i headscale_0.26.1_linux_amd64.deb\n\n修改headscale配置\n```yaml\n---\n# headscale 会按照以下顺序查找名为 `config.yaml` (或 `config.json`) 的配置文件:\n#\n# - `/etc/headscale`\n# - `~/.headscale`\n# - 当前工作目录\n\n# 客户端将要连接的 URL。\n# 通常应为一个域名,例如:\n#\n# https://myheadscale.example.com:443\n#\nserver_url: http://127.0.0.1:9091\n\n# 服务器监听/绑定的地址\n#\n# 生产环境建议:\nlisten_addr: 0.0.0.0:9092\n#listen_addr: 127.0.0.1:8080\n\n# /metrics 和 /debug 的监听地址,你可能希望\n# 将此端点限制在内网\nmetrics_listen_addr: 127.0.0.1:9090\n\n# gRPC 的监听地址。\n# gRPC 用于通过 CLI 远程控制 headscale 服务器\n# 注意:只有在使用有效证书时,远程访问才可用。\n#\n# 生产环境建议:\ngrpc_listen_addr: 0.0.0.0:50443\n#grpc_listen_addr: 127.0.0.1:50443\n\n# 是否允许 gRPC 管理接口以 **不安全** 模式运行。\n# 不推荐启用,因为流量将不加密。只有在你完全理解风险时才启用。\ngrpc_allow_insecure: false\n\n# Noise 部分包含 TS2021 Noise 协议的特定配置\nnoise:\n # Noise 私钥用于在 headscale 和 Tailscale 客户端之间\n # 使用新的基于 Noise 的协议加密流量。缺少的密钥将会自动生成。\n private_key_path: /var/lib/headscale/noise_private.key\n\n# 为 tailnet 分配地址的 IP 前缀列表。\n# 每个前缀由 IPv4 或 IPv6 地址 + 前缀长度组成,以斜杠分隔。\n# 必须在 Tailscale 客户端支持的范围内\n# 即 100.64.0.0/10 和 fd7a:115c:a1e0::/48 的子网。\n# 否则会导致异常问题。\nprefixes:\n v4: 100.64.0.0/10\n #v6: fd7a:115c:a1e0::/48\n\n # 节点 IP 分配策略,可选:\n # - sequential(默认):按顺序分配下一个可用 IP\n # - random:使用伪随机生成器分配可用 IP\n allocation: sequential\n\n# DERP 是 Tailscale 在无法建立直连时使用的中继系统。\n# https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp\n#\n# headscale 需要一个 DERP 服务器列表供客户端使用。\nderp:\n server:\n # 启用后,将运行内置 DERP 服务器并合并到 DERP 配置中\n # 上面的 server_url 必须使用 https,DERP 需要 TLS\n enabled: false\n\n # 内置 DERP 服务器的区域 ID。\n # 如果与外部配置的区域 ID 冲突,则本地 DERP 优先。\n region_id: 999\n\n # 区域代码和名称会在 Tailscale UI 中显示\n region_code: \"headscale\"\n region_name: \"Headscale Embedded DERP\"\n\n # 在指定地址上监听 UDP 端口以支持 STUN 连接(帮助 NAT 穿透)。\n # 如果启用内置 DERP,必须定义 stun_listen_addr。\n #\n # 更多详情可参考:https://tailscale.com/blog/how-tailscale-works/\n stun_listen_addr: \"0.0.0.0:3478\"\n\n # 用于加密 headscale DERP 与 Tailscale 客户端之间流量的私钥。\n # 缺少时会自动生成。\n private_key_path: /var/lib/headscale/derp_server_private.key\n\n # 此标志用于控制是否自动将内置 DERP 写入 DERP map。\n # 若设为 false,则需通过 DERP.paths 手动配置。\n automatically_add_embedded_derp_region: true\n\n # 为了更稳定的连接(特别是 Exit-Node + DNS 不可用时),\n # 可以选择性地将公网 IPv4/IPv6 地址写入 Derp-Map:\n ipv4: 1.2.3.4\n ipv6: 2001:db8::1\n\n # 外部可用的 DERP map 列表(JSON 格式)\n urls:\n # - https://controlplane.tailscale.com/derpmap/default\n #- https://你的域名/web/derp.json\n\n # 本地可用的 DERP map 文件(YAML 格式)\n #\n # 对于自建 DERP 服务器很有用:\n # https://tailscale.com/kb/1118/custom-derp-servers/\n #\n # paths:\n # - /etc/headscale/derp-example.yaml\n paths: []\n\n # 若启用,将定期刷新上述 DERP 源并更新 derpmap\n auto_update_enabled: true\n\n # 检查 DERP 更新的间隔\n update_frequency: 24h\n\n# 禁用启动时自动检查 headscale 更新\ndisable_check_updates: false\n\n# 非活跃临时节点在多久后被删除?\nephemeral_node_inactivity_timeout: 30m\n\ndatabase:\n # 数据库类型,可选:sqlite, postgres\n # 注意:强烈不推荐使用 Postgres,仅为遗留原因保留。\n # 所有新开发和优化都基于 SQLite。\n type: sqlite\n\n # 启用调试模式。需要 log.level 设置为 \"debug\" 或 \"trace\"。\n debug: false\n\n # GORM 配置\n gorm:\n # 启用预编译语句。\n prepare_stmt: true\n\n # 启用参数化查询。\n parameterized_queries: true\n\n # 跳过 “record not found” 错误日志。\n skip_err_record_not_found: true\n\n # 慢查询阈值(毫秒)\n slow_threshold: 1000\n\n # SQLite 配置\n sqlite:\n path: /var/lib/headscale/db.sqlite\n\n # 启用 WAL 模式。推荐生产环境启用。\n # https://www.sqlite.org/wal.html\n write_ahead_log: true\n\n # WAL 文件在达到多少帧时自动 checkpoint。\n # 设为 0 可禁用自动 checkpoint。\n wal_autocheckpoint: 1000\n\n # # Postgres 配置(不推荐,仅遗留支持)\n # postgres:\n # # 使用 Unix socket 时,设置 host 为 socket 路径,port 留空。\n # host: localhost\n # port: 5432\n # name: headscale\n # user: foo\n # pass: bar\n # max_open_conns: 10\n # max_idle_conns: 10\n # conn_max_idle_time_secs: 3600\n #\n # # SSL 配置,参考官方文档\n # ssl: false\n\n### TLS 配置\n#\n## Let's Encrypt / ACME\n#\n# headscale 支持使用 Let's Encrypt 自动申请 TLS 证书\n#\n# ACME 目录 URL\nacme_url: https://acme-v02.api.letsencrypt.org/directory\n\n# ACME 注册邮箱\nacme_email: \"\"\n\n# 要申请 TLS 证书的域名\ntls_letsencrypt_hostname: \"\"\n\n# 存储证书和元数据的路径\n# 生产环境建议:\ntls_letsencrypt_cache_dir: /var/lib/headscale/cache\n\n# ACME 挑战类型,目前支持:\n# HTTP-01 或 TLS-ALPN-01\n# 详见 docs/ref/tls.md\ntls_letsencrypt_challenge_type: HTTP-01\n# 使用 HTTP-01 时,letsencrypt 必须监听:\n# :http = 80 端口\ntls_letsencrypt_listen: \":http\"\n\n## 使用已有证书\ntls_cert_path: \"\"\ntls_key_path: \"\"\n\nlog:\n # 日志输出格式:text 或 json\n format: text\n # 日志级别:info, debug, trace\n level: info\n\n## 策略\n# headscale 支持 Tailscale 的 ACL 策略\n# 文档:https://tailscale.com/kb/1018/acls/\npolicy:\n # 模式:file 或 database\n mode: file\n # 若为 file 模式,指定 HuJSON 文件路径\n path: \"\"\n\n## DNS\n#\n# headscale 支持 Tailscale 的 DNS 配置和 MagicDNS。\n# 文档:\n# https://tailscale.com/kb/1054/dns/\n# https://tailscale.com/kb/1081/magicdns/\n# https://tailscale.com/blog/2021-09-private-dns-with-magicdns/\n#\n# 注意:要使 DNS 配置生效,客户端必须启用 `--accept-dns=true`。\n# 否则将不生效。\ndns:\n # 是否启用 MagicDNS\n magic_dns: true\n\n # MagicDNS 的基础域名,必须与 server_url 域名不同。\n base_domain: example.com\n\n # 是否覆盖本地 DNS 设置\n override_local_dns: false\n\n # 全局 DNS 服务器列表\n nameservers:\n global:\n - 1.1.1.1\n - 1.0.0.1\n - 2606:4700:4700::1111\n - 2606:4700:4700::1001\n # NextDNS 示例\n # - https://dns.nextdns.io/abc123\n\n # Split DNS 示例(为特定域使用不同 DNS)\n split: {}\n\n # 自定义搜索域\n search_domains: []\n\n # 额外 DNS 记录(支持 A/AAAA)\n extra_records: []\n # - name: \"grafana.myvpn.example.com\"\n # type: \"A\"\n # value: \"100.64.0.3\"\n\n# CLI 使用的 Unix socket(无认证)\n# 生产环境建议自定义\nunix_socket: /var/run/headscale/headscale.sock\nunix_socket_permission: \"0770\"\n\n# OpenID Connect 配置(实验功能)\n# oidc:\n# only_start_if_oidc_is_available: true\n# issuer: \"https://your-oidc.issuer.com/path\"\n# client_id: \"your-oidc-client-id\"\n# client_secret: \"your-oidc-client-secret\"\n# client_secret_path: \"${CREDENTIALS_DIRECTORY}/oidc_client_secret\"\n# expiry: 180d\n# use_expiry_from_token: false\n# scope: [\"openid\", \"profile\", \"email\", \"custom\"]\n# extra_params:\n# domain_hint: example.com\n# allowed_domains:\n# - example.com\n# allowed_groups:\n# - /headscale\n# allowed_users:\n# - alice@example.com\n# pkce:\n# enabled: false\n# method: S256\n\n# Logtail 配置\n# Logtail 是 Tailscale 的日志与审计系统\nlogtail:\n # 启用后,客户端将日志发送到 Tailscale 服务器\n enabled: false\n\n# 启用后,设备将优先使用随机端口进行 WireGuard 流量\n# 以避免某些防火墙兼容性问题。\n# 详见:https://tailscale.com/kb/1181/firewalls/\nrandomize_client_port: false\n\n\n```\n\n设置反向代理:\n公网域名->127.0.0.1:9092\n```txt\nlocation /web {\n index index.html;\n alias /shumengya/headscale/web;\n}\n```\n\n\n\n\n\n", + "实习求职/27双非本一腾讯IEG游戏安全后台实习面经.md": "timeline:\n9.16 一面\n9.18 二面\n9.22 三面\n9.23 HR面\n9.24 录用评估\n9.26 Offer\n\n腾讯一面(1h)\n\n1. 介绍实习需求(K8S 和 Casbin RBAC 相关)\n2. 为啥初创实习两个月离职\n3. Go 为什么支持高并发\n4. GMP模型原理\n5. Goroutine Work-Stealing 的目的\n6. P的角色的作用,如果在M上维护Goroutine队列有什么不好\n7. GMP对CPU密集型任务能提高并发么\n8. IO操作需要CPU么,什么时候需要,磁盘IO和网络IO的区别\n9. Channel的作用和底层实现\n10. Channel的缓冲区在用户态还是内核态\n11. Goroutine阻塞等待的时候由谁来唤醒,需要额外的goroutine来遍历所有的channel么\n12. M上的G0是干嘛的\n13. 介绍select/poll/epoll\n14. 网络IO的流程\n15. 了解过Go Runtime么\n\n算法:求两个数的最大公约数\n\n腾讯二面(1h)\n\n1. 介绍实习需求,最有挑战的部分\n2. RocksDB了解么,说一下LsmTree\n3. 详细介绍一下Raft协议\n4. Raft协议和Paxos协议的区别,有哪些优化\n5. 介绍一下React Agent\n6. LangChain 和 LangGraph 的区别\n7. Agent 和 LLM 的区别\n8. Function Call 和 MCP 的区别\n9. RPC的全流程\n10. 负载均衡算法有哪些\n11. 介绍一致性Hash算法,服务扩缩容之后有什么影响\n12. 网络编程\n13. 介绍一下TCP和UDP\n14. 介绍一下HTTP各个版本及实现\n\n算法:\n\n1. 编辑距离\n2. 两两交换链表中的节点\n\n腾讯三面(30min)\n\n1. 介绍实习,你做了什么\n2. 介绍项目\n3. 实习时长,到岗时间,推HR面\n\n腾讯HR面(15min)\n\n1. 离职原因\n2. 实习时长,到岗时间\n3. 聊聊天", + "实习求职/术语科普-HC.md": "“hc” 是英文 “Head Count” 的缩写,核心含义是“人员编制”,指企业或团队中计划招聘、核定的岗位人数,并非已入职的实际人数。\n \n在不同场景下还有其他常见含义,具体需结合语境判断:\n \n- 职场/招聘场景:最常用含义为“人员编制”,例如“这个部门今年还有2个hc”,即该部门今年仍有2个招聘名额。\n- 医学场景:可指“血红蛋白浓度(Hemoglobin Concentration)”,是血常规检查中评估是否贫血的重要指标。\n- 网络用语:偶尔作为“喝彩(hè cǎi)”的拼音首字母缩写,用于表达支持、夸赞,常见于社交平台评论区。", + "实习求职/术语科普-PM.md": "“pm” 是多义词缩写,核心含义需结合具体场景判断,最常见的有以下三类:\n \n- 时间场景:全称为 “Post Meridiem”,指一天中的“下午”,与表示“上午”的“am”(Ante Meridiem)对应,例如“3 pm”即“下午3点”。\n- 职场/业务场景:最常用含义为 “Product Manager”,即“产品经理”,负责产品的规划、设计、迭代及市场推广等全流程工作;也可指 “Project Manager”,即“项目经理”,主要负责项目的计划、执行与交付,确保项目按时按质完成。\n- 其他场景:在通信或社交语境中,还可表示 “Private Message”,即“私信”,例如“有问题可以pm我”,意为“有问题可以给我发私信”。", + "实习求职/面试八股/HTTP 与HTTPS/从「敲下一个 URL」到「页面出现在屏幕」整条链路全景.md": "", + "实习求职/面试八股/Nacos功能与应用场景详解.md": "Nacos 是阿里巴巴开源的 **动态服务发现、配置管理与服务治理平台**,旨在简化微服务架构的构建、交付和管理。\n\n---\n\n## 🚀 核心功能\n\n| 功能 | 主要作用 |\n|------|----------|\n| 🎯 **服务注册与发现** | 服务提供者注册自身信息,服务消费者动态发现和调用其他服务。 |\n| ⚙️ **动态配置管理** | 集中管理所有环境的配置,支持实时推送变更,无需重启应用。 |\n| 🔍 **服务健康监测** | 定期检查服务实例健康状况,自动隔离不健康实例,保障系统稳定性。 |\n| 🚦 **动态DNS与流量管理** | 支持权重路由,助力灰度发布、蓝绿部署等高级流量管理策略。 |\n\n---\n\n## 🎯 服务发现与健康检查\n\n- **服务注册**:实例启动时向 Nacos 注册自身元数据(服务名、IP、端口等)。 \n- **服务发现**:消费者通过服务名查询健康实例,实现通信而无需关心具体地址。 \n- **健康检查**:支持客户端上报与服务端主动探测,自动剔除不健康实例,保障可靠性。 \n\n---\n\n## ⚙️ 动态配置管理\n\n- **集中化管理**:统一存储数据库连接、开关、限流阈值等配置。 \n- **动态刷新**:配置变更实时推送,应用可在运行中直接生效(热更新)。 \n- **版本控制与回滚**:支持历史版本,一键回滚,降低变更风险。 \n\n---\n\n## 🚦 动态DNS与服务治理\n\n- **动态DNS服务**:支持权重路由、流量控制和简易内网 DNS 解析。 \n- **服务与元数据管理**:统一管理服务描述、依赖关系、健康状态、流量及安全策略。 \n\n---\n\n## 💡 主要应用场景\n\n- **数据库配置集中化管理**:提升安全性与合规性。 \n- **限流与降级开关**:结合 Sentinel 等组件实现运行时动态调整。 \n- **多环境与多数据中心**:基于 Namespace 与 Group 实现隔离与灵活部署。 \n\n---\n\n## 📊 与其他组件对比\n\n- ✅ **功能更全面**:Nacos = 服务发现 + 配置管理;Eureka 仅支持服务发现。 \n- ✅ **健康检查机制更强**:优于 Eureka 心跳检测。 \n- ✅ **社区与生态活跃**:Eureka 已停止维护,而 Nacos 持续迭代。 \n- ✅ **多数据中心支持优越**:原生支持多数据中心部署。 \n\n---\n\n## 📚 总结\n\nNacos 集 **服务发现、配置管理、服务治理** 于一体, \n极大简化了微服务架构复杂性,提升了 **开发效率**、**可维护性** 和 **系统弹性**。\n\n---", + "实习求职/面试八股/计算机面试经典八股.md": "+好的!计算机面试中最经典、最高频的“八股文”主要围绕以下几个核心领域展开。掌握这些基础知识和原理是通关技术面试的关键:\n\n## 🧠 一、 数据结构与算法\n\n1. **基础数据结构:**\n * **数组 vs 链表:** 内存结构、访问/插入/删除时间复杂度、适用场景。\n * **栈(Stack) & 队列(Queue):** LIFO/FIFO 原理、实现方式(数组/链表)、应用场景(函数调用栈、BFS/DFS)。\n * **哈希表(Hash Table):** 原理(哈希函数、冲突解决-开放寻址/链地址法)、时间复杂度分析、负载因子、扩容机制。\n * **堆(Heap) / 优先队列(Priority Queue):** 结构(通常是二叉堆)、操作(插入、删除堆顶、堆化)、应用(Top K、中位数、Dijkstra)。\n * **树(Tree):**\n * 二叉树(Binary Tree):遍历(前序、中序、后序、层序)- 递归与非递归实现。\n * 二叉搜索树(BST):定义、查找、插入、删除、中序遍历有序性。\n * 平衡二叉搜索树(AVL / 红黑树):平衡因子/红黑规则、旋转操作、为什么需要(避免BST退化成链表)、应用(Java HashMap的TreeBin/TreeMap)。\n * **图(Graph):** 表示方法(邻接矩阵、邻接表)、遍历算法(BFS、DFS)、常见算法(拓扑排序、最短路径-Dijkstra/Bellman-Ford/Floyd、最小生成树-Prim/Kruskal)。\n\n2. **基础算法思想:**\n * **排序算法:**\n * 比较排序:**快速排序**(分治、选基准、partition过程、时间复杂度-最好O(nlogn)/最坏O(n²)/平均、空间复杂度、稳定性❌)、**归并排序**(分治、稳定✅、时间复杂度O(nlogn)、空间复杂度O(n))、**堆排序**(建堆O(n)、排序O(nlogn)、不稳定❌)、插入排序、冒泡排序、选择排序(原理、时间复杂度)。\n * 非比较排序:计数排序、桶排序、基数排序(思想、适用场景)。\n * **搜索算法:** **二分查找**(前提有序、循环/递归实现、变种问题-找第一个/最后一个/旋转数组)。\n * **递归 & 分治:** 思想、经典问题(斐波那契、汉诺塔、归并/快排)。\n * **贪心算法(Greedy):** 思想(局部最优->全局最优?)、适用场景(活动选择、霍夫曼编码、最小生成树-Prim/Kruskal)、与动态规划区别。\n * **动态规划(DP):** **核心思想**(最优子结构、重叠子问题、状态转移方程)、**解题步骤**(定义状态、状态转移、初始化、边界、输出)、**经典问题**(斐波那契、爬楼梯、背包问题01/完全、最长公共子序列LCS、最长递增子序列LIS、编辑距离、股票买卖系列)。\n * **回溯(Backtracking):** 思想(试错、DFS+剪枝)、经典问题(N皇后、全排列、组合、子集、数独)。\n * **双指针(Two Pointers):** 应用(有序数组两数之和、滑动窗口-最小覆盖子串/最长无重复子串、快慢指针-链表判环/找中点)。\n * **位运算(Bit Manipulation):** 常用操作(与、或、异或、非、移位)、常见技巧(判断奇偶、交换两数、找出只出现一次的数字、位1的个数)。\n\n## 🖥 二、 操作系统\n\n1. **进程与线程:**\n * 进程 vs 线程(定义、资源分配、切换开销、通信方式)。\n * **进程间通信(IPC):** 管道、命名管道、信号、消息队列、共享内存、信号量、套接字。\n * **线程同步机制:** **互斥锁(Mutex)**、**信号量(Semaphore)**、**条件变量(Condition Variable)**、读写锁(Read-Write Lock)、自旋锁(Spin Lock)(原理、适用场景、死锁避免)。\n * **死锁(Deadlock):** 必要条件(互斥、请求与保持、不可剥夺、环路等待)、预防策略、避免策略(银行家算法)、检测与恢复。\n2. **内存管理:**\n * **虚拟内存(Virtual Memory):** 为什么需要?分页(Paging)机制(页表、TLB快表)、分段(Segmentation)机制。\n * **页面置换算法:** **最佳置换(OPT)**、**先进先出(FIFO)**、**最近最久未使用(LRU)**、时钟算法(Clock) 的原理和优缺点。\n * **内存分配:** 伙伴系统(Buddy System)、Slab分配器。\n3. **文件系统:** 文件描述符(File Descriptor)、inode结构、文件存储方式(连续、链式、索引)、目录结构。\n4. **CPU调度:** 调度算法(FCFS、SJF、优先级、RR轮转、多级反馈队列)的目标和特点。\n5. **I/O模型:** 阻塞I/O、非阻塞I/O、I/O多路复用(select/poll/epoll)、信号驱动I/O、异步I/O(AIO) 的区别和比较(特别是epoll的优势)。\n\n## 🌐 三、 计算机网络\n\n1. **网络模型:** **OSI七层模型** 和 **TCP/IP四层模型** 各层功能、对应协议。\n2. **核心协议:**\n * **TCP vs UDP:** 根本区别(连接、可靠性、有序性、流量控制、拥塞控制)、头部结构、应用场景。\n * **TCP可靠传输:** 序号/确认号、超时重传、滑动窗口机制。\n * **TCP连接管理:** **三次握手**(详细过程、为什么是三次?)、**四次挥手**(详细过程、为什么是四次?TIME_WAIT状态的作用?)。\n * **TCP流量控制:** 滑动窗口机制。\n * **TCP拥塞控制:** 慢启动(Slow Start)、拥塞避免(Congestion Avoidance)、快速重传(Fast Retransmit)、快速恢复(Fast Recovery) 算法原理。\n * **HTTP:**\n * 请求方法(GET/POST/PUT/DELETE等区别)、状态码(1xx/2xx/3xx/4xx/5xx常见状态码含义)。\n * **HTTP/1.0 vs HTTP/1.1 vs HTTP/2 vs HTTP/3:** 主要改进(连接复用、头部压缩、服务器推送、QUIC协议)。\n * **HTTPS:** SSL/TLS协议作用、加密过程(非对称加密交换对称密钥、对称加密通信)、数字证书作用。\n * **DNS:** 作用、查询过程(递归、迭代)、记录类型(A、AAAA、CNAME、MX、NS)。\n3. **网络安全基础:**\n * **对称加密 vs 非对称加密:** 原理、优缺点、代表算法(AES、RSA)。\n * **数字签名 & 数字证书:** 作用、原理(私钥签名,公钥验签;CA中心颁发证书)。\n * 常见攻击:XSS、CSRF、SQL注入、DDoS、中间人攻击的原理和基本防御措施。\n4. **网络层:** IP协议、IP地址分类/子网划分/CIDR、ARP协议、路由协议(RIP、OSPF、BGP基本思想)。\n5. **传输层与应用层:** 端口号作用、Socket编程基础。\n\n## 🗃 四、 数据库(以关系型数据库 MySQL 为主)\n\n1. **SQL基础:** 常用语句(SELECT, INSERT, UPDATE, DELETE, JOIN, GROUP BY, HAVING, ORDER BY, LIMIT)、多表连接(INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN)。\n2. **索引(Index):**\n * **为什么需要索引?** 加速查询。\n * **数据结构:** **B+树**(为什么比B树更适合数据库?)、哈希索引(适用场景)。\n * **聚簇索引(Clustered Index) vs 非聚簇索引(Non-Clustered Index / Secondary Index):** 根本区别(叶子节点是否存储完整行数据)、InnoDB实现。\n * **索引优化:** 覆盖索引、最左前缀原则、索引下推(ICP)。\n * **索引失效场景:** 函数操作、类型转换、`LIKE '%xx'`、OR条件(部分情况)、不等于(!=, <>)、索引列计算。\n3. **事务(Transaction):**\n * **ACID特性:** 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability) 的含义。\n * **隔离级别(Isolation Level):** **读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read - MySQL默认)、串行化(Serializable)**。每个级别能解决哪些并发问题(脏读、不可重复读、幻读)?\n * **并发问题:** 脏读、不可重复读、幻读的定义。\n * **MVCC(多版本并发控制):** 原理(Undo Log、Read View)、如何实现RC和RR级别(特别是RR如何解决幻读?)。\n4. **锁(Locking):** 共享锁(S锁/读锁)、排他锁(X锁/写锁)、意向锁、行锁、表锁、间隙锁(Gap Lock)、临键锁(Next-Key Lock)的作用和应用场景(特别是InnoDB如何解决幻读)。\n5. **日志(Logging):**\n * **Redo Log(重做日志):** 作用(保证持久性、Crash-Safe)、Write-Ahead Logging(WAL)机制。\n * **Undo Log(回滚日志):** 作用(保证原子性、实现MVCC)。\n * **Binlog(归档日志):** 作用(主从复制、数据恢复)、格式(Statement/Row/Mixed)。\n6. **数据库设计:** 三大范式(1NF, 2NF, 3NF)基本概念、反范式化设计场景。\n7. **性能优化:** Explain分析SQL执行计划、慢查询优化思路。\n\n## 📐 五、 系统设计(面向中高级岗位)\n\n1. **设计原则:** KISS, YAGNI, DRY, SOLID (尤其是单一职责、开闭原则)。\n2. **方法论:**\n * 需求澄清(功能需求、非功能需求-性能/可用性/扩展性/一致性/容错性/安全性)。\n * 估算(QPS、TPS、存储量、带宽)。\n * 抽象与模块化。\n * 核心组件设计(API、数据模型、存储方案、算法)。\n * 深入细节(扩展性、可靠性、性能优化)。\n3. **常见组件与模式:**\n * 负载均衡(LB: Nginx, HAProxy, LVS)。\n * 缓存(Cache: Redis, Memcached)- 缓存策略(Cache Aside, Read/Write Through, Write Behind)、缓存穿透/击穿/雪崩及解决方案。\n * 消息队列(MQ: Kafka, RabbitMQ, RocketMQ)- 解耦、异步、削峰填谷、保证最终一致性。\n * 数据库扩展:读写分离、分库分表(水平/垂直拆分)、分区。\n * 分布式ID生成(Snowflake算法)。\n * 分布式一致性协议:**CAP理论**、**BASE理论**、**Raft/Paxos**(选主、日志复制)基本原理(理解核心思想即可,不要求推导)。\n * 微服务架构:服务注册与发现(Eureka, Nacos, Consul)、API网关(Gateway)、配置中心、服务调用(RPC/REST)、熔断限流(Hystrix, Sentinel)。\n4. **经典系统设计题:** 设计Twitter/微博、设计短链系统、设计秒杀系统、设计分布式缓存、设计搜索引擎、设计聊天系统等。\n\n## 🐍 六、 编程语言特性(根据应聘语言选择)\n\n1. **面向对象(OOP):** 封装、继承、多态、抽象类 vs 接口、重载 vs 重写。\n2. **内存管理:** 垃圾回收(GC)原理(标记清除、复制、标记整理、分代收集-G1/ZGC)、引用类型(强引用、软引用、弱引用、虚引用)。\n3. **并发编程:** 线程生命周期、创建方式、线程池(核心参数、工作流程、拒绝策略)、锁(Synchronized底层原理、Lock/Condition)、并发容器(ConcurrentHashMap原理-CAS+synchronized+分段锁思想)、原子类(CAS操作、ABA问题)、线程间通信。\n4. **语言特性:** 如Java的JVM内存区域、类加载机制、反射、异常体系、集合框架(HashMap源码:put/get流程、扩容、JDK1.7 vs 1.8+);Python的GIL、装饰器、生成器、鸭子类型;Go的Goroutine、Channel、defer等。\n\n## 📌 关键点提醒\n\n1. **理解原理,而非死记硬背:** 面试官更关注你是否真正理解了背后的思想(为什么用这个?解决了什么问题?优缺点是什么?)。\n2. **联系实际:** 思考这些知识在实际系统/项目中是如何应用的。\n3. **清晰表达:** 能条理清晰、简洁准确地阐述概念和过程。\n4. **动手实践:** 算法题要动手写,数据库要会写SQL,系统设计要多思考多画图。\n5. **关注细节:** 很多问题会深入到具体实现细节(如HashMap冲突解决、ConcurrentHashMap分段锁演变、MySQL RR级别如何避免幻读、TCP TIME_WAIT)。\n6. **追踪发展:** 了解一些新技术趋势(如HTTP/3, QUIC, eBPF, 云原生, Serverless)的基本概念。\n\n这份清单涵盖了计算机面试中最核心、最高频的基础知识点。针对具体岗位(前端、后端、算法、运维、测试等)", "嵌入式/USB拓展坞接口数量决定因素.md": "一个USB拓展坞(或集线器)能拓展多少个USB接口,主要由以下几个因素决定:\n \n1. USB协议规范与层级限制\n \n- USB主机控制器的能力:电脑本身的USB主机控制器(如主板上的控制器)决定了初始可连接的设备数量。根据USB规范,一个主机控制器理论上最多可连接 127个设备,但这是通过多级集线器级联实现的(例如主机→一级集线器→二级集线器→……)。\n- 单级集线器的端口数:单个集线器(如拓展坞)的直接端口数通常为 4、7、10个 等,这是由集线器芯片的设计决定的。例如,常见的4口集线器是单芯片直接支持的标准配置。\n \n2. 集线器芯片的硬件设计\n \n- 主控芯片的能力:不同型号的集线器芯片(如瑞萨、德州仪器等品牌)支持的端口数量不同。芯片内部集成的物理接口数量和信号处理能力直接限制了拓展坞的端口数。\n- 信号分配与带宽共享:USB接口共享总线带宽(如USB 3.0的5Gbps),过多端口可能导致带宽不足。因此,芯片设计时会平衡端口数与性能,避免过多端口导致速度下降。\n \n3. 电源供应能力\n \n- 主机供电 vs 外接电源:\n- 无外接电源(总线供电):依赖电脑USB端口的功率(USB 2.0约500mA,USB 3.0约900mA)。若拓展坞无外接电源,总功率需低于主机端口上限,否则可能因供电不足导致设备无法工作(例如连接多个移动硬盘时易出现问题)。\n- 有外接电源(自供电):通过适配器供电,可支持更多高功耗设备,端口数主要受芯片和设计限制。\n- 单端口功率限制:每个USB端口需符合规范(如USB 2.0单端口最大500mA,USB 3.0最大900mA),总功率需在集线器设计的安全范围内。\n \n4. 信号传输与物理限制\n \n- 信号衰减与稳定性:USB信号在长距离或多端口分支中会衰减,尤其是高速率信号(如USB 3.0以上)。拓展坞的电路设计需保证信号完整性,过多端口可能增加干扰风险,因此实际端口数会受限于硬件可靠性。\n- 物理空间与布局:拓展坞的体积和接口排列也会影响端口数量,例如小型便携拓展坞通常设计为4口,而桌面级集线器可能有7-10个端口。\n \n5. 厂商设计与市场需求\n \n- 用户场景导向:厂商会根据目标用户(如普通办公、专业外设连接)设计端口数。例如,针对轻薄本的拓展坞可能集成4-6个端口(兼顾便携性和实用性),而工业级集线器可能支持更多端口。\n- 成本与性价比:更多端口意味着更高的芯片和制造成本,厂商需在功能与价格间平衡。\n \n总结\n \n核心决定因素:\n \n- USB协议的层级与单集线器端口限制\n- 集线器芯片的硬件设计(端口数、带宽分配)\n- 电源供应能力(是否外接电源及总功率)\n- 信号传输的稳定性与物理空间限制\n \n实际中,常见的USB拓展坞多为 4-7个端口,高端或专用集线器可能支持更多(如10口以上),但需结合外接电源和高效的芯片方案来保证性能。", + "嵌入式/光纤和网线的特点和区别.md": "\n## 一、 核心区别:传输原理\n\n1. **光纤 (Fiber Optic Cable):**\n * **原理:** 利用光脉冲在极细的玻璃或塑料纤维中进行传输。\n * **信号:** 光信号(激光或LED)。\n * **介质:** 玻璃纤维芯(核心)和包层(折射率不同,实现全反射)。\n\n2. **网线 (双绞线 - Twisted Pair Cable):**\n * **原理:** 利用电信号在相互缠绕的铜线中进行传输。\n * **信号:** 电信号。\n * **介质:** 铜导体(通常为4对双绞线)。\n\n## 二、 关键特点对比\n\n| 特性 | 光纤 (Fiber Optic) | 网线/双绞线 (Twisted Pair) |\n| :--------------- | :----------------------------------------------------- | :----------------------------------------------------- |\n| **传输原理** | **光信号** | **电信号** |\n| **传输介质** | 玻璃纤维芯 + 包层 | 铜线 |\n| **带宽/速度** | **极高**。理论上可达Tbps级别,远超双绞线。常用10Gbps, 40Gbps, 100Gbps甚至更高。 | **相对较低**。受限于铜线物理特性(趋肤效应、串扰)。常用1Gbps, 10Gbps(短距离)。 |\n| **传输距离** | **非常远**。单模光纤可达几十甚至上百公里(无需中继)。多模光纤可达几百米到几公里。 | **较短**。Cat5e/Cat6:100米(千兆)。Cat6a/Cat7:100米(万兆)。距离越长,信号衰减和失真越严重。 |\n| **抗干扰能力** | **极强**。光信号不受电磁干扰、无线电频率干扰影响。可在强电磁环境(如工厂、医院)或雷暴天气下稳定工作。 | **较弱**。铜线是导体,易受电磁干扰、串扰影响。需要屏蔽层(STP/FTP)在干扰环境下改善性能,但成本增加。 |\n| **安全性** | **高**。光信号不易被窃听(需要物理接入并截断光纤,且操作易被发现)。不辐射电磁信号。 | **较低**。电信号可能被电磁感应方式窃听(有一定难度)。铜线会辐射微弱电磁信号。 |\n| **尺寸与重量** | **更细、更轻**。相同容量下,光纤比铜缆细得多、轻得多。 | **较粗、较重**。尤其是高类别带屏蔽的线缆。 |\n| **成本** | **设备成本高**。光模块、光纤收发器、光纤交换机端口价格远高于铜口设备。
**线缆成本中等**。 | **设备成本低**。网卡、交换机端口非常普及且便宜。
**线缆成本中等偏低**(低类别线)。但高类别屏蔽线成本也较高。 |\n| **安装与维护** | **技术要求高**。光纤端接(熔接、研磨)需要专业工具和技能。弯曲半径要求严格,过度弯折易断芯。 | **相对简单**。RJ45水晶头压接容易学习,工具普及。允许更大的弯曲半径,更耐弯折。 |\n| **连接器** | LC, SC, ST, FC, MTP/MPO 等 | RJ45 (8P8C) |\n| **功耗** | **较低**。光模块通常功耗低于同等速率电口。 | **较高**。尤其在高速率、长距离传输时,驱动电信号需要更大功率。 |\n| **主要类型** | **单模光纤:** 细芯(~9µm),单束光,超长距离,高速。
**多模光纤:** 粗芯(50µm/62.5µm),多束光,中短距离,性价比高。 | **非屏蔽双绞线:** UTP(最常见),无屏蔽层,成本低。
**屏蔽双绞线:** STP/FTP/SFTP 等,带屏蔽层,抗干扰好,成本高。
**类别:** Cat5e (千兆), Cat6 (千兆/短距万兆), Cat6a (万兆), Cat7/7a/8 (更高性能) |\n| **典型应用场景** | 骨干网、城域网、数据中心互联、长距离传输、高干扰环境、高带宽需求(视频、云计算、存储网络)、FTTH/FTTx入户。 | 局域网接入层(电脑到交换机)、电话系统、监控系统(POE供电)、家庭网络、办公室布线、短距离设备互联。 |\n\n## 三、 总结\n\n* **选择光纤当:**\n * 你需要**极高的带宽**(10Gbps以上)。\n * 你需要**超长的传输距离**(几百米到几十公里)。\n * 你在**强电磁干扰**环境中。\n * 你对**安全性**要求非常高。\n * 你需要**节省空间和减轻重量**(如数据中心)。\n * 你需要**更低的传输延迟**(虽然差异很小,但对超低延迟场景重要)。\n * 你**不差钱**(尤其是一次性投入的设备成本)。\n\n* **选择双绞线当:**\n * 你的需求是**千兆或万兆(短距离)**。\n * 传输距离在**100米以内**。\n * 环境**电磁干扰较小**。\n * 你对**成本非常敏感**(尤其是设备端口成本)。\n * 你需要**简单易行的安装和维护**。\n * 你需要为设备提供**PoE供电**(目前光纤无法直接供电)。\n * 应用场景是**终端设备接入**(电脑、IP电话、摄像头、AP等)。\n\n**简单来说:光纤是“高速公路”,速度快、距离远、容量大、成本高、建设维护复杂;双绞线是“城市道路”,灵活方便、覆盖广、成本低、但速度和距离有限。** 现代网络通常是两者的结合:光纤做骨干和长距离互联,双绞线做最后100米的接入。", "数据库/json文件储存和MongoDB储存优缺点.md": "游戏玩家数据储存在普通JSON文件和MongoDB中各有其适用场景,二者的优缺点对比可结合游戏数据的特性(如数据量、读写频率、结构灵活性、并发需求等)展开分析:\n \n一、普通JSON文件储存\n \n普通JSON文件储存指将玩家数据以JSON格式写入本地文件(单文件或多文件,如按玩家ID分文件),依赖文件系统直接读写。\n \n优点\n \n1. 简单轻量,开发成本低\n无需部署数据库服务,直接通过编程语言的文件操作API(如Python的 json 模块、Node.js的 fs 模块)即可读写,适合小型团队或开发初期快速验证功能,学习成本几乎为0。\n2. 资源占用少\n仅依赖文件系统,不消耗额外的数据库进程资源(如内存、CPU),适合设备性能有限的场景(如单机小游戏、轻量网页游戏)。\n3. 数据直观可见\nJSON文件为文本格式,可直接用编辑器打开查看或修改,便于开发调试(如临时修改玩家数据测试功能)。\n \n缺点\n \n1. 读写效率低,不适合大数据量\n- 每次读写需加载整个JSON文件到内存解析(或写入时覆盖整个文件),当玩家数据量增大(如10万+玩家),单文件体积膨胀,读写耗时会急剧增加(例如加载100MB的JSON文件可能需要数百毫秒)。\n- 若按玩家ID分文件,虽能缓解单文件压力,但批量查询(如排行榜、全服统计)需遍历所有文件,效率极低。\n2. 并发安全问题突出\n多玩家同时操作时(如多人在线游戏的并发读写),文件系统缺乏原生锁机制,易出现“写覆盖”(如A玩家写入时B玩家同时写入,导致其中一方数据丢失)或数据损坏(如写入中断导致JSON格式错误)。\n3. 结构扩展性差\n若玩家数据结构迭代(如新增“宠物属性”“公会信息”),需手动处理旧JSON文件的格式兼容(如遍历所有文件添加新字段),操作繁琐且易出错。\n4. 缺乏数据一致性保障\n无事务支持,例如玩家“扣金币+加道具”的原子操作,若中途程序崩溃,可能导致金币已扣但道具未加,数据不一致。\n \n二、MongoDB储存\n \nMongoDB是文档型NoSQL数据库,以BSON(JSON的二进制扩展)格式存储数据,天然适配半结构化的玩家数据。\n \n优点\n \n1. 高效读写与查询能力\n- 支持索引(如按玩家ID、等级建索引),可快速定位单玩家数据(毫秒级),解决JSON文件全量解析的性能问题。\n- 支持复杂查询(如“等级>50且在线的玩家”“道具列表包含某物品的玩家”),适合游戏中的排行榜、好友列表、任务统计等场景。\n2. 良好的并发与一致性\n- 内置多版本并发控制(MVCC),支持高并发读写( thousands of TPS),避免JSON文件的并发冲突。\n- 支持事务(MongoDB 4.0+),可保证“扣钱+加道具”“升级+解锁技能”等操作的原子性,防止数据不一致。\n3. 灵活扩展,适配数据增长\n- 玩家数据量随用户增长时,可通过“分片”横向扩展(将数据分布到多台服务器),支持百万级甚至亿级玩家数据。\n- 文档结构动态灵活,新增字段无需修改表结构,旧数据可兼容(查询时自动忽略不存在的字段),适配游戏版本迭代。\n4. 完善的数据管理能力\n提供备份( mongodump )、恢复( mongorestore )、监控(MongoDB Atlas)等工具,支持数据压缩、过期索引(如清理离线玩家缓存),适合长期运行的在线游戏。\n \n缺点\n \n1. 运维与学习成本高\n需要部署、维护数据库服务(如集群配置、索引优化、故障排查),对小型团队可能增加运维压力;开发人员需学习MongoDB的查询语法(如 find 、 aggregate )、索引设计等,门槛高于JSON文件。\n2. 资源占用较高\n相比JSON文件,MongoDB需要额外的内存(缓存索引和热数据)、CPU(处理查询)和磁盘空间(数据文件+日志),不适合资源受限的极简场景(如嵌入式小游戏)。\n3. 过度设计风险\n对于单机游戏、玩家数极少(如几百人)且无复杂查询的场景,MongoDB的优势无法体现,反而因配置复杂降低开发效率。\n \n总结:适用场景\n \n- 普通JSON文件:适合单人游戏、小型休闲游戏、开发测试阶段,或数据量极小(<1万玩家)、读写频率低、无复杂查询的场景。\n- MongoDB:适合多人在线游戏(MMO、MOBA等)、中大型游戏,或玩家数多(>1万)、需高频读写、复杂查询、结构迭代频繁的场景。\n \n实际开发中,也可根据规模过渡:初期用JSON文件快速上线,待用户增长后迁移至MongoDB,利用其扩展性支撑业务。", "数据库/MongoDB数据库优化方式一览.md": "除了索引之外,MongoDB 在 CRUD 操作优化上还有多种有效策略,尤其在处理海量数据时更为关键。以下是综合各技术文档和实践总结的核心优化方法:\n\n---\n\n### 🔄 一、批量操作优化\n1. **使用 `bulkWrite` 替代单条操作** \n 通过批量写入减少网络开销和事务开销。基于 `ReplaceOneModel` 启用 `upsert`,实现存在更新、不存在插入的高效操作:\n ```java\n public void batchSave(List dataList) {\n List> bulkOps = dataList.stream()\n .map(item -> {\n Document doc = convertToDocument(item); // 转换为Document\n return new ReplaceOneModel<>(\n Filters.eq(\"_id\", doc.get(\"_id\")), \n doc, \n new UpdateOptions().upsert(true)\n );\n }).collect(Collectors.toList());\n collection.bulkWrite(bulkOps); // 批量执行\n }\n ```\n 此方法将多条操作合并为一次请求,写入性能提升显著。\n\n---\n\n### 📖 二、分页查询优化\n1. **避免精确 `count`** \n 当数据量超大时,`count` 可能极慢。采用阈值法:若跳过 `MAX_PAGE_COUNT`(如1万条)后仍有数据,则返回阈值提示“数据超过1万条”,避免全表扫描:\n ```java\n private long approxCount(MongoTemplate mongoTemplate, Query query) {\n query = query.with(PageRequest.of(MAX_PAGE_COUNT, 1));\n return mongoTemplate.find(query, Entity.class).isEmpty() \n ? mongoTemplate.count(query) \n : MAX_PAGE_COUNT;\n }\n 。\n ```\n\n2. **用条件替代 `skip`** \n 深度分页时(如第100页),避免 `skip(9900)`。改为记录上一页末尾的排序字段值(如时间戳),作为下一页查询条件:\n ```sql\n -- 原查询:db.collection.find().sort({time:-1}).skip(9900).limit(100)\n -- 优化后:\n db.collection.find({ time: { $lt: lastPageEndTime } })\n .sort({ time: -1 })\n .limit(100);\n ```\n 此方法将 **O(N)** 的跳过操作转为 **O(1)** 的条件过滤。\n\n---\n\n### 📤 三、全量导出优化\n1. **字段投影减少数据传输** \n 仅查询必要字段,降低网络与内存开销:\n ```java\n Query query = new Query();\n query.fields().include(\"_id\").include(\"name\"); // 只返回_id和name。\n ```\n\n2. **流式处理替代全量加载** \n 使用 `stream()` 逐条处理数据,避免 `findAll` 导致内存溢出:\n ```java\n try (CloseableIterator iter = mongoTemplate.stream(query, Entity.class)) {\n while (iter.hasNext()) {\n process(iter.next()); // 单条处理\n }\n }\n ```\n 相比分页查询,流式处理无 `skip` 开销,且内存占用恒定。\n\n---\n\n### 🧩 四、文档设计优化\n1. **打破第三范式** \n - **冗余字段**:将高频查询的关联字段(如部门名称)冗余到主文档,避免联表查询。\n - **内嵌设计**:一对多关系直接嵌套子文档(如订单内嵌商品列表),提升读取效率。但需注意文档大小限制(16MB)。\n - **引用设计**:多对多关系使用ID数组而非完整嵌套,避免文档膨胀:\n ```json\n // 学生文档\n {\n \"_id\": \"s001\",\n \"name\": \"Alice\",\n \"teachers\": [\"t01\", \"t02\"] // 仅存储ID\n }\n ```\n\n---\n\n### ⚙️ 五、分片集群优化\n1. **碎片整理(MongoDB <7.0)** \n 在早期版本中,分片集合可能因频繁写入产生碎片化小数据块,导致CRUD延迟。通过 `configureCollectionBalancing` 命令合并数据块,但需注意:\n - 整理期间可能短暂阻塞元数据更新。\n - MongoDB 7.0+ 已支持自动合并,通常无需手动操作。\n\n2. **负载均衡窗口设置** \n 在业务低峰期触发负载均衡器迁移数据块,减少对CRUD的影响。\n\n---\n\n### 💎 六、其他关键技巧\n1. **合理控制事务范围**:短事务减少锁竞争。\n2. **写入确认级别调整**:对非关键数据使用 `w:0`(无确认),提升写入速度(牺牲一致性)。\n3. **TTL索引自动清理**:为临时数据(如日志)设置过期时间,减少存储压力。\n\n---\n\n### 💎 优化方法效果对比表\n| **优化方向** | **适用场景** | **性能提升效果** | **实现复杂度** |\n|--------------------|--------------------------|----------------------|--------------|\n| **批量写入** | 数据导入、批量更新 | ⭐⭐⭐⭐⭐ (极高) | ⭐⭐ (中等) |\n| **流式导出** | 大数据量导出 | ⭐⭐⭐⭐ (避免OOM) | ⭐ (简单) |\n| **条件分页** | 深度分页(>100页) | ⭐⭐⭐⭐ (O(1) 跳转) | ⭐⭐ (中等) |\n| **冗余字段** | 高频关联查询 | ⭐⭐⭐ (减少联表) | ⭐⭐⭐ (较高) |\n| **分片碎片整理** | MongoDB 6.0以下分片集群 | ⭐⭐ (减少延迟) | ⭐⭐⭐⭐ (复杂) |\n\n---\n\n> 💡 **实践建议**:优先从**批量操作**和**分页策略**入手,这两类优化代码改动小且收益显著。海量数据场景下,**流式处理+字段投影**是导出标配方案。分片集群升级到 MongoDB 7.0+ 可减少运维负担。", "数据库/MongoDB的索引一览.md": "\n**索引的核心作用:**\n\n1. **大幅减少查询需要扫描的文档数量:** 没有索引时,MongoDB 必须执行集合扫描(`COLLSCAN`),即检查集合中的*每一个*文档。有了合适的索引,MongoDB 可以使用索引扫描(`IXSCAN`)快速定位到包含所需数据的文档位置。\n2. **加速排序:** 如果排序字段包含在索引中,MongoDB 可以直接利用索引中已经排好的顺序返回结果,避免昂贵的在内存中排序。\n3. **支持高效的数据去重:** `$group` 聚合阶段的分组操作可以利用索引。\n4. **实现覆盖查询:** 如果查询只需要返回索引中包含的字段,MongoDB 可以*完全*从索引中获取结果,无需去读取实际的文档数据,速度极快。\n\n**MongoDB 支持的索引类型:**\n\n1. **单字段索引:**\n * 最基本的索引类型,在单个字段上创建。\n * 示例:`db.collection.createIndex({ name: 1 })` (1 表示升序,-1 表示降序。对于纯等值查询,顺序通常不重要;对于排序查询,顺序很重要)。\n\n2. **复合索引:**\n * 在多个字段上创建的索引。\n * 字段的顺序**极其重要**。它决定了索引如何组织和哪些查询模式可以利用该索引(最左前缀原则)。\n * 示例:`db.collection.createIndex({ status: 1, order_date: -1 })`。这个索引可以高效支持:\n * 只查询 `status` 的查询\n * 同时查询 `status` 和 `order_date` 的查询\n * 查询 `status` 并按 `order_date` 排序的查询\n * 但不支持只查询 `order_date` 的查询(不符合最左前缀)。\n\n3. **多键索引:**\n * 当索引字段是数组时,MongoDB 会自动为数组中的每个元素创建索引条目。\n * 用于高效查询数组字段中的元素。\n * 示例:索引 `db.collection.createIndex({ tags: 1 })` 可以高效支持查询 `db.collection.find({ tags: \"mongodb\" })`。\n\n4. **地理空间索引:**\n * **2dsphere:** 用于查询存储为 GeoJSON 对象或传统坐标对的地理空间数据(地球球面几何)。支持邻近查询(`$near`)、包含查询(`$geoWithin`)、相交查询(`$geoIntersects`)等。\n * **2d:** 用于在二维平面上(如地图游戏)查询存储为传统坐标对的数据。主要用于平面几何计算。\n\n5. **文本索引:**\n * 支持对字符串或字符串数组字段的内容进行文本搜索。\n * 支持词干提取、停用词过滤等基本文本处理功能。\n * 示例:`db.collection.createIndex({ description: \"text\" })`,然后使用 `$text` 操作符进行搜索。\n\n6. **哈希索引:**\n * 对字段值进行哈希运算,并在哈希值上建立索引。\n * 主要用途是为**分片键**提供更均匀的数据分布(使用`hashed`分片策略时)。\n * 只支持等值匹配查询,不支持范围查询、排序或其他操作。\n * 示例:`db.collection.createIndex({ _id: \"hashed\" })`。\n\n7. **通配符索引:**\n * 可以索引文档中未知或任意字段。适用于模式动态变化的场景。\n * 示例:\n * `db.collection.createIndex({ \"userMetadata.$**\": 1 })` 索引 `userMetadata` 子文档中的所有字段。\n * `db.collection.createIndex({ \"$**\": 1 })` 索引文档中的所有字段(谨慎使用,开销大)。\n\n8. **唯一索引:**\n * 强制索引字段的值在整个集合中是唯一的(`_id` 字段默认就有唯一索引)。\n * 可以用于单字段或复合字段。\n * 示例:`db.collection.createIndex({ email: 1 }, { unique: true })`。\n\n9. **TTL 索引:**\n * 一种特殊的单字段索引,用于在指定时间后或在指定时间点自动从集合中删除文档。字段必须是日期类型或包含日期元素的数组。\n * 适用于会话数据、日志、临时数据等。\n * 示例:`db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })` (文档在 `createdAt` 时间之后 3600 秒/1 小时被删除)。\n\n10. **稀疏索引:**\n * 只包含具有索引字段的文档的条目。即使索引字段值为 `null`,也会包含在内;但如果文档*完全缺失*该索引字段,则不会被索引。\n * 节省空间,提高索引效率(当字段在大部分文档中缺失时)。\n * 示例:`db.collection.createIndex({ optionalField: 1 }, { sparse: true })`。\n\n**如何管理和使用索引:**\n\n1. **创建索引:** 使用 `db.collection.createIndex()` 方法。\n * 示例:`db.products.createIndex({ category: 1, price: -1 })`\n2. **查看索引:** 使用 `db.collection.getIndexes()` 方法。\n3. **删除索引:** 使用 `db.collection.dropIndex()` 或 `db.collection.dropIndexes()` 方法。\n4. **分析查询性能:** 使用 `explain()` 方法查看查询的执行计划,确认是否使用了索引(`IXSCAN`)以及使用了哪个索引。这是优化查询的关键步骤。\n * 示例:`db.orders.find({ status: \"A\", amount: { $gt: 100 } }).sort({ order_date: -1 }).explain(\"executionStats\")`\n5. **索引管理最佳实践:**\n * **为常用查询模式创建索引:** 分析你的应用最常见的查询(`find`, `sort`, `aggregate`中的`$match`, `$group`, `$sort`等阶段),为这些查询涉及的字段创建合适的索引(通常是复合索引)。\n * **遵循最左前缀原则:** 设计复合索引时,将最常用于过滤或排序的字段放在左边。\n * **考虑选择性:** 选择性高的字段(如唯一值多的字段)放在复合索引的前面通常更有效。\n * **使用覆盖查询:** 尽量让查询只返回索引中包含的字段。\n * **监控索引使用率:** MongoDB Profiler 或 Atlas 性能监控可以查看索引的使用情况。使用率低的索引应考虑删除,因为它们会消耗写性能和存储空间。\n * **权衡读写性能:** 索引会加速读操作,但会减慢写操作(插入、更新、删除),因为写操作需要维护索引。不要过度索引。\n * **后台创建大索引:** 在大型集合上创建索引可能耗时很长并阻塞操作。使用 `{ background: true }` 选项可以在后台创建索引(虽然仍可能有性能影响,但不会完全阻塞读写)。\n * **合理使用内存:** 确保有足够的内存将常用索引(或其活跃部分)保存在内存中,避免频繁的磁盘 I/O。\n\n**总结:**\n\nMongoDB 提供了极其丰富和强大的索引类型(单字段、复合、多键、地理空间、文本、哈希、通配符、唯一、TTL、稀疏)来满足各种查询场景的优化需求。**创建和管理合适的索引是提升 MongoDB 查询性能最关键的手段。** 务必结合你的具体查询模式,使用 `explain()` 分析执行计划,遵循索引设计的最佳实践(特别是复合索引的最左前缀原则),并持续监控和调整索引策略。", @@ -116,7 +133,7 @@ "编程语言/Android/Linux配置安卓Gradle构建环境.md": "\n---\n\n## ⭐ 概览\n\n目标:在 Debian 12 上搭建可以 **本地编译 Android 原生 APK** 的环境,包含:\n\n- ✅ OpenJDK (推荐 17)\n \n- ✅ Android SDK 命令行工具(cmdline-tools)\n \n- ✅ Platform tools(adb)与 build-tools、platforms\n \n- ✅ 可选:NDK / CMake(用于原生 C/C++)\n \n- ✅ Gradle(用于构建)\n \n\n适用场景:CI、无 GUI 的服务器、或仅需命令行编译的开发环境。\n\n---\n\n## 🧾 前置条件\n\n- 一台运行 **Debian 12** 的机器(有 sudo 权限)\n \n- 稳定的网络(用于下载 SDK 与工具)\n \n- 建议至少 10GB 可用磁盘空间(SDK + 系统镜像可能占用)\n \n\n---\n\n## 1️⃣ 安装基础工具\n\n先更新并安装基础依赖:\n\n```bash\nsudo apt update\nsudo apt install -y git unzip wget curl zip build-essential\n```\n\n这些工具用于下载、解压、构建等。\n\n---\n\n## 2️⃣ 安装 JDK(推荐:OpenJDK 17)\n\nAndroid Gradle Plugin(AGP)对 JDK 有版本要求,JDK 17 是安全选择:\n\n```bash\nsudo apt install -y openjdk-17-jdk\n```\n\n检查版本:\n\n```bash\njava -version\n# 期望输出类似:openjdk version \"17.x\"\n```\n\n---\n\n## 3️⃣ 下载并安装 Android SDK 命令行工具\n\n去 Google 官方下载 `commandlinetools` 压缩包,或者用 wget(示例):\n\n```bash\nmkdir -p $HOME/Android/cmdline-tools\ncd $HOME/Android/cmdline-tools\nwget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O cmdline-tools.zip\nunzip cmdline-tools.zip\n# 有时解压出来的目录名是 cmdline-tools,移动或重命名为 latest:\nmv cmdline-tools latest\n```\n\n> 🔔 注意:实际下载链接和版本会随时间变化,请按需到 Android 官方网站获取最新版。\n\n---\n\n## 4️⃣ 配置环境变量(推荐写入 `~/.bashrc` 或 `~/.zshrc`)\n\n将 SDK 路径加入环境变量,保证 `sdkmanager`、`adb` 等工具可用:\n\n```bash\n# 在 ~/.bashrc 或 ~/.zshrc 添加:\nexport ANDROID_HOME=$HOME/Android\nexport ANDROID_SDK_ROOT=$ANDROID_HOME\nexport PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH\n\n# 使之生效:\nsource ~/.bashrc\n```\n\n---\n\n## 5️⃣ 使用 sdkmanager 安装常用组件\n\n通过 `sdkmanager` 安装 `platform-tools`、指定 Android 平台与 build-tools:\n\n```bash\nsdkmanager --sdk_root=$ANDROID_HOME \"platform-tools\" \"platforms;android-34\" \"build-tools;34.0.0\"\n```\n\n可选安装(若需要 NDK / CMake 编译原生代码):\n\n```bash\nsdkmanager \"ndk;26.1.10909125\" \"cmake;3.22.1\"\n```\n\n如果是自动接受许可,可以使用:\n\n```bash\nyes | sdkmanager --licenses\n```\n\n---\n\n## 6️⃣ 安装 Gradle(可选:系统级)\n\nAndroid 项目通常随 Gradle Wrapper(`gradlew`)一起提供,能自动下载合适版本。但若想系统安装:\n\n```bash\nwget https://services.gradle.org/distributions/gradle-8.7-bin.zip -P /tmp\nsudo unzip -d /opt/gradle /tmp/gradle-8.7-bin.zip\n# 添加到 PATH(写入 ~/.bashrc):\nexport PATH=/opt/gradle/gradle-8.7/bin:$PATH\n```\n\n检查:\n\n```bash\ngradle -v\n```\n\n---\n\n## 7️⃣ 创建或获取一个示例 Android 项目并编译\n\n如果你已经有一个项目,进入项目目录并使用 Gradle Wrapper:\n\n```bash\n# 如果项目有 gradlew:\n./gradlew assembleDebug\n\n# 编译成功后 APK 通常位于:\napp/build/outputs/apk/debug/app-debug.apk\n```\n\n如果想新建一个空项目,可先使用 Android Studio 在本地创建(GUI 更方便),或直接从 GitHub 上的模板克隆一个样例工程。\n\n---\n\n## 8️⃣ 将 APK 部署到设备或模拟器(可选)\n\n- 真机(需开启 USB 调试):\n \n\n```bash\nadb install -r app/build/outputs/apk/debug/app-debug.apk\n```\n\n- 模拟器:需要安装 emulator 与系统镜像(`system-images`),并创建 AVD。命令行使用 `avdmanager` / `emulator`。\n \n\n---\n\n## 9️⃣ 常见问题 & 排查建议 ❗\n\n- `sdkmanager` 找不到:确认 PATH 是否包含 `$ANDROID_HOME/cmdline-tools/latest/bin`。\n \n- `java` 版本不对:Gradle/AGP 可能需要特定 JDK 版本,查看项目 `gradle.properties` / `build.gradle` 推荐的版本。\n \n- 下载慢或失败:考虑使用代理或镜像(国内网络环境常见)。\n \n- 权限问题:若在 `/opt` 等系统目录解压安装,需 `sudo`。\n \n\n---\n\n## 🔁 推荐一键脚本(示例)\n\n下面给出一个**示例脚本**的框架(**请先审阅再运行**,并根据需要改版本号):\n\n```bash\n#!/usr/bin/env bash\nset -e\n\n# 安装基础工具\nsudo apt update\nsudo apt install -y git unzip wget curl zip build-essential openjdk-17-jdk\n\n# 目录\nSDK_ROOT=$HOME/Android\nmkdir -p $SDK_ROOT/cmdline-tools\ncd $SDK_ROOT/cmdline-tools\n\n# 下载命令行工具(请确认链接是否过期)\nwget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O cmdline-tools.zip\nunzip -o cmdline-tools.zip\nmv cmdline-tools latest || true\n\n# 环境变量(仅本次会话)\nexport ANDROID_HOME=$SDK_ROOT\nexport PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH\n\n# 安装 SDK 组件\nyes | sdkmanager --sdk_root=$ANDROID_HOME \"platform-tools\" \"platforms;android-34\" \"build-tools;34.0.0\"\n\necho \"安装完成,请将下列行加入你的 ~/.bashrc 或 ~/.zshrc:\"\necho \"export ANDROID_HOME=\\$HOME/Android\"\necho \"export PATH=\\$ANDROID_HOME/cmdline-tools/latest/bin:\\$ANDROID_HOME/platform-tools:\\$PATH\"\n```\n\n---\n\n## 🔗 参考 & 延伸阅读\n\n- Android 官方开发者网站(SDK / command line tools)\n \n- Gradle 官方文档\n \n- Android NDK 文档(若使用原生 C/C++)\n \n\n> 上面链接建议直接在浏览器打开 Android 官方站点获取最新版工具和镜像。\n\n---\n\n## ✅ 小结\n\n在 Debian 12 上搭建 Android 原生构建环境的要点:\n\n- 安装合适的 **JDK(推荐 17)**\n \n- 下载并配置 **Android SDK command-line tools**,并通过 `sdkmanager` 安装 `platform-tools`、`platforms` 与 `build-tools`\n \n- 使用项目自带的 **Gradle Wrapper (`gradlew`)** 进行构建,必要时可系统安装 Gradle\n \n- 如需本地编译原生代码,记得安装 **NDK / CMake**\n \n\n---\n", "编程语言/Android/安卓Gradle构建常用命令总结.md": "\n\n##### **基础**\n\n- `./gradlew tasks` \n 列出可用的 Gradle 任务(查看当前项目能跑什么任务)。\n \n- `./gradlew dependencies` \n 列出项目依赖树(排查依赖冲突很有用)。\n \n- `./gradlew clean` \n 清理构建产物(删除 `build/` 目录)。\n \n\n##### **构建 APK / AAB**\n\n- `./gradlew assembleDebug` \n 构建 debug APK(输出:`app/build/outputs/apk/debug/*.apk`)。\n \n- `./gradlew assembleRelease` \n 构建 release APK(需签名配置,否则生成 unsigned apk)。\n \n- `./gradlew bundleRelease` \n 生成 AAB(Android App Bundle),输出:`app/build/outputs/bundle/release/*.aab`。\n \n- `./gradlew bundleDebug` \n 生成 debug bundle(少用,通常用于测试)。\n \n\n##### **按 module / productFlavor / buildType 构建**\n\n- `./gradlew :moduleName:assembleRelease` \n 构建指定 module(多模块项目时用)。\n \n- `./gradlew assembleFlavorNameRelease` \n 构建指定 flavor + buildType(例如 `assemblePaidRelease`)。\n \n\n##### **安装与卸载**\n\n- `./gradlew installDebug` \n 将 debug APK 安装到连接的设备/模拟器(需要 adb 可用)。\n \n- `./gradlew uninstallDebug` \n 从设备卸载 debug 包。\n \n- 如果用生成的 APK 手动安装:`adb install -r app/build/outputs/apk/debug/app-debug.apk`\n \n\n##### **测试**\n\n- 单元测试(JVM):`./gradlew test` 或 `./gradlew testDebugUnitTest`\n \n- 仪器/设备测试(connected devices):`./gradlew connectedAndroidTest` 或 `./gradlew connectedCheck`\n \n\n##### **静态检查 / 报表**\n\n- `./gradlew lint` 或 `./gradlew lintDebug` \n 运行 Android Lint。\n \n- `./gradlew signingReport` \n 输出签名信息(SHA1/SHA256),常用于配置 API key(Google/Firebase)。\n \n\n##### **调试构建问题的常用参数**\n\n- `--stacktrace` / `--full-stacktrace`:打印堆栈跟踪(排错用)\n \n- `--info` / `--debug`:更详细的日志级别\n \n- `--scan`:生成构建扫描(需要网络,便于深入分析)\n \n- `--no-daemon`:不使用 Gradle daemon(CI 时有时会用)\n \n- `--parallel`:并行构建模块(能加速多模块项目)\n \n- `-x test`:跳过测试(例如 `./gradlew assembleRelease -x test`)\n \n- `--offline`:离线构建(只用缓存依赖)\n \n- `--refresh-dependencies`:刷新依赖缓存\n \n\n##### **性能 / CI 常用组合示例**\n\n- 本地快速一把:`./gradlew clean assembleDebug --parallel --info`\n \n- CI (不使用 daemon,输出详细):`./gradlew clean assembleRelease --no-daemon --stacktrace -x test`\n \n- 只构建 moduleA 的 release:`./gradlew :moduleA:assembleRelease`\n \n\n##### **常见路径**\n\n- APK:`app/build/outputs/apk//...`\n \n- AAB:`app/build/outputs/bundle//...`\n \n- 临时构建缓存:`~/.gradle/caches/`\n \n\n##### **小贴士**\n\n- 始终用项目里的 Gradle Wrapper(`./gradlew`),保证 Gradle 版本一致。\n \n- Release 构建需要正确的 `signingConfig`(通常放在 `gradle.properties` + `build.gradle`),也可以在 CI 用 `-P` 传参数(注意不要把敏感信息放在日志里)。\n \n- 出问题先加 `--stacktrace --info` 看详情,再定位是依赖、ProGuard/R8、签名还是资源冲突。\n", "编程语言/C/C 代码概述:检查特定条件的素数.md": "# C 代码概述:检查特定条件的素数\r\n\r\n## 功能描述\r\n该程序对给定的整数范围内的每个整数进行检查,计算一个特定的函数,并判断该函数的结果是否为素数。\r\n\r\n## 主要组成部分\r\n\r\n### 1. `is_prime` 函数\r\n- **输入**: 一个整数 `n`\r\n- **输出**: 如果 `n` 是素数,返回 `1`,否则返回 `0`。\r\n- **逻辑**:\r\n - 如果 `n` 小于或等于 1,返回 `0`。\r\n - 通过循环检查从 `2` 到 `√n` 的所有整数,判断 `n` 是否可被整除。\r\n \r\n### 2. `main` 函数\r\n- **输入**: 从标准输入读取两个整数 `x` 和 `y`,直到输入为 `0 0`。\r\n- **逻辑**:\r\n - 使用 `x` 和 `y` 定义的范围内进行迭代。\r\n - 计算 `f = i * i + i + 41`。\r\n - 调用 `is_prime` 函数检查 `f` 是否为素数:\r\n - 如果发现任意 `f` 不是素数,输出 `\"Sorry\"` 并停止进一步检查。\r\n - 如果所有 `f` 都是素数,最终输出 `\"OK\"`。\r\n\r\n## 使用示例\r\n- **输入**:\r\n ```\r\n 1 5\r\n 0 0\r\n ```\r\n- **输出**:\r\n ```\r\n Sorry\r\n ```\r\n\r\n## 注意事项\r\n- 如果输入为 `0 0`,程序会终止。\r\n- 当范围内某个 `f` 不是素数时,输出 `\"Sorry\"`,并不再继续检查后续数字。\r\n\r\n\r\n\r\n\r\n\r\n```c\r\n#include \r\n\r\nint is_prime(int n) {\r\n if (n <= 1) return 0; \r\n for (int i = 2; i * i <= n; i++) {\r\n if (n % i == 0) return 0; \r\n }\r\n return 1; \r\n}\r\n\r\nint main() {\r\n int x, y;\r\n \r\n\r\n while (scanf(\"%d %d\", &x, &y) != EOF) {\r\n if (x == 0 && y == 0) break; \r\n \r\n int all_prime = 1; \r\n\r\n for (int i = x; i <= y; i++) {\r\n int f = i * i + i + 41; \r\n if (!is_prime(f)) { \r\n all_prime = 0; \r\n printf(\"Sorry\\n\");\r\n break; \r\n }\r\n }\r\n\r\n if (all_prime) {\r\n printf(\"OK\\n\"); \r\n }\r\n }\r\n \r\n return 0;\r\n}\r\n\r\n```\r\n\r\n", - "编程语言/C/C语言不设置临时变量交换x和y的值(方法).md": "# C语言不设置临时变量交换x和y的值(方法)\r\n\r\n```c\r\n#include \r\n//异或\r\nint main() {\r\n int x = 10, y = 20;\r\n x = x ^ y;\r\n y = x ^ y;\r\n x = x ^ y;\r\n printf(\"x的值为:%d,y的值为:%d\\n\", x, y);\r\n return 0;\r\n}\r\n\r\n```\r\n\r\n```c\r\n#include \r\n\r\nint main() {\r\n int x = 10, y = 20;\r\n x = x + y;\r\n y = x - y;\r\n x = x - y;\r\n printf(\"x的值为:%d,y的值为:%d\\n\", x, y);\r\n return 0;\r\n}\r\n\r\n```\r\n\r\n", + "编程语言/C/C语言不设置临时变量交换x和y的值(方法).md": "# C语言不设置临时变量交换x和y的值(方法)\n\n```c\n#include \n//异或\nint main() {\n int x = 10, y = 20;\n x = x ^ y;\n y = x ^ y;\n x = x ^ y;\n printf(\"x的值为:%d,y的值为:%d\\n\", x, y);\n return 0;\n}\n\n```\n\n```c\n#include \n\nint main() {\n int x = 10, y = 20;\n x = x + y;\n y = x - y;\n x = x - y;\n printf(\"x的值为:%d,y的值为:%d\\n\", x, y);\n return 0;\n}\n\n```\n\n", "编程语言/C++/C++中的语法糖.md": "C++中有不少语法糖,以下是一些常见的例子:\n \n范围-based for循环\n \n传统的 for 循环遍历容器需要使用迭代器,较为繁琐。范围 - based for循环则更简洁,例如:\n \n#include \n#include \n\nint main() {\n std::vector v = {1, 2, 3, 4, 5};\n for (int num : v) {\n std::cout << num << \" \";\n }\n return 0;\n}\n \n \n初始化列表\n \n可以使用花括号初始化列表来初始化对象或容器,例如:\n \n#include \n#include \n\nint main() {\n // 用初始化列表初始化vector\n std::vector v = {1, 2, 3, 4, 5};\n // 用初始化列表初始化自定义类对象\n class MyClass {\n public:\n int num;\n MyClass(int n) : num(n) {}\n };\n MyClass obj{10};\n std::cout << obj.num << std::endl;\n return 0;\n}\n \n \nauto关键字\n \n auto 关键字让编译器根据初始化表达式自动推导变量的类型,减少了类型声明的冗长,例如:\n \n#include \n#include \n\nint main() {\n std::vector v = {1, 2, 3, 4, 5};\n // 使用auto自动推导迭代器类型\n for (auto it = v.begin(); it!= v.end(); ++it) {\n std::cout << *it << \" \";\n }\n return 0;\n}\n \n \n模板别名\n \n通过 using 关键字定义模板别名,简化复杂的模板类型定义,例如:\n \n#include \n#include \n#include \n\nint main() {\n // 定义模板别名\n using MyMap = std::map;\n MyMap myMap;\n myMap[\"key\"] = 10;\n std::cout << myMap[\"key\"] << std::endl;\n return 0;\n}", "编程语言/C++/C++关联文件.md": "### 源文件\r\n\r\n- **.cpp 或 .cxx 或 .cc :**C++源文件的扩展名,用于编写C++代码,包含函数、类、变量等定义和实现。\r\n- **.h 或 .hpp 或 .hxx :**头文件扩展名,用于声明函数原型、类定义、常量和变量等,以便在多个源文件中共享声明。\r\n\r\n### 项目和配置文件\r\n\r\n- **.vcxproj :**Visual C++项目文件,用于Visual Studio开发环境,包含项目的配置信息、源文件列表、引用等。\r\n- **.sln :**解决方案文件,用于组织多个相关的项目,包含项目之间的依赖关系等信息。\r\n- **CMakeLists.txt :**使用CMake构建系统时的项目配置文件,用于描述项目的源文件、目标、依赖等信息,可生成不同平台和编译器的项目文件。\r\n- **Makefile :**在Unix和类Unix系统中,用于定义编译规则和目标,指定源文件如何编译链接成可执行文件或库。\r\n\r\n### 库文件\r\n\r\n- **.lib :**Windows下的静态库文件,包含已编译的代码和数据,在链接时被直接复制到可执行文件中。\r\n- **.a :**Unix和类Unix系统下的静态库文件,作用与Windows下的 .lib 类似。\r\n- **.dll :**Windows下的动态链接库文件,包含可在运行时被加载和调用的代码和数据。\r\n- **.so :**Unix和类Unix系统下的共享库文件,类似于Windows的 .dll ,在运行时动态链接。\r\n\r\n### 可执行文件\r\n\r\n- **.exe :**Windows下的可执行文件,是编译链接后的最终产物,可在操作系统中直接运行。\r\n- 在Unix和类Unix系统中,可执行文件没有特定的扩展名,但通常具有可执行权限,通过命令行或图形界面启动。", "编程语言/C++/C++模拟考试.md": "\r\n# 计算机二级 C++ 试题\r\n\r\n**考试时间:120 分钟** \r\n**满分:100 分**\r\n\r\n> **说明:** \r\n> 本试卷不涉及模板和智能指针,重点考查面向对象编程和简单算法的编程能力。\r\n\r\n---\r\n\r\n## 一、选择题 (共10题,每题2分,共20分)\r\n\r\n1. 关于 C++ 的面向对象特性,下列描述正确的是: D\r\n A. 封装使得数据与对数据的操作组合在一起 \r\n B. 继承支持代码复用 \r\n C. 多态允许同一操作在不同对象上表现出不同的行为 \r\n D. 以上全部\r\n\r\n2. 在 C++ 中,class的默认访问权限是: C\r\n A. public \r\n B. protected \r\n C. private \r\n D. 无默认权限\r\n\r\n3. 当类中存在虚函数时,运行时调用哪个函数版本取决于: A\r\n A. 指针或引用所指对象的实际类型 \r\n B. 指针或引用的类型 \r\n C. 编译时绑定 \r\n D. 函数的参数列表\r\n\r\n4. 如果希望禁止类对象的拷贝,通常的做法是: C\r\n A. 不提供拷贝构造函数和赋值运算符 \r\n B. 将拷贝构造函数和赋值运算符声明为私有 \r\n C. 使用 const 修饰所有成员变量 \r\n D. 以上都不正确\r\n\r\n5. 在 C++ 中,struct的默认访问权限是: A\r\n A. public \r\n B. protected \r\n C. private \r\n D. 无默认权限\r\n\r\n6. 以下哪条语句正确包含了 iostream 头文件? C\r\n A. `#import ` \r\n B. `#include iostream` \r\n C. `#include ` \r\n D. `using namespace std;` \r\n\r\n7. 在 C++ 中,下列哪个运算符用于获取变量的地址? A\r\n A. & \r\n B. * \r\n C. -> \r\n D. % \r\n\r\n8. 以下哪一项是正确的函数声明? B\r\n A. `int func(int a, b);` \r\n B. `int func(int a, int b);` \r\n C. `func(int a, int b);` \r\n D. `int func(a, b);` \r\n\r\n9. 下列选项中,哪一个不是 C++ 的访问控制符? D\r\n A. public \r\n B. private \r\n C. protected \r\n D. external \r\n\r\n10. 关于 C++ 中的引用,以下说法正确的是: A\r\n A. 引用必须在定义时初始化 \r\n B. 引用可以改变绑定的对象 \r\n C. 引用可以为 NULL \r\n D. 引用占用额外的内存空间 \r\n\r\n---\r\n\r\n## 二、填空题 (共4题,每题2.5分,共10分)\r\n\r\n1. C++ 的面向对象三大特性是封装、______继承__ 和多态。 \r\n \r\n2. 成员函数在类外定义时需要使用 ______::__ 运算符指定其所属的类。 \r\n \r\n3. 如果一个函数在基类中声明为虚函数,那么在派生类中重写该函数时可以选择在函数声明后加上 ______override__ 关键字以提高代码可读性。 \r\n \r\n4. 递归算法必须包含一个或多个 ______终止__ 条件,以确保递归能够终止。 \r\n\r\n---\r\n\r\n\r\n\r\n---\r\n\r\n## 三、代码分析题 (共2题,每题10分,共20分)\r\n\r\n\r\n### 题目1\r\n\r\n阅读下面的代码,并回答问题:\r\n\r\n```cpp\r\n#include \r\nusing namespace std;\r\n\r\nvoid modifyPointer(int *p) {\r\n *p = 20;\r\n}\r\n\r\nint main() {\r\n int a = 10;\r\n int *ptr = &a;\r\n \r\n modifyPointer(ptr);\r\n \r\n cout << a << endl;\r\n \r\n return 0;\r\n}\r\n```\r\n1.程序的输出结果是什么?20\r\n2.解释指针 ptr 在 modifyPointer 函数调用过程中的作用,以及它对变量 a 的影响。指向a的地址 修改a的值\r\n\r\n\r\n### 题目2\r\n\r\n阅读下面的代码,并回答问题:\r\n\r\n```cpp\r\n#include \r\nusing namespace std;\r\n\r\nclass A {\r\npublic:\r\n A() {\r\n cout << \"A Constructor\" << endl;\r\n }\r\n ~A() {\r\n cout << \"A Destructor\" << endl;\r\n }\r\n};\r\n\r\nclass B : public A {\r\npublic:\r\n B() {\r\n cout << \"B Constructor\" << endl;\r\n }\r\n ~B() {\r\n cout << \"B Destructor\" << endl;\r\n }\r\n};\r\n\r\nint main() {\r\n B obj;\r\n return 0;\r\n}\r\n```\r\n1.程序的输出结果是什么?\r\n\r\nA Constructor\r\n\r\nB Constructor\r\n\r\nB Destructor\r\n\r\nA Destructor\r\n\r\n2.解释下子类与父类的构造、析构函数的调用顺序。子类构造过了父类,子类析构过了父类\r\n\r\n## 四、编程题 (共3题,共40分)\r\n\r\n### 题目:基于继承与多态的学生管理系统设计 — 10分\r\n\r\n**要求:** \r\n- 定义一个基类 `Person`,包含下列内容:\r\n - **保护成员**:姓名(`string`)\r\n - 构造函数:用于初始化姓名\r\n - **虚函数** `display()`:用于输出人员的基本信息\r\n- 定义一个派生类 `Student`,继承自 `Person`,并添加下列私有成员:\r\n - 学号(`int`)\r\n - 成绩(`float`)\r\n- 在 `Student` 类中,重写基类中的 `display()` 函数,输出学生的姓名、学号和成绩。\r\n- 在 `main()` 函数中,创建至少两个 `Student` 对象,并使用基类 `Person` 类型的指针调用 `display()` 函数,体现虚函数的多态特性。\r\n- 注意:请确保在基类中定义虚析构函数,以便正确释放派生类对象,请填充下面的代码实现。\r\n\r\n**示例代码:**\r\n```cpp\r\n#include \r\n#include \r\nusing namespace std;\r\n\r\n// 基类 Person,包含姓名和虚函数 display()\r\nclass Person {\r\n protected:\r\n string name;\r\n public:\r\n\r\n Person(string n, int i, float g){\r\n name = n;\r\n }\r\n\r\n virtual void display(){\r\n\r\n }\r\n};\r\n\r\n// 派生类 Student,继承自 Person,并添加学号和成绩\r\nclass Student :public Person {\r\n private:\r\n int id;\r\n float grade;\r\n\r\n public:\r\n Student(string n,int i,float g) override{\r\n name =n;\r\n id = i;\r\n grade = g;\r\n }\r\n\r\n virtual void display() override{\r\n cout<<\"学生的姓名:\"<display();\r\n p2->display();\r\n\r\n // 释放内存\r\n delete p1;\r\n delete p2;\r\n \r\n return 0;\r\n}\r\n```\r\n\r\n\r\n---\r\n\r\n### 题目2:递归实现二分查找 — 20分\r\n\r\n**要求:** \r\n- 编写一个 C++ 程序,使用递归实现二分查找算法,在一个有序的整数数组中查找目标值。 \r\n- 程序应要求用户输入一个目标值,若目标值存在,则输出其在数组中的下标;否则输出 -1。 \r\n- 代码中应包含对输入数据的提示以及对边界条件的合理判断。\r\n\r\n**示例代码:**\r\n```cpp\r\n#include \r\nusing namespace std;\r\n\r\n// 递归实现二分查找函数 请你填充此函数实现\r\nint binarySearch(int arr[], int left, int right, int target) {\r\n while (left<=right){\r\n int mid = left + (right-left)/2;\r\n if(arr[mid]==target){\r\n return mid;\r\n }else if(arr[mid]> target;\r\n \r\n int index = binarySearch(arr, 0, n - 1, target);\r\n if(index != -1) {\r\n cout << \"目标值 \" << target << \" 在数组中的下标为:\" << index << endl;\r\n } else {\r\n cout << \"目标值 \" << target << \" 不在数组中。\" << endl;\r\n }\r\n return 0;\r\n}\r\n```\r\n\r\n---\r\n\r\n### 题目3:冒泡排序实现 — 10分\r\n\r\n**要求:** \r\n- 编写一个 C++ 程序,定义一个整数数组,对数组进行冒泡排序。\r\n- 程序应先输出排序前的数组,再输出排序后的数组。\r\n- 代码要求体现出对冒泡排序核心思想的理解,结构清晰、注释明确,并注意边界情况的处理。\r\n\r\n**示例代码:**\r\n```cpp\r\n#include \r\nusing namespace std;\r\n\r\n// 冒泡排序函数 请你填充这个函数\r\nvoid bubbleSort(int arr[], int n) {\r\n for(int i=0;iarr[j+1]){\r\n swap(arr[j],arr[j+1]);\r\n }\r\n }\r\n}\r\n\r\n// 打印数组函数\r\nvoid printArray(const int arr[], int n) {\r\n for (int i = 0; i < n; i++) {\r\n cout << arr[i] << \" \";\r\n }\r\n cout << endl;\r\n}\r\n\r\nint main() {\r\n int arr[] = { 5, 3, 8, 6, 2, 7, 4, 1 };\r\n int n = sizeof(arr) / sizeof(arr[0]);\r\n \r\n cout << \"排序前的数组:\" << endl;\r\n printArray(arr, n);\r\n \r\n bubbleSort(arr, n);\r\n \r\n cout << \"排序后的数组:\" << endl;\r\n printArray(arr, n);\r\n \r\n return 0;\r\n}\r\n```\r\n\r\n\r\n**注意事项:** \r\n- 请仔细阅读每道题目的要求,确保在答题时详细阐述思路及关键实现步骤。 \r\n- 编程题请在本地编译测试确保代码正确无误。 \r\n\r\n祝各位考生考试顺利!", @@ -143,23 +160,39 @@ "编程语言/Python/Kivy/kivy编译安卓APK.md": "\n\n```bash\nsudo apt update && sudo apt upgrade -y\n\n#安装必要的依赖\nsudo apt install -y \\\n build-essential \\\n git \\\n python3 \\\n python3-pip \\\n python3-venv \\\n openjdk-17-jdk \\\n unzip \\\n zip \\\n libffi-dev \\\n libssl-dev \\\n libsqlite3-dev \\\n libjpeg-dev \\\n libfreetype6-dev \\\n libgl1-mesa-dev \\\n libgles2-mesa-dev \\\n zlib1g-dev \\\n autoconf \\\n automake \\\n libtool \\\n pkg-config \\\n cmake \\\n curl \\\n lld \\\n libncurses5\n\n#创建虚拟环境 \npython3 -m venv kivy_env\nsource kivy_env/bin/activate\n\n#升级pip\npip install --upgrade pip setuptools wheel cython\n\n#安装kivy\npip install \"kivy[base]\" kivy_examples\n#检查是否安装成功\npython -m kivy.examples.demo.touchtracer\n\n#安装 Buildozer构建环境\npip install buildozer\n#验证是否安装成功\nbuildozer --version\n\n#初始化 buildozer 配置文件\nbuildozer init\n\n#打包构建apk 开梯子!\nbuildozer android debug\n\n\n```\n\n\n```python\nfrom kivy.app import App\nfrom kivy.uix.label import Label\n\nclass MyApp(App):\n def build(self):\n return Label(text=\"Hello Android from Kivy!\")\n\nif __name__ == \"__main__\":\n MyApp().run()\n\n```\n\n\n\n\n\n\n\n\n\n", "编程语言/Python/Python国内pip加速镜像.md": "\n---\n\n## 一、常见国内镜像源推荐\n\n以下是一些稳定且速度优异的国内 PyPI 镜像源:\n\n- **清华大学** \n `https://pypi.tuna.tsinghua.edu.cn/simple`\n- **阿里云** \n `https://mirrors.aliyun.com/pypi/simple/`\n- **中国科技大学(USTC)** \n `https://pypi.mirrors.ustc.edu.cn/simple/` \n- **网易** \n `https://mirrors.163.com/pypi/simple/`\n- **豆瓣** \n `http://pypi.douban.com/simple/`(推荐使用 HTTPS 若可用)\n\n---\n\n## 二、临时使用镜像方法(每次安装时添加)\n\n在你激活的虚拟环境中,使用以下方式安装包时手动指定镜像源:\n\n```bash\npip install 包名 -i https://pypi.tuna.tsinghua.edu.cn/simple\n```\n\n如果镜像为 HTTP,并提示“不受信任”,可额外加上 `--trusted-host` 参数:\n\n```bash\npip install 包名 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com\n```\n\n\n---\n\n## 三、永久配置镜像(适用于当前虚拟环境)\n\n若希望省去每次输入 -i 参数的麻烦,可以在虚拟环境中创建或修改配置文件,使 pip 默认使用国内镜像:\n\n- **Unix / macOS 下虚拟环境:** \n 在虚拟环境目录下 `$VIRTUAL_ENV/pip.conf`\n \n- **Windows 虚拟环境:** \n 在 `%VIRTUAL_ENV%\\pip.ini`\n \n\n在其中添加以下内容(以清华源为例):\n\n```ini\n[global]\ntimeout = 120\nindex-url = https://pypi.tuna.tsinghua.edu.cn/simple\ntrusted-host = pypi.tuna.tsinghua.edu.cn\n```\n\n- `timeout`:设置最长等待时间,例如 **120 秒**,避免连接中断 \n \n- `index-url`:指定清华镜像为默认源\n \n- `trusted-host`:将镜像主机设为可信,避免 HTTPS 以外的警告\n \n\n记住,pip 配置的优先级如下(高到低):\n\n1. 虚拟环境中的配置\n \n2. 当前用户目录中的配置\n \n3. 全局配置(系统范围)\n \n\n---\n\n## 四、另一种永久配置方式:使用 pip config 命令\n\n你也可以通过 pip 自带的命令来设置全局配置(不限于虚拟环境):\n\n```bash\npip config set global.index-url https://mirrors.aliyun.com/pypi/simple/\n```\n\n随后你可以用 `pip config list` 来验证是否设置成功\n\n若想恢复到默认的官方 PyPI 源,可使用:\n\n```bash\npip config unset global.index-url\n```\n\n\n---\n\n## 五、方式对比一览\n\n|方式|优点|缺点|\n|---|---|---|\n|临时 `-i` 指定|简单快速,不改配置|每次需手动指定|\n|虚拟环境配置|仅对该虚拟环境生效|需进入每个环境配置|\n|全局配置|全局生效,无需重复配置|不够灵活,不适每个项目情况|\n\n---\n\n", "编程语言/Python/Pywebview库功能一览.md": "\n---\n\n## 一、基本概述\n\n- **跨平台原生 WebView 窗口** \n pywebview 是一个轻量级包装库,可在 Python 程序中使用 HTML/CSS/JavaScript 构建 GUI,打开原生的 WebView 窗口,适用于 Windows、macOS、Linux(GTK 或 QT)、Android 平台 ([GitHub](https://github.com/r0x0r/pywebview?utm_source=chatgpt.com \"r0x0r/pywebview: Build GUI for your Python program with ...\"), [pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n\n---\n\n## 二、核心功能分类\n\n### 1. 窗口管理功能\n\n- 使用 `webview.create_window(...)` 创建窗口,可设置属性包括:标题、加载方式(URL 或直接传 HTML)、尺寸(宽高)、位置坐标(x, y)、是否可调整大小、是否全屏、最小尺寸、隐藏窗口、无边框、阴影效果(仅限 Windows)、窗口置顶、关闭确认、背景颜色、透明、文本选择、缩放能力、拖拽能力、暗色模式等 ([pywebview.idepy.com](https://pywebview.idepy.com/guide/api?utm_source=chatgpt.com \"API - pywebview中文文档\"), [pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n- `webview.start(...)` 启动 GUI 消息循环,可额外配置回调函数、调试模式、HTTP 服务器、用户代理、隐私模式、存储路径、本地化、菜单设置、图标、SSL 等参数 ([pywebview.idepy.com](https://pywebview.idepy.com/guide/api?utm_source=chatgpt.com \"API - pywebview中文文档\"))。\n \n\n---\n\n### 2. JavaScript ↔ Python 双向通信\n\n- 通过 `js_api` 参数将 Python 对象暴露给 JavaScript,以便 JS 调用 Python 方法(返回 Promise);也支持运行时调用: `window.expose(func)` ([pywebview.idepy.com](https://pywebview.idepy.com/guide/api?utm_source=chatgpt.com \"API - pywebview中文文档\"), [pywebview.flowrl.com](https://pywebview.flowrl.com/guide/usage?utm_source=chatgpt.com \"Usage | pywebview - Example\"))。\n \n\n---\n\n### 3. 内建 HTTP 服务器支持\n\n- 自动为相对路径启动 Bottle HTTP 服务器;可在 `webview.start(http_server=True, ssl=True)` 中启用,并可传入自定义 WSGI 服务(如 Flask)作为 `url` 参数,或修改默认服务器的 SSL 行为 ([pywebview.flowrl.com](https://pywebview.flowrl.com/guide/usage?utm_source=chatgpt.com \"Usage | pywebview - Example\"), [pywebview.idepy.com](https://pywebview.idepy.com/guide/api?utm_source=chatgpt.com \"API - pywebview中文文档\"))。\n \n\n---\n\n### 4. DOM 操作能力\n\n- 支持在 Python 端进行 DOM 操作,如元素创建、搜索、修改属性或样式,事件注册等,类似 jQuery 操作体验。提供 `window.dom` API,包括 `dom.body`、`dom.document`、`dom.create_element()`、`dom.get_element(s)`,并支持事件监听,如 click、scroll 等 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n- 还支持拖拽文件,并获取完整文件路径 `event['dataTransfer']['files'][0]['pywebviewFullPath']` ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n\n---\n\n### 5. 事件机制\n\n- pywebview 5 引入 DOM 操作及基本事件支持(如 click 等)。\n \n- pywebview 6 提供更先进的网络事件支持,包括 `request_sent` 和 `response_received`,可拦截并修改请求头,还新增 `initialized` 事件(GUI 渲染器选择前触发)可用于配置判定 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n### 6. 全新共享状态管理(v6)\n\n- `window.state` 对象允许自动同步 JavaScript 和 Python 间的顶层属性状态,无需额外手动同步。例如在 Python 端设置 `window.state.user_name = \"Test\"`,在 JavaScript 中通过 `window.pywebview.state.user_name` 即可访问 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n### 7. 平台增强功能\n\n- **Android 支持**:pywebview 5 开始支持 Android(虽然功能较限,如不支持文件对话框、多窗口、窗口控制,但基本功能可用)([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n- **pywebview 6 优化 Android**:引入 Kivyless 实现,提高启动速度、减小包体,并支持全屏模式 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n### 8. 应用设置与 UI 菜单\n\n- **应用级设置**(v5):通过 `webview.settings` 定制行为,如控制文件下载、允许 file:// URL、外链跳转行为、调试模式下自动打开 DevTools 等 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n- **窗口级菜单**(v6):可以为每个窗口定义自定义菜单(Menu/MenueAction),类似桌面应用的菜单栏;部分平台(如 GTK + Unity)暂不支持 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n### 9. 平台尤其增强与现代化\n\n- **现代化 API 调整**:pywebview 6 改进了 FileDialog 枚举、设置项存放路径、移除废弃 DOM API 等 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n- **平台特定增强**:\n \n - Windows:支持暗色模式自动识别\n \n - macOS:可隐藏默认菜单、更好的 JS prompt 支持\n \n - 全平台:改进屏幕坐标处理和 SSL 支持 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n## 三、总结表格\n\n|功能分类|详细内容描述|\n|---|---|\n|窗口管理|多平台窗口创建与控制(尺寸、位置、样式等)|\n|JS ↔ Python 通信|js_api 和 expose 提供双向调用|\n|HTTP 服务器|内建 Bottle 服务器,可配置 SSL 与自定义 WSGI|\n|DOM 操作|从 Python 端操作 DOM 元素、事件绑定、拖拽功能|\n|事件机制|DOM 事件、网络请求事件、初始化事件|\n|状态同步|自动同步 window.state(Python ↔ JS)|\n|平台支持|Desktop 各平台 + Android,含特性差异|\n|应用配置 & 菜单|settings 配置项 + 窗口级菜单|\n|平台增强|暗色模式、JS prompt 优化、屏幕坐标、SSL 优化等|\n\n---\n", + "编程语言/前端/css注入代码合集.md": "# CSS 效果字典 — 注入代码合集\n\n> 本文档收集了 *30+* 个常用且有趣的 CSS 注入片段。每个片段都包含:\n> - **名称**(用途)\n> - **代码**(可直接复制到控制台或写入 `