<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>8tupian</title>
    <link>https://blog-3wz.pages.dev/</link>
    <description>Recent content on 8tupian</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Fri, 16 Oct 2026 15:24:48 +0800</lastBuildDate>
    <atom:link href="https://blog-3wz.pages.dev/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Switching Cursor Pro to The X Subscription: Cursor 老用户的首年折扣</title>
      <link>https://blog-3wz.pages.dev/x-subscription-from-cursor-pro/</link>
      <pubDate>Fri, 16 Oct 2026 15:24:48 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/x-subscription-from-cursor-pro/</guid>
      <description>&lt;p&gt;我之前订阅的是 Cursor Pro，每月 20 美元。2026 年 10 月 12 日，X 推出了统一订阅（The X Subscription），把 X Premium、Grok（SuperGrok）和 Cursor 合到了一个订阅里。我把 Cursor Pro 转成了统一订阅的 Premium 档。&lt;/p&gt;
&lt;p&gt;同样是 Premium 年付，从 Cursor 那边转过去，首年约 16 美元/月；直接在 X 或 grok.com 上订，是 25 美元/月。这是给 Cursor 老用户的首年折扣，从 X 那边看不到。&lt;/p&gt;
&lt;h2 id=&#34;为什么要换&#34;&gt;为什么要换&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;我想要 X 的蓝 V（Premium checkmark），用来推广自己的产品 ENX。&lt;/li&gt;
&lt;li&gt;写代码我主要用 Claude 的订阅，Cursor 用得不多，所以统一订阅里 Cursor 不包含 Claude 用量这一点，对我影响不大。&lt;/li&gt;
&lt;li&gt;原来 Cursor Pro 一年 240 美元，统一订阅 Premium 年付原价 300 美元，多 60 美元，多出来的是 SuperGrok 和 X Premium+ 的权益。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;统一订阅的档位&#34;&gt;统一订阅的档位&lt;/h2&gt;
&lt;p&gt;X 页面（x.com/i/premium_sign_up）上的年付价格：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Doubao IME Voice Input: 语音输入后自动切回英文输入法</title>
      <link>https://blog-3wz.pages.dev/doubao-voice-auto-restore/</link>
      <pubDate>Thu, 15 Oct 2026 12:45:02 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/doubao-voice-auto-restore/</guid>
      <description>&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;
&lt;p&gt;我平时在 macOS 上停在英文 ABC 输入法。&lt;a href=&#34;./doubao-ime.md&#34;&gt;豆包输入法&lt;/a&gt; 开了「跨输入法启用语音」后，在任何输入法下都能用快捷键唤起豆包的语音输入，我设置了两个键：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;模式&lt;/th&gt;
          &lt;th&gt;快捷键&lt;/th&gt;
          &lt;th&gt;用途&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;按住说话，松开结束&lt;/td&gt;
          &lt;td&gt;Fn&lt;/td&gt;
          &lt;td&gt;短句&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;按一下开始，再按一下结束&lt;/td&gt;
          &lt;td&gt;右 Option&lt;/td&gt;
          &lt;td&gt;长段&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;唤起时豆包会把系统输入法切到豆包拼音，语音结束后不会切回来。接下来打字就是中文，每次都要再按一下切回 ABC。&lt;/p&gt;
&lt;p&gt;我想要的效果是：语音输入结束后自动回到唤起前的输入法。豆包当前版本没有这个选项，所以用 Hammerspoon 补上。&lt;/p&gt;
&lt;h2 id=&#34;第一版监听按键不成功&#34;&gt;第一版：监听按键（不成功）&lt;/h2&gt;
&lt;p&gt;最直接的思路是监听快捷键：按下时记下当前输入法，结束时切回去。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fn 模式：松开即结束，不用记状态&lt;/li&gt;
&lt;li&gt;右 Option 模式：数按键次数，按单数次记下输入法，按双数次切回&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;写好后按 Fn 测试，没有切回。在脚本里加了日志才看出两个问题。&lt;/p&gt;
&lt;h3 id=&#34;hammerspoon-没有辅助功能权限&#34;&gt;Hammerspoon 没有辅助功能权限&lt;/h3&gt;
&lt;p&gt;日志里 &lt;code&gt;hs.accessibilityState()&lt;/code&gt; 一直是 &lt;code&gt;false&lt;/code&gt;。权限要在「系统设置 → 隐私与安全性 → 辅助功能」里开，不是左侧栏顶层那个「辅助功能」（那里是 VoiceOver、缩放这类功能）。&lt;/p&gt;
&lt;p&gt;开了之后还是 &lt;code&gt;false&lt;/code&gt;，原因是 macOS 的这个权限只在进程启动时生效。我在设置里关了再开、删掉再加回来都没用，Hammerspoon 一直是开权限之前启动的那个进程。退出 Hammerspoon 再打开后，权限才变成 &lt;code&gt;true&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;豆包把-fn-吞掉了&#34;&gt;豆包把 Fn 吞掉了&lt;/h3&gt;
&lt;p&gt;权限正常以后，Control、Caps Lock、右 Option 都能在日志里看到，Fn 一次都没有出现。我又用 &lt;code&gt;hs.eventtap.checkKeyboardModifiers()&lt;/code&gt; 轮询 Fn 的按下状态，按住 Fn 说话的整个过程中也一直读到未按下。&lt;/p&gt;
&lt;p&gt;所以豆包在更底层把 Fn 拦截了，Hammerspoon 拿不到这个键的任何信息，靠按键判断的方案走不通。右 Option 倒是能收到，但切换模式要数按键次数，如果用 Esc 或鼠标结束语音，计数就会错位。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ENX Mark Known: 从等待接口改为乐观更新</title>
      <link>https://blog-3wz.pages.dev/enx-mark-known-optimistic-update/</link>
      <pubDate>Mon, 12 Oct 2026 10:04:10 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/enx-mark-known-optimistic-update/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;./enx.md&#34;&gt;enX&lt;/a&gt; 的 Chrome 扩展会给查过的生词画下划线。主窗口点一个词会弹出浮层，浮层里有 Mark Known（标为已认识）按钮，点了之后这个词的下划线消失。&lt;/p&gt;
&lt;p&gt;后来侧边栏的整句翻译也加上了同样的下划线（ADR-053），于是有了一个新问题：在主窗口标为已认识之后，侧边栏里这个词的下划线也应该一起消失。&lt;/p&gt;
&lt;h2 id=&#34;原来的做法&#34;&gt;原来的做法&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;content script → background → POST /api/mark → enx-api 写库
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                   ↓ 成功
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;content script 收到回复 → 去掉主窗口下划线
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;主窗口要等接口成功才去掉下划线，侧边栏完全不知道这件事。&lt;/p&gt;
&lt;h2 id=&#34;改成什么样&#34;&gt;改成什么样&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;content script：先去掉主窗口下划线
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  └─ runtime.sendMessage({ type: &amp;#39;markAcquainted&amp;#39;, word })
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ├─ 侧边栏：收到后立即去掉下划线，不回复
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        └─ background：调 enx-api，完成后回复 content script
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;两点变化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主窗口先改界面，再让 background 在后台调接口，也就是常说的乐观更新（optimistic update），和它相对的是原来那种等服务端确认再改界面的做法。&lt;/li&gt;
&lt;li&gt;侧边栏不需要新的通道。&lt;code&gt;chrome.runtime.sendMessage&lt;/code&gt; 从 content script 发出时，会投递给扩展里所有监听 &lt;code&gt;runtime.onMessage&lt;/code&gt; 的页面，background 和侧边栏都能收到。侧边栏只需要多注册一个监听。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;为什么可以先改界面&#34;&gt;为什么可以先改界面&lt;/h2&gt;
&lt;p&gt;标为已认识失败的代价很低：服务端没记上，用户下次读别的文章时这个词还会带下划线，再标一次就行。为了这个小概率的失败让用户每次都等一个网络往返，不划算。&lt;/p&gt;
&lt;p&gt;如果改成「background 调接口成功后再通知侧边栏」，状态会更严格一致，但侧边栏要多等一个接口的时间。对这个操作来说，一致性没有那么重要。&lt;/p&gt;
&lt;h2 id=&#34;多个接收方只能有一个回复&#34;&gt;多个接收方只能有一个回复&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;runtime.sendMessage&lt;/code&gt; 允许多个页面监听，但发送方只会收到&lt;strong&gt;第一个&lt;/strong&gt;调用 &lt;code&gt;sendResponse&lt;/code&gt; 的回复，其余的被忽略。侧边栏如果也回复，会抢在 background 前面，content script 就看不到接口的真实结果了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W38-W41</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w38-w41/</link>
      <pubDate>Fri, 09 Oct 2026 12:09:39 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w38-w41/</guid>
      <description>&lt;p&gt;临近国庆节，节奏有点乱。有四周没写周记了，W38 到 W41 合成一篇。这四周的主线还是 enx：给它取了个名字叫 Catglish，部署生产环境。最近在准备提交 Chrome Web Store，提交之前得再调整一轮 UI。&lt;/p&gt;
&lt;h2 id=&#34;catglish&#34;&gt;Catglish&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;./weekly-2026-w37.md&#34;&gt;W37&lt;/a&gt; 里纠结的名字，最后用了 Catglish。网站和 Chrome 扩展上的名字都改成了 Catglish，仓库名还是 enx，等上线之前再找时间改。&lt;/p&gt;
&lt;p&gt;W38 主要在调细节。跟 AI 一起重新做了一遍配色，统一了各个组件的颜色 token。在颜色这件事上，AI 比我专业多了。周五 Claude Code 赠送的 100 美元额度第二天就要过期，那两天开着 Opus 改了很多东西，也第一次往生产环境部署了一个版本。&lt;/p&gt;
&lt;p&gt;W39 在补生产环境的链路。部署流水线从 GHCR 加 SSH 换成了 ECR 加 SSM，机器调整成 t3a.small。扩展的内容脚本改成按需注入，不再在每个页面上都注入。周五集中做了一次依赖版本升级：Next 16、Vite 8、TypeScript 6。E2E 测试改成用真实的登录流程跑。&lt;/p&gt;
&lt;p&gt;W40 是国庆：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网站上加了 Beta 标记和 GitHub 链接&lt;/li&gt;
&lt;li&gt;加了定价页；现在的配额都是内测阶段的数字，跑一段时间再定上线时各个等级的额度&lt;/li&gt;
&lt;li&gt;除了按月订阅，也可以一次性付款购买 AI 积分&lt;/li&gt;
&lt;li&gt;本地词典查不到的词，可以调用 AI 生成释义&lt;/li&gt;
&lt;li&gt;收藏页面，以及按站点设置「在这个网站上自动开启」&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外加了 Prometheus 监控指标，homelab 和生产环境的监控面板都接上了。&lt;/p&gt;
&lt;p&gt;W41 打好了 0.1.0 Beta 的扩展包，画了个 logo：一个带猫耳朵的 C。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W37</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w37/</link>
      <pubDate>Mon, 14 Sep 2026 11:15:13 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w37/</guid>
      <description>&lt;p&gt;这周主要在给 enx 取名字。另外 enx 接了 DeepSeek，HomeLab 的 CI/CD 加了缓存，在 YouTube 上新建了一个产品频道。&lt;/p&gt;
&lt;h2 id=&#34;enx取名字&#34;&gt;enx：取名字&lt;/h2&gt;
&lt;p&gt;enx 一直是开发代号，要做成产品发布，得有一个正式的名字。取名字是最不重要、也最纠结的一件事。&lt;/p&gt;
&lt;p&gt;这一周一直在纠结叫什么。想了好多名字，一个个去查域名和商标，大部分都和现有的软件或者商标冲突：有的域名已经被人注册了，有的已经注册了商标，用了会有法律风险。&lt;/p&gt;
&lt;p&gt;最后在仅有的几个不冲突的名字里来回纠结，周六选了一个，注册了域名。&lt;/p&gt;
&lt;h2 id=&#34;enx开发&#34;&gt;enx：开发&lt;/h2&gt;
&lt;p&gt;新功能不多：Reader 页面，可以把一段英文粘贴进来阅读、查词；从浏览器扩展里发起登录，登录完会自动回到原来的页面。&lt;/p&gt;
&lt;p&gt;另外还做了一些细节上的小调整和优化。&lt;/p&gt;
&lt;p&gt;UI 和 API 的提示文案全部改成了英文。用这个工具的人本来就在学英文，UI 上简单的英文应该不是问题；&lt;/p&gt;
&lt;p&gt;MiniMax 的订阅过期了，DeepSeek 的账户里还有余额，所以给 enx 加了一个 DeepSeek 的 provider，HomeLab 上切到了 DeepSeek。HomeLab 是测试用的，对后端用哪个模型不是特别敏感。&lt;/p&gt;
&lt;h2 id=&#34;homelabcicd-提速&#34;&gt;HomeLab：CI/CD 提速&lt;/h2&gt;
&lt;p&gt;最近一直在测 enx，频繁调细节，也频繁往 HomeLab 上部署，CI/CD 跑的时间就成了一个比较明显的问题。&lt;/p&gt;
&lt;p&gt;这周优化了一下：加了缓存，加了 Nexus 私有仓库。npm 和 Go 的依赖走 Nexus 代理，镜像构建的缓存也放在 Nexus 里，依赖没变的时候可以跳过安装依赖那一步。&lt;/p&gt;
&lt;h2 id=&#34;youtube两个频道&#34;&gt;YouTube：两个频道&lt;/h2&gt;
&lt;p&gt;打算拍一些东西放到 YouTube 上，比如 enx 的安装/使用演示, 宣传视频, 这周在准备拍摄方案，周六在自己的 YouTube 账号下新建了一个产品频道。&lt;/p&gt;
&lt;p&gt;注册 YouTube 账号之后本来就会有一个默认的频道，每个注册用户都有，只是大多数人没有往里面发过视频。我的默认频道就当个人频道用。同一个账号下面还可以再新建别的频道，这一点我也是这周才知道的，算是一个新发现。&lt;/p&gt;
&lt;p&gt;这样一个账号下面就有了两个频道。个人频道放我自己的内容，比如 HomeLab 的改造、有可能的未来的房车旅行，也许会有美食类的视频，主要是个人记录。产品频道只发产品相关的内容。个人频道是全集，跟 enx 相关的视频会同时发到两个频道。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W36</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w36/</link>
      <pubDate>Mon, 07 Sep 2026 15:26:12 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w36/</guid>
      <description>&lt;p&gt;enx：认证从 Cognito 换成了 Clerk，单词高亮换成了浏览器原生的 Highlight API。&lt;/p&gt;
&lt;h2 id=&#34;enx认证从-cognito-换到-clerk&#34;&gt;enx：认证从 Cognito 换到 Clerk&lt;/h2&gt;
&lt;p&gt;当初选 Cognito 的原因是，那会儿在聊一个职位，对方公司用 Java 技术栈，也用 AWS。我想让自己更熟悉 AWS 和 Java 一些，所以 enx 选型的时候选了 Cognito，还给 enx 加了一个 Java 后端。&lt;/p&gt;
&lt;p&gt;那个职位后来没有 Offer，见 &lt;a href=&#34;./weekly-2026-w33.md&#34;&gt;W33&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;这周把认证换成了 Clerk。换的原因是 Clerk 和 Google 登录集成得更好一些，另外它同时支持 Google 和 GitHub 两种登录。网页端和扩展的会话也能同步。两端手写的 OAuth 客户端一起下线，Cognito 那套基础设施也删掉了。&lt;/p&gt;
&lt;h2 id=&#34;enx单词高亮换成浏览器原生的-highlight-api&#34;&gt;enx：单词高亮换成浏览器原生的 Highlight API&lt;/h2&gt;
&lt;p&gt;有天晚上碰到思科的前同事 Roc，聊了一会儿，发现自己的前端知识实在太匮乏了。页面上点一下要查的词，其实可以用鼠标的坐标反查到点中的是哪个词，不需要像之前那样预先改 DOM、把所有词都拆开包起来，也不用挂那么多 onClick。&lt;/p&gt;
&lt;p&gt;以前的做法就是把匹配到的单词用元素包起来，再给这个元素加样式。这样会改动页面的 DOM，在结构复杂或者会自己重绘的页面上容易出问题。&lt;/p&gt;
&lt;p&gt;这周换成了 CSS Custom Highlight API：高亮范围用 Range 描述，交给浏览器渲染，不再往页面里插元素。点击查词改成在容器上做事件委托，用 &lt;code&gt;caretPositionFromPoint&lt;/code&gt; 定位点到的是哪个词。&lt;/p&gt;
&lt;p&gt;顺带把两件事拆开了：「阅读时高亮生词」和「点击查词」现在是两个独立的开关，可以只启用其中一个。X 上切换推文时正文是原地替换的，加了自动重建。Playwright 的用例按新的实现重写了一遍。&lt;/p&gt;
&lt;h2 id=&#34;周六大黑石&#34;&gt;周六：大黑石&lt;/h2&gt;
&lt;p&gt;周六老婆公司团建，在大黑石的海边烧烤，她带着女儿去了。女儿下午有英语课，我中午开车去大黑石的沙滩接她们。&lt;/p&gt;
&lt;p&gt;据说，小朋友到了沙滩就想去海边，饭都不吃了。一开始还在岸边挖沙子，后来看妈妈下水游泳，她也要下水。下水之后就不想走了，用老婆的话说是 “血脉觉醒”。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;./weekly-2026-w32.md&#34;&gt;上次带她去海边&lt;/a&gt;是在广鹿岛，那时候她还只是在浅水里捡海星和贝壳。&lt;/p&gt;
&lt;h2 id=&#34;路边为啥要栽这么多树&#34;&gt;路边为啥要栽这么多树&amp;hellip;&lt;/h2&gt;
&lt;p&gt;开车去大黑石的路上，偶尔过桥的时候能看到远处的山，景色还不错。其余大部分时间视线都被路两边的树挡着，开多久，窗外都是一样的树。&lt;/p&gt;</description>
    </item>
    <item>
      <title>IIT Filing: 企业法人个税申报</title>
      <link>https://blog-3wz.pages.dev/legal-person-iit-filing/</link>
      <pubDate>Wed, 02 Sep 2026 12:07:10 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/legal-person-iit-filing/</guid>
      <description>&lt;p&gt;一人公司法人申报个人所得税的操作备忘。记录网页版扣缴端的零申报步骤。相关背景见 &lt;a href=&#34;./one-person-company.md&#34;&gt;一人公司&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;网页版&#34;&gt;网页版&lt;/h2&gt;
&lt;p&gt;入口：&lt;a href=&#34;https://etax.chinatax.gov.cn&#34;&gt;国家税务总局电子税务局&lt;/a&gt; → 自然人电子税务局。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开上述网站，进入自然人电子税务局&lt;/li&gt;
&lt;li&gt;用法人的个税 App 扫码登录&lt;/li&gt;
&lt;li&gt;在菜单里找「单位办税」，选择公司，进入扣缴端&lt;/li&gt;
&lt;li&gt;进入「综合所得申报」，选择税款所属月份（上一个月）&lt;/li&gt;
&lt;li&gt;「收入及减除填写」→「正常工资薪金所得」→「填写」→ 添加法人本人，本期收入填 0，保存&lt;/li&gt;
&lt;li&gt;「税款计算」→ 附表跳过 →「申报表报送」→「发送申报」&lt;/li&gt;
&lt;li&gt;「获取反馈」，显示申报成功，应缴 0，不用缴款&lt;/li&gt;
&lt;li&gt;在「扣缴申报 → 查询统计 → 单位申报记录查询」可以核对每个月的申报记录&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;公司没发工资、没有分红，也要每月零申报。征期是每月 15 日前，节假日顺延。&lt;/p&gt;
&lt;h3 id=&#34;过程中的提示&#34;&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;：选确认。收入为 0，不影响税额，专项附加扣除可以在年度汇算时享受&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;未填写三险一金，请确认是否继续&lt;/strong&gt;：选继续。公司没有代缴社保和公积金&lt;/li&gt;
&lt;li&gt;全年一次性奖金、年金等其他所得项都不用填，只填正常工资薪金&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;windows-版&#34;&gt;Windows 版&lt;/h2&gt;
&lt;p&gt;（待补）&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W35</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w35/</link>
      <pubDate>Sun, 30 Aug 2026 13:20:00 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w35/</guid>
      <description>&lt;p&gt;这周主要是 enx 的开发：接入 Stripe，以及上线前的一些细节调整。&lt;/p&gt;
&lt;h2 id=&#34;enx接入-stripe&#34;&gt;enx：接入 Stripe&lt;/h2&gt;
&lt;p&gt;订阅加积分这套方案是&lt;a href=&#34;./weekly-2026-w33.md&#34;&gt;上周&lt;/a&gt;那份规划里定下来的，这周把它落进代码。&lt;/p&gt;
&lt;p&gt;周三一天，enx 里多出了一整套计费：积分账本、Stripe 的 webhook、配额、结账和账单管理入口，网页端加了定价页和账单页，扩展这边加了积分不足和需要升级的提示。方案之前讨论过，这次是把方案细化，然后由 AI 生成代码。&lt;/p&gt;
&lt;p&gt;同一批改动里还补了一组单元测试，账本、webhook、配额、结账处理各有一份。补测试的原因是接入 Stripe 之后要开始新一轮测试，而现有代码的单元测试覆盖太小，先把底子补上。&lt;/p&gt;
&lt;p&gt;接下来是测试。&lt;/p&gt;
&lt;h2 id=&#34;订阅之外加了一次性充值包&#34;&gt;订阅之外加了一次性充值包&lt;/h2&gt;
&lt;p&gt;周四改了一次访问规则。&lt;/p&gt;
&lt;p&gt;前一天定的是：AI 翻译必须有订阅才能用，不能靠单独充值绕过。第二天推翻了，改成账户里有积分就能用，不限来源，订阅发放的积分和一次性购买的积分包都算。&lt;/p&gt;
&lt;p&gt;改的原因是有了一个新想法，可以开放一次性购买的充值包。按月订阅并不是所有人都愿意，月费也不好定太高，一次性的充值包是个补充。&lt;/p&gt;
&lt;p&gt;代价是前一天已经写进代码的那条校验现在是错的，得删掉。项目还在开发中，随时都会有变化，这些变化都是正常的。&lt;/p&gt;
&lt;h2 id=&#34;内网域名换成-wiloonlab&#34;&gt;内网域名换成 wiloon.lab&lt;/h2&gt;
&lt;p&gt;wiloon.com 是公网域名，homelab 内部之前也用它，只是在内网解析。但 DNS 分流上遇到了问题，所以内网改用 wiloon.lab，专门给 homelab 用。&lt;/p&gt;
&lt;p&gt;这周把 enx 的内网访问切了过去。&lt;/p&gt;
&lt;h2 id=&#34;公司账本把方法固化成一个仓库&#34;&gt;公司账本：把方法固化成一个仓库&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;./weekly-2026-w33.md&#34;&gt;上周&lt;/a&gt;写过决定自己记账，用 beancount，AI 出数、人工复核。这周把它做成了一个仓库。&lt;/p&gt;
&lt;p&gt;促成这件事的还有几点。找代账公司有沟通成本；在 twitter 上看到有人用 AI 处理公司的账目，我也想试试；另外公司现在没有业务，都是零申报，应该不复杂。有代账公司打电话过来，我跟他们说的也是自己先试试，实在不行再找专业人士。&lt;/p&gt;
&lt;p&gt;仓库里放的是科目表模板、余额断言、季度增值税和年终结账两份 SOP，以及法定报表的字段映射。另外把几个常用动作做成了 Claude Code 的 skill：开票申请、季度报税、出报表、报税准备。&lt;/p&gt;
&lt;p&gt;上周是决定自己记账，这周是把记账做成一套可以重复执行的流程。&lt;/p&gt;
&lt;h2 id=&#34;homelab-杂项&#34;&gt;homelab 杂项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;kubectl 的 logs 和 exec 一度用不了，加了一个 ClusterRoleBinding 修回来，交给 ArgoCD 管理。&lt;/li&gt;
&lt;li&gt;路由器那边把 IPv6 的 WAN 口改成了静态接口，之前记录过的前缀委派丢失问题走到了这一步。&lt;/li&gt;
&lt;li&gt;监控补了一批采集配置。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;blog&#34;&gt;blog&lt;/h2&gt;
&lt;p&gt;这周写了三篇：&lt;a href=&#34;../linux/mktemp.md&#34;&gt;mktemp&lt;/a&gt;、&lt;a href=&#34;../cs/database/duckdb.md&#34;&gt;DuckDB&lt;/a&gt;，以及&lt;a href=&#34;../web/wechat-qr-pdf-cloudflare-pages.md&#34;&gt;微信扫码查看与下载 PDF&lt;/a&gt;。另外给 &lt;a href=&#34;../cs/sqlite.md&#34;&gt;SQLite&lt;/a&gt; 那篇做了修订。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W34</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w34/</link>
      <pubDate>Sun, 30 Aug 2026 13:00:00 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w34/</guid>
      <description>&lt;p&gt;这一周几乎没碰键盘。带娃在老家待了五天，只有她午睡和晚上睡了之后，才有一点时间做自己的事。&lt;/p&gt;
&lt;h2 id=&#34;从鞍山到老四平&#34;&gt;从鞍山到老四平&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;./weekly-2026-w33.md&#34;&gt;上周&lt;/a&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 id=&#34;小公园&#34;&gt;小公园&lt;/h2&gt;
&lt;p&gt;周三去了老家附近的一个小公园。&lt;/p&gt;
&lt;p&gt;爷爷奶奶本来打算当个景点看一眼就回家，中午外面太热。没想到娃对什么都新奇，跟小树小草玩起来就不肯走了。有荷花池，有草地，有树林。&lt;/p&gt;
&lt;h2 id=&#34;亲戚家的动物&#34;&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;h2 id=&#34;早上跑步&#34;&gt;早上跑步&lt;/h2&gt;
&lt;p&gt;我每天早上跑步。老家在内陆，中午三十几度，早晚凉快，跑步只能放在早上。&lt;/p&gt;
&lt;p&gt;小镇上很少有人把跑步当成锻炼。老年人有打太极的，有做操的，有跳广场舞的，跑步的很少。所以 Keep 的地图上，老四平一条跑步路线都没有。上次回来我开发了一条 2 公里的，这次又开发了一条 4 公里的。路上车不多，早上跑起来很舒服。&lt;/p&gt;
&lt;p&gt;不方便的是跑完一身汗，洗澡不方便。家里没有独立的卫生间，厕所是旱厕，只能用湿毛巾擦一擦。&lt;/p&gt;
&lt;h2 id=&#34;回大连&#34;&gt;回大连&lt;/h2&gt;
&lt;p&gt;周五开车带娃和奶奶一起回大连。&lt;/p&gt;
&lt;p&gt;在大连是姥姥姥爷和爷爷奶奶轮班过来帮忙带娃，这次刚好赶上换班的周期，带娃回老家，顺便把奶奶接过来。&lt;/p&gt;
&lt;h2 id=&#34;她自己编的一个故事&#34;&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;这个故事的来源能对上。上周回老四平，路上无聊的时候给她讲过孙悟空三打白骨精，白骨精先变成一个姑娘，再变成老奶奶，最后变成老爷爷。另外最近买了 Switch 2 上的《世界游戏大全 51》，和她玩过里面的国际象棋，国际象棋有国王和王后。她把三打白骨精的情节、国际象棋的棋子，还有当时飞过来的那只鸟，编进了同一个故事。&lt;/p&gt;
&lt;p&gt;我帮她把这个故事做成了连环画，下次再找时间生成一个动画片。&lt;/p&gt;
&lt;p&gt;还是要多带她去看不同的东西，接触各种各样的事物。她会把见过的、经历过的重新排列组合，变成自己的认知。&lt;/p&gt;
&lt;h2 id=&#34;项目&#34;&gt;项目&lt;/h2&gt;
&lt;p&gt;这周项目上基本没有进展，只有她午睡和晚上睡了之后才有一点点时间。&lt;/p&gt;
&lt;p&gt;在老家这几天不碰键盘，倒是想清楚了一件事。enx 这个项目我断断续续做了很久，一直是自己在用。做了这么久，如果最后没有真正上线，我会有遗憾。所以暂时不找工作，接下来一段时间集中精力把它部署上线。&lt;/p&gt;
&lt;p&gt;2026 W34，老四平 — 大连。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W33</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w33/</link>
      <pubDate>Sun, 16 Aug 2026 23:59:59 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w33/</guid>
      <description>&lt;h2 id=&#34;面试结果&#34;&gt;面试结果&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;./weekly-2026-w32.md&#34;&gt;上周&lt;/a&gt;那场第二轮面试，周二有了结果：职位不匹配。&lt;/p&gt;
&lt;p&gt;从 4 月离职到现在同事/朋友帮推过三家公司。一家给了 offer，薪资太低，拒了；一家没有下文；这一家前后聊了四个月，两个岗位都进了二面，都没有 offer. 这一家前后接触了一位 HR 和八位面试官。感觉得出来，有的是希望我加入的，也有的对我有疑虑。anyway，最终的结论是职位不匹配。&lt;/p&gt;
&lt;p&gt;接下来先测试 enx 独立商业化的可行性：把功能做完、部署到 AWS、接上 Stripe 订阅，先在 YouTube 和 X 上推(因为只做了 google 账号登录)，看能不能有几个付费订阅用户；跑不通的话就再找工作。&lt;/p&gt;
&lt;h2 id=&#34;enx-划词翻译&#34;&gt;enx: 划词翻译&lt;/h2&gt;
&lt;p&gt;之前选中一个短语会走词典查询，而后端判定&amp;quot;包含空格就是句子&amp;quot;，直接返回一句&amp;quot;句子翻译功能暂未开放&amp;quot;，短语永远拿不到释义。现在改成：选中的如果是句子中间的几个词，侧边栏显示这个短语在整句里的含义。像 &amp;ldquo;hunt down emails&amp;rdquo;，三个词单看都认识，放进上下文里是什么意思才是要查的。&lt;/p&gt;
&lt;p&gt;另外给三个翻译 provider 各补了单测。&lt;/p&gt;
&lt;h2 id=&#34;enx上线还差什么&#34;&gt;enx：上线还差什么&lt;/h2&gt;
&lt;p&gt;周三花了一天，把 enx 距离上线还差哪些事情列了一遍，写成两份文档，一份是商业化设计，一份是任务清单。&lt;/p&gt;
&lt;p&gt;先定义什么叫&amp;quot;上线&amp;quot;：在生产环境上，真实用户可以注册、登录、订阅、使用 AI 翻译、被限流、退订，这条链路全部跑通，才谈得上开始推广。&lt;/p&gt;
&lt;p&gt;顺序定成三步。先在现在这套 homelab 环境里把订阅功能做完、测通，不用等基础设施迁移——然后把跑通的功能迁到 AWS。最后在生产环境完整跑一遍端到端冒烟测试，作为发布门禁。&lt;/p&gt;
&lt;p&gt;几条已经定下来的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;计算平台继续用 EC2，不上 ECS 或 EKS。EKS 控制面每月的固定成本，在验证付费意愿这个阶段不划算&lt;/li&gt;
&lt;li&gt;上线时数据库继续用 SQLite，先不迁 PostgreSQL。现有链路已经跑过，上线门槛越低越好，数据库迁移不是订阅功能的前置依赖&lt;/li&gt;
&lt;li&gt;域名不换。Cognito 的 callback、CORS、证书、扩展权限都已经围绕现在这个域名配好了&lt;/li&gt;
&lt;li&gt;全部开源，包括计费规则，继续用 AGPL-3.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后一条想得比较久。最初担心闭源可以防止别人用 AI 抄产品，后来推翻了：闭源只能防直接复制代码，防不了照着功能用 AI 重写一遍，而后者才是真正的风险，源码可不可见对它基本无效。定价和免费额度这些数字，用户用一遍产品就能观察到，藏代码也藏不住。真正让我决定开源的是另一件事——找工作这条退路还在，一个有真实用户、有测试和 ADR 的开源项目本身就是求职作品集，这个价值闭源换不来，而闭源换来的那点&amp;quot;防护&amp;quot;本来就是假的。&lt;/p&gt;
&lt;h2 id=&#34;局域网域名的一秒延迟&#34;&gt;局域网域名的一秒延迟&lt;/h2&gt;
&lt;p&gt;周五在准备 enx 的测试环境，发现局域网里的域名访问都带着一段很规律的延迟。查下来是 IPv6 的 DNS 问题。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W32</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w32/</link>
      <pubDate>Sun, 09 Aug 2026 23:59:59 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w32/</guid>
      <description>&lt;h2 id=&#34;广鹿岛彩虹滩赶海&#34;&gt;广鹿岛：彩虹滩赶海&lt;/h2&gt;
&lt;p&gt;上周末坐船去了广鹿岛。&lt;/p&gt;
&lt;p&gt;周一换了个海滩，去彩虹滩赶海。这次出来玩时间赶得不错，退潮都在傍晚 6 点左右，太阳快落山，正好是一天里凉快下来的时候。海滩很浅，可以往前走很远，靠岸这一段脚下都是细沙，沙滩上有很多海葵，寄居蟹更是数不过来。再往深处走，细沙变成礁石，海草也多起来，水到膝盖左右。&lt;/p&gt;
&lt;p&gt;四岁的女儿一路捡，寄居蟹、螃蟹、各种贝壳，把整个桶底铺满了。后来我们在海草附近捡到一只海星，她立刻把桶里的螃蟹和寄居蟹全倒回海里，整个桶只装这一只海星。&lt;/p&gt;
&lt;p&gt;海星带回了民宿。到晚上它大概是缺氧，开始往桶外爬。我们商量了一下，还是放回去吧，不然会死掉。于是又把海星送到离住处最近的海里。&lt;/p&gt;
&lt;p&gt;赶海的时候一边拍照一边让 AI 识别，认识了海葵和鱿鱼的卵鞘。海葵挺有意思，拿铲子碰一下，它整个身体缩进沙子里，同时喷出一股海水。鱿鱼的卵鞘在滩上到处都是，半透明、软软的、圆圆的一团。&lt;/p&gt;
&lt;p&gt;周三从广鹿岛回大连。在杏树港下船之后是我开车，女儿自己坐安全座椅，全程走国道没上高速——小朋友随时可能需要我，国道方便停车。过几周我要单独带她去爷爷奶奶家，这次算是一次 dry run。&lt;/p&gt;
&lt;h2 id=&#34;enx遮阳伞下的-side-panel&#34;&gt;enx：遮阳伞下的 side panel&lt;/h2&gt;
&lt;p&gt;周二在岛上找了家有泳池的酒店，女儿和妈妈在泳池里泡了一下午。我没带泳衣，就在遮阳伞下写码。&lt;/p&gt;
&lt;p&gt;这周 enx 主要在开发句子翻译的 side panel。&lt;/p&gt;
&lt;p&gt;后端给三个翻译 provider 都加上了「按句子上下文翻译单词」的能力，配了对应的 handler 和路由，每个 provider 补了单测。前端这边，侧边栏里点击单词后的展示从单行文字改成了卡片。&lt;/p&gt;
&lt;p&gt;卡片这块反复改了几版。一开始词、音标、上下文含义、查询次数分四行堆着，太占纵向空间，改成一行内排列、放不下才折行；有道词典的外链也删掉了，侧边栏就这么宽；「Query Count」几个字重复出现太啰嗦，换成一个放大镜图标，原文字挪到 title 属性里做悬浮提示。&lt;/p&gt;
&lt;p&gt;加载方式也调了。以前是词典查询和 AI 上下文翻译两个请求都回来才一起渲染，现在点击的时候就先插入一张骨架卡片，两个请求各自返回后只更新自己那部分。词典那边通常更快，音标和释义会先显示出来。列表按点击时间倒序排，重复点同一个词不再发请求，只把已有的卡片挪到最前面。&lt;/p&gt;
&lt;h2 id=&#34;第二轮面试&#34;&gt;第二轮面试&lt;/h2&gt;
&lt;p&gt;周三从广鹿岛回来，在杏树港排队驶出停车场的时候接到了 HR 的电话。是第二轮面试的邀请，安排在周五下午，30 分钟，听起来会是全英文。&lt;/p&gt;
&lt;p&gt;当天下午要带娃上课，距离面试还有一天多准备时间。上一次面试因为一直在看 Spring 的资料，没准备自我介绍，英文的自我介绍讲得不太好，这次得准备一下；剩下的主要是怎么用英语把简历上的经历说清楚。周四一整天和面试当天的白天，基本都在准备这些。&lt;/p&gt;
&lt;p&gt;周五当天出了个小插曲。我之前很少用 zoom，16:20 就打开了，输会议号、输密码、调整摄像头和麦克风，然后等面试官上线。等到 16:27 还没看见人，才注意到窗口右下角有一个 join 按钮——原来我一直在会议外面 -_- 赶紧点了 join，发现两位面试官已经在线了。&lt;/p&gt;
&lt;p&gt;面试过程还算顺利。我的英文不是特别好，中间有问题没听清楚就麻烦面试官再讲一遍，对方会很友好地放慢语速重复。有些问题答得还好，也有因为准备不够没能表达清楚的。面试官也问到了个人项目，我讲了 enx，说计划部署到 AWS 上，或许能帮到其他人。&lt;/p&gt;
&lt;p&gt;快结束的时候我还纠结了一下，要不要解释一句我其实一直在会议外面等着。但这么复杂的句子，我的英文暂时还撑不住，就直接 say goodbye 了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W30-W31</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w30-w31/</link>
      <pubDate>Sun, 02 Aug 2026 23:59:59 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w30-w31/</guid>
      <description>&lt;p&gt;这两周的周记合成一篇。&lt;/p&gt;
&lt;h2 id=&#34;enx先把功能做完上线再说&#34;&gt;enx：先把功能做完，上线再说&lt;/h2&gt;
&lt;p&gt;enx 是我自己的项目，一个查词加翻译的 Chrome 扩展。这两周它是主线。&lt;/p&gt;
&lt;p&gt;前一周主要在部署链路上：调查词性能（SQLite 相关的调整、给 words 表加索引的 migration），构建时把 version 注入镜像，Go API、Java API 和 UI 三条镜像链路陆续跑通，部署到 homelab。&lt;/p&gt;
&lt;p&gt;后一周是功能推进：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;合入本地 ECDICT 词典，查词路径不再依赖外部接口&lt;/li&gt;
&lt;li&gt;单词弹窗迁到 React + Shadow DOM，样式不会再被宿主页面污染&lt;/li&gt;
&lt;li&gt;加了句子翻译的 Side Panel，翻译后端做成多 provider（MiniMax、Bedrock、Kimi），用 factory 加 handler 分派&lt;/li&gt;
&lt;li&gt;修扩展的 session 超时问题，Cognito 那边改成手写刷新逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;周六在岛上想清楚一件事：微信登录先不做了。现在已经有 Google 登录，把 Stripe 接上就可以上线部署。把基本功能做完先上线，不需要等到完美。&lt;/p&gt;
&lt;h2 id=&#34;一个朋友的文档校验工具&#34;&gt;一个朋友的文档校验工具&lt;/h2&gt;
&lt;p&gt;之前写过的、给一位朋友做的文档校验工具，这两周继续往前走。&lt;/p&gt;
&lt;p&gt;前一周主要是仓库骨架落地：架构 ADR、几个模块的 Spec、测试，周末开始写 Web UI 的 SDD 和 lint 配置。后一周把它部署进了测试环境。&lt;/p&gt;
&lt;p&gt;另外这个项目按正常的需求分析、报价流程走一遍。因为如果以后真的在线接单，报价是绕不开的问题，正好拿它测试一下。&lt;/p&gt;
&lt;h2 id=&#34;starlabrys-官网&#34;&gt;starlabrys 官网&lt;/h2&gt;
&lt;p&gt;公司官网这两周加了历史项目展示页，还有一个 Site Advisor 的雏形，包括意图识别、知识库、tools 和对话几个部分。ew8 帮我改的那部分周五合并进来了。&lt;/p&gt;
&lt;h2 id=&#34;w_dashboard一个玩具级的仓库看板&#34;&gt;w_dashboard：一个玩具级的仓库看板&lt;/h2&gt;
&lt;p&gt;周末起了个新项目 w_dashboard，Linux 端用 Rust 加 Slint，macOS 端用 Swift 加 SwiftUI，两端各写了一版初版。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W29</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w29/</link>
      <pubDate>Sun, 19 Jul 2026 23:59:59 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w29/</guid>
      <description>&lt;h2 id=&#34;从-hashmap-关联到的&#34;&gt;从 HashMap 关联到的&lt;/h2&gt;
&lt;p&gt;上周说面试复盘整理了一部分，这周继续。blog 里 Java 相关的文档以前记得有些零散，重新整理一下。&lt;/p&gt;
&lt;p&gt;HashMap 关联的东西其实挺多的&amp;hellip;&lt;/p&gt;
&lt;p&gt;先是解决哈希冲突主要的两条路：开链法和开放地址法。链表长到一定程度会转成红黑树，于是又去看了红黑树。哈希值怎么来的又牵出随机数——xorshift、LCG。再往下是 CPU 层面的事：加法/乘法/除法消耗的时钟周期不一样，缓存的空间局部性会直接影响这类数据结构的实际性能。横向看，Python 的 dict、Go 的 map 用的 Swiss Table，思路各不相同。&lt;/p&gt;
&lt;p&gt;Swiss Table 这条又牵出 SIMD，还挺有意思的。1997 年的 Pentium MMX 就带了 MMX 指令集，不过只能做整数；AMD 1998 年 K6-2 上的 3DNow! 把单精度浮点加了进来；到 1999 年 Pentium III 的 SSE，才有了独立的 128 位寄存器。早年这套指令主要是拿来做多媒体和图形的。&lt;/p&gt;
&lt;p&gt;而 Swiss Table 用 SIMD 一次比对一组控制字节来定位槽位，Go 的 map 后来换成了这个结构——中间隔了二十多年。一个 90 年代末为了跑多媒体加进来的特性，现在被用来加速哈希表的查找。&lt;/p&gt;
&lt;p&gt;JVM 这边也一并整理了：HotSpot 的 GC 和 JIT。中间还跑偏去看了下 Linux 的进程调度。&lt;/p&gt;
&lt;h2 id=&#34;starlabrys把公司的壳先搭起来&#34;&gt;starlabrys：把公司的壳先搭起来&lt;/h2&gt;
&lt;p&gt;和朋友聊天，有人找到了工作但不太理想，有人还在面试。我之前注册了营业执照，就在想我们是不是可以一起做点什么。&lt;/p&gt;
&lt;p&gt;有人建议建一个 GitHub organization，这样想贡献代码的人可以加进来。公司暂时没业务，但有件事是现在就能做的——把官网建起来。&lt;/p&gt;
&lt;p&gt;于是注册了域名 starlabrys.com，建了 GitHub org，把仓库和权限用 OpenTofu 管起来，后来又把这部分 IaC 从我自己的配置仓库拆出去，单独放进了 starlabrys-infra。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W28</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w28/</link>
      <pubDate>Sun, 12 Jul 2026 23:59:59 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w28/</guid>
      <description>&lt;h2 id=&#34;魔法线路的一次重建&#34;&gt;魔法线路的一次重建&lt;/h2&gt;
&lt;p&gt;我有三条魔法线路，这周状态都不太好：炸掉了一条，另外一条流量超了配额，还有一条延迟很大。索性新建了一条顶上。&lt;/p&gt;
&lt;p&gt;配置新线路的过程中，顺带发现之前配的延迟检测不准，干脆一起修了。这一修就牵出一串：kube-prometheus-stack 里 &lt;code&gt;additionalScrapeConfigs&lt;/code&gt; 字段名写错了；把 R 线路上的 X 从 split-updown 架构切回了普通方案，本想验证问题是不是出在这个架构上，结果发现并不是；J 线路也重新调了一遍，接进了 Grafana 监控。&lt;/p&gt;
&lt;p&gt;本来只是想补一条线路，结果顺手把观测这块积了一阵子的旧账清了一遍。&lt;/p&gt;
&lt;h2 id=&#34;重新拾起-quantdinger&#34;&gt;重新拾起 QuantDinger&lt;/h2&gt;
&lt;p&gt;重新研究 QuantDinger，顺带整理自己的 enx 项目。&lt;/p&gt;
&lt;p&gt;隔了一段时间没跟，上游已经升了很多个版本，还有一次大版本更新——MT5 整个模块被删掉了，看代码仓库，主线现在主要在更新数字货币和股票相关的模块。我跟着更新了指标（indicator）相关的一批代码。&lt;/p&gt;
&lt;p&gt;也跑了一单测试，赚了 0.02866，差不多两毛钱——这也算是有正向现金流了 -_-。&lt;/p&gt;
&lt;h2 id=&#34;面试复盘&#34;&gt;面试复盘&lt;/h2&gt;
&lt;p&gt;上一次面试还没有后续&lt;/p&gt;
&lt;p&gt;比起纠结结果，我更想把遇到的问题梳理清楚。已经整理了一部分，下周找时间继续，从 blog 里挖了一些相关的文档再整理一遍，下周接着弄。&lt;/p&gt;
&lt;h2 id=&#34;女儿的一支舞和被传染的一家&#34;&gt;女儿的一支舞，和被传染的一家&lt;/h2&gt;
&lt;p&gt;上周提到女儿在排练一支舞，这周演出了。&lt;/p&gt;
&lt;p&gt;她上的是小班，周五这场是幼儿园大班的毕业典礼，小班出了几个小朋友排练了一支舞蹈，去典礼上表演。表演当天她的状态不错——一周前感冒过，到那天体温已经正常一两天，算是在恢复中，只剩一点点咳嗽，不影响跳舞，整支舞完整跳完了。&lt;/p&gt;
&lt;p&gt;感冒倒是在家里转了一圈。她把病毒传给了妈妈，周六晚上老婆开始发烧。那天我全天带娃在外面上课、玩，回到家就成了半个病房。我目前还好，没有中招的迹象——但也不敢太乐观。&lt;/p&gt;
&lt;h2 id=&#34;周日的三件不相干的小事&#34;&gt;周日的三件不相干的小事&lt;/h2&gt;
&lt;p&gt;周日修了三件事，彼此没什么关联，凑巧都在这天：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;蓝牙&lt;/strong&gt;：偶然发现开机后蓝牙不能自动启用，是 Linux 启动过程中的时序问题，调了一下。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时区&lt;/strong&gt;：为了能在这台机器上用 Claude Code，把时区问题处理了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tekton-pipelines&lt;/strong&gt;：把 PodSecurity 放宽到 baseline，是为了能在 homelab 上部署 enx 的 Java API。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;两个小工具上的调整&#34;&gt;两个小工具上的调整&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Running page 换了数据源&lt;/strong&gt;：Strava 的 API 改成了订阅模式，就把数据源换成了 Keep。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;装了 Squirrel（鼠须管）&lt;/strong&gt;：macOS 自带的五笔输入法没有造词功能，换成了 Squirrel。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>COSMIC 桌面环境与 cosmic-greeter</title>
      <link>https://blog-3wz.pages.dev/cosmic/</link>
      <pubDate>Sun, 12 Jul 2026 00:00:00 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/cosmic/</guid>
      <description>&lt;h2 id=&#34;什么是-cosmic&#34;&gt;什么是 COSMIC&lt;/h2&gt;
&lt;p&gt;COSMIC（&amp;ldquo;Computer Operating System Main Interface Components&amp;rdquo;）是 System76（Pop!_OS 的厂商）用 &lt;strong&gt;Rust + iced&lt;/strong&gt; 从零重写的新一代桌面环境，用来替代 Pop!_OS 之前基于 GNOME Shell 深度定制的 Pop Shell。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compositor：&lt;code&gt;cosmic-comp&lt;/code&gt;，基于 Smithay（Rust 的 Wayland compositor 库），只支持 &lt;strong&gt;Wayland&lt;/strong&gt;，不支持 X11。&lt;/li&gt;
&lt;li&gt;UI 工具包：&lt;code&gt;iced&lt;/code&gt;（Rust 原生 GUI 库），不依赖 GTK 或 Qt。&lt;/li&gt;
&lt;li&gt;特点：内置类似平铺窗口管理器的窗口平铺/浮动切换，风格上介于 GNOME 的简洁与传统桌面（面板 + 应用列表 + 系统托盘）之间。&lt;/li&gt;
&lt;li&gt;现状（2026-07）：Arch &lt;code&gt;extra&lt;/code&gt; 仓库已提供稳定打包（当前 &lt;code&gt;1.2.0-1&lt;/code&gt;），可通过包组 &lt;code&gt;cosmic&lt;/code&gt; 一次性安装。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;kde-plasma-对比-cosmic&#34;&gt;KDE Plasma 对比 COSMIC&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;维度&lt;/th&gt;
          &lt;th&gt;KDE Plasma&lt;/th&gt;
          &lt;th&gt;COSMIC&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;实现语言/工具包&lt;/td&gt;
          &lt;td&gt;C++ / Qt + QML&lt;/td&gt;
          &lt;td&gt;Rust / iced&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;显示协议&lt;/td&gt;
          &lt;td&gt;X11 + Wayland 双支持&lt;/td&gt;
          &lt;td&gt;仅 Wayland（&lt;code&gt;cosmic-comp&lt;/code&gt; 基于 Smithay）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;项目历史&lt;/td&gt;
          &lt;td&gt;1996 年至今，成熟度极高&lt;/td&gt;
          &lt;td&gt;2022 年立项，2024~2025 年逐步稳定，仍在快速迭代&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;窗口管理风格&lt;/td&gt;
          &lt;td&gt;浮动窗口为主，插件式支持平铺（如 KWin 脚本、Bismuth）&lt;/td&gt;
          &lt;td&gt;原生内置平铺/浮动切换，无需插件&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;可定制程度&lt;/td&gt;
          &lt;td&gt;极高：几乎每个组件（面板、快捷键、主题、特效）都可深度配置&lt;/td&gt;
          &lt;td&gt;目前较克制，配置项比 Plasma 少很多，走&amp;quot;够用即可&amp;quot;路线&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;默认发行版&lt;/td&gt;
          &lt;td&gt;Kubuntu、openSUSE、Arch 等（无绑定）&lt;/td&gt;
          &lt;td&gt;Pop!_OS（System76 主推，未来默认桌面）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;资源占用&lt;/td&gt;
          &lt;td&gt;中等，特效多时略高&lt;/td&gt;
          &lt;td&gt;更轻量，Rust 实现 + 无 Qt/GTK 依赖&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;应用生态&lt;/td&gt;
          &lt;td&gt;庞大（KDE Applications 套件：Dolphin、Kate、Okular、Konsole 等）&lt;/td&gt;
          &lt;td&gt;尚在建设中（&lt;code&gt;cosmic-files&lt;/code&gt;、&lt;code&gt;cosmic-terminal&lt;/code&gt;、&lt;code&gt;cosmic-text-editor&lt;/code&gt; 等基础应用刚起步）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;主题/外观定制&lt;/td&gt;
          &lt;td&gt;支持第三方主题、图标包、Global Theme 一键换肤&lt;/td&gt;
          &lt;td&gt;目前主题选择有限，风格由官方统一把控（类似 GNOME 的&amp;quot;少即是多&amp;quot;哲学）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;登录界面集成&lt;/td&gt;
          &lt;td&gt;SDDM（KWallet 自动解锁等深度集成）&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;cosmic-greeter&lt;/code&gt;（greetd），风格与桌面统一，但生态集成不如 SDDM 成熟&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;适合人群&lt;/td&gt;
          &lt;td&gt;想要高度自定义、功能全面、多年验证的稳定桌面&lt;/td&gt;
          &lt;td&gt;想尝鲜 Rust 生态新桌面、偏好简洁一致设计、愿意接受少数功能还不完善&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一句话总结：&lt;strong&gt;Plasma 是&amp;quot;功能全面、可深度定制&amp;quot;的成熟老牌桌面；COSMIC 是&amp;quot;简洁统一、技术栈新颖&amp;quot;的年轻桌面&lt;/strong&gt;，目前更适合尝鲜和轻量使用，还不建议完全替代 Plasma 作为主力日常桌面。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hugo &#43; Cloudflare Pages 搭建个人博客</title>
      <link>https://blog-3wz.pages.dev/hugo-cloudflare-pages-blog-setup/</link>
      <pubDate>Thu, 09 Jul 2026 23:44:19 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/hugo-cloudflare-pages-blog-setup/</guid>
      <description>&lt;p&gt;本文记录这个博客的搭建方式，从买域名到发布一个静态站点。技术选型和步骤与本站的实现保持一致。&lt;/p&gt;
&lt;h2 id=&#34;这套技术栈长什么样&#34;&gt;这套技术栈长什么样&lt;/h2&gt;
&lt;p&gt;一句话概览：用 Hugo 把 Markdown 编译成静态页面，源码在 GitHub，Cloudflare Pages 连接 GitHub 仓库并在 Cloudflare 侧构建、托管，域名解析和 CDN 也在 Cloudflare。&lt;/p&gt;
&lt;p&gt;各部分的分工：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;组件&lt;/th&gt;
          &lt;th&gt;作用&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Hugo&lt;/td&gt;
          &lt;td&gt;静态站点生成器，把 &lt;code&gt;content/&lt;/code&gt; 下的 Markdown 编译成 HTML&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;GitHub&lt;/td&gt;
          &lt;td&gt;存放源码，作为部署的触发源&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Cloudflare Pages&lt;/td&gt;
          &lt;td&gt;连接 GitHub 仓库，执行 &lt;code&gt;hugo --minify&lt;/code&gt; 构建并托管产物&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Cloudflare DNS&lt;/td&gt;
          &lt;td&gt;域名解析，把自定义域名指向 Pages 项目&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Cloudflare CDN&lt;/td&gt;
          &lt;td&gt;边缘缓存与加速，Pages 默认自带&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;整个流程没有用 GitHub Actions，也没有容器化构建，构建这一步完全由 Cloudflare Pages 在它自己的环境里完成。基础站点的构建命令就是一句 &lt;code&gt;hugo --minify&lt;/code&gt;；本站为了顺带生成搜索索引，把它包成了一个很短的脚本（见下文进阶模块），思路一样。&lt;/p&gt;
&lt;h2 id=&#34;基础模块&#34;&gt;基础模块&lt;/h2&gt;
&lt;p&gt;这一部分从 0 到「能访问」。&lt;/p&gt;
&lt;h3 id=&#34;买域名&#34;&gt;买域名&lt;/h3&gt;
&lt;p&gt;域名可以在任意注册商购买，我最早是在 GoDaddy 买的。以 GoDaddy 为例：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开 &lt;a href=&#34;https://www.godaddy.com/&#34;&gt;godaddy.com&lt;/a&gt;，在搜索框里输入想要的域名，看是否可注册。&lt;/li&gt;
&lt;li&gt;选一个后缀（&lt;code&gt;.com&lt;/code&gt;、&lt;code&gt;.dev&lt;/code&gt; 等），加入购物车，结账。注意第一年常有促销价，续费价通常更高，下单前看清续费价格。&lt;/li&gt;
&lt;li&gt;结账时可关掉 GoDaddy 自家的一堆增值服务（邮箱、隐私保护等），后面把 DNS 切到 Cloudflare 后这些大多用不上。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cloudflare 自己也能直接注册域名（Cloudflare Registrar，按批发价、免费 WHOIS 隐私保护），但支持的后缀有限。如果想要的后缀在它的列表里，直接在 Cloudflare 买、省去后面改 Nameserver 的步骤也可以；后缀不在列表里就按上面的思路在别的注册商买，再把 DNS 切过来。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Cloudflare Pages with OpenTofu: 用 IaC 管理 Pages 项目</title>
      <link>https://blog-3wz.pages.dev/cloudflare-pages-opentofu/</link>
      <pubDate>Thu, 09 Jul 2026 23:44:19 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/cloudflare-pages-opentofu/</guid>
      <description>&lt;p&gt;在 Cloudflare 后台点几下就能建好一个 Pages 项目、绑好域名。想把这些配置变成可版本化、可复现的代码，就用 OpenTofu 来管理。本文只讲 Cloudflare 场景的具体写法，Provider、Resource、State 这些基础概念见 &lt;a href=&#34;./opentofu.md&#34;&gt;OpenTofu 入门&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;目标&#34;&gt;目标&lt;/h2&gt;
&lt;p&gt;用 OpenTofu 声明式地管理三样东西：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个连接 GitHub 仓库的 Cloudflare Pages 项目（含构建命令、产物目录、环境变量）&lt;/li&gt;
&lt;li&gt;项目绑定的自定义域名&lt;/li&gt;
&lt;li&gt;指向 Pages 的 DNS 记录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;准备&#34;&gt;准备&lt;/h2&gt;
&lt;p&gt;需要两个 Cloudflare 侧的标识和一个 API Token：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;变量&lt;/th&gt;
          &lt;th&gt;从哪来&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Account ID&lt;/td&gt;
          &lt;td&gt;Cloudflare 后台任意页面右侧栏，或 Workers &amp;amp; Pages 概览页&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Zone ID&lt;/td&gt;
          &lt;td&gt;域名的 Overview 页面右侧栏&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;API Token&lt;/td&gt;
          &lt;td&gt;My Profile → API Tokens → Create Token，授予 Pages 编辑和 DNS 编辑权限&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Token 属于机密，不要写进代码，用环境变量注入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;TF_VAR_cloudflare_api_token&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;your-token-here&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;provider-配置&#34;&gt;Provider 配置&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;terraform&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;required_providers&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    cloudflare&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      source&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cloudflare/cloudflare&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;~&amp;gt; 4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cloudflare_api_token&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  sensitive&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;account_id&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;zone_id&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cloudflare&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;  api_token&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;cloudflare_api_token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;pages-项目&#34;&gt;Pages 项目&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;cloudflare_pages_project&lt;/code&gt; 对应后台的一个 Pages 项目，&lt;code&gt;source&lt;/code&gt; 块声明连接哪个 GitHub 仓库，&lt;code&gt;build_config&lt;/code&gt; 对应构建命令和产物目录，&lt;code&gt;deployment_configs&lt;/code&gt; 里可以设环境变量（例如 &lt;code&gt;HUGO_VERSION&lt;/code&gt;）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W27</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w27/</link>
      <pubDate>Sun, 05 Jul 2026 23:59:59 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w27/</guid>
      <description>&lt;h2 id=&#34;女儿上幼儿园的情绪课&#34;&gt;女儿上幼儿园的情绪课&lt;/h2&gt;
&lt;p&gt;这周女儿在排练小班毕业表演，舞蹈动作有点难，加上分离焦虑，早上去幼儿园成了每天要过的一关。周一那天她抗拒得厉害，做了近一个小时心理建设才送进去，迟到了一小时。&lt;/p&gt;
&lt;p&gt;我试着用她熟悉的东西帮她面对情绪。她在玩《星之卡比》，一开始连第一关的兔子都怕，现在已经把卡比的装备升到四级了。我就问她：现在还怕第一关的兔子吗？她说不怕了。我说幼儿园跳舞也一样，你手里的&amp;quot;冰淇淋&amp;quot;（舞蹈道具）现在是几级装备？她说是一级。我说今天带着它去跳舞，明天就升到二级，跳舞就没那么难了。她点点头，跟妈妈说了再见，蹦蹦跳跳去幼儿园&amp;quot;升级装备&amp;quot;了。&lt;/p&gt;
&lt;p&gt;后面几天肉眼可见地在进步。周三到门口离开妈妈还会有点不开心，安抚一会儿就自己跑进去了。周四早上我在路上问她冰淇淋几级了，她说二级；我说今天再升一级，她纠正我：不对，上午能升一级，下午还能再升一级。大概她的神经网络已经把跳舞和打怪升级关联起来了。&lt;/p&gt;
&lt;p&gt;比起替她扛下情绪，更想让她自己有面对情绪的办法。这套比喻能不能一直管用不好说，但这周是有效的。&lt;/p&gt;
&lt;p&gt;周六全天带娃，出门时她的&amp;quot;小怪兽钱包&amp;quot;里有些现金。到星海广场，她自己花十块买了一袋海鸥食，又花三十坐了小火车，接着想玩旋转木马，翻钱包发现只剩十三块六了。她开始琢磨：游乐场都是收费三十吗？我说我们去找找十三块能玩哪个。绕了一圈，路过一个转飞船的场地，工作人员大姐答应十三块让她上去坐一圈。让她花自己的压岁钱，她就开始比较各种东西的价格了。&lt;/p&gt;
&lt;h2 id=&#34;求职&#34;&gt;求职&lt;/h2&gt;
&lt;p&gt;周二收到了一家公司的面试邀请，周五去参加，过程还算顺利，有些问题答得还好，有些答得一般。目前结果未知。&lt;/p&gt;
&lt;h2 id=&#34;咖啡蒸气奶测试&#34;&gt;咖啡：蒸气奶测试&lt;/h2&gt;
&lt;p&gt;某天中午送老婆去公司后，我又带电脑在她楼下的星巴克找了个座位。那天出门晚，担心喝咖啡影响睡眠，又不好久占座位，翻了半天菜单，看到一项叫&amp;quot;蒸气奶&amp;quot;。跟 AI 确认了一下，蒸气奶大致等于拿铁去掉咖啡。之前喝拿铁不会触发乳糖不耐，蒸气奶应该也安全。选项里有牛奶也有燕麦奶，我选了普通牛奶——顺便测试一下：蒸气乳化的过程据说能分解一部分乳糖，气泡也可能减缓乳糖进入肠道的速度。结果跟之前喝拿铁一样，喝完没有触发乳糖不耐的症状。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Why the Blog Looked Quiet 一次构建失败导致的「假性停更」</title>
      <link>https://blog-3wz.pages.dev/why-the-blog-looked-quiet/</link>
      <pubDate>Tue, 30 Jun 2026 14:46:12 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/why-the-blog-looked-quiet/</guid>
      <description>&lt;p&gt;本文是一条故障记录。&lt;/p&gt;
&lt;p&gt;最近两天 wiloon.com 看起来像是“停更”，停在6月28号。但其实 blog 仓库是有更新的，也提交了，只是没能发布出来——博客有大约两天卡在一次构建失败上，而我自己一直不知道。&lt;/p&gt;
&lt;h2 id=&#34;不是停更是没发布出去&#34;&gt;不是停更，是没发布出去&lt;/h2&gt;
&lt;p&gt;现象很简单：本地写好、&lt;code&gt;git push&lt;/code&gt; 之后，wiloon.com 上看不到新内容。一开始我以为是 CDN 缓存或者部署延迟，没太在意。后来才发现是构建一直在失败——新提交根本没被发布出去。&lt;/p&gt;
&lt;h2 id=&#34;怎么坏的&#34;&gt;怎么坏的&lt;/h2&gt;
&lt;p&gt;原因是文章标题里的一个冒号。&lt;/p&gt;
&lt;p&gt;博客用 Hugo，文章开头的 front matter 是一段 YAML。我有几篇 Java/Spring 的文章标题是英中混写的，里面带了「冒号 + 空格」，比如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# breaks the build: &amp;#34;: &amp;#34; makes YAML parse it as a mapping&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title: Spring WebFlux&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;响应式 Web 框架&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 YAML 里，&lt;code&gt;: &lt;/code&gt;（冒号加空格）是 key/value 的分隔符。没加引号时，解析器会把这一行当成一个嵌套映射来读，于是报错、Hugo 构建中止。一篇的 front matter 解析失败，整站就一个页面都不生成。&lt;/p&gt;
&lt;p&gt;修复其实只要把整个标题值用引号包起来：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# fixed: quote the whole value so the colon is just text&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Spring WebFlux: 响应式 Web 框架&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加上引号之后，构建立刻就恢复了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2026 W26</title>
      <link>https://blog-3wz.pages.dev/weekly-2026-w26/</link>
      <pubDate>Sun, 28 Jun 2026 23:59:59 +0800</pubDate>
      <guid>https://blog-3wz.pages.dev/weekly-2026-w26/</guid>
      <description>&lt;h2 id=&#34;enx-加-java-后端&#34;&gt;enx 加 Java 后端&lt;/h2&gt;
&lt;p&gt;最近投了 Java 方向的职位，这段时间在回忆和熟悉 Java/Spring，也在整理 blog 里之前攒下的资料。但只看文档、不动手，理解很有限。过去做 Java 项目时训练过的&amp;quot;生物神经网络&amp;quot;痕迹应该还在，细节被修剪掉了，主要的连接还在，得花点时间把细节重新接上。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/wiloon/enx&#34;&gt;enx&lt;/a&gt; 是我写的一个英文学习工具，也是技术栈的 playground。这周给 enx 加了一个 Spring Boot 后端，把一个简单的 API 迁了过去，依赖走 Homelab 里的 Nexus Maven 私服，构建和部署接到现有的 Tekton + k8s 流水线上：推代码后 Tekton 自动打镜像、更新到集群。这样一个最小闭环先跑起来，后面再慢慢补。&lt;/p&gt;
&lt;h2 id=&#34;梳理-javaspring-文档&#34;&gt;梳理 Java/Spring 文档&lt;/h2&gt;
&lt;p&gt;接着 W25 的节奏，继续整理 blog 里的 Java 文档，这周重心移到 Spring 和 JVM 周边。大脑像是索引和内存，blog 像是外部存储；脑子里的东西大概是 blog 内容的一个子集加上索引，有交叉，但也不是所有东西都写进了 blog。整理的过程就像是顺着索引把外存里的细节重新梳理一下。&lt;/p&gt;
&lt;p&gt;这几个文档是本周动过的，方便以后自己回溯：classloader、Spring IoC 与 Spring Boot、graalvm native image、HotSpot，以及顺手补的 SPI / ServiceLoader 和 YAGNI。&lt;/p&gt;
&lt;h2 id=&#34;公司领照刻章开户&#34;&gt;公司：领照、刻章、开户&lt;/h2&gt;
&lt;p&gt;W24 注册了公司，这周把领营业执照、刻章办了，银行开户排到了下周。本来 6 月 24 日计划去领照，车启动打开导航才发现当天大连有达沃斯论坛限行，只好折回，在家准备面试和注册材料。第二天才正式跑完一圈。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
