<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>Kylaan</title><description>Kylaan的主页</description><link>https://kylaan.cn</link><item><title>Web 编辑器</title><link>https://kylaan.cn/blog/web_editor_deploy</link><guid isPermaLink="true">https://kylaan.cn/blog/web_editor_deploy</guid><description>基于 Hono + Vditor 的自托管博客编辑器部署记录</description><pubDate>Sat, 23 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Web 编辑器 Docker 部署&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;实现方案&lt;/strong&gt;: VPS 自托管 Hono 后端 + Vditor 前端, 走 clone-push 流程, Docker 容器化, 反代到 &lt;code&gt;editor.kylaan.cn&lt;/code&gt;
&lt;strong&gt;目标读者&lt;/strong&gt;: Kylaan, 跟着敲就上线
&lt;strong&gt;撰写时间&lt;/strong&gt;: 2026-05-23&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;你部署完之后会拥有&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;子域 https://editor.kylaan.cn (HTTPS + Basic Auth 保护)&lt;/li&gt;
&lt;li&gt;一个 Docker 容器 &lt;code&gt;blog-editor&lt;/code&gt;, 24/7 跑着, 自动重启&lt;/li&gt;
&lt;li&gt;浏览器开页 → 写文章 → 一键发布 → 1-2 分钟后 https://kylaan.cn 看到新文章&lt;/li&gt;
&lt;li&gt;一份 VPS 上的 git 工作区 (容器内), 跟 GitHub 双向同步&lt;/li&gt;
&lt;li&gt;草稿暂存 + 已发文章列表&lt;/li&gt;
&lt;li&gt;移动端可用 (Vditor 自带响应式)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;时长预估&lt;/h2&gt;
&lt;p&gt;| Phase | 内容 | 时间 |
|---|---|---|
| 0 | DNS + 服务器准备 | 10 分钟 |
| 1 | 生成 VPS push SSH key | 5 分钟 |
| 2 | 宝塔加站 + SSL | 10 分钟 |
| 3 | 写项目目录 + 配置文件 | 20 分钟 (复制粘贴) |
| 4 | nginx 反代 + Basic Auth | 10 分钟 |
| 5 | 启动 + 验证 | 10 分钟 |
| &lt;strong&gt;总计&lt;/strong&gt; | | &lt;strong&gt;~65 分钟&lt;/strong&gt; |&lt;/p&gt;
&lt;h2&gt;数据流回顾&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[浏览器: editor.kylaan.cn]
        │ HTTPS + Basic Auth
        ▼
[宝塔 nginx 反代]
        │
        ▼ 127.0.0.1:3001
[Docker 容器: blog-editor]
        │
        ├── Hono 后端 (服务 API + 静态前端)
        ├── 挂载: /app/workspace = git clone of blog repo
        ├── 挂载: /app/drafts = 草稿暂存
        └── 挂载: /root/.ssh = GitHub push key (只读)
        │
        │ 容器内: git pull → 写文件 → spawn publish.mjs → git push
        ▼
[GitHub repo: Kylaan/blog-asrto]
        │
        │ push 触发 .github/workflows/deploy.yml
        ▼
[GitHub Actions runner]
        │ pnpm install + astro build + rsync
        ▼
[/www/wwwroot/kylaan.cn] ──nginx serve──► [访客看到新文章]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;Phase 0: 前置准备&lt;/h1&gt;
&lt;h2&gt;0.1 添加 DNS A 记录&lt;/h2&gt;
&lt;p&gt;去你的域名 DNS 控制台 (阿里云/Cloudflare/腾讯云/...) 添加:&lt;/p&gt;
&lt;p&gt;| 记录类型 | 主机名 | 值 |
|---|---|---|
| A | &lt;code&gt;editor&lt;/code&gt; | &lt;code&gt;&amp;#x3C;你的服务器公网 IP&gt;&lt;/code&gt; |&lt;/p&gt;
&lt;p&gt;主机名 = &lt;code&gt;editor&lt;/code&gt;, 即完整域名 &lt;code&gt;editor.kylaan.cn&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;等 1-5 分钟后验证:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# Windows
nslookup editor.kylaan.cn
# 期望 Address 是你的服务器 IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DNS 没生效就不要往下做, 否则 SSL 申请会失败。&lt;/p&gt;
&lt;h2&gt;0.2 确认 Docker 已装好&lt;/h2&gt;
&lt;p&gt;SSH 进服务器:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;ssh root@&amp;#x3C;服务器IP&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查 Docker:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker --version
docker compose version
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;都返回版本号 → 已装好, 继续&lt;/li&gt;
&lt;li&gt;提示 command not found → 在宝塔面板里: &lt;strong&gt;软件商店 → Docker 管理器 → 安装&lt;/strong&gt;, 选最新稳定版&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;Phase 1: 生成 VPS 用的 GitHub push SSH key&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这是&lt;strong&gt;新的一对 key&lt;/strong&gt; (我们叫 Key ⑤), 跟之前 Actions 用的 Key ② 完全独立。
Key ② 让 Actions runner 进你服务器, Key ⑤ 让你服务器 push 到 GitHub。&lt;strong&gt;职责不同, 必须分开&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;1.1 在服务器上生成 key&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 还在 root SSH 会话里
mkdir -p ~/.ssh &amp;#x26;&amp;#x26; chmod 700 ~/.ssh

ssh-keygen -t ed25519 -C &quot;blog-editor-vps-push&quot; -f ~/.ssh/blog_webapp -N &quot;&quot;
# -N &quot;&quot; = passphrase 空; 容器内不能交互输入密码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生成两个文件:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/blog_webapp&lt;/code&gt; — 私钥, 等下会被容器以&lt;strong&gt;只读&lt;/strong&gt;方式挂载使用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/blog_webapp.pub&lt;/code&gt; — 公钥, 等下贴 GitHub&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;chmod 600 ~/.ssh/blog_webapp
chmod 644 ~/.ssh/blog_webapp.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;1.2 贴公钥到 GitHub&lt;/h2&gt;
&lt;p&gt;打印公钥内容:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cat ~/.ssh/blog_webapp.pub
# 输出形如: ssh-ed25519 AAAAC3...xyz blog-editor-vps-push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整行复制 (从 &lt;code&gt;ssh-ed25519&lt;/code&gt; 到末尾的注释), 然后:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;浏览器打开 https://github.com/settings/keys&lt;/li&gt;
&lt;li&gt;点 &lt;strong&gt;New SSH key&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Title: &lt;code&gt;blog-editor-vps-push&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Key type: &lt;strong&gt;Authentication Key&lt;/strong&gt; (不是 Signing Key!)&lt;/li&gt;
&lt;li&gt;Key 框里粘贴上面那一整行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add SSH key&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;注意: 这是 &lt;strong&gt;personal SSH key&lt;/strong&gt; (绑你 GitHub 账号), 不是 deploy key。因为我们要 push 到私库, deploy key 只能针对单个仓库, personal SSH key 拥有你账号下所有仓库的 push 权限。后续如果想收紧, 可以改成给单仓的 deploy key (本仓库 Settings → Deploy keys → Add deploy key, 勾 &quot;Allow write access&quot;)。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;1.3 测连通&lt;/h2&gt;
&lt;p&gt;在服务器上:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh -i ~/.ssh/blog_webapp -o IdentitiesOnly=yes -T git@github.com
# 期望输出: Hi Kylaan! You&apos;ve successfully authenticated, but GitHub does not provide shell access.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输错了的话:&lt;/p&gt;
&lt;p&gt;| 报错 | 原因 | 修法 |
|---|---|---|
| &lt;code&gt;Permission denied (publickey)&lt;/code&gt; | 公钥没贴 / 贴错账号 | 重做 1.2 |
| &lt;code&gt;Host key verification failed&lt;/code&gt; | 第一次连 github.com | 输 &lt;code&gt;yes&lt;/code&gt; 接受即可 |
| &lt;code&gt;Bad owner or permissions&lt;/code&gt; | key 文件权限 | &lt;code&gt;chmod 600 ~/.ssh/blog_webapp&lt;/code&gt; |&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;Phase 2: 宝塔加 editor 子站 + SSL&lt;/h1&gt;
&lt;h2&gt;2.1 添加站点&lt;/h2&gt;
&lt;p&gt;宝塔面板 → &lt;strong&gt;网站 → 添加站点&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;| 字段 | 值 |
|---|---|
| 域名 | &lt;code&gt;editor.kylaan.cn&lt;/code&gt; |
| 根目录 | &lt;code&gt;/www/wwwroot/editor.kylaan.cn&lt;/code&gt; (默认即可, 反代不会用到这个目录) |
| PHP 版本 | &lt;strong&gt;纯静态&lt;/strong&gt; |
| 数据库 | 不创建 |&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;提交&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;2.2 申请 SSL&lt;/h2&gt;
&lt;p&gt;刚加完的站点 → &lt;strong&gt;设置 → SSL → Let&apos;s Encrypt&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;勾选 &lt;code&gt;editor.kylaan.cn&lt;/code&gt; (只勾这一个, 不要勾 www)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;申请&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;等 30 秒, 提示证书已下发。然后:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开启 &lt;strong&gt;强制 HTTPS&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果申请失败 &quot;DNS validation failed&quot;, 回 Phase 0.1 等 DNS 再生效几分钟。&lt;/p&gt;
&lt;h2&gt;2.3 生成 Basic Auth 密码文件&lt;/h2&gt;
&lt;p&gt;服务器上:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 装 htpasswd 工具
apt update &amp;#x26;&amp;#x26; apt install -y apache2-utils

# 生成密码文件
htpasswd -c /www/server/nginx/conf/.htpasswd_editor kylaan
# 提示输入密码两次, 用强密码 (字母数字符号 12+ 位)
# 例如: blog-editor-2026!Xy7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存密码到你自己的密码管理器, 这是访问编辑器要输的密码。&lt;/p&gt;
&lt;p&gt;测试:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cat /www/server/nginx/conf/.htpasswd_editor
# 输出形如: kylaan:$apr1$xyz...$ABCDE
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;Phase 3: 项目目录 + 所有配置文件&lt;/h1&gt;
&lt;h2&gt;3.1 建目录结构&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir -p /www/docker/blog-editor/{server,frontend,workspace,drafts,ssh}
cd /www/docker/blog-editor
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.2 把 SSH key 复制 (硬链接) 到容器挂载目录&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cp ~/.ssh/blog_webapp ./ssh/blog_webapp
cp ~/.ssh/blog_webapp.pub ./ssh/blog_webapp.pub
chmod 600 ./ssh/blog_webapp
chmod 644 ./ssh/blog_webapp.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;为什么不直接挂 &lt;code&gt;~/.ssh&lt;/code&gt;? 因为里面可能还有你 root 本人的其它 key, 把整个目录暴露给容器太宽。单独建子目录只挂这把。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;3.3 写 &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nano /www/docker/blog-editor/docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  blog-editor:
    build: .
    image: blog-editor:latest
    container_name: blog-editor
    restart: unless-stopped
    ports:
      - &quot;127.0.0.1:3001:3001&quot;          # 只绑 loopback, 强制走 nginx
    volumes:
      - ./workspace:/app/workspace      # blog repo 工作区 (持久)
      - ./drafts:/app/drafts            # 草稿 (持久)
      - ./ssh:/root/.ssh:ro             # SSH key 只读挂载
    environment:
      TZ: &apos;Asia/Shanghai&apos;
      NODE_ENV: production
      PORT: 3001
      WORKSPACE_PATH: /app/workspace
      GIT_REMOTE: &apos;git@github.com:Kylaan/blog-asrto.git&apos;
      GIT_BRANCH: &apos;main&apos;
      GIT_USER_NAME: &apos;Blog Editor (kylaan.cn)&apos;
      GIT_USER_EMAIL: &apos;editor@kylaan.cn&apos;
    healthcheck:
      test: [&quot;CMD&quot;, &quot;wget&quot;, &quot;-qO-&quot;, &quot;http://localhost:3001/api/health&quot;]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 60s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Ctrl+O&lt;/code&gt; 保存, &lt;code&gt;Ctrl+X&lt;/code&gt; 退出。&lt;/p&gt;
&lt;h2&gt;3.4 写 &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nano /www/docker/blog-editor/Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;FROM node:20-alpine

# 装容器内要的工具: git + ssh + tini (PID 1 信号处理)
RUN apk add --no-cache git openssh-client tini

WORKDIR /app

# 先装后端依赖 (Hono + 一些 helpers)
COPY server/package.json ./server/package.json
RUN cd server &amp;#x26;&amp;#x26; npm install --omit=dev

# 拷后端源码 + 前端静态文件
COPY server/ ./server/
COPY frontend/ ./frontend/

# entrypoint 处理首次 clone / git config / 启动
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# 预先把 github.com 的 host key 写好, 避免容器内 ssh 提示
RUN mkdir -p /root/.ssh &amp;#x26;&amp;#x26; \
    ssh-keyscan github.com &gt;&gt; /root/.ssh/known_hosts &amp;#x26;&amp;#x26; \
    chmod 644 /root/.ssh/known_hosts

ENTRYPOINT [&quot;/sbin/tini&quot;, &quot;--&quot;, &quot;/entrypoint.sh&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.5 写 &lt;code&gt;entrypoint.sh&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nano /www/docker/blog-editor/entrypoint.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/sh
set -e

echo &quot;[entrypoint] starting blog-editor container...&quot;

# 1. 配置 git 身份
git config --global user.name &quot;${GIT_USER_NAME:-Blog Editor}&quot;
git config --global user.email &quot;${GIT_USER_EMAIL:-editor@kylaan.cn}&quot;
git config --global core.sshCommand &quot;ssh -i /root/.ssh/blog_webapp -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new&quot;
git config --global pull.rebase true
git config --global init.defaultBranch main

# 2. 首次启动 clone repo
if [ ! -d &quot;${WORKSPACE_PATH}/.git&quot; ]; then
  echo &quot;[entrypoint] cloning ${GIT_REMOTE} into ${WORKSPACE_PATH}...&quot;
  rm -rf &quot;${WORKSPACE_PATH:?}&quot;/* 2&gt;/dev/null || true
  git clone --depth=30 -b &quot;${GIT_BRANCH:-main}&quot; &quot;${GIT_REMOTE}&quot; &quot;${WORKSPACE_PATH}&quot;
else
  echo &quot;[entrypoint] workspace already exists, pulling latest...&quot;
  cd &quot;${WORKSPACE_PATH}&quot; &amp;#x26;&amp;#x26; git pull --rebase --autostash || echo &quot;[entrypoint] pull failed, will retry on first publish&quot;
fi

# 3. 启动 server
cd /app/server
echo &quot;[entrypoint] starting Hono server on :${PORT:-3001}&quot;
exec node server.mjs
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.6 写 &lt;code&gt;server/package.json&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nano /www/docker/blog-editor/server/package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;name&quot;: &quot;blog-editor-server&quot;,
  &quot;version&quot;: &quot;0.1.0&quot;,
  &quot;type&quot;: &quot;module&quot;,
  &quot;main&quot;: &quot;server.mjs&quot;,
  &quot;dependencies&quot;: {
    &quot;hono&quot;: &quot;^4.6.0&quot;,
    &quot;@hono/node-server&quot;: &quot;^1.13.0&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.7 写 &lt;code&gt;server/server.mjs&lt;/code&gt; (后端核心)&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nano /www/docker/blog-editor/server/server.mjs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { Hono } from &apos;hono&apos;
import { serve } from &apos;@hono/node-server&apos;
import { serveStatic } from &apos;@hono/node-server/serve-static&apos;
import { exec as execCb, spawn } from &apos;node:child_process&apos;
import { promisify } from &apos;node:util&apos;
import fs from &apos;node:fs/promises&apos;
import path from &apos;node:path&apos;
import { Buffer } from &apos;node:buffer&apos;

const exec = promisify(execCb)

const WORKSPACE = process.env.WORKSPACE_PATH || &apos;/app/workspace&apos;
const DRAFTS_DIR = &apos;/app/drafts&apos;
const BLOG_DIR = path.join(WORKSPACE, &apos;src/content/blog&apos;)
const PORT = parseInt(process.env.PORT || &apos;3001&apos;, 10)
const REPO_URL = (process.env.GIT_REMOTE || &apos;&apos;).replace(/^git@github\.com:/, &apos;https://github.com/&apos;).replace(/\.git$/, &apos;&apos;)

const app = new Hono()

// ===== 0. 健康检查 =====
app.get(&apos;/api/health&apos;, (c) =&gt; c.json({ ok: true, time: new Date().toISOString() }))

// ===== 1. 列出所有文章 =====
app.get(&apos;/api/posts&apos;, async (c) =&gt; {
  try {
    const entries = await fs.readdir(BLOG_DIR, { withFileTypes: true })
    const posts = []
    for (const e of entries) {
      if (!e.isDirectory()) continue
      const idxPath = path.join(BLOG_DIR, e.name, &apos;index.mdx&apos;)
      try {
        const raw = await fs.readFile(idxPath, &apos;utf-8&apos;)
        const fm = parseFrontmatter(raw)
        posts.push({
          slug: e.name,
          title: fm.title || e.name,
          publishDate: fm.publishDate || &apos;&apos;,
          draft: fm.draft === true || fm.draft === &apos;true&apos;,
          pinned: fm.pinned === true || fm.pinned === &apos;true&apos;
        })
      } catch {}
    }
    posts.sort((a, b) =&gt; (b.publishDate || &apos;&apos;).localeCompare(a.publishDate || &apos;&apos;))
    return c.json(posts)
  } catch (err) {
    return c.json({ error: err.message }, 500)
  }
})

// ===== 2. 取单篇文章 (用于编辑) =====
app.get(&apos;/api/posts/:slug&apos;, async (c) =&gt; {
  const slug = c.req.param(&apos;slug&apos;)
  if (!/^[a-z0-9-]+$/i.test(slug)) return c.json({ error: &apos;invalid slug&apos; }, 400)
  const idxPath = path.join(BLOG_DIR, slug, &apos;index.mdx&apos;)
  try {
    const raw = await fs.readFile(idxPath, &apos;utf-8&apos;)
    const { fm, body } = splitFrontmatter(raw)
    return c.json({ slug, frontmatter: fm, body })
  } catch {
    return c.json({ error: &apos;not found&apos; }, 404)
  }
})

// ===== 3. 发布 (新建或更新) =====
app.post(&apos;/api/publish&apos;, async (c) =&gt; {
  const body = await c.req.json().catch(() =&gt; ({}))
  const { slug, frontmatter, content, mode = &apos;create&apos; } = body

  // 基本校验
  if (!slug) return c.json({ error: &apos;slug 必填&apos; }, 400)
  if (!/^[a-z0-9-]+$/i.test(slug)) return c.json({ error: &apos;slug 只能字母/数字/-&apos; }, 400)
  if (!frontmatter?.title) return c.json({ error: &apos;title 必填&apos; }, 400)
  if (!frontmatter?.description) return c.json({ error: &apos;description 必填&apos; }, 400)
  if (!frontmatter?.publishDate) return c.json({ error: &apos;publishDate 必填&apos; }, 400)

  // 拉最新 (防本地端先 push 了)
  try {
    await exec(&apos;git pull --rebase --autostash&apos;, { cwd: WORKSPACE })
  } catch (err) {
    return c.json({ error: &apos;git pull 失败: &apos; + (err.stderr || err.message) }, 500)
  }

  // 写文件
  const dir = path.join(BLOG_DIR, slug)
  await fs.mkdir(dir, { recursive: true })
  const mdx = buildMdx(frontmatter, content || &apos;&apos;)
  await fs.writeFile(path.join(dir, &apos;index.mdx&apos;), mdx, &apos;utf-8&apos;)

  // 调 publish.mjs (复用本地一键发布脚本)
  const commitMsg = mode === &apos;create&apos;
    ? `feat: 新文章《${frontmatter.title}》`
    : `docs: 更新《${frontmatter.title}》`

  return new Promise((resolve) =&gt; {
    const child = spawn(&apos;node&apos;, [
      path.join(WORKSPACE, &apos;scripts/publish.mjs&apos;),
      &apos;-m&apos;, commitMsg,
      &apos;--no-check&apos;
    ], {
      cwd: WORKSPACE,
      env: { ...process.env, PUBLISH_AUTO_YES: &apos;1&apos; }
    })
    let out = &apos;&apos;, err = &apos;&apos;
    child.stdout.on(&apos;data&apos;, d =&gt; { out += d.toString() })
    child.stderr.on(&apos;data&apos;, d =&gt; { err += d.toString() })
    child.on(&apos;exit&apos;, (code) =&gt; {
      resolve(c.json({
        ok: code === 0,
        code,
        stdout: out,
        stderr: err,
        actionsUrl: REPO_URL ? REPO_URL + &apos;/actions&apos; : null
      }, code === 0 ? 200 : 500))
    })
    child.on(&apos;error&apos;, (e) =&gt; {
      resolve(c.json({ ok: false, error: &apos;spawn failed: &apos; + e.message }, 500))
    })
  })
})

// ===== 4. 图片上传 (Vditor 用) =====
app.post(&apos;/api/upload&apos;, async (c) =&gt; {
  const slug = c.req.query(&apos;slug&apos;)
  if (!slug || !/^[a-z0-9-]+$/i.test(slug)) {
    return c.json({ msg: &apos;请先填 slug&apos;, code: -1, data: { errFiles: [], succMap: {} } }, 400)
  }
  const formData = await c.req.formData()
  const files = formData.getAll(&apos;file[]&apos;)
  const dir = path.join(BLOG_DIR, slug)
  await fs.mkdir(dir, { recursive: true })

  const succMap = {}
  const errFiles = []
  for (const f of files) {
    if (!(f instanceof File)) { errFiles.push(&apos;not-a-file&apos;); continue }
    const safeName = f.name.replace(/[^a-zA-Z0-9._-]/g, &apos;_&apos;)
    const buf = Buffer.from(await f.arrayBuffer())
    await fs.writeFile(path.join(dir, safeName), buf)
    succMap[f.name] = `./${safeName}`
  }
  return c.json({ msg: &apos;&apos;, code: 0, data: { errFiles, succMap } })
})

// ===== 5. 手动同步 (从 GitHub pull) =====
app.post(&apos;/api/sync&apos;, async (c) =&gt; {
  try {
    const { stdout } = await exec(&apos;git pull --rebase --autostash&apos;, { cwd: WORKSPACE })
    return c.json({ ok: true, output: stdout })
  } catch (err) {
    return c.json({ ok: false, error: err.stderr || err.message }, 500)
  }
})

// ===== 6. 草稿 (本地暂存, 不进 git) =====
app.post(&apos;/api/drafts/:slug&apos;, async (c) =&gt; {
  const slug = c.req.param(&apos;slug&apos;) || &apos;untitled&apos;
  const safe = slug.replace(/[^a-zA-Z0-9-]/g, &apos;_&apos;)
  const data = await c.req.json()
  await fs.mkdir(DRAFTS_DIR, { recursive: true })
  await fs.writeFile(path.join(DRAFTS_DIR, safe + &apos;.json&apos;), JSON.stringify(data), &apos;utf-8&apos;)
  return c.json({ ok: true })
})

app.get(&apos;/api/drafts/:slug&apos;, async (c) =&gt; {
  const slug = c.req.param(&apos;slug&apos;)
  const safe = slug.replace(/[^a-zA-Z0-9-]/g, &apos;_&apos;)
  try {
    const raw = await fs.readFile(path.join(DRAFTS_DIR, safe + &apos;.json&apos;), &apos;utf-8&apos;)
    return c.json(JSON.parse(raw))
  } catch {
    return c.json({ error: &apos;no draft&apos; }, 404)
  }
})

// ===== 静态前端 =====
app.use(&apos;/*&apos;, serveStatic({ root: &apos;../frontend&apos; }))

serve({ fetch: app.fetch, port: PORT, hostname: &apos;0.0.0.0&apos; }, (info) =&gt; {
  console.log(`Blog Editor listening on http://0.0.0.0:${info.port}`)
})

// ===== helpers =====
function parseFrontmatter(raw) {
  const m = raw.match(/^---\s*\n([\s\S]*?)\n---/)
  if (!m) return {}
  const fm = {}
  for (const line of m[1].split(&apos;\n&apos;)) {
    const lm = line.match(/^([a-zA-Z]\w*):\s*(.*)$/)
    if (!lm) continue
    let val = lm[2].trim()
    if (val.startsWith(&quot;&apos;&quot;) &amp;#x26;&amp;#x26; val.endsWith(&quot;&apos;&quot;)) val = val.slice(1, -1)
    else if (val.startsWith(&apos;&quot;&apos;) &amp;#x26;&amp;#x26; val.endsWith(&apos;&quot;&apos;)) val = val.slice(1, -1)
    if (val === &apos;true&apos;) val = true
    else if (val === &apos;false&apos;) val = false
    fm[lm[1]] = val
  }
  return fm
}

function splitFrontmatter(raw) {
  const m = raw.match(/^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)/)
  if (!m) return { fm: {}, body: raw }
  return { fm: parseFrontmatter(raw), body: m[2] }
}

function buildMdx(fm, body) {
  const lines = [&apos;---&apos;]
  for (const [k, v] of Object.entries(fm)) {
    if (v === undefined || v === null || v === &apos;&apos;) continue
    if (Array.isArray(v)) {
      lines.push(`${k}: [${v.map(x =&gt; JSON.stringify(x)).join(&apos;, &apos;)}]`)
    } else if (typeof v === &apos;boolean&apos; || typeof v === &apos;number&apos;) {
      lines.push(`${k}: ${v}`)
    } else if (typeof v === &apos;object&apos;) {
      // heroImage 等嵌套
      lines.push(`${k}:`)
      for (const [k2, v2] of Object.entries(v)) {
        if (v2 === undefined || v2 === null || v2 === &apos;&apos;) continue
        if (typeof v2 === &apos;boolean&apos;) lines.push(`  ${k2}: ${v2}`)
        else lines.push(`  ${k2}: &apos;${String(v2).replace(/&apos;/g, &quot;&apos;&apos;&quot;)}&apos;`)
      }
    } else if (k === &apos;publishDate&apos; || k === &apos;updatedDate&apos;) {
      lines.push(`${k}: ${v}`)  // date 不加引号
    } else {
      lines.push(`${k}: &apos;${String(v).replace(/&apos;/g, &quot;&apos;&apos;&quot;)}&apos;`)
    }
  }
  lines.push(&apos;---&apos;)
  lines.push(&apos;&apos;)
  lines.push(body)
  return lines.join(&apos;\n&apos;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.8 写 &lt;code&gt;frontend/index.html&lt;/code&gt; (前端)&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nano /www/docker/blog-editor/frontend/index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;#x3C;!DOCTYPE html&gt;
&amp;#x3C;html lang=&quot;zh-CN&quot;&gt;
&amp;#x3C;head&gt;
  &amp;#x3C;meta charset=&quot;UTF-8&quot;&gt;
  &amp;#x3C;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &amp;#x3C;title&gt;Blog Editor — kylaan.cn&amp;#x3C;/title&gt;
  &amp;#x3C;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/vditor@3.10.7/dist/index.css&quot;&gt;
  &amp;#x3C;style&gt;
    * { box-sizing: border-box; }
    body { font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif; margin: 0; padding: 16px; max-width: 1400px; margin: 0 auto; color: #222; }
    h1 { margin: 0 0 12px; font-size: 20px; }
    .layout { display: grid; grid-template-columns: 220px 1fr; gap: 16px; }
    @media (max-width: 768px) { .layout { grid-template-columns: 1fr; } }
    aside { border-right: 1px solid #eee; padding-right: 12px; }
    aside h3 { font-size: 14px; margin: 12px 0 6px; color: #555; }
    aside ul { list-style: none; padding: 0; margin: 0; }
    aside li { padding: 4px 0; font-size: 13px; cursor: pointer; }
    aside li:hover { background: #f5f5f5; }
    aside li.active { font-weight: bold; color: #0066cc; }
    aside small { color: #888; font-size: 11px; display: block; }
    .meta { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 12px; padding: 10px; background: #fafafa; border: 1px solid #eee; border-radius: 4px; margin-bottom: 12px; }
    .meta label { display: flex; flex-direction: column; font-size: 12px; color: #555; gap: 2px; }
    .meta input, .meta select { padding: 6px 8px; border: 1px solid #ddd; border-radius: 3px; font: inherit; }
    .meta input:focus, .meta select:focus { outline: none; border-color: #0066cc; }
    .actions { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
    button { padding: 8px 14px; border: 0; border-radius: 4px; cursor: pointer; font-size: 13px; }
    .primary { background: #0066cc; color: #fff; }
    .primary:hover { background: #0052a3; }
    .secondary { background: #eee; color: #333; }
    .secondary:hover { background: #ddd; }
    #status { margin-top: 10px; padding: 8px 12px; border-radius: 4px; font-size: 13px; min-height: 30px; }
    #status.ok { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
    #status.err { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
    #status pre { font-size: 11px; max-height: 200px; overflow: auto; margin: 4px 0 0; white-space: pre-wrap; }
    #status a { color: inherit; text-decoration: underline; }
  &amp;#x3C;/style&gt;
&amp;#x3C;/head&gt;
&amp;#x3C;body&gt;
  &amp;#x3C;h1&gt;📝 Blog Editor &amp;#x3C;small style=&quot;font-size:12px;color:#888&quot;&gt;kylaan.cn&amp;#x3C;/small&gt;&amp;#x3C;/h1&gt;

  &amp;#x3C;div class=&quot;layout&quot;&gt;
    &amp;#x3C;aside&gt;
      &amp;#x3C;button class=&quot;primary&quot; style=&quot;width:100%&quot; onclick=&quot;newPost()&quot;&gt;+ 新建文章&amp;#x3C;/button&gt;
      &amp;#x3C;h3&gt;已发布&amp;#x3C;/h3&gt;
      &amp;#x3C;ul id=&quot;post-list&quot;&gt;&amp;#x3C;/ul&gt;
    &amp;#x3C;/aside&gt;

    &amp;#x3C;main&gt;
      &amp;#x3C;div class=&quot;meta&quot;&gt;
        &amp;#x3C;label&gt;slug (URL) &amp;#x3C;input id=&quot;f-slug&quot; placeholder=&quot;random-walk&quot;&gt;&amp;#x3C;/label&gt;
        &amp;#x3C;label&gt;title (标题) &amp;#x3C;input id=&quot;f-title&quot; placeholder=&quot;≤60 字&quot;&gt;&amp;#x3C;/label&gt;
        &amp;#x3C;label style=&quot;grid-column:1/-1&quot;&gt;description (摘要) &amp;#x3C;input id=&quot;f-description&quot; placeholder=&quot;≤160 字&quot;&gt;&amp;#x3C;/label&gt;
        &amp;#x3C;label&gt;publishDate &amp;#x3C;input id=&quot;f-publishDate&quot; type=&quot;date&quot;&gt;&amp;#x3C;/label&gt;
        &amp;#x3C;label&gt;tags (逗号分隔) &amp;#x3C;input id=&quot;f-tags&quot; placeholder=&quot;数学,概率&quot;&gt;&amp;#x3C;/label&gt;
        &amp;#x3C;label&gt;heroImage.src &amp;#x3C;input id=&quot;f-heroSrc&quot; placeholder=&quot;./cover.png&quot;&gt;&amp;#x3C;/label&gt;
        &amp;#x3C;label&gt;language &amp;#x3C;input id=&quot;f-language&quot; value=&quot;zh-CN&quot;&gt;&amp;#x3C;/label&gt;
        &amp;#x3C;label&gt;draft
          &amp;#x3C;select id=&quot;f-draft&quot;&gt;&amp;#x3C;option value=&quot;false&quot;&gt;false (公开)&amp;#x3C;/option&gt;&amp;#x3C;option value=&quot;true&quot;&gt;true (草稿)&amp;#x3C;/option&gt;&amp;#x3C;/select&gt;
        &amp;#x3C;/label&gt;
        &amp;#x3C;label&gt;pinned
          &amp;#x3C;select id=&quot;f-pinned&quot;&gt;&amp;#x3C;option value=&quot;false&quot;&gt;false&amp;#x3C;/option&gt;&amp;#x3C;option value=&quot;true&quot;&gt;true (置顶)&amp;#x3C;/option&gt;&amp;#x3C;/select&gt;
        &amp;#x3C;/label&gt;
      &amp;#x3C;/div&gt;

      &amp;#x3C;div id=&quot;editor&quot;&gt;&amp;#x3C;/div&gt;

      &amp;#x3C;div class=&quot;actions&quot;&gt;
        &amp;#x3C;button class=&quot;primary&quot; onclick=&quot;publish()&quot;&gt;🚀 发布 (push + 自动部署)&amp;#x3C;/button&gt;
        &amp;#x3C;button class=&quot;secondary&quot; onclick=&quot;syncPull()&quot;&gt;🔄 从 GitHub 同步&amp;#x3C;/button&gt;
        &amp;#x3C;button class=&quot;secondary&quot; onclick=&quot;saveDraft()&quot;&gt;💾 存草稿 (本地)&amp;#x3C;/button&gt;
      &amp;#x3C;/div&gt;

      &amp;#x3C;div id=&quot;status&quot;&gt;就绪&amp;#x3C;/div&gt;
    &amp;#x3C;/main&gt;
  &amp;#x3C;/div&gt;

  &amp;#x3C;script src=&quot;https://cdn.jsdelivr.net/npm/vditor@3.10.7/dist/index.min.js&quot;&gt;&amp;#x3C;/script&gt;
  &amp;#x3C;script&gt;
    let vditor, currentSlug = null

    document.addEventListener(&apos;DOMContentLoaded&apos;, () =&gt; {
      vditor = new Vditor(&apos;editor&apos;, {
        height: 600,
        mode: &apos;sv&apos;,
        cache: { enable: false },
        toolbarConfig: { pin: true },
        placeholder: &apos;开始写...&apos;,
        preview: {
          math: { engine: &apos;KaTeX&apos;, inlineDigit: true },
          markdown: { mark: true, footnotes: true, gfmAutoLink: true }
        },
        upload: {
          accept: &apos;image/*&apos;,
          fieldName: &apos;file[]&apos;,
          multiple: true,
          url: () =&gt; &apos;/api/upload?slug=&apos; + (document.getElementById(&apos;f-slug&apos;).value.trim() || &apos;tmp&apos;),
          format(files, responseText) { return responseText }
        },
        toolbar: [&apos;emoji&apos;, &apos;headings&apos;, &apos;bold&apos;, &apos;italic&apos;, &apos;strike&apos;, &apos;link&apos;, &apos;|&apos;,
                  &apos;list&apos;, &apos;ordered-list&apos;, &apos;check&apos;, &apos;outdent&apos;, &apos;indent&apos;, &apos;|&apos;,
                  &apos;quote&apos;, &apos;line&apos;, &apos;code&apos;, &apos;inline-code&apos;, &apos;insert-before&apos;, &apos;insert-after&apos;, &apos;|&apos;,
                  &apos;upload&apos;, &apos;table&apos;, &apos;|&apos;,
                  &apos;undo&apos;, &apos;redo&apos;, &apos;|&apos;,
                  &apos;fullscreen&apos;, &apos;edit-mode&apos;, { name: &apos;more&apos;, toolbar: [&apos;both&apos;, &apos;code-theme&apos;, &apos;content-theme&apos;, &apos;export&apos;, &apos;outline&apos;, &apos;preview&apos;, &apos;devtools&apos;, &apos;info&apos;, &apos;help&apos;] }]
      })
      loadList()
      setDefaultDate()
    })

    function setDefaultDate() {
      document.getElementById(&apos;f-publishDate&apos;).value = new Date().toISOString().slice(0, 10)
    }

    async function loadList() {
      try {
        const r = await fetch(&apos;/api/posts&apos;)
        const posts = await r.json()
        const ul = document.getElementById(&apos;post-list&apos;)
        ul.innerHTML = &apos;&apos;
        posts.forEach(p =&gt; {
          const li = document.createElement(&apos;li&apos;)
          li.className = currentSlug === p.slug ? &apos;active&apos; : &apos;&apos;
          li.innerHTML = `${p.draft ? &apos;📄&apos; : (p.pinned ? &apos;📌&apos; : &apos;📝&apos;)} ${escapeHtml(p.title)}&amp;#x3C;small&gt;${p.publishDate || &apos;&apos;} · ${p.slug}&amp;#x3C;/small&gt;`
          li.onclick = () =&gt; loadPost(p.slug)
          ul.appendChild(li)
        })
      } catch (e) {
        setStatus(&apos;加载列表失败: &apos; + e.message, &apos;err&apos;)
      }
    }

    async function loadPost(slug) {
      try {
        const r = await fetch(&apos;/api/posts/&apos; + slug)
        if (!r.ok) throw new Error(await r.text())
        const data = await r.json()
        currentSlug = slug
        document.getElementById(&apos;f-slug&apos;).value = slug
        const fm = data.frontmatter
        document.getElementById(&apos;f-title&apos;).value = fm.title || &apos;&apos;
        document.getElementById(&apos;f-description&apos;).value = fm.description || &apos;&apos;
        document.getElementById(&apos;f-publishDate&apos;).value = fm.publishDate || &apos;&apos;
        document.getElementById(&apos;f-tags&apos;).value = Array.isArray(fm.tags) ? fm.tags.join(&apos;, &apos;) : (fm.tags || &apos;&apos;)
        document.getElementById(&apos;f-heroSrc&apos;).value = (fm.heroImage &amp;#x26;&amp;#x26; fm.heroImage.src) || &apos;&apos;
        document.getElementById(&apos;f-language&apos;).value = fm.language || &apos;zh-CN&apos;
        document.getElementById(&apos;f-draft&apos;).value = String(fm.draft === true || fm.draft === &apos;true&apos;)
        document.getElementById(&apos;f-pinned&apos;).value = String(fm.pinned === true || fm.pinned === &apos;true&apos;)
        vditor.setValue(data.body || &apos;&apos;)
        setStatus(&apos;已加载 &apos; + slug + &apos; (修改后点发布会覆盖)&apos;, &apos;ok&apos;)
        loadList()
      } catch (e) {
        setStatus(&apos;加载失败: &apos; + e.message, &apos;err&apos;)
      }
    }

    function newPost() {
      currentSlug = null
      ;[&apos;slug&apos;, &apos;title&apos;, &apos;description&apos;, &apos;tags&apos;, &apos;heroSrc&apos;].forEach(k =&gt; document.getElementById(&apos;f-&apos; + k).value = &apos;&apos;)
      document.getElementById(&apos;f-language&apos;).value = &apos;zh-CN&apos;
      document.getElementById(&apos;f-draft&apos;).value = &apos;false&apos;
      document.getElementById(&apos;f-pinned&apos;).value = &apos;false&apos;
      setDefaultDate()
      vditor.setValue(&apos;# 标题\n\n开始写...\n&apos;)
      setStatus(&apos;准备写新文章&apos;, &apos;ok&apos;)
      loadList()
    }

    function collectFrontmatter() {
      const get = id =&gt; document.getElementById(&apos;f-&apos; + id).value.trim()
      const fm = {
        title: get(&apos;title&apos;),
        description: get(&apos;description&apos;),
        publishDate: get(&apos;publishDate&apos;),
        language: get(&apos;language&apos;) || &apos;zh-CN&apos;,
        draft: get(&apos;draft&apos;) === &apos;true&apos;,
        pinned: get(&apos;pinned&apos;) === &apos;true&apos;
      }
      const tags = get(&apos;tags&apos;).split(&apos;,&apos;).map(s =&gt; s.trim()).filter(Boolean)
      if (tags.length) fm.tags = tags
      const hero = get(&apos;heroSrc&apos;)
      if (hero) fm.heroImage = { src: hero, inferSize: hero.startsWith(&apos;http&apos;) }
      return fm
    }

    async function publish() {
      const slug = document.getElementById(&apos;f-slug&apos;).value.trim()
      if (!slug) return setStatus(&apos;slug 必填&apos;, &apos;err&apos;)
      if (!/^[a-z0-9-]+$/i.test(slug)) return setStatus(&apos;slug 只能字母/数字/-&apos;, &apos;err&apos;)

      const fm = collectFrontmatter()
      if (!fm.title) return setStatus(&apos;title 必填&apos;, &apos;err&apos;)
      if (!fm.description) return setStatus(&apos;description 必填&apos;, &apos;err&apos;)
      if (fm.title.length &gt; 60) return setStatus(&apos;title ≤60 字&apos;, &apos;err&apos;)
      if (fm.description.length &gt; 160) return setStatus(&apos;description ≤160 字&apos;, &apos;err&apos;)

      const content = vditor.getValue()
      setStatus(&apos;⏳ 发布中... (git push → GitHub Actions → rsync, 总共 1-2 分钟)&apos;, &apos;ok&apos;)

      try {
        const r = await fetch(&apos;/api/publish&apos;, {
          method: &apos;POST&apos;,
          headers: { &apos;Content-Type&apos;: &apos;application/json&apos; },
          body: JSON.stringify({
            slug, frontmatter: fm, content,
            mode: currentSlug === slug ? &apos;update&apos; : &apos;create&apos;
          })
        })
        const data = await r.json()
        if (data.ok) {
          currentSlug = slug
          const link = data.actionsUrl ? `&amp;#x3C;a href=&quot;${data.actionsUrl}&quot; target=&quot;_blank&quot;&gt;查看 Actions 进度&amp;#x3C;/a&gt;` : &apos;&apos;
          setStatus(`✓ 已 push! ${link}&amp;#x3C;pre&gt;${escapeHtml(data.stdout || &apos;&apos;)}&amp;#x3C;/pre&gt;`, &apos;ok&apos;)
          loadList()
        } else {
          setStatus(`✗ 失败 (exit ${data.code})\n${data.stderr || data.error || &apos;&apos;}\n${data.stdout || &apos;&apos;}`, &apos;err&apos;)
        }
      } catch (e) {
        setStatus(&apos;网络错误: &apos; + e.message, &apos;err&apos;)
      }
    }

    async function syncPull() {
      setStatus(&apos;⏳ 从 GitHub pull...&apos;, &apos;ok&apos;)
      try {
        const r = await fetch(&apos;/api/sync&apos;, { method: &apos;POST&apos; })
        const data = await r.json()
        if (data.ok) {
          setStatus(`✓ 已同步&amp;#x3C;pre&gt;${escapeHtml(data.output || &apos;&apos;)}&amp;#x3C;/pre&gt;`, &apos;ok&apos;)
          loadList()
        } else {
          setStatus(&apos;✗ &apos; + (data.error || &apos;&apos;), &apos;err&apos;)
        }
      } catch (e) {
        setStatus(&apos;网络错误: &apos; + e.message, &apos;err&apos;)
      }
    }

    async function saveDraft() {
      const slug = document.getElementById(&apos;f-slug&apos;).value.trim() || &apos;untitled&apos;
      try {
        const r = await fetch(&apos;/api/drafts/&apos; + slug, {
          method: &apos;POST&apos;,
          headers: { &apos;Content-Type&apos;: &apos;application/json&apos; },
          body: JSON.stringify({
            frontmatter: collectFrontmatter(),
            body: vditor.getValue(),
            savedAt: new Date().toISOString()
          })
        })
        const data = await r.json()
        setStatus(data.ok ? &apos;💾 草稿已存到 VPS (重启容器不丢)&apos; : &apos;✗ &apos; + data.error, data.ok ? &apos;ok&apos; : &apos;err&apos;)
      } catch (e) {
        setStatus(&apos;草稿保存失败: &apos; + e.message, &apos;err&apos;)
      }
    }

    function setStatus(msg, kind) {
      const el = document.getElementById(&apos;status&apos;)
      el.innerHTML = msg
      el.className = kind || &apos;&apos;
    }

    function escapeHtml(s) {
      return String(s).replace(/[&amp;#x26;&amp;#x3C;&gt;&quot;&apos;]/g, c =&gt; ({ &apos;&amp;#x26;&apos;: &apos;&amp;#x26;amp;&apos;, &apos;&amp;#x3C;&apos;: &apos;&amp;#x26;lt;&apos;, &apos;&gt;&apos;: &apos;&amp;#x26;gt;&apos;, &apos;&quot;&apos;: &apos;&amp;#x26;quot;&apos;, &quot;&apos;&quot;: &apos;&amp;#x26;#39;&apos; })[c])
    }
  &amp;#x3C;/script&gt;
&amp;#x3C;/body&gt;
&amp;#x3C;/html&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.9 检查目录结构&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /www/docker/blog-editor
ls -la
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;期望看到:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose.yml
Dockerfile
entrypoint.sh
server/
  package.json
  server.mjs
frontend/
  index.html
workspace/    # 空, 容器启动时 clone
drafts/       # 空
ssh/
  blog_webapp
  blog_webapp.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;Phase 4: nginx 反代 + Basic Auth&lt;/h1&gt;
&lt;h2&gt;4.1 找到 editor 站点的 nginx 配置文件&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ls /www/server/panel/vhost/nginx/
# 看到 editor.kylaan.cn.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.2 编辑反代&lt;/h2&gt;
&lt;p&gt;宝塔面板 → &lt;strong&gt;网站 → editor.kylaan.cn → 配置文件&lt;/strong&gt;, 或者命令行:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nano /www/server/panel/vhost/nginx/editor.kylaan.cn.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;找到 &lt;code&gt;server { ... }&lt;/code&gt; 块 (HTTPS 那个, 监听 443), 在里面 &lt;strong&gt;删掉/注释掉&lt;/strong&gt; 默认的 &lt;code&gt;location /&lt;/code&gt; 块, 替换成:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-nginx&quot;&gt;location / {
    # Basic Auth: 输 kylaan + 你 Phase 2.3 设的密码
    auth_basic &quot;Blog Editor (Kylaan only)&quot;;
    auth_basic_user_file /www/server/nginx/conf/.htpasswd_editor;

    # 反代到容器
    proxy_pass http://127.0.0.1:3001;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # 编辑器粘贴图片可能大一些
    client_max_body_size 20M;

    # 长轮询/上传可能慢, 给充裕的超时
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
}

# 限流防暴力破解 Basic Auth
limit_req_zone $binary_remote_addr zone=editor_login:10m rate=5r/s;
location = / {
    limit_req zone=editor_login burst=10 nodelay;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意: &lt;code&gt;limit_req_zone&lt;/code&gt; 一般要写在 &lt;code&gt;http&lt;/code&gt; 块, 写在 &lt;code&gt;server&lt;/code&gt; 块某些 nginx 版本会报错。如果保存后 nginx 报错, 把那两行 &lt;code&gt;limit_req_zone&lt;/code&gt; + &lt;code&gt;limit_req&lt;/code&gt; 删掉, 暂时不限流, 等问题不大。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;保存。宝塔会自动 &lt;code&gt;nginx -t &amp;#x26;&amp;#x26; nginx -s reload&lt;/code&gt;。报错就看顶部 banner。&lt;/p&gt;
&lt;h2&gt;4.3 验证 nginx 配置 (不启容器先试一下 auth)&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -I https://editor.kylaan.cn/
# 期望: HTTP/2 401   ← 因为还没输密码, 但 Basic Auth 已经生效

curl -I -u kylaan:你的密码 https://editor.kylaan.cn/
# 期望: HTTP/2 502   ← auth 过了, 但后端 (容器) 还没起所以 bad gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;到这一步 nginx 这一层就 OK 了。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;Phase 5: 启动!&lt;/h1&gt;
&lt;h2&gt;5.1 build + 启动容器&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /www/docker/blog-editor
docker compose up -d --build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一次 build 慢 (装 git/ssh/node 包), 大约 1-3 分钟。&lt;/p&gt;
&lt;h2&gt;5.2 看日志&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker logs -f blog-editor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;期望看到顺序:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[entrypoint] starting blog-editor container...
[entrypoint] cloning git@github.com:Kylaan/blog-asrto.git into /app/workspace...
Cloning into &apos;/app/workspace&apos;...
remote: Enumerating objects: ...
[entrypoint] starting Hono server on :3001
Blog Editor listening on http://0.0.0.0:3001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Ctrl+C&lt;/code&gt; 退出 log (容器仍在跑)。&lt;/p&gt;
&lt;h2&gt;5.3 验证容器是否健康&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker ps
# 看 blog-editor 状态 STATUS = &quot;Up X minutes (healthy)&quot;
# (healthy 标记要等 60 秒, 因为 start_period: 60s)

# 容器内直接打健康检查
docker exec blog-editor wget -qO- http://localhost:3001/api/health
# 期望: {&quot;ok&quot;:true,&quot;time&quot;:&quot;2026-...&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.4 验证通过 nginx 也能到&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -u kylaan:你的密码 https://editor.kylaan.cn/api/health
# 期望: {&quot;ok&quot;:true,&quot;time&quot;:&quot;...&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.5 浏览器打开&lt;/h2&gt;
&lt;p&gt;访问 https://editor.kylaan.cn, 浏览器弹原生 Basic Auth 对话框, 输 &lt;code&gt;kylaan&lt;/code&gt; + 你的密码。&lt;/p&gt;
&lt;p&gt;进入后应能看到:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;左侧: &quot;已发布&quot; 列表 (你现有的文章们)&lt;/li&gt;
&lt;li&gt;中间: 编辑器 + frontmatter 表单 + 发布按钮&lt;/li&gt;
&lt;li&gt;上方标题 &lt;code&gt;📝 Blog Editor&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;Phase 6: 第一次发文测试&lt;/h1&gt;
&lt;h2&gt;6.1 写一篇测试文章&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;点 &lt;strong&gt;+ 新建文章&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;填:
&lt;ul&gt;
&lt;li&gt;slug: &lt;code&gt;editor-test-1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;title: &lt;code&gt;编辑器测试文章&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;description: &lt;code&gt;从 web 编辑器发的第一篇&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;publishDate: 今天 (已自动填)&lt;/li&gt;
&lt;li&gt;tags: &lt;code&gt;测试&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;编辑器里随便写点东西, 比如:
&lt;pre&gt;&lt;code&gt;# 测试

这是从 https://editor.kylaan.cn 发出来的第一篇文章。

$E=mc^2$
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;点 &lt;strong&gt;🚀 发布&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;6.2 观察发布全流程&lt;/h2&gt;
&lt;p&gt;界面上会显示:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;⏳ 发布中... (git push → GitHub Actions → rsync, 总共 1-2 分钟)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后 5-10 秒后变成:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;✓ 已 push! 查看 Actions 进度
(stdout 日志)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;点 &quot;查看 Actions 进度&quot; 打开 GitHub → Actions, 看新触发的 run。&lt;/p&gt;
&lt;h2&gt;6.3 验证全链路&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GitHub 上有新 commit&lt;/strong&gt;: 仓库首页能看到 &lt;code&gt;feat: 新文章《编辑器测试文章》&lt;/code&gt; 的最新 commit&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Actions 跑起来&lt;/strong&gt;: Deploy to Server run, 5 step 全绿 (1-2 分钟)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rsync 完成&lt;/strong&gt;: 服务器上 &lt;code&gt;ls /www/wwwroot/kylaan.cn/blog/&lt;/code&gt; 能看到 &lt;code&gt;editor-test-1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网站可见&lt;/strong&gt;: 浏览器开 https://kylaan.cn/blog/editor-test-1, 文章页正常显示&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通了 = 全链路工作 ✅&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;维护 Cheat Sheet&lt;/h1&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /www/docker/blog-editor

# 看实时日志
docker logs -f blog-editor

# 重启容器 (改了 .env 或想强制重启)
docker compose restart

# 升级镜像 (改了 Dockerfile / server / frontend)
docker compose up -d --build

# 停掉
docker compose down

# 进容器 shell 排错
docker exec -it blog-editor sh
# 在容器里:
cd /app/workspace
git status
git log --oneline -5

# 查看 workspace 文件
ls workspace/src/content/blog/

# 查看草稿
ls drafts/

# 备份 (停容器后做)
docker compose down
tar -czf blog-editor-backup-$(date +%Y%m%d).tar.gz workspace drafts ssh docker-compose.yml Dockerfile entrypoint.sh server frontend
docker compose up -d

# 重置工作区 (假如同步混乱了)
docker compose down
rm -rf workspace/*
rm -rf workspace/.git
docker compose up -d        # entrypoint 会自动重新 clone

# 改密码
htpasswd /www/server/nginx/conf/.htpasswd_editor kylaan
# (不要带 -c, 否则会覆盖)
nginx -s reload
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;排错 FAQ&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Q: &lt;code&gt;docker compose up&lt;/code&gt; 报 &quot;permission denied&quot; 读 ssh 私钥&lt;/strong&gt;
A: &lt;code&gt;chmod 600 /www/docker/blog-editor/ssh/blog_webapp&lt;/code&gt;, 然后 &lt;code&gt;docker compose down &amp;#x26;&amp;#x26; up -d&lt;/code&gt;。SSH 强制要求 600。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: 容器一直 restarting&lt;/strong&gt;
A: &lt;code&gt;docker logs blog-editor&lt;/code&gt; 看具体报错。最常见: SSH key 不对, 或 GitHub repo URL 写错。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: 浏览器开了页面但 &quot;Vditor 未定义&quot;&lt;/strong&gt;
A: CDN 加载失败, 国内访问 jsdelivr 偶尔不通。临时方案: 等几分钟刷新; 长期方案: 把 &lt;code&gt;vditor@3.10.7/dist/index.css&lt;/code&gt; 和 &lt;code&gt;index.min.js&lt;/code&gt; 下载到 &lt;code&gt;frontend/vendor/&lt;/code&gt;, HTML 里引用本地路径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: 发布时 stderr 说 &quot;Updates were rejected because the remote contains work that you do not have locally&quot;&lt;/strong&gt;
A: 你本地用 &lt;code&gt;pnpm publish-post&lt;/code&gt; 抢先 push 了, VPS 工作区落后。点 &lt;strong&gt;🔄 从 GitHub 同步&lt;/strong&gt; 按钮, 再发布。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: 发布时 stderr 说 &quot;Permission denied (publickey)&quot; git push 不上去&lt;/strong&gt;
A: VPS 这把 push key (Key ⑤) 没装好。重做 Phase 1, 然后 &lt;code&gt;cp ~/.ssh/blog_webapp /www/docker/blog-editor/ssh/&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: 图片上传 &quot;请先填 slug&quot;&lt;/strong&gt;
A: 上传按钮要求 slug 已经填写 (因为图片要按文章归档)。先把 slug 填上, 再粘贴/上传图片。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: 文章发出去了但 https://kylaan.cn 看不到&lt;/strong&gt;
A: 看 GitHub Actions 那条 run 是否绿。绿了但还看不到 = nginx 缓存或浏览器缓存, 强刷 (Ctrl+Shift+R)。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: nginx 报 &lt;code&gt;unknown directive limit_req_zone&lt;/code&gt;&lt;/strong&gt;
A: 把 4.2 配置里 &lt;code&gt;limit_req_zone&lt;/code&gt; 和 &lt;code&gt;limit_req&lt;/code&gt; 那两段删掉。或者去 nginx 主配置 &lt;code&gt;nginx.conf&lt;/code&gt; 的 &lt;code&gt;http {}&lt;/code&gt; 块里加 &lt;code&gt;limit_req_zone $binary_remote_addr zone=editor_login:10m rate=5r/s;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: 想用 root 之外的非特权用户跑容器&lt;/strong&gt;
A: 在 &lt;code&gt;docker-compose.yml&lt;/code&gt; 加 &lt;code&gt;user: &quot;1000:1000&quot;&lt;/code&gt;, 然后把 &lt;code&gt;ssh/&lt;/code&gt;, &lt;code&gt;workspace/&lt;/code&gt;, &lt;code&gt;drafts/&lt;/code&gt; 都 &lt;code&gt;chown -R 1000:1000&lt;/code&gt;。本指南为了简单全用 root。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: 移动端访问能用吗?&lt;/strong&gt;
A: 能, Vditor 自带响应式。但移动端写长文体验一般, 推荐桌面写主要内容, 手机改小段。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;后续可扩展功能 (留给你以后做)&lt;/h1&gt;
&lt;p&gt;按优先级排:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;文章预览模式&lt;/strong&gt;: 调 Astro dev server 实时渲染当前文章, iframe 嵌入。需要在容器里多跑个 astro dev 实例&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;草稿列表&lt;/strong&gt;: 当前只有&quot;存草稿&quot;, 没有&quot;列出所有草稿&quot;的 UI。加 &lt;code&gt;GET /api/drafts&lt;/code&gt; + 前端 sidebar 多一个 tab&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;版本回滚&lt;/strong&gt;: 一个文件改坏了, 点 &quot;回滚到上一版&quot; → &lt;code&gt;git log &amp;#x3C;file&gt;&lt;/code&gt; + &lt;code&gt;git checkout &amp;#x3C;hash&gt; -- &amp;#x3C;file&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图床外接&lt;/strong&gt;: 默认图片进 git 历史会让 repo 膨胀。改成上传到 Cloudflare R2 / 七牛 / 阿里 OSS, 只写 URL 进 mdx&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多人协作&lt;/strong&gt;: 当前 nginx Basic Auth 一个密码所有人共用。改成 JWT + 用户系统, 不同人不同权限&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 辅助&lt;/strong&gt;: 集成 Claude API, 给&quot;扩写&quot;&quot;润色&quot;&quot;生成摘要&quot;按钮&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;统计&lt;/strong&gt;: 哪天写得最多、字数趋势、tags 分布&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Markdown 表格 / Mermaid 模板插入&lt;/strong&gt;: 工具栏加按钮, 一键插入常用代码块&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1&gt;相关文件&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;项目 README: &lt;a href=&quot;../README.md&quot;&gt;&lt;code&gt;../README.md&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;服务器从零搭建: &lt;a href=&quot;./SERVER_SETUP_GUIDE.md&quot;&gt;&lt;code&gt;./SERVER_SETUP_GUIDE.md&lt;/code&gt;&lt;/a&gt; — Phase 0-7 主站 + Waline&lt;/li&gt;
&lt;li&gt;Webapp 接口约定 (旧方案备份): &lt;a href=&quot;./MOBILE_WEBAPP_INTERFACE.md&quot;&gt;&lt;code&gt;./MOBILE_WEBAPP_INTERFACE.md&lt;/code&gt;&lt;/a&gt; — 走 GitHub Contents API 的版本&lt;/li&gt;
&lt;li&gt;一键发布脚本: &lt;a href=&quot;../scripts/publish.mjs&quot;&gt;&lt;code&gt;../scripts/publish.mjs&lt;/code&gt;&lt;/a&gt; — 容器内复用的核心&lt;/li&gt;
&lt;li&gt;GitHub Actions 部署: &lt;a href=&quot;../.github/workflows/deploy.yml&quot;&gt;&lt;code&gt;../.github/workflows/deploy.yml&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;更新这份文档时&lt;/strong&gt;: 改了 server.mjs / index.html 后, 把这里嵌入的代码块也同步更新, 保持 doc 和实际部署一致。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>阿里云服务器：使用 Docker + WebDAV 实现 Obsidian 多端同步</title><link>https://kylaan.cn/blog/webdav/obsidian</link><guid isPermaLink="true">https://kylaan.cn/blog/webdav/obsidian</guid><description>记录在阿里云服务器上搭建 WebDAV 的踩坑过程。从宝塔官方插件的 502 报错到最终使用 Docker Compose 完美解决，配合 Remotely Save 插件实现笔记无缝同步。</description><pubDate>Mon, 02 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Collapse } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h1&gt;阿里云服务器：使用 Docker + WebDAV 实现 Obsidian 多端同步&lt;/h1&gt;
&lt;p&gt;Obsidian 是一款极其强大的本地化双链笔记软件，但“本地化”也意味着多端同步一直是个痛点。官方的 Obsidian Sync 价格有些高昂，既然手里有一台 24 小时开机的阿里云服务器（2核2G配置），加上公网 IPv4，不如自己动手丰衣足食。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WebDAV + Remotely Save 插件&lt;/strong&gt; 是目前最主流且轻量的方案。但在宝塔面板上直接部署的过程中，我却踩了几个非常经典的坑。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;踩坑记录：被宝塔官方 WebDAV 插件背刺&lt;/h2&gt;
&lt;p&gt;一开始，我的思路非常直接：既然服务器装了宝塔面板，直接去软件商店点个安装不就行了？&lt;/p&gt;
&lt;p&gt;结果第一步就卡住了——软件商店列表无法加载。通过 SSH 终端测试发现是服务器的 DNS 解析出了问题：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ping: [www.baidu.com](https://www.baidu.com): Name or service not known

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;顺手通过向 &lt;code&gt;/etc/resolv.conf&lt;/code&gt; 写入阿里云公共 DNS (&lt;code&gt;223.5.5.5&lt;/code&gt;) 解决了断网问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但更大的坑在后面。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;安装好宝塔 WebDAV 插件并配置了 &lt;code&gt;127.0.0.1:8082&lt;/code&gt; 端口，外层套上泛域名解析并申请了 SSL 证书，做好了 Nginx 反向代理。满心欢喜地打开浏览器访问，迎接我的却是冰冷的：&lt;strong&gt;502 Bad Gateway&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;curl&lt;/code&gt; 排查，发现底层服务根本没跑起来：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl: (7) Failed to connect to 127.0.0.1 port 8082: Connection refused

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即使把监听地址换成了全局的 &lt;code&gt;0.0.0.0&lt;/code&gt;，通过 &lt;code&gt;ss -tulnp | grep :80&lt;/code&gt; 依然看不到任何程序在监听 8082 端口。&lt;strong&gt;彻底破案：宝塔官方的 WebDAV 插件存在假死 Bug，UI 显示成功，底层服务根本没有启动。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;最终方案：Docker 编排&lt;/h2&gt;
&lt;p&gt;通过 Docker Compose 跑一个极轻量的 WebDAV 镜像，不仅稳定，而且维护起来异常清晰。&lt;/p&gt;
&lt;h3&gt;1. 准备目录与配置文件&lt;/h3&gt;
&lt;p&gt;在服务器上新建专用的项目目录和笔记存储目录：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir -p /opt/obsidian-webdav
mkdir -p /www/wwwroot/obsidian_sync
cd /opt/obsidian-webdav
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建 &lt;code&gt;.env&lt;/code&gt; 文件，将账号密码和端口配置抽离出来，方便日后修改：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-env&quot;&gt;# WebDAV 账号和密码（请务必修改为强密码）
WEBDAV_USERNAME=&amp;#x3C;your_username&gt;
WEBDAV_PASSWORD=&amp;#x3C;your_secure_password&gt;

# 绑定的本地端口
WEBDAV_PORT=8082

# 宿主机的笔记存储路径
SYNC_DIR=/www/wwwroot/obsidian_sync

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 编写 Docker Compose&lt;/h3&gt;
&lt;p&gt;在同目录下创建 &lt;code&gt;docker-compose.yml&lt;/code&gt;。这里有一个细节：&lt;strong&gt;端口映射必须强制绑定 &lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/strong&gt;，这样可以防止 Docker 穿透阿里云和宝塔的防火墙将 WebDAV 裸露在公网上，确保所有的访问都必须乖乖走我们配置好 HTTPS 的反向代理。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;version: &apos;3.8&apos;

services:
  webdav:
    image: bytemark/webdav:latest
    container_name: obsidian-webdav
    restart: always
    ports:
      # 强制绑定 127.0.0.1，保障安全
      - &quot;127.0.0.1:${WEBDAV_PORT}:80&quot;
    environment:
      - AUTH_TYPE=Basic
      - USERNAME=${WEBDAV_USERNAME}
      - PASSWORD=${WEBDAV_PASSWORD}
    volumes:
      - ${SYNC_DIR}:/var/lib/dav

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行 &lt;code&gt;docker compose up -d&lt;/code&gt;，容器瞬间秒级启动。再去 &lt;code&gt;curl&lt;/code&gt; 测试，终于看到了久违的 &lt;code&gt;HTTP/1.1 401 Unauthorized&lt;/code&gt; 身份验证提示。&lt;/p&gt;
&lt;h2&gt;完善反向代理与 HTTPS（iOS 同步必备）&lt;/h2&gt;
&lt;p&gt;因为 iOS 端的 Obsidian（或者大部分手机端 WebDAV 客户端）强制要求 HTTPS 协议，所以我们必须在宝塔里做一次反向代理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在宝塔面板新建一个&lt;strong&gt;纯静态&lt;/strong&gt;站点，绑定你分配给笔记同步的子域名（例如 &lt;code&gt;obsidian.yourdomain.com&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;在 SSL 选项卡中，使用 Let&apos;s Encrypt 申请免费证书，并开启&lt;strong&gt;强制 HTTPS&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;在站点的“反向代理”设置中，添加一条代理，目标 URL 填写 &lt;code&gt;http://127.0.0.1:8082&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;成果验收与结语&lt;/h2&gt;
&lt;p&gt;打开 Obsidian，关闭安全模式，下载社区插件 &lt;strong&gt;Remotely Save&lt;/strong&gt;。
选择 WebDAV 同步，填入 &lt;code&gt;https://obsidian.yourdomain.com&lt;/code&gt; 和刚才在 &lt;code&gt;.env&lt;/code&gt; 中设置的账号密码。点击 &quot;Check&quot; 测试，成功连接。&lt;/p&gt;</content:encoded><h:img src="/_astro/obsidian-logo.BsUPOhUP.png"/><enclosure url="/_astro/obsidian-logo.BsUPOhUP.png"/></item><item><title>使用 1Panel + Docker 部署全自动 Bing Rewards 积分脚本</title><link>https://kylaan.cn/blog/bingrewards/rewards</link><guid isPermaLink="true">https://kylaan.cn/blog/bingrewards/rewards</guid><description>使用 Docker 容器化edge浏览器，在 Linux 服务器上实现 Bing Rewards 自动挂机，附带自动唤醒和日志功能的脚本改造。</description><pubDate>Sat, 21 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Collapse } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h1&gt;使用 1Panel + Docker 部署全自动 Bing Rewards 积分脚本&lt;/h1&gt;
&lt;p&gt;Microsoft Bing 每日搜索就能获得 Rewards 积分，既然手里有一台 24 小时开机的 NAS / 1Panel 面板，不妨直接部署在服务器上自动挂机，既省电又方便。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker 容器化edge浏览器&lt;/strong&gt; 实现了在无头 Linux 服务器上运行带 GUI 的浏览器，完美绕过了微软的反爬机制，配合改造后的 JavaScript 脚本实现。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;想法：纯 Python 无头浏览器？&lt;/h2&gt;
&lt;p&gt;一开始，我的思路非常直接：用 Python + Playwright 写一个脚本，放在后台跑不就行了？&lt;/p&gt;
&lt;p&gt;于是根据原本在 PC 上跑的油猴（Tampermonkey）脚本逻辑，写出了 Python 版本的自动化搜索爬虫。但最大的问题出现了：&lt;strong&gt;账号登录&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;微软的防机器人的风控非常严格。在没有显示器的 Headless Linux 服务器上，想要让脚本自动过验证码、处理 2FA 双重认证几乎是不可能的。
唯一的解法是：&lt;strong&gt;在本地电脑登录好，导出 Cookies，再传到服务器上给 Python 脚本吃。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;但 Cookies 是会过期的。这意味着每隔一段时间，我就得手动抓一次 Cookies 上传。&lt;/p&gt;
&lt;h2&gt;最终方案：Docker 化的 Web 浏览器&lt;/h2&gt;
&lt;p&gt;最终发现Dockers hub上已经有现成的 Firefox 和 Edge 浏览器镜像。&lt;/p&gt;
&lt;p&gt;我们可以通过 Docker 跑一个完整的 Firefox 或 Edge 浏览器，并通过 HTML5 的 VNC 技术，把浏览器的画面实时推送到网页上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这意味着，我可以用极其轻量的资源，在毫无图形界面的 Linux 服务器上，获得一个可以通过网页随时随地访问的“虚拟浏览器”&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;部署过程 (基于 1Panel)&lt;/h3&gt;
&lt;p&gt;在 1Panel 面板中，整个部署过程异常丝滑：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开 1Panel，进入 &lt;strong&gt;容器 -&gt; 编排 -&gt; 创建编排&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;填入以下 &lt;code&gt;docker-compose.yml&lt;/code&gt; 配置：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;version: &apos;3&apos;
services:
  edge:
    image: jlesage/edge
    container_name: bing-rewards
    restart: unless-stopped
    ports:
      - &quot;&amp;#x3C;port&gt;:5800&quot; # 映射到宿主机的访问端口
    volumes:
      - /opt/1panel/local/edge:/config:rw # 持久化配置
    environment:
      - LANG=zh_CN.UTF-8 # 中文界面
    shm_size: &quot;1gb&quot; # 给足共享内存，防止崩溃

&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;点击启动！&lt;/li&gt;
&lt;li&gt;在浏览器输入 &lt;code&gt;http://服务器IP:5800&lt;/code&gt;访问&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在这个容器化的浏览器里，像往常一样打开 Bing 登录账号，安装 Tampermonkey 插件，一切行云流水，没有任何反爬阻碍。&lt;/p&gt;
&lt;h2&gt;终极改造：让脚本成为真正的“全自动收割机”&lt;/h2&gt;
&lt;p&gt;浏览器有了，脚本也装了。但原来的脚本有一个缺陷：&lt;strong&gt;必须要手动点击菜单才能开始运行&lt;/strong&gt;。
既然是挂机，我当然希望它能够每天自动开始，完全不需要我的干预。&lt;/p&gt;
&lt;p&gt;为了让它能够真正“无人值守”，我对原版的 JavaScript 脚本进行了深度改造，加入了&lt;strong&gt;时间检测机制&lt;/strong&gt;和&lt;strong&gt;日志记录功能&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;核心改造代码片段&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 自动唤醒机制&lt;/strong&gt;
我加入了一段守护循环，只要检测到过了早上 6:00，并且今天还没运行过，脚本就会自动把计数器归零并开始执行。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function checkAndStartDailyTask() {
    let now = new Date();
    let today = now.toLocaleDateString();
    let lastRunDate = GM_getValue(&apos;LastRunDate&apos;, &apos;&apos;);

    // 每天 6:00 之后自动重置任务
    if (today !== lastRunDate &amp;#x26;&amp;#x26; now.getHours() &gt;= 6) {
        GM_setValue(&apos;Cnt&apos;, 0); 
        GM_setValue(&apos;LastRunDate&apos;, today);
        // ... 初始化日志 ...
        if (!location.href.includes(&quot;[bing.com/?br_msg=Auto-Start](https://bing.com/?br_msg=Auto-Start)&quot;)) {
            location.href = &quot;[https://www.bing.com/?br_msg=Auto-Start](https://www.bing.com/?br_msg=Auto-Start)&quot;;
            return true; 
        }
    }
    return false;
}
// 挂机守候：每 1 分钟检查一次时间
setInterval(checkAndStartDailyTask, 60000);

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. 积分抓取与可视化日志&lt;/strong&gt;
光跑完不行，我还想知道它到底拿了多少分。我加入了 DOM 元素抓取功能，在任务开始前记录初始积分，结束后记录最终积分，并利用 &lt;code&gt;Blob&lt;/code&gt; 自动生成一个精美的 HTML 日志页面。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 任务刚开始时抓取
if (currentSearchCount === 0) {
    let pts = await getPoints();
    GM_setValue(&apos;StartPoints&apos;, pts);
    addLog(`&amp;#x3C;b&gt;任务正式开始&amp;#x3C;/b&gt; 🚀 初始积分: ${pts}`);
}

// 任务结束时展示日志
else if (currentSearchCount === max_rewards) {
    let endPts = await getPoints();
    // ... 拼接 HTML 日志 ...
    let blob = new Blob([finalLog], { type: &apos;text/html;charset=utf-8&apos; });
    let url = URL.createObjectURL(blob);
    GM_openInTab(url, { active: true }); // 自动弹出日志标签页
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;成果验收与结语&lt;/h2&gt;
&lt;p&gt;现在，我的方案完美运转：
那个跑在 Docker 里的浏览器常年挂在后台，停留在 Bing 的首页。每天清晨 6 点，脚本自动启动，自己翻找热门词汇，模拟人类习惯进行滑动和搜索，并在触发风控阈值前聪明地暂停休息。&lt;/p&gt;
&lt;p&gt;当我下课或者闲暇时，只需连上我的 Tailscale 虚拟局域网，打开手机浏览器访问 &lt;code&gt;http://服务器内网IP:5800&lt;/code&gt;。映入眼帘的不是枯燥的代码报错，而是一个排版精美、记录着详细积分收益的日志页面.&lt;/p&gt;
&lt;h2&gt;附：完整脚本代码&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// ==UserScript==
// @name         Microsoft Bing Rewards每日任务脚本 (6:00自动/带日志/带积分)
// @version      V4.2.0
// @description  每天6:00后自动执行，获取热门词搜索，记录详细日志并抓取初始和结束积分。
// @note         基于V4.1.0深度修改
// @author       怀沙2049 (Modified)
// @match        https://*.bing.com/*
// @exclude      https://rewards.bing.com/*
// @license      GNU GPLv3
// @icon         https://www.bing.com/favicon.ico
// @connect      gumengya.com
// @run-at       document-end
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_openInTab
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @namespace    https://greasyfork.org/zh-CN/scripts/477107
// ==/UserScript==

var max_rewards = 25; // 重复执行的次数
var pause_time = 2000; // 暂停时长 (根据原脚本设置, 若需16分钟请改为 960000)
var search_words = []; // 搜索词
var appkey = &quot;b7a782741f667201b54880c925faec4b&quot;;
var Hot_words_apis = &quot;https://api.gmya.net/Api/&quot;;
var keywords_source = [&apos;TouTiaoHot&apos;,&apos;DouYinHot&apos;,&apos;WeiBoHot&apos;,&apos;BaiduHot&apos;];
var current_source_index = 0;

var default_search_words = [&quot;盛年不重来，一日难再晨&quot;, &quot;千里之行，始于足下&quot;, &quot;少年易学老难成&quot;, &quot;敏而好学，不耻下问&quot;, &quot;海内存知已&quot;, &quot;三人行必有我师&quot;, &quot;天生我材必有用&quot;, &quot;海纳百川&quot;, &quot;读书破万卷&quot;, &quot;学而不思则罔&quot;, &quot;莫等闲&quot;, &quot;少壮不努力&quot;, &quot;近朱者赤&quot;, &quot;学无止境&quot;, &quot;己所不欲勿施于人&quot;, &quot;天下兴亡&quot;, &quot;为中华之崛起&quot;, &quot;淡泊明志&quot;, &quot;宁静致远&quot;, &quot;卧龙跃马&quot;];

// -----------------------------------------------------
// 核心逻辑 1：6:00 自动唤醒与重置检查
// -----------------------------------------------------
function checkAndStartDailyTask() {
    let now = new Date();
    let today = now.toLocaleDateString();
    let lastRunDate = GM_getValue(&apos;LastRunDate&apos;, &apos;&apos;);

    // 每天 6:00 之后，且今天还没运行过
    if (today !== lastRunDate &amp;#x26;&amp;#x26; now.getHours() &gt;= 6) {
        console.log(&quot;达到 6:00，自动重置任务并开始！&quot;);
        GM_setValue(&apos;Cnt&apos;, 0); // 计数器归零
        GM_setValue(&apos;LastRunDate&apos;, today);
        
        // 初始化精美 HTML 日志模板
        let logTemplate = `
            &amp;#x3C;div style=&quot;font-family: &apos;Segoe UI&apos;, Tahoma, sans-serif; padding: 30px; background-color: #f3f2f1; color: #323130; min-height: 100vh;&quot;&gt;
                &amp;#x3C;div style=&quot;max-width: 800px; margin: 0 auto; background: white; padding: 25px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1);&quot;&gt;
                    &amp;#x3C;h2 style=&quot;color: #0078d4; border-bottom: 2px solid #0078d4; padding-bottom: 10px; margin-top: 0;&quot;&gt;Bing Rewards 自动搜索日志 - ${today}&amp;#x3C;/h2&gt;
                    &amp;#x3C;ul style=&quot;line-height: 2; font-size: 15px; list-style-type: none; padding-left: 0;&quot;&gt;
        `;
        GM_setValue(&apos;DailyLog&apos;, logTemplate);
        GM_setValue(&apos;StartPoints&apos;, &apos;等待获取...&apos;);

        // 如果当前不在首页，跳转回首页以确保干净的启动环境
        if (!location.href.includes(&quot;bing.com/?br_msg=Auto-Start&quot;)) {
            location.href = &quot;https://www.bing.com/?br_msg=Auto-Start&quot;;
            return true; 
        }
    }
    return false;
}

// 页面加载时执行一次检查，如果是为了启动而跳转，则中止后续脚本
if (checkAndStartDailyTask()) return;

// 挂机守候：每 1 分钟检查一次时间（专门针对 Docker 长期挂在某一页面的情况）
setInterval(checkAndStartDailyTask, 60000);

// -----------------------------------------------------
// 核心逻辑 2：日志记录与积分抓取工具
// -----------------------------------------------------
function addLog(msg) {
    let log = GM_getValue(&apos;DailyLog&apos;, &apos;&apos;);
    let timeStr = new Date().toLocaleTimeString(&apos;zh-CN&apos;, { hour12: false });
    log += `&amp;#x3C;li style=&quot;border-bottom: 1px dashed #edebe9; padding: 5px 0;&quot;&gt;&amp;#x3C;span style=&quot;color: #605e5c; margin-right: 15px;&quot;&gt;[${timeStr}]&amp;#x3C;/span&gt; ${msg}&amp;#x3C;/li&gt;`;
    GM_setValue(&apos;DailyLog&apos;, log);
}

// 异步抓取积分 (重试 5 次，等待页面加载)
async function getPoints() {
    for (let i = 0; i &amp;#x3C; 5; i++) {
        let el = document.getElementById(&apos;id_rc&apos;); // Bing 页面顶部积分元素的固定 ID
        if (el &amp;#x26;&amp;#x26; el.innerText) return el.innerText;
        await new Promise(r =&gt; setTimeout(r, 1000));
    }
    return &apos;获取失败 (可能未登录或网络延迟)&apos;;
}

// -----------------------------------------------------
// 搜索词获取与执行入口
// -----------------------------------------------------
async function douyinhot_dic() {
    while (current_source_index &amp;#x3C; keywords_source.length) {
        const source = keywords_source[current_source_index];
        let url = appkey ? `${Hot_words_apis}${source}?format=json&amp;#x26;appkey=${appkey}` : `${Hot_words_apis}${source}`;
        try {
            const response = await fetch(url);
            if (response.ok) {
                const data = await response.json();
                if (data.data &amp;#x26;&amp;#x26; data.data.some(item =&gt; item)) {
                    return data.data.map(item =&gt; item.title);
                }
            }
        } catch (error) {
            console.error(&apos;搜索词来源请求失败:&apos;, error);
        }
        current_source_index++;
    }
    return default_search_words;
}

douyinhot_dic().then(names =&gt; {
    search_words = names;
    exec();
}).catch(error =&gt; console.error(error));

// -----------------------------------------------------
// 核心逻辑 3：主执行函数 (包含完成后的日志展示)
// -----------------------------------------------------
function AutoStrTrans(st) { /* ...原函数简化... */
    let yStr = st, rStr = &quot;&quot;, zStr = &quot;&quot;, prePo = 0;
    for (let i = 0; i &amp;#x3C; yStr.length;) {
        let step = parseInt(Math.random() * 5) + 1;
        if (i &gt; 0) { zStr += yStr.substr(prePo, i - prePo) + rStr; prePo = i; }
        i += step;
    }
    return zStr + yStr.substr(prePo, yStr.length - prePo);
}

function generateRandomString(length) {
    const characters = &apos;ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&apos;;
    let result = &apos;&apos;;
    for (let i = 0; i &amp;#x3C; length; i++) result += characters.charAt(Math.floor(Math.random() * characters.length));
    return result;
}

async function exec() {
    if (GM_getValue(&apos;Cnt&apos;) == null) GM_setValue(&apos;Cnt&apos;, max_rewards + 10);
    let currentSearchCount = GM_getValue(&apos;Cnt&apos;);

    // 刚开始第一波：抓取初始积分
    if (currentSearchCount === 0) {
        let pts = await getPoints();
        GM_setValue(&apos;StartPoints&apos;, pts);
        addLog(`&amp;#x3C;b&gt;任务正式开始&amp;#x3C;/b&gt; 🚀 初始积分: &amp;#x3C;span style=&quot;color: #107c10; font-weight: bold;&quot;&gt;${pts}&amp;#x3C;/span&gt;`);
    }

    // 执行过程
    if (currentSearchCount &amp;#x3C; max_rewards) {
        document.title = &quot;[&quot; + currentSearchCount + &quot; / &quot; + max_rewards + &quot;] &quot; + document.title;
        document.documentElement.scrollIntoView({ behavior: &apos;smooth&apos;, block: &apos;end&apos; });
        GM_setValue(&apos;Cnt&apos;, currentSearchCount + 1);

        let nowtxt = search_words[currentSearchCount] || default_search_words[currentSearchCount % default_search_words.length];
        addLog(`搜索进度 &amp;#x3C;b&gt;(${currentSearchCount + 1}/${max_rewards})&amp;#x3C;/b&gt;: 关键词 &amp;#x3C;span style=&quot;color: #0078d4;&quot;&gt;${nowtxt}&amp;#x3C;/span&gt;`);
        
        nowtxt = AutoStrTrans(nowtxt);
        let randomDelay = Math.floor(Math.random() * 6000) + 2000;
        let randomString = generateRandomString(4);
        let randomCvid = generateRandomString(32);
        
        // 动态决定域名 (复刻原版逻辑)
        let domain = (currentSearchCount &gt; max_rewards / 2) ? &quot;cn.bing.com&quot; : &quot;www.bing.com&quot;;
        let targetUrl = `https://${domain}/search?q=${encodeURI(nowtxt)}&amp;#x26;form=${randomString}&amp;#x26;cvid=${randomCvid}`;

        setTimeout(function () {
            if ((currentSearchCount + 1) % 5 === 0) {
                addLog(`&amp;#x3C;span style=&quot;color: #d13438;&quot;&gt;&amp;#x3C;i&gt;触发防封控长暂停，休息 ${pause_time / 1000} 秒...&amp;#x3C;/i&gt;&amp;#x3C;/span&gt;`);
                setTimeout(() =&gt; { location.href = targetUrl; }, pause_time);
            } else {
                location.href = targetUrl;
            }
        }, randomDelay);

    } 
    // 任务刚刚结束
    else if (currentSearchCount === max_rewards) {
        let endPts = await getPoints();
        let startPts = GM_getValue(&apos;StartPoints&apos;, &apos;未知&apos;);
        addLog(`&amp;#x3C;b&gt;任务圆满完成！&amp;#x3C;/b&gt; 🎉 结束积分: &amp;#x3C;span style=&quot;color: #107c10; font-weight: bold; font-size: 18px;&quot;&gt;${endPts}&amp;#x3C;/span&gt; (初始: ${startPts})`);
        
        // 闭合 HTML 标签
        let finalLog = GM_getValue(&apos;DailyLog&apos;) + &quot;&amp;#x3C;/ul&gt;&amp;#x3C;div style=&apos;text-align: center; margin-top: 20px; font-size: 13px; color: #a19f9d;&apos;&gt;© Bing Rewards 自动助手 (运行在 Docker)&amp;#x3C;/div&gt;&amp;#x3C;/div&gt;&amp;#x3C;/div&gt;&quot;;
        
        // 将日志生成为网页文件并打开新标签页
        let blob = new Blob([finalLog], { type: &apos;text/html;charset=utf-8&apos; });
        let url = URL.createObjectURL(blob);
        GM_openInTab(url, { active: true });

        // 设置为极大值，防止无限循环打开标签
        GM_setValue(&apos;Cnt&apos;, max_rewards + 10); 
    }
}

// 菜单支持
GM_registerMenuCommand(&apos;强制开始(忽略时间)&apos;, function () {
    GM_setValue(&apos;Cnt&apos;, 0);
    location.href = &quot;https://www.bing.com/?br_msg=Manual-Start&quot;;
}, &apos;o&apos;);
GM_registerMenuCommand(&apos;停止&apos;, function () {
    GM_setValue(&apos;Cnt&apos;, max_rewards + 10);
}, &apos;o&apos;);
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/binglogo.C5mvDbvq.png"/><enclosure url="/_astro/binglogo.C5mvDbvq.png"/></item><item><title>For SDUCraft:公网转发配置不完全指南</title><link>https://kylaan.cn/blog/frp-doc/frp-doc</link><guid isPermaLink="true">https://kylaan.cn/blog/frp-doc/frp-doc</guid><description>本文档旨在帮助配置新开实例的 FRP 公网转发功能</description><pubDate>Sun, 25 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;公网转发配置不完全指南&lt;/h1&gt;
&lt;p&gt;本文档旨在帮助配置新开实例的 FRP 公网转发功能。如果有问题请联系@Kylaan.&lt;/p&gt;
&lt;h2&gt;最佳实践&lt;/h2&gt;
&lt;p&gt;我 (@Kylaan) 已经在济南和青岛的两台机器节点上开了两个独立的 FRP 客户端实例，应该直接配置这两个实例的参数之后重启即可.&lt;/p&gt;
&lt;p&gt;济南
&lt;img src=&quot;JN.png&quot; alt=&quot;JN&quot;&gt;
青岛
&lt;img src=&quot;QD.png&quot; alt=&quot;QD&quot;&gt;&lt;/p&gt;
&lt;h3&gt;配置如下内容：&lt;/h3&gt;
&lt;p&gt;面板打开对应的穿透实例找到 &lt;code&gt;./frpc.toml&lt;/code&gt; 文件
&lt;img src=&quot;frpc.png&quot; alt=&quot;frpc&quot;&gt;
编辑 &lt;code&gt;frpc.toml&lt;/code&gt; 文件，在后面添加如下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;
# 客户端转发规则
[[proxies]]
name = &quot;name_支持中文&quot;
type = &quot;tcp&quot;
localIP = &quot;127.0.0.1&quot;
localPort = 11451    # 实例对应的宿主机端口（非容器端口）
remotePort = 11451   # 公网访问端口（建议和本地端口统一）

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;请务必联系 @Kylaan 开放云服务器对应的 &lt;code&gt;remotePort&lt;/code&gt; 端口，否则还是无法访问。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;自行部署指南&lt;/h2&gt;
&lt;p&gt;如果您希望自行部署 FRP 客户端实例，比如加到实例启动命令中随实例一同开关，请参考以下步骤：&lt;/p&gt;
&lt;h3&gt;FRP基本信息&lt;/h3&gt;
&lt;p&gt;官方文档：&lt;a href=&quot;https://gofrp.org/zh-cn/docs/&quot;&gt;FRP-DOC&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;下载&lt;/h3&gt;
&lt;p&gt;您可以从 GitHub 的 &lt;a href=&quot;https://github.com/fatedier/frp/releases&quot;&gt;Release&lt;/a&gt; 页面中下载最新版本的客户端和服务器二进制文件。所有文件都打包在一个压缩包中，还包含了一份完整的配置参数说明。&lt;/p&gt;
&lt;h3&gt;客户端（待转发实例）部署&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;解压下载的压缩包。&lt;/li&gt;
&lt;li&gt;将 &lt;code&gt;frpc&lt;/code&gt; 和 &lt;code&gt;frpc.toml&lt;/code&gt; 复制到内网服务所在的实例。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;注意看清是客户端 &lt;code&gt;frpc&lt;/code&gt; 还是服务端 &lt;code&gt;frps&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;配置 &lt;code&gt;frpc.toml&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;编辑 &lt;code&gt;frpc.toml&lt;/code&gt; 文件，配置如下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;# 服务端信息
serverAddr = &quot;47.104.216.235&quot; 
serverPort = 7000
auth.token = &quot;frp-serverToken&quot;

# 客户端转发规则1
[[proxies]]
name = &quot;name_支持中文&quot;
type = &quot;tcp&quot;
localIP = &quot;127.0.0.1&quot;
localPort = 22
remotePort = 6000

# 客户端转发规则2
[[proxies]]
...

&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;参数信息&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;serverAddr&lt;/code&gt;：FRP服务端公网IP，目前使用 @Kylaan 提供的阿里云 (200Mbps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;serverPort&lt;/code&gt;：FRP 服务端监听端口，已经开放7000端口&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auth.token&lt;/code&gt;：认证 Token，请勿泄露&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[[proxies]]&lt;/code&gt;：定义一个转发规则
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;：转发规则名称，支持中文&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt;：转发类型，常用的有 &lt;code&gt;tcp&lt;/code&gt;（TCP转发）、&lt;code&gt;http&lt;/code&gt;（HTTP转发）、&lt;code&gt;https&lt;/code&gt;（HTTPS转发）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;localIP&lt;/code&gt;：内网服务所在实例的 IP 地址，通常为 &lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;localPort&lt;/code&gt;：实例对应的主机端口（非容器端口）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;开始使用&lt;/h3&gt;
&lt;p&gt;在实例上运行以下命令启动 FRP 客户端：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;./frpc -c ./frpc.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;建议直接将此命令加入实例的启动脚本中，注意后台运行。&lt;/p&gt;
&lt;p&gt;仍需联系 @Kylaan 开放对应的 &lt;code&gt;remotePort&lt;/code&gt; 端口。&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>家庭影音中心搭建：Ubuntu+Jellyfin+公网穿透+自动化踩坑实录</title><link>https://kylaan.cn/blog/jellyfin-fix/process</link><guid isPermaLink="true">https://kylaan.cn/blog/jellyfin-fix/process</guid><description>记录基于 i5-10400F + RX550 的家庭服务器搭建全过程，涵盖 Samba 直连、Jellyfin 硬解驱动修复、Nginx 反代黑屏解决及网盘自动化挂载方案。</description><pubDate>Fri, 23 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import {
Aside,
Card,
Collapse,
Timeline,
Steps,
Tabs,
TabItem,
Button,
Spoiler,
Label
} from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h2&gt;1 背景与硬件&lt;/h2&gt;
&lt;p&gt;寒假在家~~闲的蛋疼~~，受女朋友安利想看番剧和电影，奈何网络流媒体画质基本都令人汗颜。于是萌生了将家里这台闲置的电脑&lt;code&gt;10400F &amp;#x26; RX550&lt;/code&gt;变成一个集&lt;strong&gt;NAS 存储、媒体中心、远程下载、网盘挂载&lt;/strong&gt;于一体的全能家庭服务器&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;#x3C;Label title=&quot;Nginx&quot; /&gt;
  &amp;#x3C;Label title=&quot;AList&quot; /&gt;
  &amp;#x3C;Label title=&quot;Aria2&quot; /&gt;
&amp;#x3C;/div&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本文将详细记录整个折腾过程中从物理连线到驱动安装，再到反向代理的报错问题和解决方案。&lt;/p&gt;
&lt;p&gt;一些基础过程，比如 Windows 重装 Ubuntu-Server 、Jellyfin 的基础部署和使用，在前面的文章中已经记录过流程，网上也有大量详细教程，这里不再赘述。&lt;/p&gt;
&lt;p&gt;以下仅按照流程顺序记录折腾过程中的&lt;strong&gt;问题与解决方案&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2 网络与存储：Windows 直连 Ubuntu Samba&lt;/h2&gt;
&lt;p&gt;为了传输 TB 级的数据，我选择用网线直接连接 Windows 和 Ubuntu 服务器（因为路由器端口不够且速度受限）。&lt;/p&gt;
&lt;p&gt;之后遇到IP配置和Samba权限的问题，经过Gemini的帮助，选择了直接挂载服务器储存盘到Windows的方式，实现稳定的高速传输的同时为后来直接使用夸克网盘（没有Docker版本，部署在服务器代价太大）下载到服务器做了铺垫。以下是直接用网线连接两台机器的过程：&lt;/p&gt;
&lt;h3&gt;遇到的问题：Ping 得通，连不上&lt;/h3&gt;
&lt;p&gt;刚开始，我给两边分别设置了静态 IP (&lt;code&gt;192.168.50.1&lt;/code&gt; 和 &lt;code&gt;.2&lt;/code&gt;)。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;现象&lt;/strong&gt;：Linux 端配置正确，&lt;code&gt;ping&lt;/code&gt; Windows 通畅。但 Windows 端死活无法访问 Samba 共享。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;报错&lt;/strong&gt;：Windows 提示 &lt;code&gt;系统错误 1231&lt;/code&gt; 或 &lt;code&gt;网络路径不存在&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;核心原因是 Windows 将直连网络识别为“公用网络”，防火墙拦截了 SMB 流量；且 Docker 版 Samba 默认权限配置导致 Windows 匿名登录失败。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ![设置静态 IP2](SetWinIp2.png)
&amp;#x3C;/div&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.  &lt;strong&gt;Samba 部署 (Docker)&lt;/strong&gt;：
使用 Docker 部署比原生安装更干净。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;#x3C;Collapse title=&quot;查看 Samba docker-compose.yml 配置&quot;&gt;
```yaml
services:
  samba:
    image: dperson/samba
    container_name: samba
    restart: always
    ports:
      - &quot;139:139&quot;
      - &quot;445:445&quot;
    environment:
      - TZ=Asia/Shanghai
      - USERID=1000
      - GROUPID=1000
      # 关键配置：用户名;密码
      - USER=kylaan;your_password
      # 共享名;路径;只读;允许来宾;用户列表
      - SHARE=media;/mount/media;no;no;kylaan
    volumes:
      - /mnt/media:/mount/media
```
&amp;#x3C;/Collapse&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4.  &lt;strong&gt;强制挂载&lt;/strong&gt;：
为了绕过 Windows 的匿名登录限制，使用命令行强制挂载：
&lt;code&gt;powershell     # 先清除旧连接     net use * /delete /y     # 强制带用户认证挂载     net use Z: \\192.168.50.1\media /user:kylaan your_password     &lt;/code&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3 核心媒体库：Jellyfin 与显卡驱动问题&lt;/h2&gt;
&lt;p&gt;这是最耗时的一步。我的 CPU (10400F) 没核显，必须依靠 RX 550 独显进行转码。&lt;/p&gt;
&lt;h3&gt;第一回合：FFmpeg 退出代码 171 &amp;#x26; 187&lt;/h3&gt;
&lt;p&gt;Docker 部署 Jellyfin 后，直接播放视频，日志疯狂报错：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-log&quot;&gt;MediaBrowser.Common.FfmpegException: FFmpeg exited with code 171
No VA display found for device /dev/dri/renderD128.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Code 171&lt;/strong&gt;: 选择了 &lt;code&gt;AMD AMF&lt;/code&gt; 硬件加速。RX 550 对 AMF 支持极差，且我不小心勾选了 AV1 编码（老显卡根本不支持）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No VA display&lt;/strong&gt;: Docker 根本没加载显卡驱动！&lt;code&gt;ls -l /dev/dri&lt;/code&gt; 输出为空。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;第二回合：修复驱动与配置&lt;/h3&gt;
&lt;hr&gt;
&lt;h2&gt;4 公网访问：Nginx 反代配置问题&lt;/h2&gt;
&lt;p&gt;为了在外网访问，我采用了 &lt;strong&gt;FRP (内网穿透) -&gt; 阿里云服务器 -&gt; Nginx 反代&lt;/strong&gt; 的架构。&lt;/p&gt;
&lt;h3&gt;诡异现象&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;IP:端口&lt;/code&gt; 访问：一切正常。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;https://movie.kylaan.top&lt;/code&gt; 访问：网页能打开，能看海报，&lt;strong&gt;但点击播放一直转圈，最后黑屏，且服务器显示有流量跑动&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;io666.jpg&quot; alt=&quot;反代配置问题&quot;&gt;&lt;/p&gt;
&lt;h3&gt;根源与修复&lt;/h3&gt;
&lt;p&gt;这是一个经典的 Nginx 反代配置问题。原因有二：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;混合内容&lt;/strong&gt;：Jellyfin 以为自己在跑 HTTP，返回了 HTTP 的流地址，被浏览器拦截。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓冲阻塞&lt;/strong&gt;：Nginx 默认开启缓冲，试图下载完视频片段再发给客户端，导致流媒体卡死。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# ... SSL 证书配置 ...

location / {
    proxy_pass http://127.0.0.1:8096;  
    
    # 1. 告诉 Jellyfin 前端是 HTTPS
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Protocol https;
    proxy_set_header X-Forwarded-Ssl on;

    # 2. 关键！禁用缓冲，允许流式传输
    proxy_buffering off;
    
    # 3. 支持 WebSocket (防止断连)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection &quot;upgrade&quot;;
    
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;#x3C;/Collapse&gt;

&amp;#x3C;Aside type=&quot;danger&quot;&gt;
**注意：** 如果不加 `proxy_buffering off;`，Jellyfin 的视频流会被 Nginx &quot;卡&quot;在内存里，导致客户端超时。这是解决&quot;有流量无画面&quot;的核心。
&amp;#x3C;/Aside&gt;

---

## 5 资源获取：网盘自动化方案

服务器没有资源就是空壳。我配置了百度网盘和夸克网盘的自动化下载。

&amp;#x3C;Tabs&gt;
&amp;#x3C;TabItem label=&quot;百度网盘 (Docker)&quot;&gt;
**方案**：使用 `johngong/baidunetdisk` 镜像，通过 VNC (Web 界面) 操作 Linux 版客户端。


**操作重点**：
1.  部署后访问 `http://192.168.100.89:5800/`。
2.  输入 VNC 密码。
3.  **最重要的设置**：在百度网盘客户端设置里，将下载路径改为 `/media/downloads`（映射到物理硬盘的路径），否则下载的文件会在重启容器后丢失！

![插入图片：浏览器中显示的百度网盘 Linux 客户端界面](baidunetdisk.png)



&amp;#x3C;/TabItem&gt;
&amp;#x3C;TabItem label=&quot;夸克网盘 (AList + Aria2)&quot;&gt;
**方案**：夸克没有 Linux 客户端。Gemini给出的解决方案是 **AList (聚合挂载) + Aria2 (下载器)**。


**流程**：
1.  部署 AList 和 Aria2 容器。
2.  AList 挂载夸克网盘 (需要抓取 Cookie)。
3.  AList 配置 Aria2 连接 (`http://aria2:6800/jsonrpc`)。
4.  **使用**：在 AList 网页勾选文件 -&gt; &quot;发送到 Aria2&quot; -&gt; 文件自动下载到服务器。
    &amp;#x3C;Aside type=&quot;note&quot;&gt;
    但是我直接选择了使用Windows客户端下载到挂载磁盘的方案， &amp;#x3C;Spoiler&gt;毕竟即使夸克会员也跑不满千兆带宽（（（&amp;#x3C;/Spoiler&gt;🤣🤣🤣
    &amp;#x3C;/Aside&gt;
&amp;#x3C;/TabItem&gt;
&amp;#x3C;/Tabs&gt;

---

## 6 完美主义：字幕、弹幕与导航页

为了提升观影体验，我还折腾了以下细节：

### 1. 中文字幕方框问题

Jellyfin 烧录字幕时，如果容器内没有中文字体，汉字会显示为方框。
![字幕问题](zimuERR.png)
* **解决**：
1. 宿主机安装 `fonts-noto-cjk-extra`。
2. Docker 映射 `/usr/share/fonts:/usr/share/fonts`。
3. Jellyfin 后台启用“备用字体”





### 2. Bilibili 弹幕

使用了 `jellyfin-plugin-danmu` 插件。

* 安装插件仓库。
* 配置 B 站 Cookie。
* 刷新元数据，播放时选择 &quot;Bilibili&quot; 字幕轨道，弹幕就出来了！

&amp;#x3C;Aside type=&quot;tip&quot;&gt;
另外，后续经过我的发掘发现，许多 Jellyfin 的第三方客户端（比如Hills、Yamby）都原生支持爬取 B 站弹幕，无需插件，直接在播放选项里选择即可。
![弹幕设置截图](danmu.jpg)
**而且和官方插件不同的是，不用占用一个字幕通道**
&amp;#x3C;/Aside&gt;

### 3. 导航页 (Sun-Panel)

部署了 Sun-Panel，将 Jellyfin、1Panel和各个资源站等等全部聚合在一个页面，这是我的家庭云入口。

![插入图片：Sun-Panel 导航页截图，展示了所有服务的图标](Port.png)

后续还有可能把阿里云上的服务也加进去，做到真正的一键直达。

---

## 7 总结

经过几天的通宵折腾，这台 10400F + RX 550 的机器已经脱胎换骨。

* **看片**：Jellyfin 硬解 4K 流畅，支持弹幕。
* **管理**：Samba 跑满千兆带宽。
* **下载**：百度/夸克自动搬运。
* **访问**：HTTPS 域名直达，无视内网限制。

希望这篇文章能帮助到有类似需求的朋友们。如果你也在折腾家庭服务器，欢迎留言交流经验！😊
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/debug.B41Mx9Ni.png"/><enclosure url="/_astro/debug.B41Mx9Ni.png"/></item><item><title>组件使用指南</title><link>https://kylaan.cn/blog/components-guide</link><guid isPermaLink="true">https://kylaan.cn/blog/components-guide</guid><description>列举所有可用自定义组件及其用法</description><pubDate>Thu, 15 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import {
Aside,
Card,
Collapse,
Timeline,
Steps,
Tabs,
TabItem,
Button,
Spoiler,
Label
} from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h2&gt;1. Aside (提示块)&lt;/h2&gt;
&lt;p&gt;用于显示警告、提示或说明信息。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Aside&gt;默认提示&amp;#x3C;/Aside&gt;
&amp;#x3C;Aside type=&quot;tip&quot;&gt;提示信息&amp;#x3C;/Aside&gt;
&amp;#x3C;Aside type=&quot;caution&quot;&gt;警告信息&amp;#x3C;/Aside&gt;
&amp;#x3C;Aside type=&quot;danger&quot;&gt;危险信息&amp;#x3C;/Aside&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. Spoiler (黑幕)&lt;/h2&gt;
&lt;p&gt;用于隐藏剧透内容，鼠标悬停时显示。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Spoiler&gt;剧透警告：凶手是...&amp;#x3C;/Spoiler&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;真相是：你被骗了！&lt;/p&gt;
&lt;h2&gt;3. Button (按钮)&lt;/h2&gt;
&lt;p&gt;不同样式的按钮组件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Button title=&quot;Default Button&quot; href=&quot;#&quot; /&gt;
&amp;#x3C;Button title=&quot;Pill Button&quot; href=&quot;#&quot; variant=&quot;pill&quot; /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. Tabs (选项卡)&lt;/h2&gt;
&lt;p&gt;用于并在不同选项卡之间切换内容。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Tabs&gt;
  &amp;#x3C;TabItem label=&quot;Npm&quot;&gt;
    npm install astro
  &amp;#x3C;/TabItem&gt;
  &amp;#x3C;TabItem label=&quot;Pnpm&quot;&gt;
    pnpm add astro
  &amp;#x3C;/TabItem&gt;
&amp;#x3C;/Tabs&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. Timeline (时间轴)&lt;/h2&gt;
&lt;p&gt;展示时间节点事件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Timeline
  events={[
    { date: &apos;2024-01-01&apos;, content: &apos;项目启动&apos; },
    { date: &apos;2024-02-15&apos;, content: &apos;发布 v1.0&apos; },
  ]}
/&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;#x3C;Timeline
events={[
{ date: &apos;2024-01-01&apos;, content: &apos;项目启动&apos; },
{ date: &apos;2024-02-15&apos;, content: &apos;发布 v1.0 版本&apos; },
{ date: &apos;2024-03-20&apos;, content: &apos;重大更新&apos; },
]}
/&gt;&lt;/p&gt;
&lt;h2&gt;6. Steps (步骤条)&lt;/h2&gt;
&lt;p&gt;用于展示有序的步骤。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Steps&gt;
1. 第一步
2. 第二步
3. 第三步
&amp;#x3C;/Steps&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7. Collapse (折叠面板)&lt;/h2&gt;
&lt;p&gt;可折叠的内容区域。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Collapse title=&quot;点击展开详情&quot;&gt;
  这里是详细内容...
&amp;#x3C;/Collapse&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8. Card (卡片)&lt;/h2&gt;
&lt;p&gt;展示卡片式链接或内容。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Card heading=&quot;Astro&quot; subheading=&quot;The web framework&quot; href=&quot;https://astro.build&quot;&gt;
  Astro powers the world&apos;s fastest websites.
&amp;#x3C;/Card&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9. Label (标签)&lt;/h2&gt;
&lt;p&gt;带图标的标签文本。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#x3C;Label title=&quot;My Label&quot;&gt;
    &amp;#x3C;svg slot=&quot;icon&quot;&gt;...&amp;#x3C;/svg&gt;
&amp;#x3C;/Label&gt;
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Minecraft 服务器的公网穿透</title><link>https://kylaan.cn/blog/mc-server/serverfrp</link><guid isPermaLink="true">https://kylaan.cn/blog/mc-server/serverfrp</guid><description>记一次校内网 Minecraft 服务器的公网穿透折腾（阿里云 + FRP + Docker）</description><pubDate>Thu, 15 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Aside, Spoiler } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h1&gt;记一次校内网 Minecraft 服务器的公网穿透折腾（阿里云 + FRP + Docker）&lt;/h1&gt;
&lt;h2&gt;为何折腾？&lt;/h2&gt;
&lt;p&gt;起初我的设想极其“简单粗暴”：在阿里云服务器上安装学校的 &lt;code&gt;atrust&lt;/code&gt; VPN 客户端，把云服务器伪装成校内机器。但实际操作中发现，在 Linux 命令行环境下运行这种重 GUI 依赖的专有 VPN 软件极其痛苦，且极不稳定。&lt;/p&gt;
&lt;p&gt;经过一番研究（和 AI 的激辩），最终选择了更符合行业标准的 &lt;strong&gt;FRP (Fast Reverse Proxy)&lt;/strong&gt; 内网穿透方案。虽然可能会被网安办请喝茶...&lt;/p&gt;
&lt;h2&gt;环境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;服务端 (Public)&lt;/strong&gt;：阿里云 ECS (Alibaba Cloud Linux)，拥有公网 IP，安装了宝塔面板。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;客户端 (Intranet)&lt;/strong&gt;：校内服务器，运行在 Docker 容器内的 Minecraft 实例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目标&lt;/strong&gt;：通过访问 &lt;code&gt;阿里云IP:25565&lt;/code&gt; -&gt; 自动转发 -&gt; &lt;code&gt;校内服务器:25565&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;第一步：服务端配置 (阿里云 frps)&lt;/h2&gt;
&lt;p&gt;服务端只需要负责“监听”和“转发”。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;下载对应架构的 FRP 包（通常是 &lt;code&gt;linux_amd64&lt;/code&gt;），解压得到 &lt;code&gt;frps&lt;/code&gt; 和 &lt;code&gt;frps.toml&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置 &lt;code&gt;frps.toml&lt;/code&gt;：&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;# frps.toml
bindPort = 7000           # frp 服务端监听端口，等待校内机器连接
auth.token = &quot;[密钥]&quot;  # 鉴权密钥，客户端和服务端必须一致
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;部署运行&lt;/strong&gt;：
为了稳定运行，我使用了宝塔面板的 &lt;strong&gt;“Go 项目管理”&lt;/strong&gt; 功能：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;执行文件&lt;/strong&gt;：选择 &lt;code&gt;frps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：&lt;code&gt;-c frps.toml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;端口&lt;/strong&gt;：&lt;code&gt;7000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开机自启&lt;/strong&gt;：勾选 ✅&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;防火墙放行（关键！）&lt;/strong&gt;：
需要在阿里云控制台的安全组 &lt;strong&gt;和&lt;/strong&gt; 宝塔面板的安全页面同时放行：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;7000&lt;/code&gt; (FRP 通信端口)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;25565&lt;/code&gt; (MC 游戏端口)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;第二步：客户端配置 (校内 frpc)&lt;/h2&gt;
&lt;p&gt;在 MCSM 面板的文件管理中，将 &lt;code&gt;frpc&lt;/code&gt; 二进制文件和 &lt;code&gt;frpc.toml&lt;/code&gt; 上传到服务器根目录（和 &lt;code&gt;server.jar&lt;/code&gt; 放在一起）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;配置 &lt;code&gt;frpc.toml&lt;/code&gt;：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;# frpc.toml
serverAddr = &quot;&amp;#x3C;ali_ip4&gt;&quot;    # 阿里云的公网IP
serverPort = 7000         # 对应 frps 的 bindPort
auth.token = &quot;[密钥]&quot;    # 必须和服务端一致

[[proxies]]
name = &quot;mc-server-main&quot;   # 代理名称，不能重复
type = &quot;tcp&quot;
localIP = &quot;127.0.0.1&quot;     # 因为 frpc 就在容器内部，直接填回环地址
localPort = 25565         # MC 容器内部的端口
remotePort = 25565        # 暴露给公网访问的端口
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;第三步：踩坑与排查 (Connection Refused)&lt;/h2&gt;
&lt;p&gt;配置好后，我尝试启动，结果后台报错：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[W] connect to server error: dial tcp 172.17.0.1:7890: connect: connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;原因分析&lt;/strong&gt;：
我的校内服务器宿主机上可能挂了 Clash 或其他代理软件，并且设置了系统级的环境变量（&lt;code&gt;http_proxy&lt;/code&gt;）。Docker 容器在启动时继承了这些环境变量。导致 &lt;code&gt;frpc&lt;/code&gt; 启动时，傻乎乎地去连接 &lt;code&gt;172.17.0.1:7890&lt;/code&gt; 这个代理地址，而不是直连阿里云。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方法&lt;/strong&gt;：
在启动命令前，强制清空代理相关的环境变量。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;第四步：最终的启动脚本 (run.sh)&lt;/h2&gt;
&lt;p&gt;这是最终的解决方案。我修改了服务器的启动脚本 &lt;code&gt;run.sh&lt;/code&gt;，实现了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;自动启动 FRP&lt;/strong&gt;：在开服前后台静默运行穿透服务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;环境隔离&lt;/strong&gt;：使用 &lt;code&gt;env -u&lt;/code&gt; 或变量置空法清除代理干扰。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JVM 优化&lt;/strong&gt;：集成了 Fabric/MCDR 所需的 Aikar&apos;s flags 优化参数。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

# ===========================
# 1. 启动 FRP 内网穿透模块
# ===========================

# 确保 frpc 有执行权限
chmod +x ./frpc

# 启动 frpc 并挂起在后台
# 关键操作：http_proxy=... 强制清空代理变量，防止连接被宿主机代理拒绝；&apos;&amp;#x26;&apos; 放到后台并行运行
echo &quot;正在启动内网穿透...&quot;
http_proxy= https_proxy= all_proxy= ./frpc -c frpc.toml &gt; /dev/null 2&gt;&amp;#x26;1 &amp;#x26;

# 等待 1 秒确保 frp 进程就绪
sleep 1

# ===========================
# 2. 启动 Minecraft Server (Fabric)
# ===========================

echo &quot;正在启动 Minecraft 服务器...&quot;

# 使用 Aikar&apos;s flags 进行 GC 优化
java -server -Xms4G -Xmx8G \
  -XX:+UseG1GC \
  -XX:+ParallelRefProcEnabled \
  -XX:MaxGCPauseMillis=130 \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+DisableExplicitGC \
  -XX:+AlwaysPreTouch \
  -XX:G1NewSizePercent=30 \
  -XX:G1MaxNewSizePercent=40 \
  -XX:G1HeapRegionSize=8M \
  -XX:G1ReservePercent=20 \
  -XX:G1HeapWastePercent=5 \
  -XX:InitiatingHeapOccupancyPercent=15 \
  -XX:SurvivorRatio=32 \
  -XX:MaxTenuringThreshold=1 \
  -XX:+UseStringDeduplication \
  -Dfabric.development=false \
  -Dfile.encoding=UTF-8 \
  -jar fabric-server-launch.jar nogui &quot;$@&quot;

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;第五步：配置域名解析&lt;/h2&gt;
&lt;p&gt;解析我的域名 &lt;code&gt;mc.kylaan.top&lt;/code&gt; 到阿里云的公网 IP，然后在 Minecraft 客户端直接连接 &lt;code&gt;mc.kylaan.top:&amp;#x3C;port&gt; (25565端口可省略)&lt;/code&gt; 即可。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;域名解析配置&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主机记录：&lt;code&gt;mc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;记录类型：&lt;code&gt;A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;记录值：&lt;code&gt;&amp;#x3C;阿里云公网IP&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;TTL：默认&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;效果&lt;/h2&gt;
&lt;p&gt;配置完成后，在公网使用 &lt;code&gt;mc.kylaan.top&lt;/code&gt; 或 &lt;code&gt;阿里云IP:&amp;#x3C;port&gt;&lt;/code&gt;  即可丝滑进入校内服务器，且无需对校内服务器的网络设置做任何系统层面的侵入式修改。后续可选择更多端口给不同实例。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Riesz–Schauder理论与Fredholm理论</title><link>https://kylaan.cn/blog/rieszschauder</link><guid isPermaLink="true">https://kylaan.cn/blog/rieszschauder</guid><description>总结对比Riesz–Schauder理论与Fredholm理论的理解，整理相关笔记。</description><pubDate>Mon, 05 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Fredholm 算子与 Riesz–Schauder（紧算子谱理论）速记整理&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;设 $X$ 为 Banach（或 Hilbert）空间，算子默认是 &lt;strong&gt;有界线性算子&lt;/strong&gt;。&lt;br&gt;
记 $\ker(T)$ 为核，$R(T)$ 为值域（像），$T&apos;:X&apos;\to X&apos;$ 为对偶算子。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;1. Fredholm 算子（Fredholm operator）&lt;/h2&gt;
&lt;h3&gt;1.1 定义&lt;/h3&gt;
&lt;p&gt;算子 $T:X\to X$ 称为 &lt;strong&gt;Fredholm 算子&lt;/strong&gt;，如果满足：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;核有限维&lt;/strong&gt;：$\dim\ker(T)&amp;#x3C;\infty$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;值域闭&lt;/strong&gt;：$R(T)$ 在 $X$ 中是闭子空间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;余核有限维&lt;/strong&gt;（值域余维有限）：
$$
\operatorname{codim}R(T):=\dim(X/R(T))&amp;#x3C;\infty
$$&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;直观：$T$ “几乎可逆”，不可逆性只发生在有限维的方向上。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3&gt;1.2 指标（index）&lt;/h3&gt;
&lt;p&gt;若 $T$ 是 Fredholm，则定义 &lt;strong&gt;指标&lt;/strong&gt;
$$
\operatorname{ind}(T):=\dim\ker(T)-\operatorname{codim}R(T).
$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;指标为 0&lt;/strong&gt;：
$$
\operatorname{ind}(T)=0
\iff
\dim\ker(T)=\operatorname{codim}R(T).
$$
含义：被压扁的维数（核）与漏掉的维数（余核）“刚好相等”。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;1.3 关键推论（特别常用）&lt;/h3&gt;
&lt;p&gt;若 $T$ 是 Fredholm 且 $\operatorname{ind}(T)=0$，则
$$
T \text{ 单射 } \iff T \text{ 满射 }.
$$
理由：单射 $\Leftrightarrow \dim\ker(T)=0 \Rightarrow \operatorname{codim}R(T)=0 \Rightarrow R(T)=X$；反之同理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. Riesz–Schauder 理论（紧算子谱理论 / Fredholm Alternative）&lt;/h2&gt;
&lt;h3&gt;2.1 紧算子（compact operator）&lt;/h3&gt;
&lt;p&gt;$K\in\mathcal B(X)$ 称为紧算子：若 $K$ 将单位球 $B_X$ 映到相对紧集（像的闭包紧）。&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;2.2 Riesz–Schauder（紧算子谱）核心结论（常用表述）&lt;/h3&gt;
&lt;p&gt;设 $K$ 紧，则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;非零谱点都是特征值&lt;/strong&gt;：&lt;br&gt;
若 $\mu\neq0$ 且 $\mu\in\sigma(K)$，则 $\mu$ 是特征值（存在 $x\neq0$ 使 $Kx=\mu x$）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;非零特征值的特征空间有限维&lt;/strong&gt;：&lt;br&gt;
$$
\dim\ker(K-\mu I)&amp;#x3C;\infty\quad(\mu\neq0).
$$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;非零谱点离散，唯一可能聚点为 0&lt;/strong&gt;：&lt;br&gt;
$\sigma(K)\setminus{0}$ 至多可数，且其聚点只能是 0。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;2.3 Fredholm Alternative（对 $\lambda I-K$ 的版本）&lt;/h3&gt;
&lt;p&gt;设 $K$ 紧且 $\lambda\neq0$，令
$$
T=\lambda I-K.
$$
则（Riesz–Schauder / Fredholm Alternative 结论）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$T$ 是 &lt;strong&gt;Fredholm 算子&lt;/strong&gt;，并且
$$
\dim\ker(T)&amp;#x3C;\infty,\quad R(T)\ \text{闭},\quad \operatorname{codim}R(T)&amp;#x3C;\infty.
$$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可解性判别（对偶核控制像）&lt;/strong&gt;：
$$
Tx=y \text{ 可解 }
\iff
f(y)=0\ \ \forall f\in\ker(T&apos;).
$$
等价写法：
$$
R(T)=\bigl(\ker(T&apos;)\bigr)^\perp.
$$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;特别地：
$$
R(T)=X \iff \ker(T&apos;)={0}.
$$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;3. 连接：为什么 $\lambda I-K$ 的指标为 0？&lt;/h2&gt;
&lt;p&gt;对 $T=\lambda I-K$（$\lambda\neq0$, $K$ 紧），Riesz–Schauder 给出更强的对称性：
$$
\boxed{\dim\ker(T)=\dim\ker(T&apos;)&amp;#x3C;\infty.}
$$&lt;/p&gt;
&lt;p&gt;再结合一般恒等式（对闭值域）：
$$
\operatorname{codim}R(T)=\dim\ker(T&apos;),
$$
得到
$$
\operatorname{codim}R(T)=\dim\ker(T&apos;)=\dim\ker(T),
$$
因此
$$
\boxed{\operatorname{ind}(T)=\dim\ker(T)-\operatorname{codim}R(T)=0.}
$$&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. 你常见的三个等价（对应紧扰动情形）&lt;/h2&gt;
&lt;p&gt;对 $T=\lambda I-K$（$\lambda\neq0$, $K$ 紧）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$$
\ker(T)={0}\iff R(T)=X
$$&lt;/li&gt;
&lt;li&gt;$$
\dim\ker(T)=0 \iff \dim\ker(T&apos;)=0
$$&lt;/li&gt;
&lt;li&gt;$$
\dim\ker(T)=\dim\ker(T&apos;)&amp;#x3C;\infty
$$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;它们都来自：&lt;strong&gt;$T$ 是 Fredholm 且指标为 0&lt;/strong&gt;（Riesz–Schauder / Fredholm Alternative）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;5. 总结&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fredholm&lt;/strong&gt;：核有限维 + 像闭 + 像的余维有限（“几乎可逆”）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;指标&lt;/strong&gt;：$\dim\ker - \operatorname{codim}R$（“压扁多少维 vs 漏掉多少维”）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Riesz–Schauder&lt;/strong&gt;：紧算子/紧扰动让所有“不可逆现象”只能发生在有限维上；对 $\lambda I-K$ 甚至核与余核维数相等（指标 0）。&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>要走群众路线，但群众身上有那么多劣根性，怎么办？</title><link>https://kylaan.cn/blog/masses</link><guid isPermaLink="true">https://kylaan.cn/blog/masses</guid><description>原作者：知乎-小岚</description><pubDate>Mon, 05 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;问题：要走群众路线，但群众身上有那么多劣根性，怎么办？&lt;/h1&gt;
&lt;p&gt;在组织管理与政治实践中，只要深入基层，必然会撞上一堵厚重的现实高墙。&lt;/p&gt;
&lt;p&gt;理论上，我们被反复教导群众路线，到群众中去，从群众中来。但当你真正置身于复杂的现实，你会发现群众的面孔远非想象中那般光辉圣洁。你看到的是一种令人窒息的复杂性：封建迷信思想根深蒂固，资本主义的利己本能无孔不入，短视、盲从、甚至愚昧的现象比比皆是。&lt;/p&gt;
&lt;p&gt;这时候，一个巨大的悖论横亘在所有所有人面前：面对这样一群满身缺点、思想甚至可以说是落后的具体的人，我们能依靠，怎么依靠吗？&lt;/p&gt;
&lt;p&gt;解决这个问题，不能靠文学修辞和道德文章，而是有冷峻的政治逻辑。群众路线之所以被称为屠龙术，不是因为它是一碗道德鸡汤，而是因为它是一套关于权力来源与人的改造的精密科学。&lt;/p&gt;
&lt;h2&gt;英雄史观与人民史观&lt;/h2&gt;
&lt;p&gt;要解决怎么做的问题，首先要解决怎么看的问题。这不仅仅是定义问题，而是两种截然不同的世界观在根本对立。&lt;/p&gt;
&lt;p&gt;人类历史上，始终存在两种解释历史动力的逻辑：一种是英雄史观（或精英史观），一种是人民史观。&lt;/p&gt;
&lt;p&gt;英雄史观是符合直觉的，也是傲慢的。&lt;/p&gt;
&lt;p&gt;在曹操看来，百姓只是草芥；在西方精英主义者眼中，大众是勒庞笔下的乌合之众。这种史观认为，历史是由极少数天才、帝王、精英创造的。群众只是一个庞大的分母，是背景板，甚至是由于智力低下而必须被少数人驾驭的工具。&lt;/p&gt;
&lt;p&gt;这种观点的诱惑力极大。当你作为一个管理者或先行者，看到周围人的目光短浅时，很难抑制住那种众人皆醉我独醒的优越感。你会下意识地认为：只要我设计好蓝图，群众听令执行就好。&lt;/p&gt;
&lt;p&gt;但历史反复证明，这种逻辑是脆弱的。项羽是极致的英雄，最终乌江自刎；蒋介石拥有一切精英资源，最终败退孤岛。他们失败的根源在于不懂群众之势。&lt;/p&gt;
&lt;p&gt;这就是人民史观的冷酷真相：社会变革的最终力量，不取决于顶层设计的完美程度，而取决于底层共识的广度与深度。&lt;/p&gt;
&lt;p&gt;教员提出人民，只有人民，才是创造世界历史的动力，这并非对群众的盲目吹捧或政治宣传，而是对实实在在的物理力道的客观陈述与皈依。无论精英多么聪明，生产力掌握在群众手里，战争的兵源在群众家里，政权的根基在群众脚下。&lt;/p&gt;
&lt;p&gt;谁要是背离了这个势大力沉的基本盘，注定要被历史的铁拳锤得鼻青脸肿。&lt;/p&gt;
&lt;p&gt;当然，这并不意味着我们要否定精英的作用。恰恰相反，在人民史观的逻辑里，精英肩负着前所未有的重任。&lt;/p&gt;
&lt;p&gt;如果把历史的进程比作一艘巨轮：群众是这艘船本身，是船体，是引擎，是承载一切重量的实体。没有船，一切航行都无从谈起。&lt;/p&gt;
&lt;p&gt;精英则是船舵，是罗盘。&lt;/p&gt;
&lt;p&gt;没有船舵，巨轮就会在历史的惊涛骇浪中原地打转，甚至触礁沉没，这正是群众运动往往容易陷入盲目的原因；但如果没有船，船舵不过是一块毫无意义的木头，连出航的资格都没有。&lt;/p&gt;
&lt;p&gt;所以，依靠群众，绝不是否定引导；强调群众主体地位，也绝不是要精英放弃责任。两者的关系是辩证统一的：船舵必须长在船身上，并指引船的方向。&lt;/p&gt;
&lt;h2&gt;论人的改造：精英与群众并非物种隔离&lt;/h2&gt;
&lt;p&gt;当我们确认了必须依靠群众这一历史唯物主义前提后，那个最扎心的问题依然存在：群众身上严重的封建思想和资本主义习气，难道不会腐蚀我们的事业吗？&lt;/p&gt;
&lt;p&gt;这里涉及到一个更深层的人性拷问。&lt;/p&gt;
&lt;p&gt;许多持精英主义立场的人，潜意识里认为劣根性是群众的专属标签，认为人与人之间存在某种天然的智力与道德隔离。他们认为自己是天生的理性者，而群众是天生的愚昧者。&lt;/p&gt;
&lt;p&gt;这种观点是大错特错的。&lt;/p&gt;
&lt;p&gt;首先，人性的弱点是普遍存在的。 自私、短视、趋利避害、甚至某种程度的盲从，这些不仅存在于群众身上，同样存在于精英身上。知识分子有知识分子的软弱，官僚有官僚的狭隘，商人有商人的贪婪。并没有哪一个阶层是天生免疫人性弱点的圣人。&lt;/p&gt;
&lt;p&gt;还有更关键的一点：精英是如何产生的？&lt;/p&gt;
&lt;p&gt;翻开中国革命史，那些后来运筹帷幄、目光远大的开国将帅，那些坚定的马克思主义者，绝大多数原本也是普通的农民、手工业者或旧军阀的士兵。&lt;/p&gt;
&lt;p&gt;彭德怀元帅出身贫苦农家，早年也曾在旧军队里讨生活；许世友将军在接受红军教育前，也有着浓重的江湖习气。&lt;/p&gt;
&lt;p&gt;他们最初也带有各种旧社会的烙印。但为什么后来他们成为了精英，成为了先锋队？&lt;/p&gt;
&lt;p&gt;因为他们经历了改造。&lt;/p&gt;
&lt;p&gt;是在残酷的斗争实践中，在先进组织的熔炉里，他们剥离了狭隘的小农意识，建立起了宏大的政治视野。&lt;/p&gt;
&lt;p&gt;既然精英可以从旧人脱胎换骨变成新人，那么群众为什么不可以？&lt;/p&gt;
&lt;p&gt;辩证唯物主义告诉我们：社会存在决定社会意识。&lt;/p&gt;
&lt;p&gt;群众身上的封建思想，是因为他们几千年来被禁锢在封建土地关系中；群众身上的资本主义思想，是因为市场经济的丛林法则逼迫他们必须利己才能生存。&lt;/p&gt;
&lt;p&gt;这些落后，不是基因里的缺陷，而是环境与制度诱发的病症。&lt;/p&gt;
&lt;p&gt;所以，走群众路线的本质，包含着一种对人性终极可能性的信仰：我们相信人是可以被改造的。&lt;/p&gt;
&lt;p&gt;同样是那群农民，在晚清是麻木不仁看客，在民国是散兵游勇；但一旦被红军的组织架构所吸纳，一旦被党的纲领和打土豪分田地的口号所唤醒，他们就能在冰天雪地里潜伏几天几夜，就能推着独轮车支援淮海战役。&lt;/p&gt;
&lt;p&gt;人还是那些人，基因没变，血肉没变，但是精神觉悟已经完全不同。只要改变了生产关系，只要建立了先进的组织形式，只要进行了有效的政治教育，哪怕是昨天还在求神拜佛的文盲老农，今天就能变成拥有高度阶级觉悟的战士。&lt;/p&gt;
&lt;p&gt;在对人的改造方面，古田会议是彪炳千古的&lt;/p&gt;
&lt;p&gt;红四军建立初期，军队里充满了流寇主义、极端民主化、单纯军事观点等各种非无产阶级思想。这其实就是典型的群众落后性的体现。&lt;/p&gt;
&lt;p&gt;教员没有因为士兵落后就解散队伍，也没有选择只依靠少数军官。而是通过思想建党、政治建军，通过高强度的政治教育和组织生活，硬是将一支以农民为主体的队伍，改造成了具有钢铁意志的无产阶级先锋队。&lt;/p&gt;
&lt;p&gt;依靠群众，依靠的不是他们当下的弱点，而是依靠他们被组织、被唤醒、被改造后的巨大潜能和历史洪流的力量。&lt;/p&gt;
&lt;h2&gt;如何改造？&lt;/h2&gt;
&lt;p&gt;搞清楚了世界观和可能性，最后才是怎么做。&lt;/p&gt;
&lt;p&gt;如何在依靠群众的同时，有效克服他们身上的封建与资本主义思想？&lt;/p&gt;
&lt;p&gt;在实践中，要警惕两个极端：&lt;/p&gt;
&lt;p&gt;一是命令主义。觉得群众落后，就不屑于解释，直接下指令。这在苏联后期的政治实践中表现明显，结果导致党群关系割裂，最终大厦崩塌时无人救援。&lt;/p&gt;
&lt;p&gt;二是尾巴主义。这是当下互联网时代最容易犯的错误。为了流量或所谓的民意，群众喜欢什么就给什么，群众情绪极端化就跟着极端化。这是放弃了船舵的责任，最终会被狂暴的水流冲毁。&lt;/p&gt;
&lt;p&gt;真正的群众路线，是教员在《关于领导方法的若干问题》中提出的那个那些真知灼见。&lt;/p&gt;
&lt;p&gt;这个过程分为三个严密的步骤，缺一不可：&lt;/p&gt;
&lt;p&gt;第一步：全量输入的从群众中来。&lt;/p&gt;
&lt;p&gt;我们要深入群众，收集意见。这时候，我们收到的必然是混合物：既有群众对生存发展的真实渴望，也有迷信、狭隘、偏激的情绪。&lt;/p&gt;
&lt;p&gt;注意，这一步的关键是诚实。不能因为嫌弃杂质就拒绝原材料。你必须听懂那个想发财的农民背后，是对美好生活的向往；听懂那个抱怨社会不公的愤青背后，是对公平正义的朴素诉求。&lt;/p&gt;
&lt;p&gt;第二步：去伪存真的核心加工。&lt;/p&gt;
&lt;p&gt;这是体现先锋队水平的关键。&lt;/p&gt;
&lt;p&gt;我们要运用马克思主义的立场观点方法，或者现代科学的理性思维，对收集来的材料进行去粗取精，去伪存真，由此及彼，由表及里的改造制作。&lt;/p&gt;
&lt;p&gt;群众想要绝对平均主义（小农平均观），我们不能给，但我们要提炼出反对贫富悬殊的合理内核，制定共同富裕的政策。&lt;/p&gt;
&lt;p&gt;群众想要青天大老爷做主（封建依附观），我们不能做大老爷，但我们要提炼出法治与公正的需求，建立完善的制度体系。&lt;/p&gt;
&lt;p&gt;这一步，就是剥离封建与资本主义的壳，提取出人民根本利益的核。&lt;/p&gt;
&lt;p&gt;第三步：转化输出的到群众中去。&lt;/p&gt;
&lt;p&gt;将提炼好的方针政策，再拿回到群众中去。但不是发一纸文件了事，而是要进行宣传、解释、转化。&lt;/p&gt;
&lt;p&gt;要把高深的理论翻译成群众听得懂的语言，要把长远的利益与群众眼前的实惠结合起来。&lt;/p&gt;
&lt;p&gt;这就不得不提土改中的诉苦运动。最初分土地时，很多贫雇农受封建宿命论影响，认为命里注定受穷，不敢拿地主的地。这时候工作队没有强迫命令，而是组织诉苦会。让大家互诉苦水，分析穷根。&lt;/p&gt;
&lt;p&gt;通过这种方式，让群众自己意识到：穷不是因为命不好，而是因为剥削制度。这就是把先进的阶级理论，转化成了群众自己的觉悟。一旦觉悟被唤醒，封建思想的枷锁就被砸碎了，爆发出的就是保卫胜利果实的无穷力量。&lt;/p&gt;
&lt;h2&gt;不仅是方法论，更是世界观&lt;/h2&gt;
&lt;p&gt;群众路线首先不仅是一个方法论问题，更含有一个世界观问题。&lt;/p&gt;
&lt;p&gt;它要求我们必须具备彻底的唯物主义勇气，敢于承认并面对现实的不完美，实事求是；同时具备坚定的革命乐观主义精神，相信任何普通人通过改造都能迸发出改天换地的力量。&lt;/p&gt;
&lt;p&gt;所谓的屠龙术，不是你手里有一把无坚不摧的利剑去单挑恶龙。&lt;/p&gt;
&lt;p&gt;而是你有能力，让千千万万的人，即使手里拿着锄头，哪怕他们昨天还胆小怕事、满腹牢骚，但今天，他们能在你的组织和感召下，自觉地站在一起，挥向那条看似不可战胜的恶龙。&lt;/p&gt;
&lt;p&gt;从一盘散沙到钢铁洪流，中间的那个魔法，就叫群众路线。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;原作者：知乎-小岚|链接：&lt;a href=&quot;https://zhuanlan.zhihu.com/p/1988602960712840061&quot;&gt;https://zhuanlan.zhihu.com/p/1988602960712840061&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>咕咕嘎嘎咕咕嘎嘎</title><link>https://kylaan.cn/blog/galafa</link><guid isPermaLink="true">https://kylaan.cn/blog/galafa</guid><description>gugugaga</description><pubDate>Mon, 05 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;你为啥直接拿个算子就说“可逆”啊？！😨泛函分析里根本不是这样！😡你以为在有限维里 $\det$ 不为 0 就完事了？你这是把无限维 Banach 空间当 $\mathbb{R}^n$ 玩呢！你应该先跟我好好聊天☝，把空间、范数、完备性都交代清楚：到底是 Banach 还是 Hilbert？是有界线性算子还是闭算子？定义域是不是整个空间？然后你得先刷我的好感度——先证明它是 &lt;strong&gt;有界&lt;/strong&gt; 的，再讨论它是不是 &lt;strong&gt;单射&lt;/strong&gt;，是不是 &lt;strong&gt;稠密像&lt;/strong&gt;，像是不是 &lt;strong&gt;闭&lt;/strong&gt;，这些都是剧情前置条件啊☺️。你还得偶尔给我送送礼物：来几个估计式，给我一个 $|Tx|\ge c|x|$ 的下界，或者给我一个紧扰动 $T=\lambda I-K$ 的结构，让我知道你至少在 Riesz–Schauder 这条线里走剧情😮。到了特殊节日的时候你再来互动：比如你想说 $T$ 几乎可逆，那就把 Fredholm 指标、核的维数、余核的维数都摆出来，告诉我 $\mathrm{ind}(T)=\dim\ker T-\mathrm{codim}R(T)$ 你算清楚了没☺️。最后必须等到我内心那个神秘事件触发——比如你发现 (K) 是紧算子所以谱除了 0 之外全是特征值、而且只能聚到 0；或者你用开映射定理/闭图定理把“满射 $\Rightarrow$ 有界逆”这种关键 CG 点打出来😮！然后你再在关键节点向我表白：不是“我觉得它可逆”，而是$\ker T={0}$ 且 $R(T)=X$，所以 $T^{-1}\in\mathcal{B}(X)$”这种正儿八经的告白！我同意跟你在一起☺️，然后我才给你看我的特殊CG啊😃——比如给你放一个&lt;strong&gt;分解&lt;/strong&gt;：$X=\ker T\oplus M$，在 (M) 上 (T) 同构；或者给你一个 $\overline{R(T)}=(\ker T&apos;)^\perp$ 的正交关系，顺便告诉你什么时候能把闭包去掉，什么时候不行。你怎么一上来就“显然可逆”“显然像闭”“显然核为0就满射”啊？！😡你这跳过了稠密性、闭性、伴随、紧扰动不变指标这些支线剧情，直接冲进结局线，谁给你的勇气？！嘎啦分析里根本不是这样！😡我不接受！！😡😡😡&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>泛函分析</title><link>https://kylaan.cn/blog/functional/review</link><guid isPermaLink="true">https://kylaan.cn/blog/functional/review</guid><description>使用课本：《泛函分析》江泽坚（第二版），高等教育出版社。前四章</description><pubDate>Sat, 03 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;距离线性空间&lt;/h1&gt;
&lt;h2&gt;基本概念回顾&lt;/h2&gt;
&lt;h3&gt;线性空间&lt;/h3&gt;
&lt;p&gt;加法和数乘 符合{8}公设
交换、结合、零元、加法逆、加法分配、数乘分配、数乘结合、数乘单位&lt;/p&gt;
&lt;h3&gt;线性流形&lt;/h3&gt;
&lt;p&gt;对加法和数乘封闭的子空间&lt;/p&gt;
&lt;h3&gt;Hamel基&lt;/h3&gt;
&lt;p&gt;H线性无关 &amp;#x26; H能张成整个线性空间&lt;/p&gt;
&lt;h3&gt;距离空间&lt;/h3&gt;
&lt;p&gt;距离函数符合{3}公设
非负、对称、三角&lt;/p&gt;
&lt;h3&gt;稠密&lt;/h3&gt;
&lt;p&gt;大集合里的所有元素都有任意靠近他的子集元素&lt;/p&gt;
&lt;h3&gt;距离空间的完备化&lt;/h3&gt;
&lt;p&gt;$\langle X,d \rangle$ 等距映射到一个完备空间的稠密子集&lt;/p&gt;
&lt;h3&gt;列紧&lt;/h3&gt;
&lt;p&gt;集合的任何序列都有收敛子序列
&lt;strong&gt;紧集 = 列紧集 + 闭集&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-mermaid&quot;&gt;graph LR
    A[一个集合] --&gt; B{是否有界?}
    B -- 否 --&gt; C[绝不是紧集或列紧集]
    B -- 是 --&gt; D{是否有极限?}
    D -- 序列必有收敛子列 --&gt; E[列紧集]
    E --&gt; F{是否包含极限点?}
    F -- 是 --&gt; G[紧集]
    F -- 否 --&gt; H[相对紧但非紧]
    D -- 序列可能发散到无穷 --&gt; I[仅是有界集]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三个条件：非负、齐次、三角&lt;/p&gt;
&lt;h3&gt;内积空间&lt;/h3&gt;
&lt;p&gt;平方非负、共轭线性、共轭交换&lt;/p&gt;
&lt;p&gt;在 Hilbert 空间中，泛函的概念变得异常简单且强大，这归功于我们之前讨论的 &lt;strong&gt;Riesz 表示定理&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 Hilbert 空间 $H$ 中，任何一个连续线性泛函 $f: H \to \mathbb{C}$，其实都对应着空间里的一个固定的向量（函数）$y$。&lt;/li&gt;
&lt;li&gt;泛函的作用效果等同于做内积：$f(x) = \langle x, y \rangle$。
&lt;strong&gt;这意味着：&lt;/strong&gt; 在 Hilbert 空间里，所有的“观测”（泛函）本质上都是在拿一个“模板” $y$ 去衡量输入 $x$ 的“投影”大小。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;关键区分：泛函 (Functional) vs 算子 (Operator)&lt;/h3&gt;
&lt;p&gt;| &lt;strong&gt;概念&lt;/strong&gt;              | &lt;strong&gt;映射关系&lt;/strong&gt;              | &lt;strong&gt;输入&lt;/strong&gt; | &lt;strong&gt;输出&lt;/strong&gt;    | &lt;strong&gt;例子&lt;/strong&gt;                       |
| ------------------- | --------------------- | ------ | --------- | ---------------------------- |
| &lt;strong&gt;泛函 (Functional)&lt;/strong&gt; | $f: X \to \mathbb{K}$ | 一个函数   | &lt;strong&gt;一个数&lt;/strong&gt;   | 定积分、点处取值 $f(t_0)$            |
| &lt;strong&gt;算子 (Operator)&lt;/strong&gt;   | $T: X \to Y$          | 一个函数   | &lt;strong&gt;另一个函数&lt;/strong&gt; | 微分算子 $D = \frac{d}{dt}$、不定积分 |&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这里的 $\mathbb{K}$ 是 $\mathbb{C}$ 或 $\mathbb{R}$&lt;/li&gt;
&lt;li&gt;在无穷维空间，“有界”等价于“连续”，这是泛函分析的基础。&lt;/li&gt;
&lt;li&gt;这样说，&lt;strong&gt;Fréchet-Riesz 定理&lt;/strong&gt;只需要看出目标泛函是“有界+线性”就可以（“连续线性”）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Lax-Milgram 定理&lt;/h3&gt;
&lt;p&gt;其实就是把 Fréchet − Riesz 表示定理中的内积推广为共轭双线性泛函
内积是一个性质非常好的共轭双线性泛函
我们在这里给他推广，只要满足&lt;strong&gt;有界+强正定&lt;/strong&gt;性质的共轭双线性泛函就可以
然后我们如此给出的$f(x)\to x\in H\to $“内积”-即这个共轭双线性泛函，这个$x$能更加精确估计大小：$|x|\le \dfrac{1}{\alpha}|f|_{H^*}$&lt;/p&gt;
&lt;p&gt;在第三章一定要注意区分各种&lt;strong&gt;模、范数、算子范数&lt;/strong&gt;
关于算子范数有一个等价引理：
$\displaystyle |T|=\sup_{|x|=|y|=1}{|(Tx,y)|}$&lt;/p&gt;
&lt;p&gt;比如：
&lt;strong&gt;例1&lt;/strong&gt; $K(s,t)$是$[0,1]^2$上的连续函数，$C[0,1]$上的积分算子$$(Ax)(s)=\int_0^1K(s,t)x(t)\mathrm{d}t$$
&lt;strong&gt;求范数：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$Ax$作为向量的模：$$|(Ax)(s)| \le \left( \int_0^1 |K(s,t)| dt \right) \cdot |x|_\infty$$&lt;/li&gt;
&lt;li&gt;$|Ax|$在$C[0,1]$空间的无穷范数 $$|Ax|&lt;em&gt;\infty = \max&lt;/em&gt;{s \in [0,1]} |(Ax)(s)| \le \max_{s \in [0,1]} \left[ \left( \int_0^1 |K(s,t)| dt \right) \cdot |x|&lt;em&gt;\infty \right]\le \left( \max&lt;/em&gt;{s \in [0,1]} \int_0^1 |K(s,t)| dt \right) \cdot |x|_\infty$$&lt;/li&gt;
&lt;li&gt;$A$的算子范数（对 $x$ 取上确界）$$|A| = \sup_{x \neq 0} \frac{|Ax|&lt;em&gt;\infty}{|x|&lt;/em&gt;\infty} \le \max_{s \in [0,1]} \int_0^1 |K(s,t)| dt$$&lt;/li&gt;
&lt;li&gt;然后验证能取得等号即可，存在$x$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;注意一个命题：&lt;/strong&gt;$A,B\in L(X)$则$AB\in L(X)$，而且$|AB|\le |A||B|$&lt;/p&gt;
&lt;h3&gt;范数的强于和等价&lt;/h3&gt;
&lt;p&gt;两个范数互相强于($|\cdot|&lt;em&gt;{1}$收敛 $\Rightarrow|\cdot|&lt;/em&gt;{2}$收敛)另一个则叫&lt;strong&gt;等价&lt;/strong&gt;
等价范数就是在说他们是同阶的：$$r_{1}\le \dfrac{|x|&lt;em&gt;{2}}{|x|&lt;/em&gt;{1}}\le r_{2}$$
而且，线性空间上的两个范数如果都使其成为Banach空间那么两个范数等价&lt;/p&gt;
&lt;h3&gt;算子的逆&lt;/h3&gt;
&lt;p&gt;算子像的缩小比例有下界则可逆连续，类似Lax-Milgram说的强正定，不会把非零$x$映为$0$&lt;/p&gt;
&lt;h3&gt;压缩算子的性质&lt;/h3&gt;
&lt;p&gt;Banach空间X，$A\in L(X)$，$|A|&amp;#x3C; 1$则$I-A$有界可逆而且$$(I-A)^{-1}=\sum_{n=0}^{\infty}A^n$$
$$|(I-A)^{-1}|\le \dfrac{1}{1-|A|}$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$L(X)$中全体有界可逆元形成一个开集&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Banach扩张定理&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;实&lt;/strong&gt;线性流形$G\subset X$上的实线性泛函$f(x)$，如果有$X$上的&lt;strong&gt;实值&lt;/strong&gt;泛函$p(x)$，使得&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$p(x+y)\le p(x)+p(y),\ p(tx)=tp(x);\ x,y\in X,t\ge 0$&lt;/li&gt;
&lt;li&gt;$f(x)\le p(x),\ \text{当}x\in G$
则存在$X$上的实线性泛函$F(x)$，使得$$F(x)=f(x),\ \text{当}x\in G$$
且$$F(x)\le p(x),\ \text{当}x\in X$$&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;所谓“控制延拓”，$f$ 在 $G$ 以外能被 $p$ 控制那么就存在延拓 $F$（同样被 $p$ 控制）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;复值的也类似，然后总结出Hahn-Banach：&lt;/p&gt;
&lt;h3&gt;Hahn-Banach&lt;/h3&gt;
&lt;p&gt;赋范线性空间 $X$ 上的线性流形 $G$，有 $G$ 上的连续线性泛函$f(x)$ ，如此始终有 $f$ 的扩张$F(x)$：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$F(x)=f(x),\ x\in G$&lt;/li&gt;
&lt;li&gt;$|F|=|f|_{G}$&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;说的就是：赋范线性空间的流形上的泛函恒可以保范扩张&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在&lt;strong&gt;非零的赋范线性空间&lt;/strong&gt;上总存在非零的连续线性泛函，但是一般的距离线性空间就不行了。eg：S[0,1]不能赋以范数&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“范数”通过凸性保证了泛函的丰富性，而一般的“距离”则可能让空间变得过于“扁平”，以至于无法支撑起任何非零的线性泛函。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Hahn-Banach定理的两种常见几何表达&lt;/h3&gt;
&lt;h4&gt;A. 点与集的严格分离&lt;/h4&gt;
&lt;p&gt;如果 $K$ 是一个闭凸集，$x_0 \notin K$，那么存在一个连续线性泛函 $f$ 和常数 $c$，使得：&lt;/p&gt;
&lt;p&gt;$$f(x) \le c &amp;#x3C; f(x_0) \quad \forall x \in K$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;理解&lt;/strong&gt;：这意味着 $x_0$ 处的“高度”严格大于整个 $K$ 集合的“最高点”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;B. 两个凸集的分离（支撑平面）&lt;/h4&gt;
&lt;p&gt;如果 $A$ 和 $B$ 是两个互不相交的凸集，且其中一个有内点（比如是开集），那么存在一个超平面将它们分开。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;特殊情况：支撑定理&lt;/strong&gt;。如果点 $x_0$ 在凸集 $K$ 的边界上，你总能找到一个超平面“贴”在 $K$ 的边缘通过 $x_0$，但不穿过 $K$ 的内部。这就像在球体表面放一块平整的切板。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;C. 书上讲的用线性簇&lt;/h4&gt;
&lt;p&gt;线性簇：线性流形G，比如一条直线。$x_0+x,\ x\in G$，这样线性簇 $g$ 就是一个小条带，定理说我们可以扩张到一个超平面（存在超平面包含g而与凸集不相交）&lt;/p&gt;
&lt;h3&gt;分离定理中关于集合性质的描述&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;平衡：&lt;/strong&gt; 说的是$x\in M,|\lambda|\le 1$总有$\lambda x \in M$，也就是说&lt;strong&gt;集合内部没有空腔而且关于原点对称&lt;/strong&gt;，反例就是[0,2]、单位球挖去里面的原点邻域球等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;吸收：&lt;/strong&gt; 说的是可以把整个空间的任意向量压缩到$M$里面，如果是闭的那一定有原点（$\varepsilon\to 0$）]&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;半范数&lt;/h3&gt;
&lt;p&gt;设 $X$ 是线性空间，映射 $p: X \to \mathbb{R}$ 称为&lt;strong&gt;半范数&lt;/strong&gt;，如果它满足以下两条性质：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;次可加性 (三角不等式)&lt;/strong&gt;：$p(x+y) \le p(x) + p(y)$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;绝对齐次性&lt;/strong&gt;：$p(\alpha x) = |\alpha| p(x)$。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可以把半范数想象成一种&lt;strong&gt;降维观测&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;投影视角&lt;/strong&gt;：想象在三维空间里，我们只看一个向量在 $x-y$ 平面上的投影长度。
&lt;ul&gt;
&lt;li&gt;对于向量 $v = (0, 0, 1)$，它的投影长度是 0。&lt;/li&gt;
&lt;li&gt;虽然 $v$ 不是零向量，但在这个“观测方式”下，它的大小是 0。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核 (Kernel / Null Space)&lt;/strong&gt;：所有满足 $p(x) = 0$ 的点构成的集合 $N$ 是一个线性子空间。在这个子空间里的所有向量，在半范数 $p$ 的眼里都是“透明”的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;闵可夫斯基泛函&lt;/h3&gt;
&lt;p&gt;一种经典的重要的半范数Minkowski泛函，也叫&lt;strong&gt;示性函数 (Gauge)&lt;/strong&gt;
$$p_M(x) = \inf { t &gt; 0 : \frac{x}{t} \in M }$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这个公式的直觉非常美：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把 $M$ 看作是一个“容器”。&lt;/li&gt;
&lt;li&gt;为了把向量 $x$ 装进这个容器，你需要把容器放大 $t$ 倍。&lt;/li&gt;
&lt;li&gt;那个&lt;strong&gt;刚好能装下 $x$ 的最小放大倍数 $t$&lt;/strong&gt;，就是 $x$ 的“长度”（半范数）。&lt;/li&gt;
&lt;li&gt;反过来其实就是看 $x$ 缩小到 $M$ 所需要的倍数&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;弱序列闭集&lt;/h4&gt;
&lt;p&gt;设 $X$ 为赋范线性空间，$M \subset X$。
如果对于 $M$ 中的任意序列 ${x_n}$，只要它弱收敛于 $x$（记作 $x_n \rightharpoonup x$），就有 $x \in M$，那么称 $M$ 是弱序列闭集。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;弱收敛的含义&lt;/strong&gt;：对于所有连续线性泛函 $f \in X^*$，都有 $f(x_n) \to f(x)$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;弱序列闭 $\Rightarrow$ 强闭&lt;/strong&gt;： 这是显然的。因为强收敛（范数收敛）一定能推出弱收敛。如果一个集合连弱极限都能锁住，那它肯定能锁住强极限。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;强闭&lt;/strong&gt;$\nRightarrow$&lt;strong&gt;弱序列闭&lt;/strong&gt;：在无穷维空间中，很多范数意义下的闭集在弱拓扑下会“漏水”。
&lt;ul&gt;
&lt;li&gt;eg：&lt;strong&gt;单位球面 $S = {x : |x| = 1}$&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;在 Hilbert 空间中，标准正交基序列 ${e_n}$ 满足 $|e_n| = 1$，所以它们都在单位球面上。&lt;/li&gt;
&lt;li&gt;但是 $e_n \rightharpoonup 0$（弱收敛到原点）。&lt;/li&gt;
&lt;li&gt;原点 $0$ 的范数是 $0$，不在球面上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结论&lt;/strong&gt;：单位球面是强闭的，但&lt;strong&gt;不是&lt;/strong&gt;弱序列闭的。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3&gt;马祖尔定理 (Mazur&apos;s Theorem)：凸性的桥梁&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;对于赋范线性空间中的&lt;strong&gt;凸集&lt;/strong&gt;，其&lt;strong&gt;强闭性&lt;/strong&gt;与&lt;strong&gt;弱序列闭性&lt;/strong&gt;是等价的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;无处稠密 / 无内点&lt;/h4&gt;
&lt;p&gt;| &lt;strong&gt;概念&lt;/strong&gt;                   | &lt;strong&gt;数学定义&lt;/strong&gt;                               | &lt;strong&gt;直观解释&lt;/strong&gt;                     |
| ------------------------ | -------------------------------------- | ---------------------------- |
| &lt;strong&gt;无内点&lt;/strong&gt; (Empty Interior) | $\text{int}(E) = \emptyset$            | 集合里&lt;strong&gt;没有任何一个小开球&lt;/strong&gt;。            |
| &lt;strong&gt;无处稠密&lt;/strong&gt; (Nowhere Dense) | $\text{int}(\overline{E}) = \emptyset$ | &lt;strong&gt;闭包&lt;/strong&gt;之后依然没有内点。即：它在任何局部都不稠密。 |
eg：有理数集 $Q$ 无内点（内点：存在邻域完全包含在集合，但是任何有理数邻域中必有无理数）、闭包是 $R$ 有内点，所以 $Q$ 是无内点但非无处稠密的&lt;/p&gt;
&lt;h4&gt;纲&lt;/h4&gt;
&lt;p&gt;第一纲：距离空间 $X$ 中 $E=\bigcup_{n=1}^{\infty}S_{n}$，而每个$S_{n}$都是$X$中无处稠密的，那么称$E$是&lt;strong&gt;第一纲&lt;/strong&gt;的
第二纲：不是第一纲的叫第二纲&lt;/p&gt;
&lt;h3&gt;贝尔纲定理 (Baire Category Theorem)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;只要空间是完备的（比如序列空间 $(s)$），你就不可能仅仅通过叠加这种“没厚度”的薄片（无处稠密集）来填满整个厚实的空间。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;严格叙述就是说：完备的距离空间必然是第二纲的&lt;/p&gt;
&lt;h3&gt;一致有界原理 / 共鸣定理&lt;/h3&gt;
&lt;p&gt;设 $X$ 是一个 &lt;strong&gt;Banach 空间&lt;/strong&gt;（完备性是关键），$Y$ 是一个赋范线性空间。设 ${T_\alpha}&lt;em&gt;{\alpha \in A}$ 是从 $X$ 到 $Y$ 的一族&lt;strong&gt;有界线性算子&lt;/strong&gt;。
如果对于每一个固定的 $x \in X$，这族算子在 $x$ 处的取值都是有界的，那么，这族算子的范数集合也必然是有界的，即$$\sup&lt;/em&gt;{\alpha \in A} |T_\alpha x| &amp;#x3C; \infty \implies \sup_{\alpha \in A} |T_\alpha| &amp;#x3C; \infty$$&lt;/p&gt;
&lt;h3&gt;例：证明多项式在 $C[0,1]$ 中稠密&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Bernstein多项式&lt;/strong&gt;：对于任意 $f \in C[0,1]$，定义 $n$ 次多项式 $B_n(f; x)$ 为：&lt;/p&gt;
&lt;p&gt;$$B_n(f; x) = \sum_{k=0}^n f\left(\frac{k}{n}\right) \binom{n}{k} x^k (1-x)^{n-k}$$
记 $b_{n,k}(x) = \binom{n}{k} x^k (1-x)^{n-k}$：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;总和为 1&lt;/strong&gt;：$\sum_{k=0}^n b_{n,k}(x) = 1$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一阶矩（期望）&lt;/strong&gt;：$\sum_{k=0}^n \frac{k}{n} b_{n,k}(x) = x$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;二阶矩（方差相关）&lt;/strong&gt;：$\sum_{k=0}^n \left(\frac{k}{n} - x\right)^2 b_{n,k}(x) = \frac{x(1-x)}{n}$&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;直观理解&lt;/strong&gt;：$b_{n,k}(x)$ 可以看作随机变量 $X \sim B(n, x)$ 取值为 $k$ 的概率。当 $n$ 很大时，样本平均值 $k/n$ 会高度集中在期望值 $x$ 附近。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们要证明：对任意 $\epsilon &gt; 0$，当 $n$ 足够大时，对于所有 $x \in [0,1]$，都有 $|B_n(f; x) - f(x)| &amp;#x3C; \epsilon$。
$$|B_n(f; x) - f(x)| = \left| \sum_{k=0}^n \left( f\left(\frac{k}{n}\right) - f(x) \right) b_{n,k}(x) \right|$$
$$|B_n(f; x) - f(x)| \le \sum_{k=0}^n \left| f\left(\frac{k}{n}\right) - f(x) \right| b_{n,k}(x)$$
由于 $f$ 在紧区间 $[0,1]$ 上连续，它必然是&lt;strong&gt;一致连续&lt;/strong&gt;的。因此对于给定的 $\epsilon$，存在 $\delta &gt; 0$，使得当 $|x - y| &amp;#x3C; \delta$ 时，$|f(x) - f(y)| &amp;#x3C; \epsilon/2$。 同时，$f$ 是有界的，设 $|f(x)| \le M$。我们将求和号下的索引 $k$ 分成两部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;集合 $K_1$&lt;/strong&gt;：满足 $|\frac{k}{n} - x| &amp;#x3C; \delta$ 的点（距离 $x$ 较近的点）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;集合 $K_2$&lt;/strong&gt;：满足 $|\frac{k}{n} - x| \ge \delta$ 的点（距离 $x$ 较远的点）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;分段估计：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对于 $K_1$ 部分：
由于此时 $|k/n - x| &amp;#x3C; \delta$，根据一致连续性，$|f(k/n) - f(x)| &amp;#x3C; \epsilon/2$。
$$\sum_{k \in K_1} |f(k/n) - f(x)| b_{n,k}(x) &amp;#x3C; \frac{\epsilon}{2} \sum_{k \in K_1} b_{n,k}(x) \le \frac{\epsilon}{2} \cdot 1 = \frac{\epsilon}{2}$$&lt;/li&gt;
&lt;li&gt;对于 $K_2$ 部分：
由于 $|f(k/n) - f(x)| \le 2M$，且在 $K_2$ 中满足 $\frac{(k/n - x)^2}{\delta^2} \ge 1$，我们有：
$$\sum_{k \in K_2} |f(k/n) - f(x)| b_{n,k}(x) \le 2M \sum_{k \in K_2} b_{n,k}(x) \le 2M \sum_{k \in K_2} \frac{(k/n - x)^2}{\delta^2} b_{n,k}(x)$$
利用恒等式 (3)：
$$\text{Sum}&lt;em&gt;{K_2} \le \frac{2M}{\delta^2} \sum&lt;/em&gt;{k=0}^n (k/n - x)^2 b_{n,k}(x) = \frac{2M}{\delta^2} \frac{x(1-x)}{n}$$
由于 $x(1-x)$ 在 $[0,1]$ 上的最大值是 $1/4$，所以：
$$\text{Sum}_{K_2} \le \frac{2M}{\delta^2} \cdot \frac{1}{4n} = \frac{M}{2\delta^2 n}$$
$$|B_n(f; x) - f(x)| &amp;#x3C; \frac{\epsilon}{2} + \frac{M}{2\delta^2 n} &amp;#x3C;\epsilon ,\ \ as\ n\to \infty$$&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;开映射定理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Banach空间$X,Y$，$T\in L(X,Y)$，如果$R(T)$是第二纲的那么 $T$ 映开集的像也是开集（就是所谓&lt;strong&gt;开映射&lt;/strong&gt;）&lt;/li&gt;
&lt;li&gt;设 $X$ 和 $Y$ 都是Banach 空间。若 $T: X \to Y$ 是一个有界（连续）线性算子，且 $T$ 是满射，则 $T$ 是一个&lt;strong&gt;开映射&lt;/strong&gt;。
两个叙述等价，也即 $R(T)\text{第二纲} \Leftrightarrow T\text{是满射}$
&lt;strong&gt;推论：&lt;/strong&gt; Banach空间上的连续线性算子的像一定是&lt;strong&gt;第一纲点集&lt;/strong&gt;或者&lt;strong&gt;全空间&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Banach逆算子定理&lt;/h3&gt;
&lt;p&gt;Banach空间$X,Y$，$T\in L(X,Y)$，如果 $T$ 是双射那么 $T^{-1}$连续&lt;/p&gt;
&lt;h3&gt;算子的图形&lt;/h3&gt;
&lt;p&gt;定义：$$G(T)={\langle x,y \rangle \in X \times Y: x\in \mathcal{D}(T),y=Tx}$$闭算子（说的是T对x,y的极限封闭）等价于T的图形是闭集&lt;/p&gt;
&lt;h3&gt;闭图形定理&lt;/h3&gt;
&lt;p&gt;$T$ 是Banach空间 $X\to Y$处处有定义的闭算子，那么 $T$ 是有界的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;作用？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;$x_{n}\to x_{0}$&lt;/li&gt;
&lt;li&gt;$Tx_n \to y_0$&lt;/li&gt;
&lt;li&gt;$Tx_0 = y_0$
要证明 $T$ 在 $x_{0}$ 连续，需要$1. \Rightarrow 2. &amp;#x26; 1. \Rightarrow 3.$，但是闭图形定理让我们只要从1和2推3就可以&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;推论：Hellinger-Toeplitz定理&lt;/h4&gt;
&lt;p&gt;Hilbert空间$H$上的线性算子$A$，如果$$(Ax,y)=(x,Ay)$$则$A$有界&lt;/p&gt;
&lt;h2&gt;对偶空间 / 共轭空间&lt;/h2&gt;
&lt;p&gt;设 $X$ 是一个赋范线性空间。$X$ 的 &lt;strong&gt;对偶空间 $X&apos;$&lt;/strong&gt; 是指定义在 $X$ 上的所有&lt;strong&gt;连续线性泛函&lt;/strong&gt;组成的集合。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定理：&lt;/strong&gt; 对偶能传递可分性——Banach空间X的对偶空间X&apos;可分那么X可分&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定理：&lt;/strong&gt; $l^1$ (曼哈顿距离)空间上连续线性泛函 $f\in (l^1)&apos;$ 可表示为：
$$f(x)=\sum_{n=1}^\infty a_{n}x_{n}$$
其中 $x={x_{n}}\in l^1$，$a={a_{n}}\in (m)$，$|f|=|a|=\sup{|a_{n}|}$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定理：&lt;/strong&gt; $C[0,1]$上所有连续线性泛函 $f \in C[0,1]^*$ 都可以对应有界变差函数 $g(t)$ 积分来表示：
$$f(x) = \int_0^1 x(t) \mathrm{d}g(t)$$
这里的 $g$ 显然不是唯一的，进行限制 $g(t)\in V_{0}[0,1]$ 之后则 $f$ 唯一对应 $g$，此时还有：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定理：&lt;/strong&gt; $(C[0,1])&apos;$ 与 $V_{0}[0,1]$ 保范线性同构&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;$V_0[0,1]$ 是由满足以下三个条件的函数 $g(x)$ 组成的集合：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;有界变差&lt;/strong&gt;：$g(x)$ 在 $[0,1]$ 上是有界变差函数（$V_0^1(g) &amp;#x3C; \infty$）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;左端点归零&lt;/strong&gt;：$g(0) = 0$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;右连续性&lt;/strong&gt;：$g(x)$ 在开区间 $(0,1)$ 内处处右连续，即 $g(x+0) = g(x)$。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定理：&lt;/strong&gt; $L^p[a,b]$上的有界线性泛函 $f$，存在唯一 $y\in L^q[a,b],\ q=\dfrac{p}{p-1}$，使得：
$$f(x)=\int_{a}^bx(t)y(t)\mathrm{d}t$$
其中$\displaystyle |\ f\ |=|\ y\ |=\Big(\int_{a}^b|y(t)|^q\mathrm{d}t\Big)^{1/q}$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定理：&lt;/strong&gt; $l^p$ 的有界线性泛函 $f$ 可以表示为：
$$f(x)=\sum_{k=1}^{\infty}c_{k}\xi_{k}\quad x={\xi_{k}}&lt;em&gt;{k=0}^{\infty}\in l^p$$
其中 $\displaystyle |f |=|c|=\Big(\sum&lt;/em&gt;{k=1}^{\infty}|c_{k}|^q\Big)^{1/q}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样的话，有&lt;strong&gt;等距同构&lt;/strong&gt; $\Phi:(L^p)&apos;\to L^q,\ (L^p)&apos;\cong  L^q$&lt;/p&gt;
&lt;h4&gt;二次对偶空间&lt;/h4&gt;
&lt;p&gt;Banach空间 $X$，对偶空间 $X&apos;$，二次对偶 $X&apos;&apos;$
$$x_{0}(t)\in X \longrightarrow x_{0}&apos;(x_{0})\in X&apos;\longrightarrow x&apos;&apos;&lt;em&gt;{0}(x&lt;/em&gt;{0}&apos;)\in X&apos;&apos;$$
&lt;strong&gt;典型映射：&lt;/strong&gt; $\tau: X \to X&apos;&apos;, \tau(x_{0})=x_{0}&apos;&apos;$&lt;/p&gt;
&lt;h4&gt;自反空间&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;定义:&lt;/strong&gt; 如果 $\tau(X)=X&apos;&apos;$ 则称之为自反的&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有限维赋范线性空间都是自反的&lt;/li&gt;
&lt;li&gt;自反性的研究正是为了保证有限维赋范线性空间的定理在无限维上仍然成立&lt;/li&gt;
&lt;li&gt;一个 Banach 空间 $X$ 是自反的，当且仅当它的&lt;strong&gt;自然嵌入映射&lt;/strong&gt; $J: X \to X^{**}$ 是满射。 其中 $J(x)$ 定义为：$J(x)(f) = f(x)$，对于所有 $f \in X^*$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定理：&lt;/strong&gt; 自反的Banach空间的任何子空间自反&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;$L^p$ 与 $L^q$（以及 $l^p$ 与 $l^q$）是&lt;strong&gt;相互对偶&lt;/strong&gt;的
但是 $l^1$ 的对偶空间是 $l^\infty$，反之不成立。$l^{\infty}$ 的对偶空间很复杂&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;|&lt;strong&gt;空间类型&lt;/strong&gt;|&lt;strong&gt;空间符号&lt;/strong&gt;|&lt;strong&gt;是否可分&lt;/strong&gt;|&lt;strong&gt;稠密子集（示例）&lt;/strong&gt;|
|---|---|---|---|
|&lt;strong&gt;序列空间&lt;/strong&gt;|$l^1$|&lt;strong&gt;是&lt;/strong&gt;|只有有限项非零且取值为有理数的序列。|
||$l^p$ ($1 &amp;#x3C; p &amp;#x3C; \infty$)|&lt;strong&gt;是&lt;/strong&gt;|同上。|
||$l^\infty$ (即 $m$)|&lt;strong&gt;否&lt;/strong&gt;|元素太多且间隔太远，无法用可数集覆盖。|
|&lt;strong&gt;函数空间&lt;/strong&gt;|$L^1[a, b]$|&lt;strong&gt;是&lt;/strong&gt;|具有有理端点的阶梯函数或有理系数多项式。|
||$L^p[a, b]$ ($1 &amp;#x3C; p &amp;#x3C; \infty$)|&lt;strong&gt;是&lt;/strong&gt;|同上。|
||$L^\infty[a, b]$|&lt;strong&gt;否&lt;/strong&gt;|包含不可数个互不相交的“开球”。|&lt;/p&gt;
&lt;p&gt;| &lt;strong&gt;特性&lt;/strong&gt;   | &lt;strong&gt;Banach 共轭 $T&apos;$&lt;/strong&gt;           | &lt;strong&gt;Hilbert 共轭 $T^*$&lt;/strong&gt;                                                                                                                                       |
| -------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| &lt;strong&gt;定义空间&lt;/strong&gt; | 映射在对偶空间之间，映泛函为泛函：$Y&apos; \to X&apos;$ | 映射在原始空间之间，映向量为向量：$H_2 \to H_1$                                                                                                                             |
| &lt;strong&gt;线性性质&lt;/strong&gt; | 总是线性的                        | 如果是复空间，则关于标量是&lt;strong&gt;共轭线性&lt;/strong&gt;的（$(\alpha T)^* = \bar{\alpha} T^&lt;em&gt;$）                                                                                                  |
| &lt;strong&gt;联系&lt;/strong&gt;   | $T&apos;$ 是抽象的泛函变换                | $T^&lt;/em&gt;$ 是通过内积 $\langle \cdot, \cdot \rangle$ 具象化的变换                                                                                                          |
| &lt;strong&gt;特殊性质&lt;/strong&gt; |                              | $T^{&lt;strong&gt;} = T$（这直接对应了 Hilbert 空间的&lt;/strong&gt;自反性**）-  $$\begin{cases}\text{ker}(T^&lt;em&gt;) = R(T)^\perp\ \overline{R(T^&lt;/em&gt;)} = (\text{ker } T)^\perp\end{cases}$$ |
|          |                              |                                                                                                                                                            |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;有界线性算子谱论&lt;/h2&gt;
&lt;p&gt;谱的概念本质上是在问：&lt;strong&gt;对于哪些复数 $\lambda$，算子 $(T - \lambda I)$ 是“不健康”的（不可逆）？&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;如何快速判断 $\lambda$ 的身份？&lt;/h4&gt;
&lt;p&gt;你可以按照这个逻辑图进行自我检测：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-mermaid&quot;&gt;graph TD
    A([开始判断 λ]) --&gt; B{&quot;方程 λI - T x = 0 &amp;#x3C;br&gt;是否有非零解?&quot;}
    
    B -- 有 --&gt; C[&quot;**点谱** σₚ(T)&amp;#x3C;br&gt;(λ 为特征值)&quot;]
    B -- 没有 --&gt; D{&quot;值域 R(λI - T)&amp;#x3C;br&gt;是否等于全空间 X?&quot;：验证**双射+逆算子有界**}
    
    D -- 是 --&gt; E[&quot;**预解集** ρ(T)&amp;#x3C;br&gt;(λ 为正则值)&quot;]
    D -- 否 --&gt; F{&quot;值域闭包 R(λI - T)⁻&amp;#x3C;br&gt;是否等于全空间 X?&quot;}
    
    F -- &quot;是 (稠密)&quot; --&gt; G[&quot;**连续谱** σ꜀(T)&quot;]
    F -- &quot;否 (不稠密)&quot; --&gt; H[&quot;**剩余谱** σᵣ(T)&quot;]

    %% 样式美化
    style E fill:#e1f5fe,stroke:#01579b,stroke-width:1px
    style C fill:#fff9c4,stroke:#fbc02d,stroke-width:2px
    style G fill:#f1f8e9,stroke:#33691e,stroke-width:2px
    style H fill:#ffebee,stroke:#b71c1c,stroke-width:2px
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;如何判断预解集？&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;逆算子是满射&lt;/strong&gt;：即 $R(\lambda I - T) = X$。这保证了算子是“满射”的，方程 $(\lambda I - T)x = y$ 对任何 $y$ 都有解。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;逆算子有界&lt;/strong&gt;：即 $(\lambda I - T)^{-1} \in L(X)$。这意味着逆映射不仅存在，而且是连续的、稳定的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;隐藏的前提：课本定义中提到 $(\lambda I - T)^{-1}$ 存在，这实际上已经包含了 $\lambda I - T$ 必须是“单射”的意思（即 $\lambda$ 不是特征值）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是说，任意一个算子 $T$ 把复数域 $\mathbb{C}$ 分成了四部分：$$\begin{align*}\mathbb{C}&amp;#x26;=\rho(T)\ \bigcup \ \sigma(T)\
&amp;#x26;=\rho(T)\ \bigcup \ \sigma_{p}(T)\ \bigcup \ \sigma_{c}(T)\ \bigcup\ \sigma_{r}(T)
\end{align*}$$
而且，$$\begin{cases}
\ |\lambda|&gt;|T|\quad 则 \lambda\in\rho(T)\ \
\ |\lambda|\le|T|\quad 则\lambda\in \sigma(T)
\end{cases}$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一个重要的引理：&lt;/strong&gt;
对于 Hilbert 空间中的任何有界线性算子 $A$，其值域的交补等于其共轭算子的零空间，即：
$$R(A)^\perp = \text{ker}(A^*)$$&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;自共轭算子的谱&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;自共轭算子的谱 $\sigma(T)$ 必然在实轴上，即 $\sigma(T) \subset \mathbb{R}$。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特征值（点谱）是实数&lt;/strong&gt;：如果 $Tx = \lambda x$ 且 $x \neq 0$，利用自共轭性 $\langle Tx, x \rangle = \langle x, Tx \rangle$，可以推导出 $\lambda \langle x, x \rangle = \bar{\lambda} \langle x, x \rangle$。因为 $\langle x, x \rangle &gt; 0$，所以 $\lambda = \bar{\lambda}$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;整个谱都是实数&lt;/strong&gt;：不仅是点谱，连续谱和剩余谱（如果存在的话）中的 $\lambda$ 也必须是实数。如果 $\lambda$ 带有虚部，算子 $\lambda I - T$ 总是可以证明是可逆且有界的，因此虚数点必然落在预解集 $\rho(T)$ 中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自共轭算子的剩余谱必然为空集，即 $\sigma_r(T) = \emptyset$。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;谱半径&lt;/h3&gt;
&lt;h4&gt;定义&lt;/h4&gt;
&lt;p&gt;设 $T$ 是 Banach 空间 $X$ 上的有界线性算子，其谱半径 $r(T)$ 定义为谱集 $\sigma(T)$ 中元素绝对值的上确界：
$$r(T) = \sup { |\lambda| : \lambda \in \sigma(T) }$$
从几何上看，谱半径是包含整个谱集 $\sigma(T)$ 的最小闭圆盘的半径。&lt;/p&gt;
&lt;h4&gt;谱半径公式 (Gelfand 公式)&lt;/h4&gt;
&lt;p&gt;这是由数学家 Gelfand 证明的一个极其重要的极限公式，它建立了算子幂的范数与谱分布之间的定量联系：
$$r(T) = \lim_{n \to \infty} |T^n|^{1/n}$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;存在性&lt;/strong&gt;：对于任何有界线性算子，这个极限始终存在且唯一。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算意义&lt;/strong&gt;：虽然谱集 $\sigma(T)$ 有时很难求解，但通过计算算子幂的范数极限，我们可以直接得到谱半径。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Neumann 级数&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Neumann 级数&lt;/strong&gt;（Neumann Series）是线性代数中矩阵逆公式 $(I-A)^{-1} = \sum A^n$ 在有界线性算子上的推广。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;设 $T \in L(X)$ 是 Banach 空间 $X$ 上的有界线性算子。如果算子的谱半径满足 &lt;strong&gt;$r(T) &amp;#x3C; |\lambda|$&lt;/strong&gt;，那么：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;算子 $\lambda I - T$ 是可逆的（即 $\lambda$ 属于预解集 $\rho(T)$）。&lt;/li&gt;
&lt;li&gt;其逆算子（预解式）可以用级数形式表示：$$(\lambda I - T)^{-1} = \sum_{n=0}^{\infty} \dfrac{T^n}{\lambda ^ {n+1}} $$&lt;/li&gt;
&lt;li&gt;该级数在算子范数 $|\cdot|$ 意义下绝对收敛。&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;重要作用：估计谱的范围&lt;/h5&gt;
&lt;p&gt;所有的谱点 $\lambda \in \sigma(T)$ 必须满足 $|\lambda| \le r(T)$。因为一旦 $|\lambda| &gt; r(T)$，级数就收敛，意味着 $(\lambda I - T)$ 一定有界可逆，那么 $\lambda$ 就不可能在谱集里。&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;移位算子的关系&lt;/h3&gt;
&lt;p&gt;左右移位算子 $T_R,T_{L}$ 相互共轭 $(T_{R}^&lt;em&gt;=T_{L})$，同理 $T_L= T_R^&lt;/em&gt;$&lt;/p&gt;
&lt;p&gt;| &lt;strong&gt;特性&lt;/strong&gt;   | &lt;strong&gt;右移位算子 $T_R$​&lt;/strong&gt;                                                 | &lt;strong&gt;左移位算子 $T_{L}$​&lt;/strong&gt;                                               |
| -------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- |
| &lt;strong&gt;保范性&lt;/strong&gt;  | 保范的，因为多一位 $0$ 在内积范数中求和没影响                                        | 非保范，$|T_{L}(x)|^2={|x|}^2-{|x_{1}|}^2$                     |
| &lt;strong&gt;可逆性&lt;/strong&gt;  | 单射但非满射（值域缺第一位）                                                   | 满射但非单射（核空间包含 $(1,0,0,\dots)$                                     |
| &lt;strong&gt;组合关系&lt;/strong&gt; | $T_L T_R = I$ (左逆存在)                                             | $T_R T_L \neq I$ (它会强制将第一位变为 0)                                  |
| &lt;strong&gt;谱集&lt;/strong&gt;   | $\sigma(T_R) = { \lambda \in \mathbb{C} : |\lambda| \le 1 }$ | $\sigma(T_L) = { \lambda \in \mathbb{C} : |\lambda| \le 1 }$ |&lt;/p&gt;
&lt;h4&gt;右移位算子 $T_R$ 的谱分解&lt;/h4&gt;
&lt;p&gt;定义：$T_R(x_1, x_2, \dots) = (0, x_1, x_2, \dots)$。其谱集为 $\sigma(T_R) = { \lambda \in \mathbb{C} : |\lambda| \le 1 }$。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;点谱 $\sigma_p(T_R) = \emptyset$&lt;/strong&gt;：&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;剩余谱 $\sigma_r(T_R) = { \lambda \in \mathbb{C} : |\lambda| &amp;#x3C; 1 }$&lt;/strong&gt;：&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连续谱 $\sigma_c(T_R) = { \lambda \in \mathbb{C} : |\lambda| = 1 }$&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;左移位算子 $T_L$ 的谱分解&lt;/h4&gt;
&lt;p&gt;定义：$T_L(x_1, x_2, \dots) = (x_2, x_3, \dots)$。其谱集同样为 $\sigma(T_L) = { \lambda \in \mathbb{C} : |\lambda| \le 1 }$。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;点谱 $\sigma_p(T_L) = { \lambda \in \mathbb{C} : |\lambda| &amp;#x3C; 1 }$&lt;/strong&gt;：&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;剩余谱 $\sigma_r(T_L) = \emptyset$&lt;/strong&gt;：&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连续谱 $\sigma_c(T_L) = { \lambda \in \mathbb{C} : |\lambda| = 1 }$&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;| &lt;strong&gt;谱的分量&lt;/strong&gt;           | &lt;strong&gt;右移算子 TR​&lt;/strong&gt; | &lt;strong&gt;左移算子 TL​&lt;/strong&gt; | &lt;strong&gt;对称性解释&lt;/strong&gt;                  |
| ------------------ | ------------ | ------------ | -------------------------- |
| &lt;strong&gt;点谱 $\sigma_p$&lt;/strong&gt;  | $\emptyset$  | &lt;strong&gt;单位开圆盘&lt;/strong&gt;    | $T_L$ 丢失第一位信息导致产生零空间。      |
| &lt;strong&gt;剩余谱 $\sigma_r$&lt;/strong&gt; | &lt;strong&gt;单位开圆盘&lt;/strong&gt;    | $\emptyset$  | $T_R$ 的值域不稠密对应 $T_L$ 的特征值。 |
| &lt;strong&gt;连续谱 $\sigma_c$&lt;/strong&gt; | 单位圆周         | 单位圆周         | 边界上的不稳定性                   |
| &lt;strong&gt;总谱 $\sigma$&lt;/strong&gt;    | 单位闭圆盘        | 单位闭圆盘        | $|T_{R}|=|T_{L}|$      |&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;紧算子&lt;/h3&gt;
&lt;p&gt;紧算子 (Compact Operator) 是研究得最透彻的一类算子。可以把它直观地理解为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;无限维空间中“最像有限维矩阵”的算子。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在无限维空间中，有界集不一定是列紧的。紧算子的作用就是通过“压缩”作用，把原本发散的有界集拉回到紧凑的状态。&lt;/p&gt;
&lt;h4&gt;定义&lt;/h4&gt;
&lt;p&gt;设 $X, Y$ 是两个 Banach 空间，线性算子 $T: X \to Y$ 被称为&lt;strong&gt;紧算子&lt;/strong&gt;，如果满足以下任一等价条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;几何定义&lt;/strong&gt;：$T$ 把 $X$ 中的每一个&lt;strong&gt;有界集&lt;/strong&gt;映成 $Y$ 中的&lt;strong&gt;列紧集（相对紧集）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;序列定义&lt;/strong&gt;：对于 $X$ 中的任何&lt;strong&gt;有界序列&lt;/strong&gt; ${x_n}$，其像序列 ${Tx_n}$ 在 $Y$ 中都存在&lt;strong&gt;收敛的子序列&lt;/strong&gt;。
即：$\forall \ 有界{x_{n}}&lt;em&gt;{n=1}^\infty \subset X,\ {Ax&lt;/em&gt;{n}}有收敛子列$，${x_{n}}$换成集合同样&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;常见的紧算子&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;有限秩算子：$A\in L(X),\dim{R(A)}&amp;#x3C;\infty$，根据有限维有界集的列紧性即可&lt;/li&gt;
&lt;li&gt;积分算子：$K(s,t)\in C[0,1]^2$，积分算子$\displaystyle A\ \mathrm{on}\ C[0,1]:\ Ax(s)=\int_{0}^1K(s,t)x(t)\mathrm{d}{t}$，借助Arzelà-Ascoli 定理证明列紧性&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$\mathscr{K}(X)$表示 $X$ 上所有的紧算子&lt;/p&gt;
&lt;h4&gt;性质&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;紧算子的线性封闭&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;紧算子$\mathscr{K}(X)$ 是 $L(X)$ 的非零双边理想&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$\mathscr{K}(X)\subset L(X)$&lt;/li&gt;
&lt;li&gt;$x,y \in \mathscr{K}(X),z\in L(X):\ zx\in \mathscr{K}(X)$，双边所以 $xz$ 也是&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;在范数收敛下是闭的：&lt;/strong&gt;
${A_{n}}&lt;em&gt;{n=0}^\infty\in \mathscr{K}(X)$  ，若 $|A&lt;/em&gt;{n}-A|\to {0}$ 则 $A\in \mathscr{K}(X)$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;eg：$L^2(\mathbb{R^2})\ 上的算子A是紧算子$
$\displaystyle K(x,y)\in L^2(\mathbb{R^2})，Af(x)=\int_{a}^bK(x,y)f(y)\mathrm{d}y$&lt;/li&gt;
&lt;li&gt;关于 $L^2(\mathbb{R^2})$ 上的积分算子：&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;紧算子能增强收敛性：&lt;/strong&gt;
$A$ 是紧算子，$x_{n}\overset{w}{\longrightarrow}x,则Ax_{n}\to Ax_{0}$
这其实就是由于紧算子的压缩性质（有界$\to$列紧）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在无穷维空间中，单射紧算子不可能是满的
$X$ 是无穷维的，$A$ 是紧算子且是单射（即没有非零解满足 $Ax=0$），那么它的值域 $R(A)$ 一定&lt;strong&gt;填不满&lt;/strong&gt;整个空间 $X$。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结论：&lt;/strong&gt; 对于无穷维空间上的紧算子，$0$ 永远在谱集 $\sigma(A)$ 中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;情形 A：如果 $A$ 不是单射，那么 $0$ 就是特征值，即 $0 \in \sigma_p(A)$。&lt;/li&gt;
&lt;li&gt;情形 B：如果 $A$ 是单射，根据命题 3.1，$R(A) \neq X$。这意味着 $0$ 绝对不可能在预解集 $\rho(A)$ 中。
&lt;ul&gt;
&lt;li&gt;如果值域稠密（$\overline{R(A)}=X$），则 $0 \in \sigma_c(A)$（连续谱）。&lt;/li&gt;
&lt;li&gt;如果值域不稠密，则 $0 \in \sigma_r(A)$（剩余谱）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$R(A)$ 一定是可分的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;算子共轭能传递算子紧性&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;算子$A$ 是紧的当且仅当$A&apos;$ 也是紧的&lt;/li&gt;
&lt;li&gt;$A\in \mathscr{K}(X)$，则其共轭算子$A&apos;\in \mathscr{K}(X&apos;)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;紧算子的可逼近性&lt;/h4&gt;
&lt;p&gt;可分Hilbert空间 $H$ 上的紧算子 $A$ 则存在一列有限秩算子 $\displaystyle A_{n},\ \lim_{ n \to \infty }|A_{n}-A|=0$&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;关于无穷维空间，带基Banach空间：
可分Banach空间 $X$ 中有一串 ${ e_{j} }&lt;em&gt;{j=1}^\infty$ 使每个 $x\in X$ 可唯一表为$$x=\sum&lt;/em&gt;{j=1}^\infty \xi_{j}e_{j}$$
$\mathrm{RHS}$ 依范数收敛则称  ${ e_{j} }_{j=1}^\infty$ 为 $X$ 的基&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;紧算子谱理论（Riesz-Schauder 理论）&lt;/h3&gt;
&lt;h4&gt;命题1&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;紧算子的非零特征值的特征空间是有限维的
对于紧算子 $A$ 和任何非零的 $\lambda$，特征空间 $\ker(A - \lambda I)$ 必须是&lt;strong&gt;有限维&lt;/strong&gt;的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;Riesz 引理：一个空间的单位球是列紧的，当且仅当该空间是有限维的
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;命题2&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;紧算子的非零特征值的特征算子值域是闭的
当 $\lambda \neq 0$ 时，算子 $A - \lambda I$ 的值域 $R(A - \lambda I)$ 永远是&lt;strong&gt;闭集&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;命题3&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;紧算子的特征算子 $\lambda I - A$，单射必导致满射。
$\ker(\lambda I - A) = {0}$ 则 $R(\lambda I - A) = X$
注意这里说的是特征算子 $\lambda I - A$，而在无穷维空间中，单射紧算子 $A$ 不可能是满的
也就是说，单射紧算子 $A$ 不可能是满的，非特征值（$\ker={ 0 }$）的 $\lambda I - A$ 一定是满的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;命题2.1&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;对于 $T = I - A$，$T$ 是单射当且仅当其共轭算子 $T&apos;$ 是单射。
$\dim \ker(I-A) = \dim \ker(I-A)&apos;$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;注意这里的讨论中有一个等价：$$T是单射 \Longleftrightarrow \dim \ker(T) = 0 \Longleftrightarrow \ker(T)={0}$$&lt;/p&gt;
&lt;h4&gt;命题2.2&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;$A\in \mathscr{K}(X),\ \forall \lambda\ne 0$有$$\dim \ker(\lambda I-A)=\dim \ker(\lambda I-A&apos;)&amp;#x3C;\infty$$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;以上为了引出重要的&lt;strong&gt;两则一定理&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;两则一定理&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;$A\in \mathscr{K}(X),\ \forall \lambda\ne 0$有$$\lambda\in \rho(A)\ 或\ \lambda\in \sigma_{p}(A)$$
对于紧算子而言非零数 $\lambda$ 要么是特征值要么是正则值&lt;/p&gt;
&lt;p&gt;而 $0$ 的讨论在上面已经有了：对于无穷维空间上的紧算子，$0$ 永远在谱集 $\sigma(A)$ 中&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3&gt;自伴算子 / 自共轭算子&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;谱集必然在实轴上 $\sigma(T)\subset \mathbb{R}$&lt;/li&gt;
&lt;li&gt;剩余谱必然为空集&lt;/li&gt;
&lt;li&gt;$T$ 是自伴的 $\Leftrightarrow$ $(Tx,x)\in \mathbb{R}$&lt;/li&gt;
&lt;li&gt;$T$ 是自伴的则 $\displaystyle |T|=\sup_{|x|=1}{(Tx,x)}$&lt;/li&gt;
&lt;li&gt;$|T^*T|=|T|^2$&lt;/li&gt;
&lt;li&gt;Hilbert空间上的有界射影 $P$ 是正交射影当且仅当 $P$ 是自伴的&lt;/li&gt;
&lt;li&gt;谱半径 $|r|=|T|$&lt;/li&gt;
&lt;li&gt;属于不同特征值的特征向量必正交&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hilbert 空间上的紧自伴算子必然至少有一个非零特征值。
（实对称矩阵一定可以被对角化。）&lt;/p&gt;</content:encoded><h:img src="/_astro/fa-jiang.Cvt-BN5_.png"/><enclosure url="/_astro/fa-jiang.Cvt-BN5_.png"/></item><item><title>LaTeX 常用模型样式</title><link>https://kylaan.cn/blog/latexmodel/styles</link><guid isPermaLink="true">https://kylaan.cn/blog/latexmodel/styles</guid><description>列出一些常用的 LaTeX 模型样式，方便在写作中使用。</description><pubDate>Wed, 31 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;常用字体 (Fonts)&lt;/h2&gt;
&lt;p&gt;| 命令 | 效果 | 描述 |
| :--- | :--- | :--- |
| &lt;code&gt;\mathbb{ABC}&lt;/code&gt; | $\mathbb{ABC}$ | 黑板粗体 (Blackboard Bold) |
| &lt;code&gt;\mathbf{abc}&lt;/code&gt; | $\mathbf{abc}$ | 粗体 (Bold Face) |
| &lt;code&gt;\mathtt{abc}&lt;/code&gt; | $\mathtt{abc}$ | 打字机字体 (Typewriter) |
| &lt;code&gt;\mathrm{abc}&lt;/code&gt; | $\mathrm{abc}$ | 罗马字体 (Roman) |
| &lt;code&gt;\mathsf{abc}&lt;/code&gt; | $\mathsf{abc}$ | 无衬线字体 (Sans Serif) |
| &lt;code&gt;\mathcal{ABC}&lt;/code&gt; | $\mathcal{ABC}$ | 书法字体 (Calligraphy) |
| &lt;code&gt;\mathscr{ABC}&lt;/code&gt; | $\mathscr{ABC}$ | 手写体 (Script) |
| &lt;code&gt;\mathfrak{abc}&lt;/code&gt; | $\mathfrak{abc}$ | 哥特字体 (Fraktur) |&lt;/p&gt;
&lt;h2&gt;常用符号与括号 (Symbols &amp;#x26; Delimiters)&lt;/h2&gt;
&lt;h3&gt;基础括号&lt;/h3&gt;
&lt;p&gt;| 类型 | 代码 | 效果 | 备注 |
| :--- | :--- | :--- | :--- |
| 圆括号 | &lt;code&gt;( ... )&lt;/code&gt; | $( ... )$ | |
| 方括号 | &lt;code&gt;[ ... ]&lt;/code&gt; | $[ ... ]$ | |
| 大括号 | &lt;code&gt;\{ ... \}&lt;/code&gt; | ${ ... }$ | 需转义 |
| 尖括号 | &lt;code&gt;\langle ... \rangle&lt;/code&gt; | $\langle ... \rangle$ | |
| 绝对值 | &lt;code&gt;\lvert ... \rvert&lt;/code&gt; 或 &lt;code&gt;\| ... \|&lt;/code&gt; | $\lvert ... \rvert$ | |
| 范数 | &lt;code&gt;\lVert ... \rVert&lt;/code&gt; 或 &lt;code&gt;\| ... \|&lt;/code&gt; | $\lVert ... \rVert$ | |&lt;/p&gt;
&lt;h3&gt;括号大小调整&lt;/h3&gt;
&lt;p&gt;| 尺寸 | 代码 | 效果 |
| :--- | :--- | :--- |
| 自动 | &lt;code&gt;\left( ... \right)&lt;/code&gt; | $\left( \frac{a}{b} \right)$ |
| Big | &lt;code&gt;\big( ... \big)&lt;/code&gt; | $\big( ... \big)$ |
| Big (大) | &lt;code&gt;\Big( ... \Big)&lt;/code&gt; | $\Big( ... \Big)$ |
| bigg (更大) | &lt;code&gt;\bigg( ... \bigg)&lt;/code&gt; | $\bigg( ... \bigg)$ |
| Bigg (最大) | &lt;code&gt;\Bigg( ... \Bigg)&lt;/code&gt; | $\Bigg( ... \Bigg)$ |&lt;/p&gt;
&lt;h2&gt;字体大小 (Font Sizes)&lt;/h2&gt;
&lt;p&gt;| 命令 | 效果 |
| :--- | :--- |
| &lt;code&gt;\tiny&lt;/code&gt; | $\tiny \text{Hello}$ |
| &lt;code&gt;\scriptsize&lt;/code&gt; | $\scriptsize \text{Hello}$ |
| &lt;code&gt;\footnotesize&lt;/code&gt; | $\footnotesize \text{Hello}$ |
| &lt;code&gt;\small&lt;/code&gt; | $\small \text{Hello}$ |
| &lt;code&gt;\normalsize&lt;/code&gt; | $\normalsize \text{Hello}$ |
| &lt;code&gt;\large&lt;/code&gt; | $\large \text{Hello}$ |
| &lt;code&gt;\Large&lt;/code&gt; | $\Large \text{Hello}$ |
| &lt;code&gt;\LARGE&lt;/code&gt; | $\LARGE \text{Hello}$ |
| &lt;code&gt;\huge&lt;/code&gt; | $\huge \text{Hello}$ |
| &lt;code&gt;\Huge&lt;/code&gt; | $\Huge \text{Hello}$ |&lt;/p&gt;
&lt;h2&gt;颜色对照表 (Colors)&lt;/h2&gt;
&lt;p&gt;| 颜色名 | 代码 | 效果 |
| :--- | :--- | :--- |
| Black | &lt;code&gt;\color{black}&lt;/code&gt; | $\color{black} \text{Text}$ |
| Red | &lt;code&gt;\color{red}&lt;/code&gt; | $\color{red} \text{Text}$ |
| Green | &lt;code&gt;\color{green}&lt;/code&gt; | $\color{green} \text{Text}$ |
| Blue | &lt;code&gt;\color{blue}&lt;/code&gt; | $\color{blue} \text{Text}$ |
| Cyan | &lt;code&gt;\color{cyan}&lt;/code&gt; | $\color{cyan} \text{Text}$ |
| Magenta | &lt;code&gt;\color{magenta}&lt;/code&gt; | $\color{magenta} \text{Text}$ |
| Yellow | &lt;code&gt;\color{yellow}&lt;/code&gt; | $\color{yellow} \text{Text}$ |
| Orange | &lt;code&gt;\color{orange}&lt;/code&gt; | $\color{orange} \text{Text}$ |
| Purple | &lt;code&gt;\color{purple}&lt;/code&gt; | $\color{purple} \text{Text}$ |
| Teal | &lt;code&gt;\color{teal}&lt;/code&gt; | $\color{teal} \text{Text}$ |
| Lime | &lt;code&gt;\color{lime}&lt;/code&gt; | $\color{lime} \text{Text}$ |
| Pink | &lt;code&gt;\color{pink}&lt;/code&gt; | $\color{pink} \text{Text}$ |
| Gray | &lt;code&gt;\color{gray}&lt;/code&gt; | $\color{gray} \text{Text}$ |
| Silver | &lt;code&gt;\color{silver}&lt;/code&gt; | $\color{silver} \text{Text}$ |
| Maroon | &lt;code&gt;\color{maroon}&lt;/code&gt; | $\color{maroon} \text{Text}$ |
| Olive | &lt;code&gt;\color{olive}&lt;/code&gt; | $\color{olive} \text{Text}$ |
| Navy | &lt;code&gt;\color{navy}&lt;/code&gt; | $\color{navy} \text{Text}$ |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>证明自共轭算子的剩余谱必然为空集</title><link>https://kylaan.cn/blog/spectrum</link><guid isPermaLink="true">https://kylaan.cn/blog/spectrum</guid><description>自共轭算子的剩余谱必然为空集，他的谱全部由点谱和连续谱组成。</description><pubDate>Tue, 30 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;问题&lt;/h2&gt;
&lt;p&gt;证明在 Hilbert 空间 $H$ 中，自共轭算子 $T$ ($T=T^*$) 的剩余谱 $\sigma_r(T)$ 为空集&lt;/p&gt;
&lt;h2&gt;Step1 引理1：&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;对于 Hilbert 空间中的任何有界线性算子 $A$，其值域的交补等于其共轭算子的零空间，即：
$$R(A)^\perp = \text{ker}(A^*)$$&lt;br&gt;
&lt;strong&gt;证明：&lt;/strong&gt;
$A: H_1 \to H_2$ 是有界线性算子，$y \in H_2$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;任取$y \in R(A)^\perp$ ：$\langle Ax, y \rangle = 0$ 对所有 $x \in H_1$ 成立。&lt;/li&gt;
&lt;li&gt;Hilbert 共轭算子: $\langle Ax, y \rangle = \langle x, A^*y \rangle$，上述等式等价于： $\langle x, A^*y \rangle = 0$ 对所有 $x \in H_1$ 成立。&lt;/li&gt;
&lt;li&gt;则向量 $A^*y$ 与空间中的每一个向量 $x$ 都正交，那么这个向量本身必须是零向量。
即：$A^*y = 0$。&lt;/li&gt;
&lt;li&gt;根据零空间的定义：
$A^&lt;em&gt;y = 0$ 意味着 $y$ 属于 $A^&lt;/em&gt;$ 的零空间。
即：$y \in \text{ker}(A^&lt;em&gt;)$。
以上每一步都是充分必要的（$\iff$），所以 $R(A)^\perp = \text{ker}(A^&lt;/em&gt;)$，证毕。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Step2 引理2：&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;自共轭算子的谱必为实数：若 $T = T^*$，则其谱集 $\sigma(T) \subset \mathbb{R}$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;证明简述&lt;/strong&gt;：对于任何 $x \in H$，$\langle Tx, x \rangle = \langle x, Tx \rangle = \overline{\langle Tx, x \rangle}$，说明内积 $\langle Tx, x \rangle$ 总是实数。
&lt;ul&gt;
&lt;li&gt;若 $\lambda = \alpha + i\beta$ ($\beta \neq 0$)，可以证明 $|(\lambda I - T)x| \ge |\beta||x|$。这说明 $\lambda I - T$ 是下有界的，从而推导出 $\lambda$ 必然在预解集 $\rho(T)$ 中。&lt;/li&gt;
&lt;li&gt;因此，自共轭算子的谱点 $\lambda$ 必然满足 $\lambda = \bar{\lambda}$。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step3 反证：&lt;/h2&gt;
&lt;p&gt;假设存在某个 $\lambda \in \sigma_r(T)$。根据定义，$\lambda$ 必须满足以下两个条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;条件 (a)&lt;/strong&gt;：$\lambda I - T$ 是单射，即 $\text{ker}(\lambda I - T) = {0}$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;条件 (b)&lt;/strong&gt;：值域不稠密，即其闭包 $\overline{R(\lambda I - T)} \neq H$。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;根据条件 (b)，因为值域的闭包不等于全空间 $H$，由正交分解定理可知，必存在非零向量 $y \perp R(\lambda I - T)$，即 $R(\lambda I - T)^\perp \neq {0}$。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;利用引理1，令 $A = \lambda I - T$：$$R(\lambda I - T)^\perp = \text{ker}((\lambda I - T)^*)$$&lt;/li&gt;
&lt;li&gt;计算共轭算子：由于 $(\lambda I - T)^* = \bar{\lambda} I - T^&lt;em&gt;$，且已知 $\lambda$ 是实数 ($\bar{\lambda} = \lambda$) 以及 $T$ 是自共轭的 ($T^&lt;/em&gt; = T$)，我们得到：$$(\lambda I - T)^* = \lambda I - T$$&lt;/li&gt;
&lt;li&gt;因此，上面的等式变为：$$R(\lambda I - T)^\perp = \text{ker}(\lambda I - T)$$&lt;/li&gt;
&lt;li&gt;由于我们已经推导出 $R(\lambda I - T)^\perp \neq {0}$，所以必然有：$$\text{ker}(\lambda I - T) \neq {0}$$&lt;/li&gt;
&lt;li&gt;这意味着方程 $(\lambda I - T)x = 0$ 存在非零解。根据课本定义，这意味着 $\lambda$ 属于&lt;strong&gt;点谱&lt;/strong&gt; $\sigma_p(T)$。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际上此时已经推出矛盾了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$\lambda\in \sigma_{r}(T)$的同时$\lambda\in \sigma_{p}(T)$，但是两个谱是不交的&lt;/li&gt;
&lt;li&gt;$\text{ker}(\lambda I - T) \neq {0}$但$\lambda I - T$ 是单射，即 $\text{ker}(\lambda I - T) = {0}$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从而一定不存在上述 $\lambda$，证毕。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>腾讯文档自动填表脚本开发与部署记录</title><link>https://kylaan.cn/blog/auto-submit/work</link><guid isPermaLink="true">https://kylaan.cn/blog/auto-submit/work</guid><description>从环境搭建、报错排查到最终代码优化的所有关键步骤</description><pubDate>Wed, 10 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. 项目目标&lt;/h2&gt;
&lt;p&gt;在 Linux 服务器（CentOS + 宝塔面板）上，利用 Python + Selenium 实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;每天定时自动打开腾讯文档收集表。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动登录&lt;/strong&gt;（只需扫码一次，后续自动维持登录状态）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动填写&lt;/strong&gt;指定内容（单选、文本等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动提交&lt;/strong&gt;并处理“二次确认”弹窗。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;2. 环境搭建与依赖解决&lt;/h2&gt;
&lt;h3&gt;2.1 基础环境&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OS&lt;/strong&gt;: CentOS (宝塔面板)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language&lt;/strong&gt;: Python 3.x&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Library&lt;/strong&gt;: Selenium&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 遇到的问题 &amp;#x26; 解决方案&lt;/h3&gt;
&lt;h4&gt;问题一：无法下载 ChromeDriver (网络问题)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;现象&lt;/strong&gt;：使用 &lt;code&gt;webdriver-manager&lt;/code&gt; 自动安装时报错 &lt;code&gt;ConnectionResetError&lt;/code&gt;，因为国内服务器无法连接 Google API。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;查看 Chrome 版本：&lt;code&gt;google-chrome --version&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;从国内淘宝镜像源手动下载对应版本的驱动：
&lt;code&gt;https://npmmirror.com/mirrors/chrome-for-testing/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;手动解压并移动到 &lt;code&gt;/usr/bin/chromedriver&lt;/code&gt;，赋予 &lt;code&gt;chmod +x&lt;/code&gt; 权限。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;问题二：Chrome 启动即崩溃 (内存不足/环境限制)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;现象&lt;/strong&gt;：脚本报错 &lt;code&gt;Chrome instance exited&lt;/code&gt; 或无任何报错直接断开，无法生成截图。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原因&lt;/strong&gt;：Linux 无头模式下 &lt;code&gt;/dev/shm&lt;/code&gt;（共享内存）过小，且服务器物理内存不足。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;增加虚拟内存 (Swap)&lt;/strong&gt;：通过宝塔“Linux工具箱”添加 2GB~4GB Swap。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化启动参数&lt;/strong&gt;：
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;options.add_argument(&quot;--disable-dev-shm-usage&quot;) # 使用硬盘代替共享内存
options.add_argument(&quot;--no-sandbox&quot;) #以此绕过沙盒限制
options.add_argument(&quot;--headless=new&quot;) # 使用新版无头模式
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;问题三：残留进程导致卡死&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;现象&lt;/strong&gt;：多次调试后，提示 &lt;code&gt;SessionNotCreatedException&lt;/code&gt;，因为旧的 Chrome 僵尸进程占用了资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决&lt;/strong&gt;：在脚本开头加入“暴力清理”逻辑：
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;os.system(&quot;pkill -9 chrome&quot;)
os.system(&quot;pkill -9 chromedriver&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;3. 核心逻辑演进&lt;/h2&gt;
&lt;p&gt;为了解决 &lt;strong&gt;“需要登录”&lt;/strong&gt; 和 &lt;strong&gt;“每日自动运行”&lt;/strong&gt; 的矛盾，我们将脚本拆分为两个独立文件。&lt;/p&gt;
&lt;h3&gt;3.1 登录脚本 (&lt;code&gt;login.py&lt;/code&gt;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：人工运行一次。打开网页 -&gt; 点击登录 -&gt; 截图二维码 -&gt; 等待用户扫码 -&gt; 保存 Cookie 到本地目录。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;难点攻克&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定位登录按钮&lt;/strong&gt;：最初使用文字匹配失败（因中英文环境差异），最终通过分析 HTML 源码，锁定了唯一 ID &lt;code&gt;header-login-btn&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多步弹窗处理&lt;/strong&gt;：实现了 &lt;code&gt;点击右上角 -&gt; 点击中间&quot;立即登录&quot; -&gt; 点击&quot;同意协议&quot; -&gt; 截图二维码&lt;/code&gt; 的完整链条。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.2 填表脚本 (&lt;code&gt;submit.py&lt;/code&gt;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：定时任务运行。读取已保存的 Cookie -&gt; 填表 -&gt; 提交 -&gt; 确认。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;难点攻克&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;选项无法选中&lt;/strong&gt;：最初只点击了文字，但腾讯文档的 React 框架未识别点击。
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;修正&lt;/em&gt;：改为定位 &lt;code&gt;role=&quot;radio&quot;&lt;/code&gt; 的父容器，并优先点击内部的小圆圈元素。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;双重验证&lt;/em&gt;：点击后检查 &lt;code&gt;aria-checked=&quot;true&quot;&lt;/code&gt; 属性，未选中则重试。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提交确认弹窗失效&lt;/strong&gt;：脚本找不到“Confirm”按钮。
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;原因&lt;/em&gt;：界面语言变成了英文（Confirm），脚本在找中文（确定）。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;修正&lt;/em&gt;：通过源码找到确认按钮的唯一 CSS 类名 &lt;code&gt;button.dui-modal-footer-ok&lt;/code&gt;，无视语言差异，精准点击。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;4. 最终代码&lt;/h2&gt;
&lt;h3&gt;文件结构&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/www/wwwroot/python_txwd/login.py&lt;/code&gt; (登录专用)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/www/wwwroot/python_txwd/submit.py&lt;/code&gt; (填表专用)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/www/wwwroot/python_txwd/chrome_user_data/&lt;/code&gt; (存放登录凭证的文件夹)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;脚本 A: 登录 (&lt;code&gt;login.py&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;(仅需运行一次，用于生成 Cookie)&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# -*- coding: utf-8 -*-
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 配置区
USER_DATA_DIR = &quot;/www/wwwroot/python_txwd/chrome_user_data&quot;
FORM_URL = &quot;https://docs.qq.com/form/page/DVGNMRU9WSHFNSUZQ&quot; # 你的表单地址

def login_task():
    print(&quot;=== 启动登录脚本 ===&quot;)
    chrome_options = Options()
    chrome_options.add_argument(&quot;--headless=new&quot;) 
    chrome_options.add_argument(&quot;--no-sandbox&quot;)
    chrome_options.add_argument(&quot;--disable-dev-shm-usage&quot;)
    chrome_options.add_argument(&quot;--lang=zh-CN&quot;) 
    chrome_options.add_argument(f&quot;--user-data-dir={USER_DATA_DIR}&quot;)
    chrome_options.binary_location = &quot;/usr/bin/google-chrome&quot;
    chrome_options.add_argument(&quot;--window-size=1920,1080&quot;)

    service = Service(&quot;/usr/bin/chromedriver&quot;)
    driver = webdriver.Chrome(service=service, options=chrome_options)
    
    try:
        driver.get(FORM_URL)
        wait = WebDriverWait(driver, 20)
        
        # 1. 点击右上角登录 (ID定位)
        print(&quot;寻找登录按钮...&quot;)
        login_btn = wait.until(EC.element_to_be_clickable((By.ID, &quot;header-login-btn&quot;)))
        driver.execute_script(&quot;arguments[0].click();&quot;, login_btn)

        # 2. 点击中间的“立即登录” (兼容中英文)
        print(&quot;点击弹窗登录...&quot;)
        login_now = wait.until(EC.element_to_be_clickable((By.XPATH, &quot;//button[contains(., &apos;立即登录&apos;)] | //button[contains(., &apos;Log in now&apos;)]&quot;)))
        driver.execute_script(&quot;arguments[0].click();&quot;, login_now)

        # 3. 处理协议 (如果有)
        try:
            agree = WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH, &quot;//button[contains(., &apos;同意&apos;)] | //button[contains(., &apos;Agree&apos;)]&quot;)))
            driver.execute_script(&quot;arguments[0].click();&quot;, agree)
        except:
            pass

        # 4. 截图二维码
        time.sleep(5)
        driver.save_screenshot(&quot;login_qrcode.png&quot;)
        print(&quot;✅ 二维码已生成: login_qrcode.png，请去宝塔扫码！&quot;)

        # 5. 等待登录成功
        for i in range(120):
            if i % 5 == 0: print(f&quot;等待扫码... {i}s&quot;)
            try:
                # 如果登录按钮消失，说明登录成功
                if not driver.find_element(By.ID, &quot;header-login-btn&quot;).is_displayed():
                    print(&quot;🎉 登录成功！&quot;)
                    break
            except:
                print(&quot;🎉 登录成功！&quot;)
                break
            time.sleep(1)

    finally:
        driver.quit()

if __name__ == &quot;__main__&quot;:
    login_task()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;脚本 B: 每日自动填表 (&lt;code&gt;submit.py&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;(适配每日归寝统计)&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# -*- coding: utf-8 -*-
import time
import os
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# === 配置 ===
USER_DATA_DIR = &quot;/www/wwwroot/python_txwd/chrome_user_data&quot;
FORM_URL = &quot;https://docs.qq.com/form/page/DVGNMRU9WSHFNSUZQ&quot; # 归寝统计表单
# ============

def clean_zombie_processes():
    os.system(&quot;pkill -9 chrome&quot;)
    os.system(&quot;pkill -9 google-chrome&quot;)
    os.system(&quot;pkill -9 chromedriver&quot;)
    time.sleep(2)

def ensure_select(driver, text):
    &quot;&quot;&quot;根据文字选中单选框，带状态校验&quot;&quot;&quot;
    print(f&quot;   -&gt; 选择: &apos;{text}&apos;&quot;)
    try:
        # 寻找包含特定文字的单选框容器
        xpath = f&quot;//div[@role=&apos;radio&apos; and .//*[text()=&apos;{text}&apos;]]&quot;
        option = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, xpath)))
        
        # 如果未选中则点击
        if option.get_attribute(&quot;aria-checked&quot;) != &quot;true&quot;:
            try:
                # 尝试点圆圈
                circle = option.find_element(By.CSS_SELECTOR, &quot;[class*=&apos;choice-option-normal&apos;]&quot;)
                driver.execute_script(&quot;arguments[0].click();&quot;, circle)
            except:
                driver.execute_script(&quot;arguments[0].click();&quot;, option)
            time.sleep(0.5)
        
        # 校验
        if option.get_attribute(&quot;aria-checked&quot;) == &quot;true&quot;:
            print(f&quot;      ✅ 成功选中&quot;)
            return True
        else:
            print(f&quot;      ⚠️ 补刀点击...&quot;)
            option.click()
            return True
    except Exception as e:
        print(f&quot;      ❌ 选择失败: {e}&quot;)
        return False

def submit_task():
    clean_zombie_processes()
    print(&quot;=== 开始填表任务 ===&quot;)
    
    chrome_options = Options()
    chrome_options.add_argument(&quot;--headless=new&quot;) 
    chrome_options.add_argument(&quot;--no-sandbox&quot;)
    chrome_options.add_argument(&quot;--disable-gpu&quot;)
    chrome_options.add_argument(&quot;--disable-dev-shm-usage&quot;)
    chrome_options.add_argument(&quot;--lang=zh-CN&quot;) 
    chrome_options.add_argument(f&quot;--user-data-dir={USER_DATA_DIR}&quot;)
    chrome_options.binary_location = &quot;/usr/bin/google-chrome&quot;
    chrome_options.add_argument(&quot;--window-size=1920,1080&quot;)

    service = Service(&quot;/usr/bin/chromedriver&quot;)
    driver = webdriver.Chrome(service=service, options=chrome_options)
    
    try:
        driver.get(FORM_URL)
        time.sleep(5)

        # 检查登录
        try:
            if driver.find_element(By.ID, &quot;header-login-btn&quot;).is_displayed():
                print(&quot;❌ 未登录，请先运行 login.py&quot;)
                return
        except:
            pass

        # --- 填表逻辑 ---
        ensure_select(driver, &quot;6&quot;)        # 第1题
        # 第2题跳过
        ensure_select(driver, &quot;全部归寝&quot;)  # 第3题
        
        time.sleep(1)

        # --- 提交 ---
        print(&quot;   -&gt; 点击提交&quot;)
        submit_btn = WebDriverWait(driver, 5).until(
            EC.element_to_be_clickable((By.XPATH, &quot;//button[contains(text(), &apos;Submit&apos;) or contains(text(), &apos;提交&apos;)]&quot;))
        )
        driver.execute_script(&quot;arguments[0].scrollIntoView(true);&quot;, submit_btn)
        driver.execute_script(&quot;arguments[0].click();&quot;, submit_btn)

        # --- 确认弹窗 (使用类名定位) ---
        print(&quot;   -&gt; 等待确认弹窗&quot;)
        try:
            confirm_btn = WebDriverWait(driver, 5).until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, &quot;button.dui-modal-footer-ok&quot;))
            )
            driver.execute_script(&quot;arguments[0].click();&quot;, confirm_btn)
            print(&quot;      ✅ 确认按钮已点击&quot;)
        except:
            print(&quot;      ⚠️ 未检测到弹窗(可能已成功)&quot;)

        time.sleep(3)
        driver.save_screenshot(&quot;final_result.png&quot;)
        print(&quot;✅ 任务完成，查看 final_result.png&quot;)

    except Exception as e:
        print(f&quot;❌ 错误: {e}&quot;)
    finally:
        driver.quit()

if __name__ == &quot;__main__&quot;:
    submit_task()
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;5. 定时任务设置&lt;/h2&gt;
&lt;p&gt;在宝塔面板的【计划任务】中添加 Shell 脚本：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;周期&lt;/strong&gt;：每天 23:00&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;脚本&lt;/strong&gt;：
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;/usr/bin/python3 /www/wwwroot/python_txwd/submit.py &gt;&gt; /www/wwwroot/python_txwd/log.txt 2&gt;&amp;#x26;1
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;维护说明&lt;/strong&gt;：如果某天发现日志提示“未登录”，或者截图显示登录按钮，只需手动运行一次 &lt;code&gt;python login.py&lt;/code&gt; 重新扫码即可，无需修改代码。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>2025高百赛后记</title><link>https://kylaan.cn/blog/gaobai/gaobai</link><guid isPermaLink="true">https://kylaan.cn/blog/gaobai/gaobai</guid><description>2025年高百总决赛，一段难忘的经历与感悟。</description><pubDate>Mon, 08 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;我可能不算是个喜欢写长文的人，但是很幸运也很荣幸能在高百十周年写下这些文字，记录一下这段难忘的经历。毕竟，这次比赛是我的第一届高百决赛，也有可能是最后一届代表山大的高百。&lt;/p&gt;
&lt;p&gt;大一时候，我看到了北航跑团的高百总决赛推文，了解到了原来国内也有一群人在为学校而奔跑，原来也是能有这样一个舞台能让我们这些普通大学生去拼搏，去挑战。后来在和各个学校的朋友交流中了解到了更多关于高百的故事，从最初对箱根驿传的模仿，到逐渐发展成如今独具特色的全国高校间顶级接力赛事。那时候就想着，等我有机会了，一定要代表学校闯入这个高校跑者的最高殿堂。&lt;/p&gt;
&lt;p&gt;后来我阴差阳错成了马协负责人，在管理跑团的过程中认识了全国各地许许多多的高校跑友，看到了大家热爱如一的热情，从他们身上学习到了许多组织经验。那时候开始，心中升起了一个想法：我能不能带领山大闯进全国总决赛？是不是我也有机会追随《强风吹拂》里灰二的脚步？我不知道我是否有这样的魄力和能力可以带领整个队伍一致向前，只是在跑团师兄师姐的鼓励下尽力而为，锤炼自己的同时争取打出自己在团队内的公信力。24年校运会有幸拿了长跑项目双冠，虽然如今回望当时的水平不算很高，但是我能感觉到或许我真的能够把大家聚在一起，冲向更高的舞台。&lt;/p&gt;
&lt;p&gt;24年济南站，是我们第一次参赛，赛前队员不够临时叫了两位体育学院练400的社体专业的同学才凑齐队伍。没有专业的训练指导，没有学校的经费支持，也没有完善的组织架构，队服是找了个公共模板印上校名（后来扬州半马跟人撞衫了🤣），就这样选择了家门口的济南站感受了一把高百。最终以分站第八的成绩收场，带着一千元奖金回家，还算是个不错的结果。赛后，我和队员讲，给我一年时间，给你们一个全新的跑团。我有信心在明年的赛场上创造不一样的结果。&lt;/p&gt;
&lt;p&gt;那之后，我和济南站认识的几位高校跑者创办了山东省大学生长跑协会，在喵扎特、阿迪达斯等品牌的支持下了解到了全国各地的大学生跑者，包括一些之前只能在社媒上看到的强校和一些高水平同学，对科学训练、团队管理有了更深的认识。我记得是24年认识吉大雪豹的队长之后，通过了解他们的训练模式和成长历程，坚定了我创建正式的长跑队的信念：山大一校三地一共八个校区，即使是济南校区也分隔很远，跑步社团还分成了三四个。虽说大家都互相认识，但于情于理上总归会有隔阂。我们亟需一个统一的组织架构带动大家，可能不需要强制队员像球队一样统一训练，至少让我们的成员有归属感，在外参赛时能打出自己是山东大学长跑队的队员，能在山东大学长跑队找到组织，能为了进入A队而有提升自己的初始动力。靠着这样的信念，我去寻求了体育学院范书记的支持（感谢书记和学院），最终在今年年初挂牌成立。&lt;/p&gt;
&lt;p&gt;诚然，初创的队伍还有许多不完善的地方，训练的系统性、队员的选拔和发掘等等无数的问题需要解决。但是我相信我不是在做无用功，中学时老师曾经送过我一句话：“种下一棵树最好的时间是十年前，其次是现在”。外有重大、清华、北航等老牌队伍的底蕴，内有山大车协20载的传承，他们的经验都是对我的启发，我愿意在2025年做那个栽树人，就好像高百盗总说的，下一个十年之后当我们回望这次经历时会有完全不一样的感觉。再过十年、二十年当我们回望大学期间的宝贵经历时，我希望我会从容的说，我做到了。而今年，我们首次代表山东大学在高百十周年这一节点闯进总决赛，虽然比赛的历程有些许波折，但我始终坚信，一切都是最好的结果（略逊北大的成绩其实也还不赖😁）。&lt;/p&gt;
&lt;p&gt;这次比赛真的给了我太多，每个队伍都有自己那令人动容的成长经历，群里的分享和交流传递出整个大学生跑者群体无比的韧劲，年轻是我们最大的资本也是我们最硬的底气，可能我们在多年以后不一定会坚持跑步训练，但是大家传递出的信念感正是我们在大学的青春时光为了“情怀与追赶”所交出的答卷。我不知道再过十年、百年，高百能不能成为箱根一样的现象级高校赛事，但是我认为，我们这群人来了、做过、走了，这就已经足够。&lt;/p&gt;
&lt;p&gt;有一种青春 叫并肩奔跑&lt;/p&gt;
&lt;p&gt;有一种力量 叫永不言败&lt;/p&gt;
&lt;p&gt;有一段记忆 叫刻骨铭心&lt;/p&gt;
&lt;p&gt;有一种热爱 叫 高百接力赛！&lt;/p&gt;
&lt;p&gt;风华正茂，热爱如一，成功收官！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;before.jpg&quot; alt=&quot;赛前&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;gogogo.jpg&quot; alt=&quot;我们的定妆照&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;poster.png&quot; alt=&quot;海报&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/gate.Ckj-YIZD.jpg"/><enclosure url="/_astro/gate.Ckj-YIZD.jpg"/></item><item><title>Markdown测试</title><link>https://kylaan.cn/blog/mdtest/mdtest</link><guid isPermaLink="true">https://kylaan.cn/blog/mdtest/mdtest</guid><description>Markdown测试</description><pubDate>Fri, 28 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;::alert
你好
::&lt;/p&gt;
&lt;p&gt;::alert{type=&quot;question&quot;}
默认插槽的 &lt;a href=&quot;#alert&quot;&gt;超链接&lt;/a&gt; &lt;strong&gt;粗体&lt;/strong&gt; &lt;code&gt;Inline code&lt;/code&gt;
::&lt;/p&gt;
&lt;p&gt;::alert{type=&quot;info&quot; title=&quot;自定义标题&quot;}
默认插槽的 &lt;a href=&quot;#alert&quot;&gt;超链接&lt;/a&gt; &lt;strong&gt;粗体&lt;/strong&gt; &lt;code&gt;Inline code&lt;/code&gt;
::&lt;/p&gt;
&lt;p&gt;::alert{type=&quot;warning&quot; card}
#title
卡片风格 标题插槽的 &lt;a href=&quot;#alert&quot;&gt;超链接&lt;/a&gt; &lt;strong&gt;粗体&lt;/strong&gt; &lt;code&gt;Inline code&lt;/code&gt;
#default
默认插槽的 &lt;a href=&quot;#alert&quot;&gt;超链接&lt;/a&gt; &lt;strong&gt;粗体&lt;/strong&gt; &lt;code&gt;Inline code&lt;/code&gt;
::&lt;/p&gt;
&lt;p&gt;::alert{type=&quot;error&quot; flat}
#title
扁平风格 标题插槽的 &lt;a href=&quot;#alert&quot;&gt;超链接&lt;/a&gt; &lt;strong&gt;粗体&lt;/strong&gt; &lt;code&gt;Inline code&lt;/code&gt;
#default
默认插槽的 &lt;a href=&quot;#alert&quot;&gt;超链接&lt;/a&gt; &lt;strong&gt;粗体&lt;/strong&gt; &lt;code&gt;Inline code&lt;/code&gt;
::&lt;/p&gt;
&lt;p&gt;:alert{icon=&quot;ph:files-duotone&quot; color=&quot;var(--c-accent)&quot; title=&quot;仅标题，并且自定义图标和颜色&quot;}&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>泛函分析复习整理</title><link>https://kylaan.cn/blog/fa-review/fa</link><guid isPermaLink="true">https://kylaan.cn/blog/fa-review/fa</guid><description>简单整理泛函分析中的基本概念</description><pubDate>Sun, 16 Nov 2025 15:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;空间汇总&lt;/h1&gt;
&lt;pre&gt;&lt;code class=&quot;language-mermaid&quot;&gt;  graph TD
      A[线性空间 / 向量空间] 
      
      B[距离空间]

      C[距离线性空间]

      D[完备的距离空间]

      E[赋范线性空间]

      F[Banach空间 / 完备的赋范线性空间]

      G[内积空间]

      H[Hilbert空间 / 完备的内积空间]

      A --&gt; |距离函数对加法数乘连续|C
      B --&gt; |柯西序列都收敛|D
      A --&gt; |定义范数|E
      E --&gt; |完备化|F
      D --&gt; |赋范|F
      G --&gt; |完备化|H
        
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;基本证明&lt;/h1&gt;
&lt;h2&gt;距离&lt;/h2&gt;
&lt;p&gt;证明三个条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;非负性：&lt;/strong&gt;$d(x,y) \ge 0,d(x,y)=0 $当且仅当$x=y$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对称性：&lt;/strong&gt;$d(x,y)=d(y,x)$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;三角不等式&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;开集&lt;/h3&gt;
&lt;p&gt;任意 $ x\in O$ 都有 $B(x,r)\subset O$&lt;/p&gt;
&lt;h3&gt;闭集&lt;/h3&gt;
&lt;p&gt;所有极限点都在内部&lt;/p&gt;
&lt;h3&gt;连续函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;开集映为开集&lt;/li&gt;
&lt;li&gt;$T: X\to X$满足 $\mathrm{Lipschitz}$ 条件&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;完备&lt;/h3&gt;
&lt;p&gt;距离空间里的Cauchy序列都收敛&lt;/p&gt;
&lt;h3&gt;列紧&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;M中任何序列都有收敛子序列&lt;/li&gt;
&lt;li&gt;闭的列紧集叫&lt;strong&gt;自列紧集&lt;/strong&gt;，就是&lt;strong&gt;紧集&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;紧集&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;闭的列紧集&lt;/li&gt;
&lt;li&gt;有界闭集&lt;/li&gt;
&lt;li&gt;任何开覆盖存在有限子覆盖&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;范数/赋范线性空间&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;非负性：&lt;/strong&gt; $ | x | \ge 0\ , |x|=0 $ 当且仅当 $x=0 $&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线性性：&lt;/strong&gt; $|\alpha x|=|\alpha|\ |x|$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;三角不等式：&lt;/strong&gt; $|x+y|\le | x|+|y|$&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;线性算子&lt;/h3&gt;
&lt;h4&gt;定义&lt;/h4&gt;
&lt;p&gt;$T(\alpha x+\beta y)=\alpha Tx+\beta Ty$&lt;/p&gt;
&lt;h4&gt;有界线性算子&lt;/h4&gt;
&lt;p&gt;$|Tx| \le C\ |x|$&lt;/p&gt;
&lt;h4&gt;算子范数&lt;/h4&gt;
&lt;p&gt;$\displaystyle |T|=\sup_{|x|=1}|Tx|=\sup\frac{|Tx|}{|x|}$&lt;/p&gt;
&lt;h3&gt;内积空间&lt;/h3&gt;
&lt;h4&gt;内积验证&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;非负：&lt;/strong&gt;$\langle x,x \rangle \ge 0$等于0当且仅当$x=0$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;共轭线性：&lt;/strong&gt; $ \langle \alpha x+\beta y , z \rangle $ 线性，
$\langle x, \alpha y \rangle = \overline{\alpha}\langle x,y \rangle $&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;共轭对称：&lt;/strong&gt; $ \langle x,y \rangle = \overline{\langle y,x \rangle}$&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;验证Hilbert空间&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;完备的内积空间：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;验证内积：平行四边形法则（对角线平方和等于两倍临边平方和）&lt;/li&gt;
&lt;li&gt;验证完备：内积范数下Cauchy序列都收敛&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;或者同构于一个已知的内积空间&lt;/p&gt;
&lt;h3&gt;正规正交基&lt;/h3&gt;
&lt;p&gt;有多种方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;验证 $S$ 是正规正交集，而且没有比他更大的（更高维的）&lt;/li&gt;
&lt;li&gt;与 $S$ 的每个元正交的只有零元&lt;/li&gt;
&lt;li&gt;$S\subset H $ 在 $H$ 中完备（ $S$ 张成的子空间稠密）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Parseval 公式&lt;/h3&gt;
&lt;p&gt;可分的 $\mathrm{Hilbert}$ 空间 $H$ 有可数基 $ { x_n}&lt;em&gt;{n=1}^\infty$ ，则对任何 $x \in X$:
$$x = \sum&lt;/em&gt;{n=1}^\infty \langle x,x_n \rangle x_n$$
$$ |x|^2 =\sum_{n=1}^\infty |\langle x,x_n \rangle |^2 $$&lt;/p&gt;
&lt;h3&gt;Frecht-Reisz 表示定理&lt;/h3&gt;
&lt;p&gt;$f\in H^*$
定义在 $H$ 上的有界线性泛函 $f$ 的作用唯一对应一个内积，从而唯一对应一个 $H$ 中的元素&lt;br&gt;
而且是保范的 $|f|=|z_f|$&lt;/p&gt;
&lt;h3&gt;Laz-Milgram 定理&lt;/h3&gt;
&lt;p&gt;把 $\mathrm{F.R.}$ 定理的内积推广成一个共轭双线性泛函 $B(f,g)$ 满足条件：
$$
\begin{cases}
\text{有界：}B(f,g) \le C|f| \ |g| \
\text{强制：}B(f,f) \ge \alpha |f|^2
\end{cases}
$$
那么有界线性泛函和B是一一对应的 $ f(x)=B(x,y_0) \quad i.e.\ f\mapsto y_0$ ，此时保范变成了：
$$
|y_0|\le \dfrac{1}{\alpha}|f|
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这时强制性保证了B对应的线性算子是有界可逆的 $ \Big( B(x,y)=\langle Ax,y \rangle ：A\leftrightarrow A^{-1}\Big )$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;共轭双线性泛函的一个性质&lt;/h3&gt;
&lt;p&gt;有界共轭双线性泛函 $\varphi(x,y)$ 唯一对应到 $H$ 上的一个线性算子 $A$ :$$ \varphi(x,y)=\langle Ax,y\rangle $$&lt;/p&gt;
&lt;h3&gt;伴随算子&lt;/h3&gt;
&lt;p&gt;连续线性泛函 $f$ 和有界线性算子 $T$ :
$$f(x)   \overset{\mathrm{def}}{=}  \langle Tx,y\rangle  \overset{\mathrm{F.R.}}{=}   \langle x,\hat{y}\rangle\overset{\mathrm{def}}{=}\langle x,T^&lt;em&gt;y\rangle$$
$$\hat{y}\Longleftrightarrow f\Longleftrightarrow T \Longleftrightarrow T^&lt;/em&gt;$$&lt;/p&gt;
&lt;h2&gt;常见的例子&lt;/h2&gt;
&lt;p&gt;$L^2[a,b]$ 空间&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;范数：$\displaystyle |x|_2 = \Big(\int_a^b |x(t)|^2 , \mathrm{d}t \Big)^{1/2}$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内积：$\displaystyle \langle x,y\rangle = \int_a^b x(t)\ \overline{y(t)}\ \mathrm{d}t $&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$\mathcal{l}^2$ 空间（复的我们表示为&lt;code&gt;\usepackage{boondox-cal}（解决小写花体） \mathscr{l}^2 &lt;/code&gt;）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;范数：$\displaystyle |x|&lt;em&gt;2=\Big (\sum&lt;/em&gt;{n=1}^\infty |\langle x,x_n \rangle|^2 \Big)^{1/2} $&lt;/li&gt;
&lt;li&gt;内积：&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="/_astro/FA.t8TLwPrd.png"/><enclosure url="/_astro/FA.t8TLwPrd.png"/></item><item><title>常见空间的联系</title><link>https://kylaan.cn/blog/space/space</link><guid isPermaLink="true">https://kylaan.cn/blog/space/space</guid><description>泛函分析中提到的空间</description><pubDate>Sun, 16 Nov 2025 09:55:00 GMT</pubDate><content:encoded>&lt;p&gt;泛函分析课程整理&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-mermaid&quot;&gt;  graph TD
      A[线性空间 / 向量空间] 
      
      B[距离空间]

      C[距离线性空间]

      D[完备的距离空间]

      E[赋范线性空间]

      F[Banach空间 / 完备的赋范线性空间]

      G[内积空间]

      H[Hilbert空间 / 完备的内积空间]

      A --&gt; |距离函数对加法数乘连续|C
      A --&gt; |定义范数|E
      G --&gt; |内积范数|E
      B --&gt; |柯西序列都收敛|D
      E --&gt; |完备化|F
      D --&gt; |赋范|F
      G --&gt; |完备化|H
        
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/image.BIu0CkZQ.png"/><enclosure url="/_astro/image.BIu0CkZQ.png"/></item><item><title>Markdown 语法支持</title><link>https://kylaan.cn/blog/markdown-zh</link><guid isPermaLink="true">https://kylaan.cn/blog/markdown-zh</guid><description>Markdown 是一种轻量级的「标记语言」。</description><pubDate>Sat, 15 Nov 2025 06:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;基本语法&lt;/h2&gt;
&lt;p&gt;Markdown 是一种轻量级且易于使用的语法，用于为您的写作设计风格。&lt;/p&gt;
&lt;h3&gt;标题&lt;/h3&gt;
&lt;p&gt;文章内容较多时，可以用标题分段：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;# 标题 1

## 标题 2

## 大标题

### 小标题
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;标题预览会打乱文章的结构，所以在此不展示。&lt;/p&gt;
&lt;h3&gt;粗斜体&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;_斜体文本_

**粗体文本**

**_粗斜体文本_**
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;&lt;em&gt;斜体文本&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;粗体文本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;粗斜体文本&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;链接&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;文字链接 [链接名称](http://链接网址)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;文字链接 &lt;a href=&quot;http://%E9%93%BE%E6%8E%A5%E7%BD%91%E5%9D%80&quot;&gt;链接名称&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;行内代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;这是一条 `单行代码`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;这是一条 &lt;code&gt;行内代码&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;代码块&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;```js
// calculate fibonacci
function fibonacci(n) {
  if (n &amp;#x3C;= 1) return 1
  return fibonacci(n - 1) + fibonacci(n - 2)
}
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// calculate fibonacci
function fibonacci(n) {
  if (n &amp;#x3C;= 1) return 1
  return fibonacci(n - 1) + fibonacci(n - 2)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当前使用 shiki 作为代码高亮插件，支持的语言请参考 &lt;a href=&quot;https://shiki.matsu.io/languages.html&quot;&gt;shiki / languages&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;行内公式&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;这是一条行内公式 $e^{i\pi} + 1 = 0$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;这是一条行内公式 $e^{i\pi} + 1 = 0$&lt;/p&gt;
&lt;h3&gt;公式块&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;$$
\hat{f}(\xi) = \int_{-\infty}^{\infty} f(x) e^{-2\pi i x \xi} \, dx
$$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;$$
\hat{f}(\xi) = \int_{-\infty}^{\infty} f(x) e^{-2\pi i x \xi} , dx
$$&lt;/p&gt;
&lt;p&gt;当前使用 KaTeX 作为数学公式插件，支持的语法请参考 &lt;a href=&quot;https://katex.org/docs/supported.html&quot;&gt;KaTeX Supported Functions&lt;/a&gt;。&lt;/p&gt;
&lt;h4&gt;图片&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;![CWorld](https://cravatar.cn/avatar/1ffe42aa45a6b1444a786b1f32dfa8aa?s=200)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cravatar.cn/avatar/1ffe42aa45a6b1444a786b1f32dfa8aa?s=200&quot; alt=&quot;CWorld&quot;&gt;&lt;/p&gt;
&lt;h4&gt;删除线&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;~~删除线~~
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;~~删除线~~&lt;/p&gt;
&lt;h3&gt;列表&lt;/h3&gt;
&lt;p&gt;普通无序列表&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;- 1
- 2
- 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1&lt;/li&gt;
&lt;li&gt;2&lt;/li&gt;
&lt;li&gt;3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;普通有序列表&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;1. GPT-4
2. Claude Opus
3. LLaMa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GPT-4&lt;/li&gt;
&lt;li&gt;Claude Opus&lt;/li&gt;
&lt;li&gt;LLaMa&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;列表里可以继续嵌套语法&lt;/p&gt;
&lt;h3&gt;引用&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;&gt; 枪响，雷鸣，剑起。繁花血景。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;枪响，雷鸣，剑起。繁花血景。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;引用里也可以继续嵌套语法。&lt;/p&gt;
&lt;h3&gt;换行&lt;/h3&gt;
&lt;p&gt;markdown 分段落是需要空一行的。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;如果不空行
就会在一段

第一段

第二段
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;如果不空行
就会在一段&lt;/p&gt;
&lt;p&gt;第一段&lt;/p&gt;
&lt;p&gt;第二段&lt;/p&gt;
&lt;h3&gt;分隔符&lt;/h3&gt;
&lt;p&gt;如果你有写分割线的习惯，可以新起一行输入三个减号&lt;code&gt;---&lt;/code&gt; 或者星号 &lt;code&gt;***&lt;/code&gt;。当前后都有段落时，请空出一行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;高级技巧&lt;/h2&gt;
&lt;h3&gt;行内 HTML 元素&lt;/h3&gt;
&lt;p&gt;目前只支持部分段内 HTML 元素效果，包括 &lt;code&gt;&amp;#x3C;kdb&gt; &amp;#x3C;b&gt; &amp;#x3C;i&gt; &amp;#x3C;em&gt; &amp;#x3C;sup&gt; &amp;#x3C;sub&gt; &amp;#x3C;br&gt;&lt;/code&gt; ，如&lt;/p&gt;
&lt;h4&gt;键位显示&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;使用 &amp;#x3C;kbd&gt;Ctrl&amp;#x3C;/kbd&gt; + &amp;#x3C;kbd&gt;Alt&amp;#x3C;/kbd&gt; + &amp;#x3C;kbd&gt;Del&amp;#x3C;/kbd&gt; 重启电脑
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;使用 Ctrl + Alt + Del 重启电脑&lt;/p&gt;
&lt;h4&gt;粗斜体&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;&amp;#x3C;b&gt; Markdown 在此处同样适用，如 _加粗_ &amp;#x3C;/b&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt; Markdown 在此处同样适用，如 &lt;em&gt;加粗&lt;/em&gt; &lt;/p&gt;
&lt;h3&gt;其他 HTML 写法&lt;/h3&gt;
&lt;h4&gt;折叠块&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;&amp;#x3C;details&gt;&amp;#x3C;summary&gt;点击展开&amp;#x3C;/summary&gt;它被隐藏了&amp;#x3C;/details&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;h3&gt;表格&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;| 表头1 | 表头2 |
| ----- | ----- |
| 内容1 | 内容2 |
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;| 表头1 | 表头2 |
| ----- | ----- |
| 内容1 | 内容2 |&lt;/p&gt;
&lt;h3&gt;注释&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;在引用的地方使用 [^注释] 来添加注释。

然后在文档的结尾，添加注释的内容（会默认于文章结尾渲染之）。

[^注释]: 这里是注释的内容
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;在引用的地方使用 &lt;a href=&quot;%E8%BF%99%E9%87%8C%E6%98%AF%E6%B3%A8%E9%87%8A%E7%9A%84%E5%86%85%E5%AE%B9&quot;&gt;^注释&lt;/a&gt; 来添加注释。&lt;/p&gt;
&lt;p&gt;然后在文档的结尾，添加注释的内容（会默认于文章结尾渲染之）。&lt;/p&gt;
&lt;h3&gt;To-Do 列表&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;- [ ] 未完成的任务
- [x] 已完成的任务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ] 未完成的任务&lt;/li&gt;
&lt;li&gt;[x] 已完成的任务&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;符号转义&lt;/h3&gt;
&lt;p&gt;如果你的描述中需要用到 markdown 的符号，比如 _ # * 等，但又不想它被转义，这时候可以在这些符号前加反斜杠，如 &lt;code&gt;\_&lt;/code&gt; &lt;code&gt;\#&lt;/code&gt; &lt;code&gt;\*&lt;/code&gt; 进行避免。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;\_不想这里的文本变斜体\_

\*\*不想这里的文本被加粗\*\*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;p&gt;_不想这里的文本变斜体_&lt;/p&gt;
&lt;p&gt;**不想这里的文本被加粗**&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;内嵌 Astro 组件&lt;/h2&gt;
&lt;p&gt;See &lt;a href=&quot;/docs/integrations/components&quot;&gt;User Components&lt;/a&gt; and &lt;a href=&quot;/docs/integrations/advanced&quot;&gt;Advanced Components&lt;/a&gt; for details.&lt;/p&gt;</content:encoded><h:img src="/_astro/thumbnail.HAXFr_hw.jpg"/><enclosure url="/_astro/thumbnail.HAXFr_hw.jpg"/></item><item><title>鞅理论与随机游走问题</title><link>https://kylaan.cn/blog/random-walk</link><guid isPermaLink="true">https://kylaan.cn/blog/random-walk</guid><description>使用随机过程课程中的鞅理论研究一维随机游走</description><pubDate>Fri, 14 Nov 2025 18:55:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;本报告整理了利用鞅理论和停时方法解决“一维随机游动”问题的解题过程要点，并初步探究了二维随机游动的相关问题。给出了包括有吸收壁的简单对称随机游走、单边游走与常返性、有偏的随机游走等三种典型情形的详细分析，讨论了吸收概率、期望停止时间等关键量的计算方法。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关键字：鞅，可选停止定理，吸收概率，期望停时，离散调和函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h1&gt;一维随机游走&lt;/h1&gt;
&lt;h2&gt;Case I：有吸收壁的简单对称随机游走&lt;/h2&gt;
&lt;p&gt;设 $X_1, X_2, \dots$ 独立同分布（i.i.d.），且 $P(X_i=1)=P(X_i=-1)=1/2$，随机游走过程定义为 $S_0=0,; S_n=\sum_{i=1}^n X_i$，$\mathcal{F}_n=\sigma(X_1,\dots,X_n)$。&lt;/p&gt;
&lt;p&gt;定义停时 $T=\inf{n:; S_n=-a \text{ 或 } S_n=b}$，其中 $a,b&gt;0$。&lt;/p&gt;
&lt;h3&gt;Step 1-3：计算吸收结果分布 $P(S_T=-a)、P(S_T=b)$&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;构造鞅&lt;/strong&gt;： 过程 $S_n$ 是一个鞅，因为 $E[S_n|\mathcal{F}&lt;em&gt;{n-1}] = S&lt;/em&gt;{n-1} + E[X_n] = S_{n-1}$。
根据 Doob 可选停止定理，对于停时 $T$，过程 $S_{n \wedge T}$ 也是一个鞅，因此 $E[S_{n \wedge T}] = E[S_0] = 0$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;控制收敛（DCT）&lt;/strong&gt;： 我们的目标是证明 $E[S_T]=0$。
由于 $S_n$ 在停时 $T$ 之前始终位于 $(-a, b)$ 区间内，所以 $|S_{n \wedge T}| \le \max(a,b)$，即 $S_{n \wedge T}$ 是一致有界的。
当 $n \to \infty$ 时，$S_{n \wedge T} \to S_T$。根据控制收敛定理，我们可以交换期望和极限：
$$ E[S_T] = E[\lim_{n \to \infty} S_{n \wedge T}] = \lim_{n \to \infty} E[S_{n \wedge T}] = 0 $$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;吸收概率&lt;/strong&gt;：在停时 $T$ 刻，$S_T$ 的取值只能是 $-a$ 或 $b$。设 $P_a = P(S_T=-a)$ 和 $P_b = P(S_T=b)$。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$$
\begin{cases}
-aP_a + bP_b = 0,\
P_a + P_b = 1
\end{cases}\&lt;/p&gt;
&lt;p&gt;\Rightarrow
\begin{cases}
P(S_T=-a)=\dfrac{b}{a+b},\
P(S_T=b)=\dfrac{a}{a+b}
\end{cases}
$$&lt;/p&gt;
&lt;h3&gt;Step 4：计算期望停止时间 $E[T]$&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;新的鞅&lt;/strong&gt;：构造一个新过程 $M_n = S_n^2 - n$。这是一个鞅，因为：
$$
\begin{align*}
E[M_n|\mathcal{F}&lt;em&gt;{n-1}] &amp;#x26;= E[S_n^2 - n | \mathcal{F}&lt;/em&gt;{n-1}] \
&amp;#x26;= E[(S_{n-1}+X_n)^2 - n | \mathcal{F}&lt;em&gt;{n-1}] \
&amp;#x26;= E[S&lt;/em&gt;{n-1}^2 + 2S_{n-1}X_n + X_n^2 - n | \mathcal{F}&lt;em&gt;{n-1}] \
&amp;#x26;= S&lt;/em&gt;{n-1}^2 + 2S_{n-1}E[X_n] + E[X_n^2] - n \
&amp;#x26;= S_{n-1}^2 + 0 + 1 - n = (S_{n-1}^2 - (n-1)) = M_{n-1}
\end{align*}
$$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;应用可选停止与收敛定理（OST）&lt;/strong&gt;：对鞅 $M_n$ 应用可选停止定理，有 $E[M_{n \wedge T}] = E[M_0] = 0$，即 $E[S_{n \wedge T}^2] = E[n \wedge T]$。
当 $n \to \infty$ 时，由于 $S_{n \wedge T}^2$ 有界，由 DCT 可得 $E[S_{n \wedge T}^2] \to E[S_T^2]$。
同时，由单调收敛定理 (MCT) 可得 $E[n \wedge T] \to E[T]$。
因此，我们得到 $E[S_T^2] = E[T]$，这即是 $Wald&apos;s Identity$ 的一个特例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;求解 $E[T]$&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$$
\begin{align*}
E[S_T^2] &amp;#x26;= (-a)^2 P(S_T=-a) + b^2 P(S_T=b) \
&amp;#x26;= a^2 \frac{b}{a+b} + b^2 \frac{a}{a+b} \
&amp;#x26;= \frac{ab(a+b)}{a+b} = ab
\end{align*}
$$
所以，期望停止时间为 $E[T] = ab$&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Case II：单边停时与常返性&lt;/h2&gt;
&lt;p&gt;考虑一维对称随机游走是否会回到任意整数点（常返性）。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;设停时 $U = \inf{n: S_n = -a}$，其中 $a&gt;0$。我们想计算 $P(U &amp;#x3C; \infty)$&lt;/li&gt;
&lt;li&gt;我们可以借助双边吸收壁的结果。设另一个吸收壁在 $b$ 处，停时为 $H_b = \inf{n: S_n = b}$。总停时为 $\tau = U \wedge H_b$&lt;/li&gt;
&lt;li&gt;从 Case I 的结果可知，粒子被 $b$ 吸收的概率为 $P(S_\tau = b) = \frac{a}{a+b}$&lt;/li&gt;
&lt;li&gt;那么，不被 $b$ 吸收（即被 $-a$ 吸收）的概率为 $P(S_\tau = -a) = P(U &amp;#x3C; H_b) = \frac{b}{a+b}$&lt;/li&gt;
&lt;li&gt;$b \to \infty$，则 $P(U &amp;#x3C; \infty) = \lim_{b \to \infty} \frac{b}{a+b} = 1$
**结论：**一维对称随机游走是常返的，它终将到达任何一个整数点。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;尝试求解 $P(U=k)$&lt;/h3&gt;
&lt;h4&gt;方法一：组合计数&lt;/h4&gt;
&lt;p&gt;这种方法实际上就是在解决&lt;strong&gt;伯特兰选票问题(Bertrand&apos;s Ballot Problem,1887)&lt;/strong&gt;.
我们的目标其实就是求解
$$P(T_{-a}=k|S_k=-a)=\dfrac{P(T_{-a}=k \cap S_k=-a)}{P(S_k=-a)}=\dfrac{P(T_{-a}=k)}{P(S_k=-a)}=p_0$$
即 &lt;strong&gt;“在已知第k步在-a被吸收的条件下，这是首次到达的概率”&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;定理&lt;/strong&gt;：若 $k$ 步中向右 $m$ 步，则 $P(T_{-a}=k)=\dfrac{|a|}{k}\cdot\dfrac{\binom{k}{m}}{2^k}$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面介绍一下Bertrand选票问题中 $p_0 $的证明思路:
在一场选举中候选人A得到了p张选票，而候选人B得到了q张选票(p&gt;q)，那么在整个点票过程中A的票数都&lt;strong&gt;严格大于&lt;/strong&gt;B的概率是多少。这个问题的答案是$$\dfrac{p-q}{p+q}$$&lt;/p&gt;
&lt;p&gt;我们将此概率问题转化为一个二维格路计数 (Lattice Path Counting) 问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A每得一票，路径向上走一步 $(0,1)$。&lt;/li&gt;
&lt;li&gt;B每得一票，路径向右走一步 $(1,0)$。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;计票过程可以看作一条从原点 $(0,0)$ 出发，经过 $p+q$ 步到达终点 $(q, p)$ 的路径。因为A获得 $p$ 票（向上），B获得 $q$ 票（向右），所以总的路径数量为：
$$N_{\text{total}} = \binom{p+q}{p}$$&lt;/p&gt;
&lt;p&gt;“A的票数始终严格领先于B”这一条件，在格路模型中意味着路径上的任意一点 $(x_k, y_k)$ 均满足 $y_k &gt; x_k$（除了起点 $(0,0)$）。换言之，路径不能触碰或穿过对角线 $y=x$。
下面寻找不合规路径（“坏”路径）的策略。一条“坏”路径是指至少触碰过一次直线 $y=x$ 的路径。所有“坏”路径可以分为两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;$B_1$ 类&lt;/strong&gt;: 第一步向右（即第一张票给B）的所有路径。这样的路径在第一步就到达了 $y=x$下方，终点在上方，由连续性则必然穿过直线，因此所有此类路径都是“坏”路径。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$B_2$ 类&lt;/strong&gt;: 第一步向上（即第一张票给A），但在后续过程中至少触碰过一次直线 $y=x$ 的路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;./figure.png&quot; alt=&quot;反射原理示意图，蓝色实线 (B2 类) 与红色虚线 (B1 类) 关于 y = x 对
称变换&quot;&gt;&lt;/p&gt;
&lt;p&gt;从图中可以看出，对于第一步向上的情况，在路径首次触碰 $y=x$ 的点 $P$ 处，将触碰前的路径段关于 $y=x$ 进行反射变换，得到一条以第一步向右开始的路径（即 $B_1$ 类路径）。这种映射是双射，因此
$|B_1|=|B_2|=\binom{p+q-1}{p}$
最终的合法路径数为：
$$N_{\text{valid}} = N_{\text{total}} - |B_1| - |B_2| = \binom{p+q}{p} - 2\binom{p+q-1}{p} = \frac{p-q}{p+q} \binom{p+q}{p}$$
因此，A始终领先B的概率为：
$$ P(\text{A始终领先B}) = \frac{N_{\text{valid}}}{N_{\text{total}}} = \frac{p-q}{p+q} $$
问题中的 $p_0$ 即为 $\displaystyle \frac{a}{k}$，从而得出上述定理。&lt;/p&gt;
&lt;h4&gt;方法二：概率母函数&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;构造指数鞅&lt;/strong&gt;：寻找一个参数 $\rho \in (0,1)$，使得 $Z_n = \rho^{S_n} r^n$ 是一个鞅。
$$
\begin{align*}
E[Z_n|\mathcal{F}&lt;em&gt;{n-1}] &amp;#x26;= E[\rho^{S&lt;/em&gt;{n-1}+X_n} r^n | \mathcal{F}&lt;em&gt;{n-1}] \
&amp;#x26;= \rho^{S&lt;/em&gt;{n-1}} r^n E[\rho^{X_n}] \
&amp;#x26;= Z_{n-1} r E[\rho^{X_n}] = Z_{n-1} r \left( \frac{1}{2}\rho^1 + \frac{1}{2}\rho^{-1} \right)
\end{align*}
$$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;要使其为鞅，需要 $r \left( \frac{\rho+\rho^{-1}}{2} \right) = 1$，即 $r = \frac{2}{\rho+\rho^{-1}}$。&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;求解参数&lt;/strong&gt;：解方程求出 $\rho = \frac{1-\sqrt{1-r^2}}{r}$ 取较小的根（$0&amp;#x3C;\rho&amp;#x3C;1$）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;应用可选停止定理&lt;/strong&gt; ：考虑停时 $U = \inf{n: S_n=a}$。$Z_n$ 是有界鞅（$0 \le S_{n \wedge U} \le a$），因此 $E[Z_U] = E[Z_0] = \rho^{S_0} r^0 = 1$。
$$ E[Z_U] = E[\rho^{S_U} r^U] = E[\rho^a r^U] = \rho^a E[r^U] = 1 $$
因此，停时 $U$ 的概率母函数为：
$$ E[r^U] = \rho^{-a} = \left( \frac{1-\sqrt{1-r^2}}{r} \right)^{-a} $$
通过展开此母函数，可以得到 $P(U=k)$ 的具体分布。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Case III：有偏随机游走（一般情况）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;设 $P(X_i=1)=p, P(X_i=-1)=q=1-p$，且 $p \neq q$。&lt;/li&gt;
&lt;li&gt;此时 $E[X_i] = p-q \neq 0$，所以 $S_n$ 不再是鞅。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 1-2: 构造鞅并计算 $E[T]$&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;构造补偿过程&lt;/strong&gt;: 定义 $M_n = S_n - n(p-q)$。这是一个鞅，因为：
$$
\begin{align*}
E[M_n|\mathcal{F}&lt;em&gt;{n-1}] &amp;#x26;= E[S&lt;/em&gt;{n-1}+X_n - n(p-q) | \mathcal{F}&lt;em&gt;{n-1}] \
&amp;#x26;= S&lt;/em&gt;{n-1} + E[X_n] - n(p-q) \
&amp;#x26;= S_{n-1} + (p-q) - n(p-q) \
&amp;#x26;= S_{n-1} - (n-1)(p-q) = M_{n-1}
\end{align*}
$$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;应用可选停止定理&lt;/strong&gt;: 对停时 $T = \inf{n: S_n=-a \text{ or } S_n=b}$，应用可选停止定理于鞅 $M_n$。
与 Case I 类似，可证明 $E[M_T] = E[M_0] = 0$。
$$E[S_T - T(p-q)] = 0 \implies E[T] = \frac{E[S_T]}{p-q}  $$&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Step 3: 计算吸收概率&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;构造指数鞅&lt;/strong&gt;：定义 $U_n = \left(\frac{q}{p}\right)^{S_n}$。这是一个鞅，因为：
$$
\begin{align*}
E[U_n|\mathcal{F}&lt;em&gt;{n-1}] &amp;#x26;= E\left[\left(\frac{q}{p}\right)^{S&lt;/em&gt;{n-1}+X_n} \Big| \mathcal{F}&lt;em&gt;{n-1}\right] \
&amp;#x26;= \left(\frac{q}{p}\right)^{S&lt;/em&gt;{n-1}} E\left[\left(\frac{q}{p}\right)^{X_n}\right] \
&amp;#x26;= U_{n-1} \left( p \cdot \frac{q}{p} + q \cdot \frac{p}{q} \right) = U_{n-1} (q+p) = U_{n-1}
\end{align*}
$$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;应用可选停止与收敛定理&lt;/strong&gt;：对停时 $T$ 应用可选停止定理于有界鞅 $U_n$。
$$ E[U_T] = E[U_0] = \left(\frac{q}{p}\right)^{S_0} = 1 $$
展开 $E[U_T]$:
$$ E\left[\left(\frac{q}{p}\right)^{S_T}\right] = \left(\frac{q}{p}\right)^{-a} P(S_T=-a) + \left(\frac{q}{p}\right)^{b} P(S_T=b) = 1 $$
结合 $P(S_T=-a) + P(S_T=b) = 1$，解得：
$$ P(S_T=-a) = \frac{\left(\frac{q}{p}\right)^b - 1}{\left(\frac{q}{p}\right)^b - \left(\frac{q}{p}\right)^{-a}}, \quad P(S_T=b) = \frac{1 - \left(\frac{q}{p}\right)^{-a}}{\left(\frac{q}{p}\right)^b - \left(\frac{q}{p}\right)^{-a}} $$&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Step 4-5: 求解 $E[T]$ 和 $E[S_T]$&lt;/h3&gt;
&lt;p&gt;将吸收概率代入 $E[S_T] = (-a)P(S_T=-a) + b P(S_T=b)$，然后可以得到 $E[T]$:
$$ E[T] = \frac{1}{p-q} \left( b \frac{1 - (\frac{q}{p})^{-a}}{(\frac{q}{p})^b - (\frac{q}{p})^{-a}} - a \frac{(\frac{q}{p})^b - 1}{(\frac{q}{p})^b - (\frac{q}{p})^{-a}} \right)$$&lt;/p&gt;
&lt;p&gt;单边吸收（例如 $p&gt;q$ 时，游走趋向于 $+\infty$）的情况，可以通过令 $b \to \infty$ 来分析。&lt;/p&gt;
&lt;h1&gt;二维随机游走&lt;/h1&gt;
&lt;h2&gt;二维简单对称随机游走&lt;/h2&gt;
&lt;p&gt;我们考虑一个在二维整数格点 $\mathbb{Z}^2$ 上的随机游走 $P_n = (X_n, Y_n)$，从原点 $P_0 = (0,0)$ 出发。每一步，粒子等概率 (1/4) 地移动到其四个最近邻点之一，即 $(\pm 1, 0)$ 或 $(0, \pm 1)$。
令 $\mathcal{F}_n = \sigma(P_1, \dots, P_n)$ 为自然流（包含到时刻n为止的所有路径信息）。&lt;/p&gt;
&lt;h2&gt;鞅方法及其应用&lt;/h2&gt;
&lt;h3&gt;构造二维随机游走的鞅&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;坐标过程&lt;/strong&gt;：我们定义X和Y坐标的变化$X_n$ 和 $Y_n$ 各自都是关于 $\mathcal{F}_n$ 的鞅。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;证明：$E[X_{n+1}|\mathcal{F}&lt;em&gt;n] = E[X_n + \xi&lt;/em&gt;{n+1}|\mathcal{F}&lt;em&gt;n] = X_n + E[\xi&lt;/em&gt;{n+1}] = X_n + 0 = X_n$。$Y_n$ 同理。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;补偿的距离平方过程&lt;/strong&gt;： $$M_n = |P_n|^2 - n = X_n^2 + Y_n^2 - n$$ 是一个鞅。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;证明：$E[|P_{n+1}|^2 - (n+1)|\mathcal{F}&lt;em&gt;n] = E[(X_n+\xi&lt;/em&gt;{n+1})^2 + (Y_n+\eta_{n+1})^2 - (n+1)|\mathcal{F}&lt;em&gt;n] = X_n^2+Y_n^2 + E[\xi&lt;/em&gt;{n+1}^2+\eta_{n+1}^2] - (n+1) = |P_n|^2 + 1 - (n+1) = |P_n|^2 - n = M_n$。这里利用了 $E[\xi_{n+1}^2+\eta_{n+1}^2]=1$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;基于离散调和函数的鞅 (最通用)&lt;/strong&gt;：若函数 $f: \mathbb{Z}^2 \to \mathbb{R}$ 是离散调和的，即满足 $$f(P) = \frac{1}{4}\sum_{P&apos; \sim P} f(P&apos;)$$ （P&apos;是P的邻居），则 $M_n = f(P_n)$ 是一个鞅。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;证明：$E[M_{n+1}|\mathcal{F}&lt;em&gt;n] = E[f(P&lt;/em&gt;{n+1})|P_n] = \frac{1}{4}\sum_{P&apos; \sim P_n} f(P&apos;) = f(P_n) = M_n$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;常见的离散调和函数包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$f(x,y) = c$ (常数)&lt;/li&gt;
&lt;li&gt;$f(x,y) = x$ (导出 $X_n$ 是鞅)&lt;/li&gt;
&lt;li&gt;$f(x,y) = y$ (导出 $Y_n$ 是鞅)&lt;/li&gt;
&lt;li&gt;$f(x,y) = x^2 - y^2$ (导出 $X_n^2 - Y_n^2$ 是鞅)&lt;/li&gt;
&lt;li&gt;$f(x,y) = xy$ (导出 $X_n Y_n$ 是鞅)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;应用一：求解撞击概率&lt;/h3&gt;
&lt;p&gt;设 $D$ 是 $\mathbb{Z}^2$ 上的一个有限区域，边界 $\partial D = \partial D_A \cup \partial D_B$。粒子从 $P_0 \in D$ 出发，停时 $T = \inf{n : P_n \in \partial D}$。求粒子在撞击 $\partial D_B$ 之前先撞击 $\partial D_A$ 的概率 $h(P_0)$。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;寻找调和函数&lt;/strong&gt;: 寻找一个离散调和函数 $h(P)$，满足边界条件：$h(P) = 1$ 对所有 $P \in \partial D_A$，$h(P) = 0$ 对所有 $P \in \partial D_B$。这是一个离散狄利克雷问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;构造鞅&lt;/strong&gt;: 令 $M_n = h(P_n)$。由于 $h$ 是调和的，$M_n$ 是一个鞅。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;应用可选停止定理 (OST)&lt;/strong&gt;: 停时 $T$ 几乎必然有限，且过程 $M_{n \wedge T} = h(P_{n \wedge T})$ 的值被限制在 $[0, 1]$ 内，是有界的。因此 OST 适用，$E[M_T] = E[M_0]$。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;求解概率&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$E[M_0] = h(P_0)$。&lt;/li&gt;
&lt;li&gt;$E[M_T] = E[h(P_T)] = 1 \cdot P(\text{停在}\partial D_A) + 0 \cdot P(\text{停在}\partial D_B) = P(\text{停在}\partial D_A)$。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;联立得到 $P(\text{停在}\partial D_A) = h(P_0)$。
&lt;strong&gt;结论&lt;/strong&gt;: 撞击概率等于满足相应边界条件的离散调和函数在起始点的值。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;应用二：求解期望停止时间 $E[T]$&lt;/h3&gt;
&lt;p&gt;问题设定同上，求解 $E[T|P_0]$。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;鞅求解策略&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;构造鞅&lt;/strong&gt;：使用鞅 $M_n = |P_n|^2 - n$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;建立方程&lt;/strong&gt;：
$$
\begin{cases}
E[M_0] = |P_0|^2 - 0 = |P_0|^2\
E[M_T] = E[|P_T|^2 - T] = E[|P_T|^2] - E[T]
\end{cases}
$$
联立得到 $E[|P_T|^2] - E[T] = |P_0|^2$。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;: 求解期望时间 $E[T]$ 的问题被转化为了求解粒子在边界上的停止位置的{\bf 期望平方距离} $E[|P_T|^2]$。这需要先知道粒子撞击边界各点的概率分布（即先解决撞击概率问题）。&lt;/p&gt;
&lt;h2&gt;与物理类比：离散泊松方程&lt;/h2&gt;
&lt;p&gt;求解期望停止时间 $k(P) = E[T|P_0=P]$ 也可以通过马尔可夫链方法，建立并求解一个差分方程：
$$ k(P) = 1 + \frac{1}{4} \sum_{P&apos; \sim P} k(P&apos;) $$
整理后得到离散泊松方程：
$$ \Delta k(P) = -1 $$
其中 $\Delta k(P) = (\frac{1}{4} \sum_{P&apos; \sim P} k(P&apos;)) - k(P)$ 是离散拉普拉斯算子。边界条件为 $k(P) = 0$ 对所有 $P \in \partial D$。&lt;/p&gt;
&lt;p&gt;这与静电学中求解有均匀电荷分布区域的电势问题相对应，而撞击概率问题则对应于求解无源区域电势的拉普拉斯方程。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;附录&lt;/h1&gt;
&lt;h2&gt;手写推导扫描&lt;/h2&gt;
&lt;p&gt;原稿位于文末供参考：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./1.jpg&quot; alt=&quot;步骤 1：问题建模与基本设定&quot;&gt;
&lt;img src=&quot;./2.jpg&quot; alt=&quot;步骤 2：关键量的递推与差分&quot;&gt;
&lt;img src=&quot;./3.jpg&quot; alt=&quot;步骤 3：边界条件与通解&quot;&gt;
&lt;img src=&quot;./4.jpg&quot; alt=&quot;步骤 4：常数确定与概率结论&quot;&gt;
&lt;img src=&quot;./5.jpg&quot; alt=&quot;步骤 5：特殊情形讨论&quot;&gt;&lt;/p&gt;
&lt;h2&gt;常用符号表&lt;/h2&gt;
&lt;p&gt;| 符号 | 含义 |
| --- | --- |
| $S_n$ | 时刻 $n$ 的游走位置 |
| $X_i$ | 第 $i$ 步增量，取 $\pm 1$ |
| $\mathcal{F}_n$ | 自然信息流 |
| $T,U,H_b$ | 不同停时 |
| $p,q$ | 向右/向左概率，$p+q=1$ |
| $M_n$ | 构造的鞅过程 |
| $E[\cdot],P(\cdot)$ | 期望与概率 |&lt;/p&gt;</content:encoded><h:img src="/_astro/image.BYw_-RxF.png"/><enclosure url="/_astro/image.BYw_-RxF.png"/></item><item><title>签名组件演示</title><link>https://kylaan.cn/blog/signature-demo</link><guid isPermaLink="true">https://kylaan.cn/blog/signature-demo</guid><description>展示如何在博客中使用动态签名组件</description><pubDate>Fri, 14 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Signature from &apos;@/components/Signature.astro&apos;
import { Aside } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h2&gt;签名组件演示&lt;/h2&gt;
&lt;p&gt;这篇文章展示了如何在博客中使用动态 SVG 签名组件。&lt;/p&gt;
&lt;h3&gt;功能特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;✨ 流畅的手写动画效果&lt;/li&gt;
&lt;li&gt;🔄 支持循环播放或单次触发&lt;/li&gt;
&lt;li&gt;🎨 自动适配深色模式&lt;/li&gt;
&lt;li&gt;⚡ 性能优化，支持无障碍访问&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;默认循环模式&lt;/h3&gt;
&lt;p&gt;下面是一个循环播放的签名动画：&lt;/p&gt;
&lt;h3&gt;进入视口触发模式&lt;/h3&gt;
&lt;p&gt;滚动到下方，当签名进入视野时会自动播放一次：&lt;/p&gt;
&lt;h3&gt;使用示例&lt;/h3&gt;
&lt;p&gt;在 MDX 文件中导入并使用：&lt;/p&gt;
&lt;p&gt;```jsx
import Signature from &apos;@/components/Signature.astro&apos;&lt;/p&gt;
&lt;p&gt;// 默认循环模式
&lt;/p&gt;
&lt;p&gt;// 进入视口触发一次
&lt;/p&gt;
&lt;p&gt;// 自定义样式

```&lt;/p&gt;
&lt;h3&gt;自定义你的签名&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;使用 Figma、Illustrator 或在线工具创建 SVG&lt;/li&gt;
&lt;li&gt;确保使用 &lt;strong&gt;描边(stroke)&lt;/strong&gt; 而不是填充&lt;/li&gt;
&lt;li&gt;将文件保存为 `src/assets/signature.svg`&lt;/li&gt;
&lt;li&gt;在组件中使用！&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;文章结尾签名&lt;/h3&gt;
&lt;p&gt;通常我们会在文章末尾添加签名：&lt;/p&gt;
&lt;p&gt;感谢阅读这篇演示文章！如果你觉得这个组件有用，欢迎在自己的博客中使用。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;详细使用指南请查看项目根目录的 &lt;code&gt;SIGNATURE_GUIDE.md&lt;/code&gt; 文件。&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="https://images.unsplash.com/photo-1455390582262-044cdead277a?w=1200"/><enclosure url="https://images.unsplash.com/photo-1455390582262-044cdead277a?w=1200"/></item><item><title>欢迎来到我的博客</title><link>https://kylaan.cn/blog/welcome-pinned</link><guid isPermaLink="true">https://kylaan.cn/blog/welcome-pinned</guid><description>这是一篇置顶文章，介绍了博客的主要内容和特色功能。</description><pubDate>Fri, 14 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Aside } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h2&gt;欢迎！👋&lt;/h2&gt;
&lt;p&gt;欢迎来到我的个人博客！这里是我分享学习笔记、技术心得和生活感悟的地方。&lt;/p&gt;
&lt;h3&gt;博客特色&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;📝 &lt;strong&gt;技术文章&lt;/strong&gt;：分享编程技巧和学习经验&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;精美设计&lt;/strong&gt;：基于 Astro Pure 主题打造&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;互动评论&lt;/strong&gt;：支持 Waline 评论系统&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;快速搜索&lt;/strong&gt;：集成 Pagefind 全文搜索&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;关于作者&lt;/h3&gt;
&lt;p&gt;我是一名热爱编程的学生，目前就读于山东大学。喜欢探索新技术，分享学习心得。&lt;/p&gt;
&lt;p&gt;欢迎通过评论或社交媒体与我交流！&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;💡 &lt;strong&gt;提示&lt;/strong&gt;：在文章的 frontmatter 中添加 &lt;code&gt;pinned: true&lt;/code&gt; 即可将文章设为置顶。&lt;/p&gt;</content:encoded><h:img src="https://images.unsplash.com/photo-1499750310107-5fef28a66643?w=1200"/><enclosure url="https://images.unsplash.com/photo-1499750310107-5fef28a66643?w=1200"/></item><item><title>签名组件演示</title><link>https://kylaan.cn/blog/signature-demo/signature-demo</link><guid isPermaLink="true">https://kylaan.cn/blog/signature-demo/signature-demo</guid><description>展示如何在博客中使用动态签名组件</description><pubDate>Fri, 14 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Signature from &apos;@/components/Signature.astro&apos;
import { Aside } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h2&gt;签名组件演示&lt;/h2&gt;
&lt;p&gt;这篇文章展示了如何在博客中使用动态 SVG 签名组件。&lt;/p&gt;
&lt;h3&gt;功能特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;✨ 流畅的手写动画效果&lt;/li&gt;
&lt;li&gt;🔄 支持循环播放或单次触发&lt;/li&gt;
&lt;li&gt;🎨 自动适配深色模式&lt;/li&gt;
&lt;li&gt;⚡ 性能优化，支持无障碍访问&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;默认循环模式&lt;/h3&gt;
&lt;p&gt;下面是一个循环播放的签名动画：&lt;/p&gt;
&lt;h3&gt;进入视口触发模式&lt;/h3&gt;
&lt;p&gt;滚动到下方，当签名进入视野时会自动播放一次：&lt;/p&gt;
&lt;h3&gt;使用示例&lt;/h3&gt;
&lt;p&gt;在 MDX 文件中导入并使用：&lt;/p&gt;
&lt;p&gt;```jsx
import Signature from &apos;@/components/Signature.astro&apos;&lt;/p&gt;
&lt;p&gt;// 默认循环模式
&lt;/p&gt;
&lt;p&gt;// 进入视口触发一次
&lt;/p&gt;
&lt;p&gt;// 自定义样式

```&lt;/p&gt;
&lt;h3&gt;自定义你的签名&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;使用 Figma、Illustrator 或在线工具创建 SVG&lt;/li&gt;
&lt;li&gt;确保使用 &lt;strong&gt;描边(stroke)&lt;/strong&gt; 而不是填充&lt;/li&gt;
&lt;li&gt;将文件保存为 `src/assets/signature.svg`&lt;/li&gt;
&lt;li&gt;在组件中使用！&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;文章结尾签名&lt;/h3&gt;
&lt;p&gt;通常我们会在文章末尾添加签名：&lt;/p&gt;
&lt;p&gt;感谢阅读这篇演示文章！如果你觉得这个组件有用，欢迎在自己的博客中使用。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;详细使用指南请查看项目根目录的 &lt;code&gt;SIGNATURE_GUIDE.md&lt;/code&gt; 文件。&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/sig.BiDn2g_V.jpg"/><enclosure url="/_astro/sig.BiDn2g_V.jpg"/></item><item><title>博客搭建指南</title><link>https://kylaan.cn/blog/blog-setup-guide-pinned</link><guid isPermaLink="true">https://kylaan.cn/blog/blog-setup-guide-pinned</guid><description>详细介绍如何使用 Astro Pure 主题搭建自己的个人博客。</description><pubDate>Thu, 13 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;快速开始&lt;/h2&gt;
&lt;p&gt;使用 Astro Pure 主题可以快速搭建一个现代化的个人博客。&lt;/p&gt;
&lt;h3&gt;安装步骤&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;克隆仓库&lt;/li&gt;
&lt;li&gt;安装依赖：&lt;code&gt;bun install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;启动开发服务器：&lt;code&gt;bun dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;访问 &lt;code&gt;http://localhost:4321&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;自定义配置&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;src/site.config.ts&lt;/code&gt; 中修改网站配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;站点标题和描述&lt;/li&gt;
&lt;li&gt;作者信息&lt;/li&gt;
&lt;li&gt;社交链接&lt;/li&gt;
&lt;li&gt;评论系统配置&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;发布文章&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;src/content/blog/&lt;/code&gt; 目录下创建 &lt;code&gt;.md&lt;/code&gt; 或 &lt;code&gt;.mdx&lt;/code&gt; 文件即可发布新文章。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;更多详细信息请查看 &lt;a href=&quot;https://astro-pure.js.org/docs&quot;&gt;官方文档&lt;/a&gt;。&lt;/p&gt;</content:encoded><h:img src="https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=1200"/><enclosure url="https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=1200"/></item><item><title>我的技术栈</title><link>https://kylaan.cn/blog/my-tech-stack-pinned</link><guid isPermaLink="true">https://kylaan.cn/blog/my-tech-stack-pinned</guid><description>分享我目前使用的技术栈和学习路线。</description><pubDate>Wed, 12 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前端技术&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;框架&lt;/strong&gt;：Astro, React, Vue&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语言&lt;/strong&gt;：TypeScript, JavaScript&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;构建工具&lt;/strong&gt;：Vite, Webpack&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;样式&lt;/strong&gt;：UnoCSS, Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;后端技术&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;运行时&lt;/strong&gt;：Node.js, Bun&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;部署&lt;/strong&gt;：Vercel, Cloudflare Pages&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;学习计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;深入学习 TypeScript 高级特性&lt;/li&gt;
&lt;li&gt;掌握服务端渲染（SSR）&lt;/li&gt;
&lt;li&gt;学习数据库设计与优化&lt;/li&gt;
&lt;li&gt;了解容器化部署&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;持续学习，不断进步！🚀&lt;/p&gt;</content:encoded><h:img src="https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=1200"/><enclosure url="https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=1200"/></item><item><title>Tips to improve concentration</title><link>https://kylaan.cn/blog/improve-concentration</link><guid isPermaLink="true">https://kylaan.cn/blog/improve-concentration</guid><description>Mindfulness, cognitive training, and a healthy lifestyle may help sharpen your focus.</description><pubDate>Sat, 10 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Aside } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;p&gt;You&apos;re trying to concentrate, but your mind is wandering or you&apos;re easily distracted. What happened to the laser-sharp focus you once enjoyed? As we age, we tend to have more difficulty filtering out stimuli that are not relevant to the task at hand.&lt;/p&gt;
&lt;h2&gt;What&apos;s fogging up focus?&lt;/h2&gt;
&lt;p&gt;Like a computer that slows with use, the brain accumulates wear and tear that affects processing. This can be caused by a number of physiological stressors such as inflammation, injury to blood vessels (especially if you have high blood pressure), the buildup of abnormal proteins, and naturally occurring brain shrinkage.&lt;/p&gt;
&lt;p&gt;The following factors can also affect your concentration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Underlying conditions.&lt;/strong&gt; Depression or sleep disorders (such as sleep apnea) can undermine your ability to concentrate. So can the effects of vision or hearing loss. You waste precious cognitive resources when you spend too much time trying to make out what&apos;s written on a page or just hear what someone is saying.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Medication side effects.&lt;/strong&gt; Some drugs, especially anticholinergics (such as treatments for incontinence, depression, or allergies), can slow processing speed and your ability to think clearly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Excessive drinking.&lt;/strong&gt; Having too much alcohol impairs thinking and causes interrupted sleep, which affects concentration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Information overload.&lt;/strong&gt; We are bombarded with information from TVs, computers, and messages such as texts or emails. When there&apos;s too much material, it burdens our filtering system and it&apos;s easy to get distracted.&lt;/p&gt;
&lt;h2&gt;Strategies to stay focused&lt;/h2&gt;
&lt;p&gt;To improve attention, consider the following strategies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mindfulness.&lt;/strong&gt; &quot;Mindfulness is about focusing attention on the present moment, and practicing mindfulness has been shown to rewire the brain so that attention is stronger in everyday life,&quot; says Kim Willment, a neuropsychologist with Brigham and Women&apos;s Hospital. She recommends sitting still for a few minutes each day, closing your eyes, and focusing on your breathing as well as the sounds and sensations around you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cognitive training.&lt;/strong&gt; Computerized cognitive training games aim to improve your response times and attention. Evidence that this works has been mixed. &quot;The goal of playing these games is not to get better at them, but to get better in the cognitive activities of everyday life,&quot; Willment says. &quot;But there is evidence that a person&apos;s ability to pay attention can be improved by progressively pushing the person to higher levels of performance. So if you reach a certain level of sustained attention, pushing it to the next level can help improve it, and this may translate to everyday life.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A healthier lifestyle.&lt;/strong&gt; Many aspects of a healthy lifestyle can help attention, starting with sleep and exercise. There is a direct link between exercise and cognitive ability, especially attention. When you exercise, you increase the availability of brain chemicals that promote new brain connections, reduce stress, and improve sleep. And when we sleep, we reduce stress hormones that can be harmful to the brain, and we clear out proteins that injure it.&lt;/p&gt;
&lt;p&gt;Aim for seven to eight hours of sleep each night, and 150 minutes per week of aerobic exercise, such as brisk walking.&lt;/p&gt;
&lt;p&gt;Other healthy steps to improve focus: eat a Mediterranean-style diet, which has been shown to support brain health; treat underlying conditions; and change medications that may be affecting your ability to focus.&lt;/p&gt;
&lt;p&gt;Getting older is out of your control, but healthier living is something you determine, and it may improve concentration.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Article from: &lt;a href=&quot;https://www.health.harvard.edu/mind-and-mood/tips-to-improve-concentration&quot;&gt;Harvard Health Publishing&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="/_astro/thumbnail.1GZ294Dz.jpg"/><enclosure url="/_astro/thumbnail.1GZ294Dz.jpg"/></item><item><title>Using MDX</title><link>https://kylaan.cn/blog/using-mdx</link><guid isPermaLink="true">https://kylaan.cn/blog/using-mdx</guid><description>Learning how to use MDX in Astro</description><pubDate>Sun, 01 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This theme comes with the &lt;a href=&quot;https://docs.astro.build/en/guides/integrations-guide/mdx/&quot;&gt;@astrojs/mdx&lt;/a&gt; integration installed and configured in your &lt;code&gt;astro.config.mjs&lt;/code&gt; config file. If you prefer not to use MDX, you can disable support by removing the integration from your config file.&lt;/p&gt;
&lt;h2&gt;Why MDX?&lt;/h2&gt;
&lt;p&gt;MDX is a special flavor of Markdown that supports embedded JavaScript &amp;#x26; JSX syntax. This unlocks the ability to &lt;a href=&quot;https://docs.astro.build/en/guides/markdown-content/#mdx-features&quot;&gt;mix JavaScript and UI Components into your Markdown content&lt;/a&gt; for things like interactive charts or alerts.&lt;/p&gt;
&lt;p&gt;If you have existing content authored in MDX, this integration will hopefully make migrating to Astro a breeze.&lt;/p&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;p&gt;Here is how you import and use a UI component inside of MDX.&lt;br&gt;
When you open this page in the browser, you should see the clickable button below.&lt;/p&gt;
&lt;p&gt;import { Button } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;p&gt;Click Me&lt;/p&gt;
&lt;h2&gt;More Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mdxjs.com/docs/what-is-mdx&quot;&gt;MDX Syntax Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages&quot;&gt;Astro Usage Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;a href=&quot;https://docs.astro.build/en/reference/directives-reference/#client-directives&quot;&gt;Client Directives&lt;/a&gt; are still required to create interactive components. Otherwise, all components in your MDX will render as static HTML (no JavaScript) by default.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>The Impact of Technology on the Music World</title><link>https://kylaan.cn/blog/music-journey</link><guid isPermaLink="true">https://kylaan.cn/blog/music-journey</guid><description>The evolution of music is a symphony of creativity, rhythm, and technology.</description><pubDate>Sat, 30 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The evolution of music is a symphony of creativity, rhythm, and technology. From the humble beginnings of acoustic instruments to the present-day digital era, the relationship between music and technology has been transformative. In this article, we will explore the historical milestones, digital revolution, and emerging technologies that have shaped the music world. Join us on a journey through the chords of innovation as we discuss how technology has changed music.&lt;/p&gt;
&lt;h2&gt;Historical Perspective&lt;/h2&gt;
&lt;p&gt;The marriage of music and technology dates back centuries, with pivotal moments shaping the industry. The invention of the phonograph by Thomas Edison in the late 19th century marked the first time music could be recorded and replayed. Subsequent milestones, such as the electric guitar and the synthesizer, revolutionized music creation, paving the way for new genres and sounds.&lt;/p&gt;
&lt;p&gt;These technological leaps didn&apos;t merely shape the musical landscape of their time but laid a foundation for the continuous evolution of the intersection between music and technology. As artists embraced these innovations, they unlocked new avenues for creativity, paving the way for diverse sounds and genres that have become integral to the vibrant tapestry of the modern music industry. The historical perspective illuminates the symbiotic relationship between music and technology, highlighting the transformative impact that each innovation has had on the way we create, consume, and experience music.&lt;/p&gt;
&lt;h2&gt;Digital Revolution&lt;/h2&gt;
&lt;p&gt;The digital revolution has been a seismic shift in the music industry, altering how music is consumed, distributed, and produced. The transition from physical formats like CDs and vinyl to digital formats such as MP3s and streaming services has democratized access to music. The ease of streaming has transformed how listeners discover and enjoy music, challenging traditional revenue models while offering unparalleled convenience.&lt;/p&gt;
&lt;h2&gt;Technology in Music Consumption and Distribution&lt;/h2&gt;
&lt;p&gt;Streaming services have become the heartbeat of music consumption, causing a decline in traditional music stores. The accessibility of music online has reshaped distribution channels, impacting both artists and record labels. While it provides exposure to a global audience, it also poses challenges regarding fair compensation for artists. The dynamics of the industry are evolving, reflecting the intricate dance between technology and music.
Music Production and Creation&lt;/p&gt;
&lt;p&gt;The advent of digital audio workstations (DAWs), software instruments, and electronic production techniques has democratized music creation. Artists now have powerful tools at their fingertips, enabling them to experiment with sounds, collaborate remotely, and produce music independently. This technological shift has broken down barriers, allowing for a diverse array of voices to be heard in the ever-expanding realm of music.&lt;/p&gt;</content:encoded><h:img src="/_astro/thumbnail.Cx18cRmB.jpg"/><enclosure url="/_astro/thumbnail.Cx18cRmB.jpg"/></item><item><title>Personalized Customization Guide</title><link>https://kylaan.cn/blog/customize</link><guid isPermaLink="true">https://kylaan.cn/blog/customize</guid><description>astro-theme-pure Personalized Customization Guide</description><pubDate>Sat, 27 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Site Configuration&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cworld1/astro-theme-pure&quot;&gt;astro-theme-pure&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Customizing this theme requires adjusting a significant amount of source code.&lt;/p&gt;
&lt;p&gt;We have made efforts to centralize the configuration options in the &lt;code&gt;src/site.config.ts&lt;/code&gt; file for user convenience and have integrated a variety of common social media/tools icons. If you want to add new icons, you will need to modify the source code yourself.&lt;/p&gt;
&lt;p&gt;You can globally search for the following keywords to find the text that needs to be replaced:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Lorem ipsum&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;astro-theme-pure&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cworld&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, we will introduce each aspect in detail.&lt;/p&gt;
&lt;h3&gt;Configuration Files&lt;/h3&gt;
&lt;p&gt;See &lt;a href=&quot;/docs/setup/configuration&quot;&gt;Configuration Files&lt;/a&gt; for details.&lt;/p&gt;
&lt;h4&gt;Waline Comment System&lt;/h4&gt;
&lt;p&gt;See &lt;a href=&quot;/docs/integrations/comment&quot;&gt;Waline Comment System&lt;/a&gt; for details.&lt;/p&gt;
&lt;h4&gt;Footer&lt;/h4&gt;
&lt;p&gt;Currently supported social media include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;coolapk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;telegram&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;github&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bilibili&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;twitter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zhihu&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;steam&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;netease_music&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to add new social media, you need to modify the following files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;src/types.ts&lt;/code&gt;: Add a new &lt;code&gt;SocialLink.name&lt;/code&gt; enum value and the icon mapping relationship for &lt;code&gt;SocialMediaIconId&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;public/icons/social.svg&lt;/code&gt;: Follow the existing format and add a new icon as a symbol&lt;/p&gt;
&lt;p&gt;It is recommended to find social media icons on the following websites to maintain consistency:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://remixicon.com/&quot;&gt;remixicon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mingcute.com/&quot;&gt;mingcute&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Other Files to Replace&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;public/favicon&lt;/code&gt;: The site&apos;s favicon. You can generate a favicon at &lt;a href=&quot;https://favicon.io/favicon-converter/&quot;&gt;favicon.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public/images/social-card.png&lt;/code&gt;: The site&apos;s social card&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/assets/&lt;/code&gt;: This directory contains client-rendered avatars, sponsorship QR codes, and other images. Please replace them with your own images&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Other Pages&lt;/h2&gt;
&lt;h3&gt;About&lt;/h3&gt;
&lt;p&gt;Currently supported icons can be found in the &lt;code&gt;src/icons&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;If you want to add new Tools icons, you need to add a new icon in the &lt;code&gt;src/icons&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;It is recommended to find new icons on the following websites to maintain consistency:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://icon-sets.iconify.design/&quot;&gt;iconify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://icones.js.org/&quot;&gt;icones&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Deployment Mode&lt;/h2&gt;
&lt;p&gt;See &lt;a href=&quot;/docs/deployment&quot;&gt;Deployment&lt;/a&gt; for details.&lt;/p&gt;</content:encoded><h:img src="/_astro/thumbnail.H3t_xmcX.jpg"/><enclosure url="/_astro/thumbnail.H3t_xmcX.jpg"/></item></channel></rss>